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