blob: c54e9e50675fc65efd70c9a81db8fc24f9b5bb1c [file] [log] [blame]
Julian Halle35efa52022-10-31 16:34:58 +00001/*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <assert.h>
9#include <stdlib.h>
10#include <string.h>
11#include <common/uuid/uuid.h>
12#include <protocols/service/fwu/packed-c/status.h>
13#include <protocols/service/fwu/packed-c/fwu_proto.h>
14#include <service/fwu/fw_store/fw_store.h>
15#include <service/fwu/inspector/fw_inspector.h>
16#include "img_dir_serializer.h"
17#include "update_agent.h"
18
19
20static bool open_image_directory(
21 struct update_agent *update_agent,
22 const struct uuid_octets *uuid,
23 uint32_t *handle,
24 int *status);
25
26static bool open_fw_store_object(
27 struct update_agent *update_agent,
28 const struct uuid_octets *uuid,
29 uint32_t *handle,
30 int *status);
31
32static bool open_fw_image(
33 struct update_agent *update_agent,
34 const struct uuid_octets *uuid,
35 uint32_t *handle,
36 int *status);
37
38
39int update_agent_init(
40 struct update_agent *update_agent,
41 unsigned int boot_index,
42 fw_inspector_inspect fw_inspect_method,
43 struct fw_store *fw_store)
44{
45 assert(update_agent);
46 assert(fw_inspect_method);
47 assert(fw_store);
48
49 int status = FWU_STATUS_UNKNOWN;
50
51 update_agent->state = FWU_STATE_INITIALIZING;
52 update_agent->fw_inspect_method = fw_inspect_method;
53 update_agent->fw_store = fw_store;
54 update_agent->image_dir_buf_size = 0;
55 update_agent->image_dir_buf = NULL;
56
57 stream_manager_init(&update_agent->stream_manager);
58
59 /* Initialize and populate the fw_directory. The fw_inspector will
60 * obtain trustworthy information about the booted firmware and
61 * populate the fw_directory to reflect information about the booted
62 * firmware.
63 */
64 fw_directory_init(&update_agent->fw_directory);
65
66 status = update_agent->fw_inspect_method(
67 &update_agent->fw_directory,
68 boot_index);
69 if (status != FWU_STATUS_SUCCESS)
70 return status;
71
72 /* Allow the associated fw_store to synchronize its state to the
73 * state of the booted firmware reflected by the fw_directory.
74 */
75 status = fw_store_synchronize(
76 update_agent->fw_store,
77 &update_agent->fw_directory,
78 boot_index);
79 if (status != FWU_STATUS_SUCCESS)
80 return status;
81
82 /* Allocate a buffer for holding the serialized image directory */
83 update_agent->image_dir_buf_size = img_dir_serializer_get_len(&update_agent->fw_directory);
84 update_agent->image_dir_buf = malloc(update_agent->image_dir_buf_size);
85 if (!update_agent->image_dir_buf)
86 return FWU_STATUS_UNKNOWN;
87
88 /* Transition to initial state */
89 update_agent->state =
90 fw_store_is_trial(update_agent->fw_store) ?
91 FWU_STATE_TRIAL : FWU_STATE_REGULAR;
92
93 return FWU_STATUS_SUCCESS;
94}
95
96void update_agent_deinit(
97 struct update_agent *update_agent)
98{
99 update_agent->state = FWU_STATE_DEINITIALZED;
100
101 free(update_agent->image_dir_buf);
102 fw_directory_deinit(&update_agent->fw_directory);
103 stream_manager_deinit(&update_agent->stream_manager);
104}
105
106int update_agent_begin_staging(
107 struct update_agent *update_agent)
108{
109 int status = FWU_STATUS_DENIED;
110
111 /* If already staging, any previous installation state is discarded */
112 update_agent_cancel_staging(update_agent);
113
114 if (update_agent->state == FWU_STATE_REGULAR) {
115
116 status = fw_store_begin_install(update_agent->fw_store);
117
118 /* Check if ready to install images */
119 if (status == FWU_STATUS_SUCCESS)
120 update_agent->state = FWU_STATE_STAGING;
121 }
122
123 return status;
124}
125
126int update_agent_end_staging(
127 struct update_agent *update_agent)
128{
129 int status = FWU_STATUS_DENIED;
130
131 if (update_agent->state == FWU_STATE_STAGING) {
132
133 /* The client is responsible for committing each installed image. If any
134 * install streams have been left open, not all images were committed.
135 */
136 bool any_uncommitted = stream_manager_is_open_streams(
137 &update_agent->stream_manager, FWU_STREAM_TYPE_INSTALL);
138
139 if (!any_uncommitted) {
140
141 /* All installed images have been committed so we're
142 * ready for a trial.
143 */
144 status = fw_store_finalize_install(update_agent->fw_store);
145
146 if (status == FWU_STATUS_SUCCESS)
147 /* Transition to TRAIL_PENDING state. The trial actually starts
148 * when installed images are activated through a system restart.
149 */
150 update_agent->state = FWU_STATE_TRIAL_PENDING;
151
152 } else {
153
154 /* Client failed to commit all images installed */
155 status = FWU_STATUS_BUSY;
156 }
157 }
158
159 return status;
160}
161
162int update_agent_cancel_staging(
163 struct update_agent *update_agent)
164{
165 int status = FWU_STATUS_DENIED;
166
167 if (update_agent->state == FWU_STATE_STAGING) {
168
169 stream_manager_cancel_streams(
170 &update_agent->stream_manager, FWU_STREAM_TYPE_INSTALL);
171
172 fw_store_cancel_install(update_agent->fw_store);
173
174 update_agent->state = FWU_STATE_REGULAR;
175
176 status = FWU_STATUS_SUCCESS;
177 }
178
179 return status;
180}
181
182int update_agent_accept(
183 struct update_agent *update_agent,
184 const struct uuid_octets *image_type_uuid)
185{
186 int status = FWU_STATUS_DENIED;
187
188 if (update_agent->state == FWU_STATE_TRIAL) {
189
190 const struct image_info *image_info = fw_directory_find_image_info(
191 &update_agent->fw_directory,
192 image_type_uuid);
193
194 if (image_info) {
195
196 if (fw_store_notify_accepted(
197 update_agent->fw_store, image_info)) {
198
199 /* From the fw_store perspective, the update has
200 * been fully accepted.
201 */
202 status = fw_store_commit_to_update(update_agent->fw_store);
203 update_agent->state = FWU_STATE_REGULAR;
204
205 } else
206 /* Still more images to accept */
207 status = FWU_STATUS_SUCCESS;
208 } else
209 /* Unrecognised image uuid */
210 status = FWU_STATUS_UNKNOWN;
211 }
212
213 return status;
214}
215
216int update_agent_select_previous(
217 struct update_agent *update_agent)
218{
219 int status = FWU_STATUS_DENIED;
220
221 if ((update_agent->state == FWU_STATE_TRIAL) ||
222 (update_agent->state == FWU_STATE_TRIAL_PENDING)) {
223
224 status = fw_store_revert_to_previous(update_agent->fw_store);
225 update_agent->state = FWU_STATE_REGULAR;
226 }
227
228 return status;
229}
230
231int update_agent_open(
232 struct update_agent *update_agent,
233 const struct uuid_octets *uuid,
234 uint32_t *handle)
235{
236 int status;
237
238 /* Pass UUID along a chain-of-responsibility until it's handled */
239 if (!open_image_directory(update_agent, uuid, handle, &status) &&
240 !open_fw_store_object(update_agent, uuid, handle, &status) &&
241 !open_fw_image(update_agent, uuid, handle, &status)) {
242
243 /* UUID not recognised */
244 status = FWU_STATUS_UNKNOWN;
245 }
246
247 return status;
248}
249
250int update_agent_commit(
251 struct update_agent *update_agent,
252 uint32_t handle,
253 bool accepted)
254{
255 return stream_manager_close(
256 &update_agent->stream_manager,
257 handle,
258 accepted);
259}
260
261int update_agent_write_stream(
262 struct update_agent *update_agent,
263 uint32_t handle,
264 const uint8_t *data,
265 size_t data_len)
266{
267 return stream_manager_write(
268 &update_agent->stream_manager,
269 handle,
270 data, data_len);
271}
272
273int update_agent_read_stream(
274 struct update_agent *update_agent,
275 uint32_t handle,
276 uint8_t *buf,
277 size_t buf_size,
278 size_t *read_len,
279 size_t *total_len)
280{
281 return stream_manager_read(
282 &update_agent->stream_manager,
283 handle,
284 buf, buf_size,
285 read_len, total_len);
286}
287
288static bool open_image_directory(
289 struct update_agent *update_agent,
290 const struct uuid_octets *uuid,
291 uint32_t *handle,
292 int *status)
293{
294 struct uuid_octets target_uuid;
295
296 uuid_guid_octets_from_canonical(&target_uuid, FWU_DIRECTORY_CANONICAL_UUID);
297
298 if (uuid_is_equal(uuid->octets, target_uuid.octets)) {
299
300 /* Serialize a fresh view of the image directory */
301 size_t serialized_len = 0;
302
303 *status = img_dir_serializer_serialize(
304 &update_agent->fw_directory,
305 update_agent->fw_store,
306 update_agent->image_dir_buf,
307 update_agent->image_dir_buf_size,
308 &serialized_len);
309
310 if (*status == FWU_STATUS_SUCCESS) {
311
312 *status = stream_manager_open_buffer_stream(
313 &update_agent->stream_manager,
314 update_agent->image_dir_buf,
315 serialized_len,
316 handle);
317 }
318
319 return true;
320 }
321
322 return false;
323}
324
325static bool open_fw_store_object(
326 struct update_agent *update_agent,
327 const struct uuid_octets *uuid,
328 uint32_t *handle,
329 int *status)
330{
331 const uint8_t *exported_data;
332 size_t exported_data_len;
333
334 if (fw_store_export(
335 update_agent->fw_store,
336 uuid,
337 &exported_data, &exported_data_len,
338 status)) {
339
340 if (*status == FWU_STATUS_SUCCESS) {
341
342 *status = stream_manager_open_buffer_stream(
343 &update_agent->stream_manager,
344 exported_data,
345 exported_data_len,
346 handle);
347 }
348
349 return true;
350 }
351
352 return false;
353}
354
355static bool open_fw_image(
356 struct update_agent *update_agent,
357 const struct uuid_octets *uuid,
358 uint32_t *handle,
359 int *status)
360{
361 const struct image_info *image_info = fw_directory_find_image_info(
362 &update_agent->fw_directory,
363 uuid);
364
365 if (image_info) {
366
367 if (update_agent->state == FWU_STATE_STAGING) {
368
369 struct installer *installer;
370
371 *status = fw_store_select_installer(
372 update_agent->fw_store,
373 image_info,
374 &installer);
375
376 if (*status == FWU_STATUS_SUCCESS) {
377
378 *status = stream_manager_open_install_stream(
379 &update_agent->stream_manager,
380 update_agent->fw_store,
381 installer,
382 image_info,
383 handle);
384 }
385 } else {
386
387 /* Attempting to open a fw image when not staging */
388 *status = FWU_STATUS_DENIED;
389 }
390
391 return true;
392 }
393
394 return false;
395}