1 /*
2 * Copyright (c) 2022-2024, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <CppUTest/TestHarness.h>
8 #include <vector>
9
10 #include "protocols/service/fwu/status.h"
11 #include "service/fwu/test/fwu_dut/fwu_dut.h"
12 #include "service/fwu/test/fwu_dut_factory/fwu_dut_factory.h"
13 /*
14 * Tests to check that FWU metadata is never left in an invalid state
15 * during the update process when unexpected power failures occur. Power
16 * failures are simulated by shutting down the DUT after each write to
17 * metadata and re-boot to check all conditions for a successful boot
18 * are met.
19 */
TEST_GROUP(FwuPowerFailureTests)20 TEST_GROUP(FwuPowerFailureTests)
21 {
22 void setup()
23 {
24 m_dut = NULL;
25 m_fwu_client = NULL;
26 m_metadata_checker = NULL;
27 }
28
29 void teardown()
30 {
31 delete m_metadata_checker;
32 m_metadata_checker = NULL;
33
34 delete m_fwu_client;
35 m_fwu_client = NULL;
36
37 delete m_dut;
38 m_dut = NULL;
39 }
40
41 fwu_dut *m_dut;
42 metadata_checker *m_metadata_checker;
43 fwu_client *m_fwu_client;
44 };
45
TEST(FwuPowerFailureTests,powerFailureDuringStaging)46 TEST(FwuPowerFailureTests, powerFailureDuringStaging)
47 {
48 int status = 0;
49 struct uuid_octets uuid;
50 uint32_t stream_handle = 0;
51 std::vector<uint8_t> image_data;
52
53 m_dut = fwu_dut_factory::create(3, true);
54 m_fwu_client = m_dut->create_fwu_client();
55 m_metadata_checker = m_dut->create_metadata_checker();
56
57 m_dut->boot();
58
59 /* Check assumptions about the first boot. */
60 struct boot_info boot_info = m_dut->get_boot_info();
61 UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
62 m_metadata_checker->check_regular(boot_info.boot_index);
63
64 /* Begin staging */
65 status = m_fwu_client->begin_staging(0, 0, NULL);
66 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
67 m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
68
69 /* Power cycle */
70 m_dut->shutdown();
71 m_dut->boot();
72
73 /* Expect to reboot into the regular state without errors */
74 boot_info = m_dut->get_boot_info();
75 m_metadata_checker->check_regular(boot_info.boot_index);
76
77 /* Begin staging again */
78 status = m_fwu_client->begin_staging(0, 0, NULL);
79 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
80 m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
81
82 /* Start installing an image but don't commit it */
83 m_dut->whole_volume_image_type_uuid(0, &uuid);
84 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
85 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
86
87 m_dut->generate_image_data(&image_data);
88
89 status = m_fwu_client->write_stream(stream_handle,
90 reinterpret_cast<const uint8_t *>(image_data.data()),
91 image_data.size());
92 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
93
94 /* Power cycle */
95 m_dut->shutdown();
96 m_dut->boot();
97
98 /* Expect to reboot into the regular state without errors */
99 boot_info = m_dut->get_boot_info();
100 m_metadata_checker->check_regular(boot_info.boot_index);
101
102 /* Begin staging again */
103 status = m_fwu_client->begin_staging(0, 0, NULL);
104 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
105 m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
106
107 /* Start installing an image but this time commit it without ending staging */
108 m_dut->whole_volume_image_type_uuid(1, &uuid);
109 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
110 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
111
112 m_dut->generate_image_data(&image_data);
113
114 status = m_fwu_client->write_stream(stream_handle,
115 reinterpret_cast<const uint8_t *>(image_data.data()),
116 image_data.size());
117 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
118
119 status = m_fwu_client->commit(stream_handle, false);
120 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
121
122 /* Power cycle */
123 m_dut->shutdown();
124 m_dut->boot();
125
126 /* Expect to reboot into the regular state without errors */
127 boot_info = m_dut->get_boot_info();
128 m_metadata_checker->check_regular(boot_info.boot_index);
129 }
130
TEST(FwuPowerFailureTests,powerFailureDuringTrial)131 TEST(FwuPowerFailureTests, powerFailureDuringTrial)
132 {
133 int status = 0;
134 struct uuid_octets uuid;
135 uint32_t stream_handle = 0;
136 std::vector<uint8_t> image_data;
137
138 m_dut = fwu_dut_factory::create(3, true);
139 m_fwu_client = m_dut->create_fwu_client();
140 m_metadata_checker = m_dut->create_metadata_checker();
141
142 m_dut->boot();
143
144 /* Check assumptions about the first boot. */
145 struct boot_info boot_info = m_dut->get_boot_info();
146 UNSIGNED_LONGS_EQUAL(boot_info.boot_index, boot_info.active_index);
147 m_metadata_checker->check_regular(boot_info.boot_index);
148
149 /* Begin staging */
150 status = m_fwu_client->begin_staging(0, 0, NULL);
151 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
152 m_metadata_checker->check_ready_for_staging(boot_info.boot_index);
153
154 /* Install a partial update */
155 m_dut->whole_volume_image_type_uuid(2, &uuid);
156 status = m_fwu_client->open(&uuid, fwu_client::op_type::WRITE, &stream_handle);
157 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
158
159 m_dut->generate_image_data(&image_data);
160
161 status = m_fwu_client->write_stream(stream_handle,
162 reinterpret_cast<const uint8_t *>(image_data.data()),
163 image_data.size());
164 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
165
166 status = m_fwu_client->commit(stream_handle, false);
167 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
168
169 /* Transition to the trial state */
170 status = m_fwu_client->end_staging();
171 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
172 m_metadata_checker->check_ready_to_activate(boot_info.boot_index);
173
174 /* Power cycle */
175 m_dut->shutdown();
176 m_dut->boot();
177
178 /* Check the metadata after the reboot to activate the update */
179 boot_info = m_dut->get_boot_info();
180 m_metadata_checker->check_trial(boot_info.boot_index);
181
182 /* Power cycle again */
183 m_dut->shutdown();
184 m_dut->boot();
185
186 /* Check trial is still active */
187 boot_info = m_dut->get_boot_info();
188 m_metadata_checker->check_trial(boot_info.boot_index);
189
190 /* Power cycle again */
191 m_dut->shutdown();
192 m_dut->boot();
193
194 /* Check trial is still active */
195 boot_info = m_dut->get_boot_info();
196 m_metadata_checker->check_trial(boot_info.boot_index);
197
198 /* Only image 2 should need accepting as it was the only image updated */
199 m_dut->whole_volume_image_type_uuid(2, &uuid);
200 status = m_fwu_client->accept(&uuid);
201 LONGS_EQUAL(FWU_STATUS_SUCCESS, status);
202
203 /* Power cycle again */
204 m_dut->shutdown();
205 m_dut->boot();
206
207 /* Check transition to regular */
208 boot_info = m_dut->get_boot_info();
209 m_metadata_checker->check_regular(boot_info.boot_index);
210 }
211