blob: 2a4d19d999471ef4a35d44827ae302eb61757968 [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
Gyorgy Szing3c446242023-03-31 01:53:15 +02008#include "update_agent.h"
9
Julian Halle35efa52022-10-31 16:34:58 +000010#include <assert.h>
11#include <stdlib.h>
12#include <string.h>
Gyorgy Szing3c446242023-03-31 01:53:15 +020013
14#include "common/uuid/uuid.h"
Julian Halle35efa52022-10-31 16:34:58 +000015#include "img_dir_serializer.h"
Gyorgy Szing3c446242023-03-31 01:53:15 +020016#include "protocols/service/fwu/packed-c/fwu_proto.h"
17#include "protocols/service/fwu/packed-c/status.h"
18#include "service/fwu/fw_store/fw_store.h"
19#include "service/fwu/inspector/fw_inspector.h"
Julian Halle35efa52022-10-31 16:34:58 +000020
Gyorgy Szing3c446242023-03-31 01:53:15 +020021static bool open_image_directory(struct update_agent *update_agent, const struct uuid_octets *uuid,
22 uint32_t *handle, int *status);
Julian Halle35efa52022-10-31 16:34:58 +000023
Gyorgy Szing3c446242023-03-31 01:53:15 +020024static bool open_fw_store_object(struct update_agent *update_agent, const struct uuid_octets *uuid,
25 uint32_t *handle, int *status);
Julian Halle35efa52022-10-31 16:34:58 +000026
Gyorgy Szing3c446242023-03-31 01:53:15 +020027static bool open_fw_image(struct update_agent *update_agent, const struct uuid_octets *uuid,
28 uint32_t *handle, int *status);
Julian Halle35efa52022-10-31 16:34:58 +000029
Gyorgy Szing3c446242023-03-31 01:53:15 +020030int update_agent_init(struct update_agent *update_agent, unsigned int boot_index,
31 fw_inspector_inspect fw_inspect_method, struct fw_store *fw_store)
Julian Halle35efa52022-10-31 16:34:58 +000032{
33 assert(update_agent);
34 assert(fw_inspect_method);
35 assert(fw_store);
36
37 int status = FWU_STATUS_UNKNOWN;
38
39 update_agent->state = FWU_STATE_INITIALIZING;
40 update_agent->fw_inspect_method = fw_inspect_method;
41 update_agent->fw_store = fw_store;
42 update_agent->image_dir_buf_size = 0;
43 update_agent->image_dir_buf = NULL;
44
45 stream_manager_init(&update_agent->stream_manager);
46
47 /* Initialize and populate the fw_directory. The fw_inspector will
48 * obtain trustworthy information about the booted firmware and
49 * populate the fw_directory to reflect information about the booted
50 * firmware.
51 */
52 fw_directory_init(&update_agent->fw_directory);
53
Gyorgy Szing3c446242023-03-31 01:53:15 +020054 status = update_agent->fw_inspect_method(&update_agent->fw_directory, boot_index);
Julian Halle35efa52022-10-31 16:34:58 +000055 if (status != FWU_STATUS_SUCCESS)
56 return status;
57
58 /* Allow the associated fw_store to synchronize its state to the
59 * state of the booted firmware reflected by the fw_directory.
60 */
Gyorgy Szing3c446242023-03-31 01:53:15 +020061 status = fw_store_synchronize(update_agent->fw_store, &update_agent->fw_directory,
62 boot_index);
Julian Halle35efa52022-10-31 16:34:58 +000063 if (status != FWU_STATUS_SUCCESS)
64 return status;
65
66 /* Allocate a buffer for holding the serialized image directory */
67 update_agent->image_dir_buf_size = img_dir_serializer_get_len(&update_agent->fw_directory);
68 update_agent->image_dir_buf = malloc(update_agent->image_dir_buf_size);
69 if (!update_agent->image_dir_buf)
70 return FWU_STATUS_UNKNOWN;
71
72 /* Transition to initial state */
Gyorgy Szing3c446242023-03-31 01:53:15 +020073 update_agent->state = fw_store_is_trial(update_agent->fw_store) ? FWU_STATE_TRIAL :
74 FWU_STATE_REGULAR;
Julian Halle35efa52022-10-31 16:34:58 +000075
76 return FWU_STATUS_SUCCESS;
77}
78
Gyorgy Szing3c446242023-03-31 01:53:15 +020079void update_agent_deinit(struct update_agent *update_agent)
Julian Halle35efa52022-10-31 16:34:58 +000080{
81 update_agent->state = FWU_STATE_DEINITIALZED;
82
83 free(update_agent->image_dir_buf);
84 fw_directory_deinit(&update_agent->fw_directory);
85 stream_manager_deinit(&update_agent->stream_manager);
86}
87
Gyorgy Szing3c446242023-03-31 01:53:15 +020088int update_agent_begin_staging(struct update_agent *update_agent)
Julian Halle35efa52022-10-31 16:34:58 +000089{
90 int status = FWU_STATUS_DENIED;
91
92 /* If already staging, any previous installation state is discarded */
93 update_agent_cancel_staging(update_agent);
94
95 if (update_agent->state == FWU_STATE_REGULAR) {
Julian Halle35efa52022-10-31 16:34:58 +000096 status = fw_store_begin_install(update_agent->fw_store);
97
98 /* Check if ready to install images */
99 if (status == FWU_STATUS_SUCCESS)
100 update_agent->state = FWU_STATE_STAGING;
101 }
102
103 return status;
104}
105
Gyorgy Szing3c446242023-03-31 01:53:15 +0200106int update_agent_end_staging(struct update_agent *update_agent)
Julian Halle35efa52022-10-31 16:34:58 +0000107{
108 int status = FWU_STATUS_DENIED;
109
110 if (update_agent->state == FWU_STATE_STAGING) {
Julian Halle35efa52022-10-31 16:34:58 +0000111 /* The client is responsible for committing each installed image. If any
112 * install streams have been left open, not all images were committed.
113 */
Gyorgy Szing3c446242023-03-31 01:53:15 +0200114 bool any_uncommitted = stream_manager_is_open_streams(&update_agent->stream_manager,
115 FWU_STREAM_TYPE_INSTALL);
Julian Halle35efa52022-10-31 16:34:58 +0000116
117 if (!any_uncommitted) {
Julian Halle35efa52022-10-31 16:34:58 +0000118 /* All installed images have been committed so we're
119 * ready for a trial.
120 */
121 status = fw_store_finalize_install(update_agent->fw_store);
122
123 if (status == FWU_STATUS_SUCCESS)
124 /* Transition to TRAIL_PENDING state. The trial actually starts
125 * when installed images are activated through a system restart.
126 */
127 update_agent->state = FWU_STATE_TRIAL_PENDING;
128
129 } else {
Julian Halle35efa52022-10-31 16:34:58 +0000130 /* Client failed to commit all images installed */
131 status = FWU_STATUS_BUSY;
132 }
133 }
134
135 return status;
136}
137
Gyorgy Szing3c446242023-03-31 01:53:15 +0200138int update_agent_cancel_staging(struct update_agent *update_agent)
Julian Halle35efa52022-10-31 16:34:58 +0000139{
140 int status = FWU_STATUS_DENIED;
141
142 if (update_agent->state == FWU_STATE_STAGING) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200143 stream_manager_cancel_streams(&update_agent->stream_manager,
144 FWU_STREAM_TYPE_INSTALL);
Julian Halle35efa52022-10-31 16:34:58 +0000145
146 fw_store_cancel_install(update_agent->fw_store);
147
148 update_agent->state = FWU_STATE_REGULAR;
149
150 status = FWU_STATUS_SUCCESS;
151 }
152
153 return status;
154}
155
Gyorgy Szing3c446242023-03-31 01:53:15 +0200156int update_agent_accept(struct update_agent *update_agent,
157 const struct uuid_octets *image_type_uuid)
Julian Halle35efa52022-10-31 16:34:58 +0000158{
159 int status = FWU_STATUS_DENIED;
160
161 if (update_agent->state == FWU_STATE_TRIAL) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200162 const struct image_info *image_info =
163 fw_directory_find_image_info(&update_agent->fw_directory, image_type_uuid);
Julian Halle35efa52022-10-31 16:34:58 +0000164
165 if (image_info) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200166 if (fw_store_notify_accepted(update_agent->fw_store, image_info)) {
Julian Halle35efa52022-10-31 16:34:58 +0000167 /* From the fw_store perspective, the update has
168 * been fully accepted.
169 */
170 status = fw_store_commit_to_update(update_agent->fw_store);
171 update_agent->state = FWU_STATE_REGULAR;
172
173 } else
174 /* Still more images to accept */
175 status = FWU_STATUS_SUCCESS;
176 } else
177 /* Unrecognised image uuid */
178 status = FWU_STATUS_UNKNOWN;
179 }
180
181 return status;
182}
183
Gyorgy Szing3c446242023-03-31 01:53:15 +0200184int update_agent_select_previous(struct update_agent *update_agent)
Julian Halle35efa52022-10-31 16:34:58 +0000185{
186 int status = FWU_STATUS_DENIED;
187
188 if ((update_agent->state == FWU_STATE_TRIAL) ||
Gyorgy Szing3c446242023-03-31 01:53:15 +0200189 (update_agent->state == FWU_STATE_TRIAL_PENDING)) {
Julian Halle35efa52022-10-31 16:34:58 +0000190 status = fw_store_revert_to_previous(update_agent->fw_store);
191 update_agent->state = FWU_STATE_REGULAR;
192 }
193
194 return status;
195}
196
Gyorgy Szing3c446242023-03-31 01:53:15 +0200197int update_agent_open(struct update_agent *update_agent, const struct uuid_octets *uuid,
198 uint32_t *handle)
Julian Halle35efa52022-10-31 16:34:58 +0000199{
200 int status;
201
202 /* Pass UUID along a chain-of-responsibility until it's handled */
203 if (!open_image_directory(update_agent, uuid, handle, &status) &&
Gyorgy Szing3c446242023-03-31 01:53:15 +0200204 !open_fw_store_object(update_agent, uuid, handle, &status) &&
205 !open_fw_image(update_agent, uuid, handle, &status)) {
Julian Halle35efa52022-10-31 16:34:58 +0000206 /* UUID not recognised */
207 status = FWU_STATUS_UNKNOWN;
208 }
209
210 return status;
211}
212
Gyorgy Szing3c446242023-03-31 01:53:15 +0200213int update_agent_commit(struct update_agent *update_agent, uint32_t handle, bool accepted)
Julian Halle35efa52022-10-31 16:34:58 +0000214{
Gyorgy Szing3c446242023-03-31 01:53:15 +0200215 return stream_manager_close(&update_agent->stream_manager, handle, accepted);
Julian Halle35efa52022-10-31 16:34:58 +0000216}
217
Gyorgy Szing3c446242023-03-31 01:53:15 +0200218int update_agent_write_stream(struct update_agent *update_agent, uint32_t handle,
219 const uint8_t *data, size_t data_len)
Julian Halle35efa52022-10-31 16:34:58 +0000220{
Gyorgy Szing3c446242023-03-31 01:53:15 +0200221 return stream_manager_write(&update_agent->stream_manager, handle, data, data_len);
Julian Halle35efa52022-10-31 16:34:58 +0000222}
223
Gyorgy Szing3c446242023-03-31 01:53:15 +0200224int update_agent_read_stream(struct update_agent *update_agent, uint32_t handle, uint8_t *buf,
225 size_t buf_size, size_t *read_len, size_t *total_len)
Julian Halle35efa52022-10-31 16:34:58 +0000226{
Gyorgy Szing3c446242023-03-31 01:53:15 +0200227 return stream_manager_read(&update_agent->stream_manager, handle, buf, buf_size, read_len,
228 total_len);
Julian Halle35efa52022-10-31 16:34:58 +0000229}
230
Gyorgy Szing3c446242023-03-31 01:53:15 +0200231static bool open_image_directory(struct update_agent *update_agent, const struct uuid_octets *uuid,
232 uint32_t *handle, int *status)
Julian Halle35efa52022-10-31 16:34:58 +0000233{
234 struct uuid_octets target_uuid;
235
236 uuid_guid_octets_from_canonical(&target_uuid, FWU_DIRECTORY_CANONICAL_UUID);
237
238 if (uuid_is_equal(uuid->octets, target_uuid.octets)) {
Julian Halle35efa52022-10-31 16:34:58 +0000239 /* Serialize a fresh view of the image directory */
240 size_t serialized_len = 0;
241
Gyorgy Szing3c446242023-03-31 01:53:15 +0200242 *status = img_dir_serializer_serialize(&update_agent->fw_directory,
243 update_agent->fw_store,
244 update_agent->image_dir_buf,
245 update_agent->image_dir_buf_size,
246 &serialized_len);
Julian Halle35efa52022-10-31 16:34:58 +0000247
248 if (*status == FWU_STATUS_SUCCESS) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200249 *status = stream_manager_open_buffer_stream(&update_agent->stream_manager,
250 update_agent->image_dir_buf,
251 serialized_len, handle);
Julian Halle35efa52022-10-31 16:34:58 +0000252 }
253
254 return true;
255 }
256
257 return false;
258}
259
Gyorgy Szing3c446242023-03-31 01:53:15 +0200260static bool open_fw_store_object(struct update_agent *update_agent, const struct uuid_octets *uuid,
261 uint32_t *handle, int *status)
Julian Halle35efa52022-10-31 16:34:58 +0000262{
263 const uint8_t *exported_data;
264 size_t exported_data_len;
265
Gyorgy Szing3c446242023-03-31 01:53:15 +0200266 if (fw_store_export(update_agent->fw_store, uuid, &exported_data, &exported_data_len,
267 status)) {
Julian Halle35efa52022-10-31 16:34:58 +0000268 if (*status == FWU_STATUS_SUCCESS) {
Gyorgy Szing3c446242023-03-31 01:53:15 +0200269 *status = stream_manager_open_buffer_stream(&update_agent->stream_manager,
270 exported_data,
271 exported_data_len, handle);
Julian Halle35efa52022-10-31 16:34:58 +0000272 }
273
274 return true;
275 }
276
277 return false;
278}
279
Gyorgy Szing3c446242023-03-31 01:53:15 +0200280static bool open_fw_image(struct update_agent *update_agent, const struct uuid_octets *uuid,
281 uint32_t *handle, int *status)
Julian Halle35efa52022-10-31 16:34:58 +0000282{
Gyorgy Szing3c446242023-03-31 01:53:15 +0200283 const struct image_info *image_info =
284 fw_directory_find_image_info(&update_agent->fw_directory, uuid);
Julian Halle35efa52022-10-31 16:34:58 +0000285
286 if (image_info) {
Julian Halle35efa52022-10-31 16:34:58 +0000287 if (update_agent->state == FWU_STATE_STAGING) {
Julian Halle35efa52022-10-31 16:34:58 +0000288 struct installer *installer;
289
Gyorgy Szing3c446242023-03-31 01:53:15 +0200290 *status = fw_store_select_installer(update_agent->fw_store, image_info,
291 &installer);
Julian Halle35efa52022-10-31 16:34:58 +0000292
293 if (*status == FWU_STATUS_SUCCESS) {
Julian Halle35efa52022-10-31 16:34:58 +0000294 *status = stream_manager_open_install_stream(
Gyorgy Szing3c446242023-03-31 01:53:15 +0200295 &update_agent->stream_manager, update_agent->fw_store,
296 installer, image_info, handle);
Julian Halle35efa52022-10-31 16:34:58 +0000297 }
298 } else {
Julian Halle35efa52022-10-31 16:34:58 +0000299 /* Attempting to open a fw image when not staging */
300 *status = FWU_STATUS_DENIED;
301 }
302
303 return true;
304 }
305
306 return false;
307}