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, &region_offset, &region_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