1 /*
2 * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "host_flash_atu.h"
9
10 #include "flash_layout.h"
11 #include "device_definition.h"
12 #include "gpt.h"
13 #include "fip_parser.h"
14 #include "plat_def_fip_uuid.h"
15 #include "host_base_address.h"
16 #include "platform_base_address.h"
17
18 #include <string.h>
19
20 #define RSE_ATU_REGION_TEMP_SLOT 2
21 #define RSE_ATU_REGION_INPUT_IMAGE_SLOT_0 3
22 #define RSE_ATU_REGION_INPUT_IMAGE_SLOT_1 4
23 #define RSE_ATU_REGION_OUTPUT_IMAGE_SLOT 5
24 #define RSE_ATU_REGION_OUTPUT_HEADER_SLOT 6
25
round_down(uint32_t num,uint32_t boundary)26 static inline uint32_t round_down(uint32_t num, uint32_t boundary)
27 {
28 return num - (num % boundary);
29 }
30
round_up(uint32_t num,uint32_t boundary)31 static inline uint32_t round_up(uint32_t num, uint32_t boundary)
32 {
33 return (num + boundary - 1) - ((num + boundary - 1) % boundary);
34 }
35
setup_aligned_atu_slot(uint64_t physical_address,uint32_t size,uint32_t boundary,uint32_t atu_slot,uint32_t logical_address,uint32_t * alignment_offset,size_t * atu_slot_size)36 static int setup_aligned_atu_slot(uint64_t physical_address, uint32_t size,
37 uint32_t boundary, uint32_t atu_slot,
38 uint32_t logical_address,
39 uint32_t *alignment_offset,
40 size_t *atu_slot_size)
41 {
42 uint64_t aligned_physical_address;
43 int err;
44
45 aligned_physical_address = round_down(physical_address, boundary);
46 *atu_slot_size = round_up(physical_address + size, boundary)
47 - aligned_physical_address;
48
49 *alignment_offset = physical_address - aligned_physical_address;
50
51 /* Sanity check our parameters, as we do _not_ trust them. We can only map
52 * within the host flash, the parameters must not overflow, and we cannot
53 * map further than the bounds of the logical address slot.
54 */
55 if (aligned_physical_address < HOST_FLASH0_BASE
56 || aligned_physical_address + *atu_slot_size > HOST_FLASH0_BASE + HOST_FLASH0_SIZE
57 || aligned_physical_address + *atu_slot_size < aligned_physical_address
58 || aligned_physical_address + *atu_slot_size < *atu_slot_size
59 || *atu_slot_size > HOST_IMAGE_MAX_SIZE
60 || *alignment_offset > boundary) {
61 return 1;
62 }
63
64 err = atu_initialize_region(&ATU_DEV_S, atu_slot, logical_address,
65 aligned_physical_address, *atu_slot_size);
66 if (err != ATU_ERR_NONE) {
67 return 1;
68 }
69
70 return 0;
71 }
72
host_flash_atu_setup_image_input_slots_from_fip(uint64_t fip_offset,uint32_t slot,uintptr_t logical_address,uuid_t image_uuid,uint32_t * logical_address_offset,size_t * slot_size)73 int host_flash_atu_setup_image_input_slots_from_fip(uint64_t fip_offset,
74 uint32_t slot,
75 uintptr_t logical_address,
76 uuid_t image_uuid,
77 uint32_t *logical_address_offset,
78 size_t *slot_size)
79 {
80 enum atu_error_t err;
81 int rc;
82 uint64_t region_offset;
83 size_t region_size;
84 uint64_t physical_address = HOST_FLASH0_BASE + fip_offset;
85 uint32_t alignment_offset;
86 size_t atu_slot_size;
87 size_t page_size = get_page_size(&ATU_DEV_S);
88
89 /* There's no way to tell how big the FIP TOC will be before reading it, so
90 * we just map 0x1000.
91 */
92 rc = setup_aligned_atu_slot(physical_address, 0x1000, page_size,
93 RSE_ATU_REGION_TEMP_SLOT,
94 HOST_FLASH0_TEMP_BASE_S, &alignment_offset,
95 &atu_slot_size);
96 if (rc) {
97 return rc;
98 }
99
100 rc = fip_get_entry_by_uuid(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
101 atu_slot_size - alignment_offset,
102 image_uuid, ®ion_offset, ®ion_size);
103 if (rc) {
104 return rc;
105 }
106
107 err = atu_uninitialize_region(&ATU_DEV_S, RSE_ATU_REGION_TEMP_SLOT);
108 if (err != ATU_ERR_NONE) {
109 return 1;
110 }
111
112 /* Initialize primary input region */
113 rc = setup_aligned_atu_slot(physical_address + region_offset, region_size,
114 page_size, slot, logical_address,
115 &alignment_offset, &atu_slot_size);
116 if (rc) {
117 return rc;
118 }
119
120 if (logical_address_offset != NULL) {
121 *logical_address_offset = alignment_offset;
122 }
123 if (slot_size != NULL) {
124 *slot_size = atu_slot_size;
125 }
126
127 return 0;
128 }
129
host_flash_atu_get_fip_offsets(bool fip_found[2],uint64_t fip_offsets[2])130 int host_flash_atu_get_fip_offsets(bool fip_found[2], uint64_t fip_offsets[2])
131 {
132 #ifdef RSE_GPT_SUPPORT
133 int rc;
134 enum atu_error_t err;
135 gpt_header_t header;
136 gpt_entry_t entry;
137 size_t page_size = get_page_size(&ATU_DEV_S);
138 uint64_t physical_address;
139 uint32_t alignment_offset;
140 size_t atu_slot_size;
141 #endif /* RSE_GPT_SUPPORT */
142
143 #ifdef RSE_GPT_SUPPORT
144 physical_address = HOST_FLASH0_BASE + FLASH_LBA_SIZE;
145 rc = setup_aligned_atu_slot(physical_address, FLASH_LBA_SIZE,
146 page_size, RSE_ATU_REGION_TEMP_SLOT,
147 HOST_FLASH0_TEMP_BASE_S, &alignment_offset,
148 &atu_slot_size);
149 if (rc) {
150 return rc;
151 }
152
153 rc = gpt_get_header(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
154 atu_slot_size - alignment_offset, &header);
155 if (rc) {
156 return rc;
157 }
158
159 err = atu_uninitialize_region(&ATU_DEV_S,
160 RSE_ATU_REGION_TEMP_SLOT);
161 if (err != ATU_ERR_NONE) {
162 return 1;
163 }
164
165 physical_address = HOST_FLASH0_BASE
166 + header.list_lba * FLASH_LBA_SIZE;
167 rc = setup_aligned_atu_slot(physical_address,
168 header.list_entry_size * header.list_num, page_size,
169 RSE_ATU_REGION_TEMP_SLOT,
170 HOST_FLASH0_TEMP_BASE_S, &alignment_offset,
171 &atu_slot_size);
172 if (rc) {
173 return rc;
174 }
175
176 rc = gpt_get_list_entry_by_name(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
177 header.list_num, header.list_entry_size,
178 (uint8_t *)PRIMARY_FIP_GPT_NAME,
179 sizeof(PRIMARY_FIP_GPT_NAME),
180 atu_slot_size - alignment_offset, &entry);
181 if (rc == 0) {
182 fip_found[0] = true;
183 fip_offsets[0] = entry.first_lba * FLASH_LBA_SIZE;
184 } else {
185 fip_found[0] = false;
186 }
187
188 rc = gpt_get_list_entry_by_name(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
189 header.list_num, header.list_entry_size,
190 (uint8_t *)SECONDARY_FIP_GPT_NAME,
191 sizeof(SECONDARY_FIP_GPT_NAME),
192 atu_slot_size - alignment_offset, &entry);
193 if (rc == 0) {
194 fip_found[1] = true;
195 fip_offsets[1] = entry.first_lba * FLASH_LBA_SIZE;
196 } else {
197 fip_found[1] = false;
198 }
199
200 err = atu_uninitialize_region(&ATU_DEV_S,
201 RSE_ATU_REGION_TEMP_SLOT);
202 if (err != ATU_ERR_NONE) {
203 return 1;
204 }
205 #else
206 fip_found[0] = true;
207 fip_offsets[0] = FLASH_FIP_A_OFFSET;
208 fip_found[1] = true;
209 fip_offsets[1] = FLASH_FIP_B_OFFSET;
210 #endif /* RSE_GPT_SUPPORT */
211
212 return 0;
213 }
214
setup_image_input_slots(uuid_t image_uuid,uint32_t offsets[2])215 static int setup_image_input_slots(uuid_t image_uuid, uint32_t offsets[2])
216 {
217 int rc;
218 bool fip_found[2];
219 uint64_t fip_offsets[2];
220 bool fip_mapped[2] = {false};
221
222 rc = host_flash_atu_get_fip_offsets(fip_found, fip_offsets);
223 if (rc) {
224 return rc;
225 }
226
227 /* MCUBoot requires that we map both regions. If we can only have the offset
228 * of one, then map it to both slots.
229 */
230 if (fip_found[0] && !fip_found[1]) {
231 fip_offsets[1] = fip_offsets[0];
232 } else if (fip_found[1] && !fip_found[0]) {
233 fip_offsets[0] = fip_offsets[1];
234 } else if (!fip_found[0] && !fip_found[1]) {
235 return 1;
236 }
237
238 rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[0],
239 RSE_ATU_REGION_INPUT_IMAGE_SLOT_0,
240 HOST_FLASH0_IMAGE0_BASE_S, image_uuid,
241 &offsets[0], NULL);
242 if (rc == 0) {
243 fip_mapped[0] = true;
244 }
245
246 rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[1],
247 RSE_ATU_REGION_INPUT_IMAGE_SLOT_1,
248 HOST_FLASH0_IMAGE1_BASE_S, image_uuid,
249 &offsets[1], NULL);
250 if (rc == 0) {
251 fip_mapped[1] = true;
252 }
253
254
255 /* If one of the mappings failed (more common without GPT support since in
256 * that case we're just hoping there's a FIP at the offset) then map the
257 * other one into the slot. At this stage if a backup map fails then it's an
258 * error since otherwise MCUBoot will attempt to access unmapped ATU space
259 * and fault.
260 */
261 if (fip_mapped[0] && !fip_mapped[1]) {
262 rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[0],
263 RSE_ATU_REGION_INPUT_IMAGE_SLOT_1,
264 HOST_FLASH0_IMAGE1_BASE_S,
265 image_uuid, &offsets[1], NULL);
266 if (rc) {
267 return rc;
268 }
269 } else if (fip_mapped[1] && !fip_mapped[0]) {
270 rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[1],
271 RSE_ATU_REGION_INPUT_IMAGE_SLOT_0,
272 HOST_FLASH0_IMAGE0_BASE_S,
273 image_uuid, &offsets[0], NULL);
274 if (rc) {
275 return rc;
276 }
277 } else if (!fip_mapped[0] && !fip_mapped[1]) {
278 return 1;
279 }
280
281 return 0;
282 }
283
setup_image_output_slots(uuid_t image_uuid)284 static int setup_image_output_slots(uuid_t image_uuid)
285 {
286 uuid_t case_uuid;
287 enum atu_error_t atu_err;
288
289 case_uuid = UUID_RSE_FIRMWARE_SCP_BL1;
290 if (memcmp(&image_uuid, &case_uuid, sizeof(uuid_t)) == 0) {
291 /* Initialize SCP ATU header region */
292 atu_err = atu_initialize_region(&ATU_DEV_S,
293 RSE_ATU_REGION_OUTPUT_HEADER_SLOT,
294 HOST_BOOT_IMAGE1_LOAD_BASE_S,
295 SCP_BOOT_SRAM_BASE + SCP_BOOT_SRAM_SIZE
296 - HOST_IMAGE_HEADER_SIZE,
297 HOST_IMAGE_HEADER_SIZE);
298 if (atu_err != ATU_ERR_NONE) {
299 return 1;
300 }
301
302 /* Initialize SCP ATU output region */
303 atu_err = atu_initialize_region(&ATU_DEV_S,
304 RSE_ATU_REGION_OUTPUT_IMAGE_SLOT,
305 HOST_BOOT_IMAGE1_LOAD_BASE_S + HOST_IMAGE_HEADER_SIZE,
306 SCP_BOOT_SRAM_BASE,
307 SCP_BOOT_SRAM_SIZE - HOST_IMAGE_HEADER_SIZE);
308 if (atu_err != ATU_ERR_NONE) {
309 return 1;
310 }
311
312 return 0;
313 }
314
315 case_uuid = UUID_RSE_FIRMWARE_AP_BL1;
316 if (memcmp(&image_uuid, &case_uuid, sizeof(uuid_t)) == 0) {
317 /* Initialize AP ATU header region */
318 atu_err = atu_initialize_region(&ATU_DEV_S,
319 RSE_ATU_REGION_OUTPUT_HEADER_SLOT,
320 HOST_BOOT_IMAGE0_LOAD_BASE_S,
321 AP_BOOT_SRAM_BASE + AP_BOOT_SRAM_SIZE
322 - HOST_IMAGE_HEADER_SIZE,
323 HOST_IMAGE_HEADER_SIZE);
324 if (atu_err != ATU_ERR_NONE) {
325 return 1;
326 }
327 /* Initialize AP ATU region */
328 atu_err = atu_initialize_region(&ATU_DEV_S,
329 RSE_ATU_REGION_OUTPUT_IMAGE_SLOT,
330 HOST_BOOT_IMAGE0_LOAD_BASE_S + HOST_IMAGE_HEADER_SIZE,
331 AP_BOOT_SRAM_BASE,
332 AP_BOOT_SRAM_SIZE - HOST_IMAGE_HEADER_SIZE);
333 if (atu_err != ATU_ERR_NONE) {
334 return 1;
335 }
336
337 return 0;
338 }
339
340 return 0;
341 }
342
host_flash_atu_init_regions_for_image(uuid_t image_uuid,uint32_t offsets[2])343 int host_flash_atu_init_regions_for_image(uuid_t image_uuid, uint32_t offsets[2])
344 {
345 int rc;
346
347 rc = setup_image_input_slots(image_uuid, offsets);
348 if (rc) {
349 return rc;
350 }
351
352 rc = setup_image_output_slots(image_uuid);
353 if (rc) {
354 return rc;
355 }
356
357 return 0;
358 }
359
host_flash_atu_uninit_regions(void)360 int host_flash_atu_uninit_regions(void)
361 {
362 enum atu_error_t atu_err;
363
364 atu_err = atu_uninitialize_region(&ATU_DEV_S,
365 RSE_ATU_REGION_INPUT_IMAGE_SLOT_0);
366 if (atu_err != ATU_ERR_NONE) {
367 return 1;
368 }
369
370 atu_err = atu_uninitialize_region(&ATU_DEV_S,
371 RSE_ATU_REGION_INPUT_IMAGE_SLOT_1);
372 if (atu_err != ATU_ERR_NONE) {
373 return 1;
374 }
375
376 atu_err = atu_uninitialize_region(&ATU_DEV_S,
377 RSE_ATU_REGION_OUTPUT_IMAGE_SLOT);
378 if (atu_err != ATU_ERR_NONE) {
379 return 1;
380 }
381
382 atu_err = atu_uninitialize_region(&ATU_DEV_S,
383 RSE_ATU_REGION_OUTPUT_HEADER_SLOT);
384 if (atu_err != ATU_ERR_NONE) {
385 return 1;
386 }
387
388 return 0;
389 }
390