xref: /rk3399_ARM-atf/plat/arm/common/arm_io_storage.c (revision 6051bc9954c18dbe2840a5b25b0be49dbeb943fd)
1 /*
2  * Copyright (c) 2015-2026, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <string.h>
8 
9 #include <common/debug.h>
10 #include <drivers/fwu/fwu_metadata.h>
11 #include <drivers/io/io_driver.h>
12 #include <drivers/io/io_encrypted.h>
13 #include <drivers/io/io_fip.h>
14 #include <drivers/io/io_memmap.h>
15 #include <drivers/io/io_storage.h>
16 #include <drivers/partition/partition.h>
17 #include <lib/utils.h>
18 
19 #include <plat/arm/common/arm_fconf_getter.h>
20 #include <plat/arm/common/arm_fconf_io_storage.h>
21 #include <plat/arm/common/arm_gpt_partition_guid.h>
22 #include <plat/arm/common/plat_arm.h>
23 #include <plat/common/platform.h>
24 #include <platform_def.h>
25 
26 /* IO devices */
27 static const io_dev_connector_t *fip_dev_con;
28 uintptr_t fip_dev_handle;
29 static const io_dev_connector_t *memmap_dev_con;
30 uintptr_t memmap_dev_handle;
31 #ifndef DECRYPTION_SUPPORT_none
32 static const io_dev_connector_t *enc_dev_con;
33 uintptr_t enc_dev_handle;
34 #endif
35 
36 #if ARM_GPT_SUPPORT
37 /* fip partition names */
38 static const char * const fip_part_names[] = {"FIP_A", "FIP_B"};
39 CASSERT(sizeof(fip_part_names)/sizeof(char *) == NR_OF_FW_BANKS,
40 	assert_fip_partition_names_missing);
41 
42 #if PSA_FWU_SUPPORT
43 static const struct efi_guid fwu_metadata_type_guid =
44 	ARM_GPT_FWU_METADATA_TYPE_GUID;
45 #if PSA_FWU_METADATA_FW_STORE_DESC
46 static const struct efi_guid fip_img_type_guid = ARM_FIP_IMG_TYPE_GUID;
47 #else
48 static const struct efi_guid fip_img_type_guid = NULL_GUID;
49 #endif /* PSA_FWU_METADATA_FW_STORE_DESC */
50 #endif /* PSA_FWU_SUPPORT */
51 static const struct efi_guid null_guid = NULL_GUID;
52 #endif /* ARM_GPT_SUPPORT */
53 
54 /* Weak definitions may be overridden in specific ARM standard platform */
55 #pragma weak plat_arm_io_setup
56 #pragma weak plat_arm_get_alt_image_source
57 
open_fip(const uintptr_t spec)58 int open_fip(const uintptr_t spec)
59 {
60 	int result;
61 	uintptr_t local_image_handle;
62 
63 	/* See if a Firmware Image Package is available */
64 	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
65 	if (result == 0 && spec != (uintptr_t)NULL) {
66 		result = io_open(fip_dev_handle, spec, &local_image_handle);
67 		if (result == 0) {
68 			VERBOSE("Using FIP\n");
69 			io_close(local_image_handle);
70 		}
71 	}
72 	return result;
73 }
74 
open_memmap(const uintptr_t spec)75 int open_memmap(const uintptr_t spec)
76 {
77 	int result;
78 	uintptr_t local_image_handle;
79 
80 	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
81 	if (result == 0) {
82 		result = io_open(memmap_dev_handle, spec, &local_image_handle);
83 		if (result == 0) {
84 			VERBOSE("Using Memmap\n");
85 			io_close(local_image_handle);
86 		}
87 	}
88 	return result;
89 }
90 
arm_io_setup(void)91 int arm_io_setup(void)
92 {
93 	int io_result;
94 
95 	io_result = register_io_dev_fip(&fip_dev_con);
96 	if (io_result < 0) {
97 		return io_result;
98 	}
99 
100 	io_result = register_io_dev_memmap(&memmap_dev_con);
101 	if (io_result < 0) {
102 		return io_result;
103 	}
104 
105 	/* Open connections to devices and cache the handles */
106 	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
107 				&fip_dev_handle);
108 	if (io_result < 0) {
109 		return io_result;
110 	}
111 
112 	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
113 				&memmap_dev_handle);
114 
115 	if (io_result < 0) {
116 		return io_result;
117 	}
118 
119 #ifndef DECRYPTION_SUPPORT_none
120 	io_result = register_io_dev_enc(&enc_dev_con);
121 	if (io_result < 0) {
122 		return io_result;
123 	}
124 
125 	io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL,
126 			&enc_dev_handle);
127 	if (io_result < 0) {
128 		return io_result;
129 	}
130 #endif
131 
132 	return io_result;
133 }
134 
plat_arm_io_setup(void)135 void plat_arm_io_setup(void)
136 {
137 	int err;
138 
139 	err = arm_io_setup();
140 	if (err < 0) {
141 		panic();
142 	}
143 }
144 
plat_arm_get_alt_image_source(unsigned int image_id __unused,uintptr_t * dev_handle __unused,uintptr_t * image_spec __unused)145 int plat_arm_get_alt_image_source(
146 	unsigned int image_id __unused,
147 	uintptr_t *dev_handle __unused,
148 	uintptr_t *image_spec __unused)
149 {
150 	/* By default do not try an alternative */
151 	return -ENOENT;
152 }
153 
154 /* Return an IO device handle and specification which can be used to access
155  * an image. Use this to enforce platform load policy */
plat_get_image_source(unsigned int image_id,uintptr_t * dev_handle,uintptr_t * image_spec)156 int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
157 			  uintptr_t *image_spec)
158 {
159 	int result;
160 	const struct plat_io_policy *policy;
161 
162 	policy = FCONF_GET_PROPERTY(arm, io_policies, image_id);
163 	assert(policy->check != NULL);
164 	result = policy->check(policy->image_spec);
165 	if (result == 0) {
166 		*image_spec = policy->image_spec;
167 		*dev_handle = *(policy->dev_handle);
168 	} else {
169 		VERBOSE("Trying alternative IO\n");
170 		result = plat_arm_get_alt_image_source(image_id, dev_handle,
171 						       image_spec);
172 	}
173 
174 	return result;
175 }
176 
177 /*
178  * See if a Firmware Image Package is available,
179  * by checking if TOC is valid or not.
180  */
arm_io_is_toc_valid(void)181 bool arm_io_is_toc_valid(void)
182 {
183 	return (io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID) == 0);
184 }
185 
186 #if ARM_GPT_SUPPORT
187 /******************************************************************************
188  * Retrieve partition entry details such as offset and length, and set these
189  * details in the I/O policy of the requested image.
190  *
191  * @image_id: image id whose I/O policy to be updated
192  *
193  * @part_guid: partition GUID whose details to be retrieved (preferred)
194  * @part_name: partition name whose details to be retrieved (fallback)
195  *
196  * Returns 0 on success, error otherwise
197  * Alongside, returns device handle and image specification of requested
198  * image.
199  ******************************************************************************/
arm_get_partition_entry(const struct efi_guid * part_guid,const char * part_name)200 static const partition_entry_t *arm_get_partition_entry(
201 	const struct efi_guid *part_guid, const char *part_name)
202 {
203 	const partition_entry_t *entry = NULL;
204 
205 	if ((part_guid != NULL) && (guidcmp(part_guid, &null_guid) != 0)) {
206 		entry = get_partition_entry_by_guid(part_guid);
207 	}
208 
209 	if ((entry == NULL) && (part_name != NULL)) {
210 		entry = get_partition_entry(part_name);
211 	}
212 
213 	return entry;
214 }
215 
arm_set_image_source(unsigned int image_id,const struct efi_guid * part_guid,const char * part_name,uintptr_t * dev_handle,uintptr_t * image_spec)216 int arm_set_image_source(unsigned int image_id, const struct efi_guid *part_guid,
217 			 const char *part_name, uintptr_t *dev_handle,
218 			 uintptr_t *image_spec)
219 {
220 	const partition_entry_t *entry = arm_get_partition_entry(part_guid,
221 								 part_name);
222 
223 	if (entry == NULL) {
224 		if (part_name != NULL) {
225 			ERROR("Unable to find the %s partition\n", part_name);
226 		} else {
227 			ERROR("Unable to find partition by GUID\n");
228 		}
229 		return -ENOENT;
230 	}
231 
232 	struct plat_io_policy *policy = FCONF_GET_PROPERTY(arm,
233 							   io_policies,
234 							   image_id);
235 
236 	assert(policy != NULL);
237 	assert(policy->image_spec != 0UL);
238 
239 	io_block_spec_t *spec = (io_block_spec_t *)policy->image_spec;
240 	/* set offset and length of the image */
241 	spec->offset = PLAT_ARM_FLASH_IMAGE_BASE + entry->start;
242 	spec->length = entry->length;
243 
244 	*dev_handle = *(policy->dev_handle);
245 	*image_spec = policy->image_spec;
246 
247 	return 0;
248 }
249 
250 /*******************************************************************************
251  * Set the source offset and length of the FIP image in its I/O policy.
252  *
253  * @active_fw_bank_idx: active firmware bank index gathered from FWU metadata.
254  ******************************************************************************/
arm_set_fip_addr(uint32_t active_fw_bank_idx)255 void arm_set_fip_addr(uint32_t active_fw_bank_idx)
256 {
257 	uintptr_t dev_handle __unused;
258 	uintptr_t image_spec __unused;
259 
260 	assert(active_fw_bank_idx < NR_OF_FW_BANKS);
261 
262 	INFO("Booting with partition %s\n", fip_part_names[active_fw_bank_idx]);
263 
264 	int result = arm_set_image_source(FIP_IMAGE_ID,
265 					  NULL,
266 					  fip_part_names[active_fw_bank_idx],
267 					  &dev_handle,
268 					  &image_spec);
269 	if (result != 0) {
270 		panic();
271 	}
272 }
273 #endif /* ARM_GPT_SUPPORT */
274 
275 #if PSA_FWU_SUPPORT
276 /*******************************************************************************
277  * Read the FIP partition of the GPT image corresponding to the active firmware
278  * bank to get its offset and length, and update these details in the I/O policy
279  * of the FIP image.
280  ******************************************************************************/
plat_fwu_set_images_source(const struct fwu_metadata * metadata)281 void plat_fwu_set_images_source(const struct fwu_metadata *metadata)
282 {
283 	const struct fwu_fw_store_descriptor *fw_desc;
284 	const struct fwu_image_entry *img_entry;
285 	const struct efi_guid *img_guid = NULL;
286 	struct efi_guid img_guid_local;
287 	uint32_t i;
288 	uintptr_t dev_handle __unused;
289 	uintptr_t image_spec __unused;
290 
291 	if (metadata->desc_offset == 0U) {
292 		arm_set_fip_addr(metadata->active_index);
293 		return;
294 	}
295 
296 	fw_desc = (const struct fwu_fw_store_descriptor *)
297 		((const uint8_t *)metadata + metadata->desc_offset);
298 	img_entry = fw_desc->img_entry;
299 	for (i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
300 		if (guidcmp(&img_entry[i].img_type_guid,
301 			    &fip_img_type_guid) == 0) {
302 			/* Copy out of packed metadata to avoid unaligned pointer. */
303 			memcpy(&img_guid_local,
304 			       &img_entry[i]
305 					.img_bank_info[metadata->active_index]
306 					.img_guid,
307 			       sizeof(img_guid_local));
308 			img_guid = &img_guid_local;
309 			break;
310 		}
311 	}
312 
313 	if (img_guid == NULL) {
314 		arm_set_fip_addr(metadata->active_index);
315 		return;
316 	}
317 
318 	if (arm_set_image_source(FIP_IMAGE_ID, img_guid,
319 				 fip_part_names[metadata->active_index],
320 				 &dev_handle, &image_spec) != 0) {
321 		panic();
322 	}
323 }
324 
325 /*******************************************************************************
326  * Read the requested FWU metadata partition of the GPT image to get its offset
327  * and length, and update these details in the I/O policy of the requested FWU
328  * metadata image.
329  ******************************************************************************/
plat_fwu_set_metadata_image_source(unsigned int image_id,uintptr_t * dev_handle,uintptr_t * image_spec)330 int plat_fwu_set_metadata_image_source(unsigned int image_id,
331 				       uintptr_t *dev_handle,
332 				       uintptr_t *image_spec)
333 {
334 	const partition_entry_t *entry = NULL;
335 	struct plat_io_policy *policy = NULL;
336 	io_block_spec_t *spec = NULL;
337 
338 	if (image_id == FWU_METADATA_IMAGE_ID) {
339 		if (guidcmp(&fwu_metadata_type_guid, &null_guid) != 0) {
340 			entry = get_partition_entry_by_type_index(
341 				&fwu_metadata_type_guid, 0U);
342 		}
343 	} else if (image_id == BKUP_FWU_METADATA_IMAGE_ID) {
344 		if (guidcmp(&fwu_metadata_type_guid, &null_guid) != 0) {
345 			entry = get_partition_entry_by_type_index(
346 				&fwu_metadata_type_guid, 1U);
347 		}
348 	}
349 
350 	if (entry == NULL) {
351 		if (image_id == FWU_METADATA_IMAGE_ID) {
352 			return arm_set_image_source(FWU_METADATA_IMAGE_ID,
353 						    NULL, "FWU-Metadata",
354 						    dev_handle, image_spec);
355 		}
356 		return arm_set_image_source(BKUP_FWU_METADATA_IMAGE_ID,
357 					    NULL, "Bkup-FWU-Metadata",
358 					    dev_handle, image_spec);
359 	}
360 
361 	policy = FCONF_GET_PROPERTY(arm, io_policies, image_id);
362 	assert(policy != NULL);
363 	assert(policy->image_spec != 0UL);
364 
365 	spec = (io_block_spec_t *)policy->image_spec;
366 	spec->offset = PLAT_ARM_FLASH_IMAGE_BASE + entry->start;
367 	spec->length = entry->length;
368 	*dev_handle = *(policy->dev_handle);
369 	*image_spec = policy->image_spec;
370 
371 	return 0;
372 }
373 #endif /* PSA_FWU_SUPPORT */
374 
375 #ifndef DECRYPTION_SUPPORT_none
open_enc_fip(const uintptr_t spec)376 int open_enc_fip(const uintptr_t spec)
377 {
378 	int result;
379 	uintptr_t local_image_handle;
380 
381 	/* See if an encrypted FIP is available */
382 	result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID);
383 	if (result == 0) {
384 		result = io_open(enc_dev_handle, spec, &local_image_handle);
385 		if (result == 0) {
386 			VERBOSE("Using encrypted FIP\n");
387 			io_close(local_image_handle);
388 		}
389 	}
390 	return result;
391 }
392 #endif
393