1 /*
2 * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fwu_app.h"
8
9 #include <cassert>
10 #include <cstddef>
11 #include <cstring>
12 #include <errno.h>
13
14 #include "media/volume/factory/volume_factory.h"
15 #include "metadata_reader.h"
16 #include "service/block_storage/factory/file/block_store_factory.h"
17 #include "service/fwu/agent/update_agent.h"
18 #include "service/fwu/config/fwu_configure.h"
19 #include "service/fwu/fw_store/banked/bank_scheme.h"
20 #include "service/fwu/fw_store/banked/banked_fw_store.h"
21 #include "service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h"
22 #include "service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h"
23 #include "service/fwu/inspector/direct/direct_fw_inspector.h"
24 #include "service/fwu/installer/factory/installer_factory.h"
25
26 extern "C" {
27 #include "trace.h"
28 }
29
fwu_app()30 fwu_app::fwu_app()
31 : m_update_agent()
32 , m_fw_store()
33 {
34 memset(&m_fw_store, 0, sizeof(m_fw_store));
35 }
36
~fwu_app()37 fwu_app::~fwu_app()
38 {
39 update_agent_deinit(m_update_agent);
40 banked_fw_store_deinit(&m_fw_store);
41
42 fwu_deconfigure();
43 volume_factory_deinit();
44 }
45
configure(const char * disk_img_filename)46 int fwu_app::configure(const char *disk_img_filename)
47 {
48 if (disk_img_filename)
49 file_block_store_factory_set_filename(disk_img_filename);
50
51 struct uuid_octets device_uuids[MAX_STORAGE_DEVICES];
52 size_t num_storage_devices = 0;
53
54 int status = volume_factory_init(device_uuids, MAX_STORAGE_DEVICES, &num_storage_devices);
55
56 if (status) {
57 EMSG("Failed to init volume factory: %d", status);
58 return -EIO;
59 }
60
61 status = fwu_configure(device_uuids, num_storage_devices);
62
63 if (status) {
64 EMSG("Failed to setup FWU configuration: %d", status);
65 return -EIO;
66 }
67
68 return 0;
69 }
70
get_boot_info(unsigned int & active_index,unsigned int & metadata_version)71 int fwu_app::get_boot_info(unsigned int &active_index, unsigned int &metadata_version)
72 {
73 return metadata_reader::instance()->get_boot_info(active_index, metadata_version);
74 }
75
init_update_agent(unsigned int boot_index,unsigned int metadata_version)76 int fwu_app::init_update_agent(unsigned int boot_index, unsigned int metadata_version)
77 {
78 if (boot_index >= BANK_SCHEME_NUM_BANKS) {
79 IMSG("Invalid boot index");
80 return -1;
81 }
82
83 const struct metadata_serializer *serializer = select_metadata_serializer(metadata_version);
84
85 if (!serializer) {
86 IMSG("Unsupported FWU metadata version");
87 return -1;
88 }
89
90 /* Initialise update_agent */
91 int status = banked_fw_store_init(&m_fw_store, serializer);
92
93 if (status) {
94 IMSG("fw store initialisation error %d", status);
95 return -1;
96 }
97
98 m_update_agent = update_agent_init(boot_index, direct_fw_inspector_inspect, &m_fw_store);
99
100 if (!m_update_agent) {
101 IMSG("update agent initialisation error %d", status);
102 return -1;
103 }
104
105 /* Success */
106 return 0;
107 }
108
update_image(const struct uuid_octets & img_type_uuid,const uint8_t * img_data,size_t img_size)109 int fwu_app::update_image(const struct uuid_octets &img_type_uuid, const uint8_t *img_data,
110 size_t img_size)
111 {
112 int status = update_agent_begin_staging(m_update_agent, 0, 0, NULL);
113
114 if (status)
115 return status;
116
117 uint32_t stream_handle = 0;
118 uint32_t progress = 0;
119 uint32_t total_work = 0;
120
121 status = update_agent_open(m_update_agent, &img_type_uuid, FWU_OP_TYPE_WRITE,
122 &stream_handle);
123
124 if (!status) {
125 status = update_agent_write_stream(m_update_agent, stream_handle, img_data,
126 img_size);
127
128 if (!status)
129 status = update_agent_commit(m_update_agent, stream_handle, false, 0,
130 &progress, &total_work);
131 }
132
133 if (!status)
134 status = update_agent_end_staging(m_update_agent);
135 else
136 update_agent_cancel_staging(m_update_agent);
137
138 return status;
139 }
140
read_object(const struct uuid_octets & object_uuid,std::vector<uint8_t> & data)141 int fwu_app::read_object(const struct uuid_octets &object_uuid, std::vector<uint8_t> &data)
142 {
143 uint32_t stream_handle = 0;
144 int status = update_agent_open(m_update_agent, &object_uuid, FWU_OP_TYPE_READ,
145 &stream_handle);
146
147 if (status)
148 return status;
149
150 /* Don't yet know how big the object will be so allocate some space to get
151 * started with the initial read.
152 */
153 size_t reported_total_len = 0;
154 size_t read_so_far = 0;
155 size_t vector_capacity = 512;
156 uint32_t progress = 0;
157 uint32_t total_work = 0;
158
159 data.resize(vector_capacity);
160
161 do {
162 size_t data_len_read = 0;
163 size_t requested_read_len = vector_capacity - read_so_far;
164
165 status = update_agent_read_stream(m_update_agent, stream_handle,
166 &data[read_so_far], requested_read_len,
167 &data_len_read, &reported_total_len);
168
169 read_so_far += data_len_read;
170 data.resize(read_so_far);
171
172 if (reported_total_len > vector_capacity) {
173 vector_capacity = reported_total_len;
174 data.resize(vector_capacity);
175 }
176
177 assert(read_so_far <= reported_total_len);
178
179 if (read_so_far == reported_total_len) {
180 /* Read all the data */
181 if (vector_capacity > reported_total_len)
182 data.resize(reported_total_len);
183
184 break;
185 }
186
187 } while (!status);
188
189 status = update_agent_commit(m_update_agent, stream_handle, false, 0, &progress,
190 &total_work);
191
192 return status;
193 }
194
update_agent()195 struct update_agent *fwu_app::update_agent()
196 {
197 return m_update_agent;
198 }
199
select_metadata_serializer(unsigned int version)200 const struct metadata_serializer *fwu_app::select_metadata_serializer(unsigned int version)
201 {
202 if (version == 1)
203 return metadata_serializer_v1();
204
205 if (version == 2)
206 return metadata_serializer_v2();
207
208 return NULL;
209 }
210