1 /*
2  * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <string.h>
9 #include <assert.h>
10 
11 #include "fip_parser.h"
12 #include "tfm_plat_defs.h"
13 #include "flash_layout.h"
14 #include "Driver_Flash.h"
15 
fip_get_entry_by_uuid(const ARM_DRIVER_FLASH * flash_dev,uint32_t fip_offset,uint32_t atu_slot_size,uuid_t uuid,uint64_t * offset,size_t * size)16 enum tfm_plat_err_t fip_get_entry_by_uuid(const ARM_DRIVER_FLASH *flash_dev,
17                                           uint32_t fip_offset, uint32_t atu_slot_size,
18                                           uuid_t uuid, uint64_t *offset, size_t *size)
19 {
20     ARM_FLASH_CAPABILITIES DriverCapabilities = flash_dev->GetCapabilities();
21     assert(DriverCapabilities.data_width <= 2);
22     /* Valid entries for data item width */
23     const uint32_t data_width_byte[] = {
24         sizeof(uint8_t),
25         sizeof(uint16_t),
26         sizeof(uint32_t),
27     };
28     const size_t data_width =
29         data_width_byte[DriverCapabilities.data_width <= 2 ? DriverCapabilities.data_width : 0];
30     int rc;
31     uint32_t idx = 0;
32     fip_toc_header_t toc_header;
33     fip_toc_entry_t toc_entry;
34     uuid_t null_uuid;
35 
36     /* The NULL UUID is all-zeroes */
37     memset(&null_uuid, 0, sizeof(null_uuid));
38 
39     rc = flash_dev->ReadData(fip_offset, &toc_header,
40                              sizeof(toc_header) / data_width);
41     if (rc != sizeof(toc_header) / data_width) {
42         return TFM_PLAT_ERR_FIP_TOC_HEADER_INVALID_READ;
43     }
44 
45     if (toc_header.name != TOC_HEADER_NAME) {
46         return TFM_PLAT_ERR_FIP_TOC_HEADER_INVALID_NAME;
47     }
48 
49     idx += sizeof(toc_header);
50 
51     do {
52         /* Prevent reading out of bounds */
53         if (idx + sizeof(toc_entry) > atu_slot_size) {
54             return TFM_PLAT_ERR_FIP_TOC_ENTRY_OVERFLOW;
55         }
56 
57         rc = flash_dev->ReadData(fip_offset + idx, &toc_entry,
58                                  sizeof(toc_entry) / data_width);
59         if (rc != sizeof(toc_entry) / data_width) {
60             return TFM_PLAT_ERR_FIP_TOC_ENTRY_INVALID_READ;
61         }
62 
63         if (!memcmp(&uuid, &toc_entry.uuid, sizeof(uuid))) {
64             *offset = toc_entry.offset_address;
65 
66             /* We can't deal with partitions that are greater than UINT32_MAX,
67              * since they aren't wholly mappable into the RSE memory space. This
68              * is in reality bounded by the ATU mappable size, but that'll be
69              * checked once the ATU region is set up, this just allows us to
70              * perform safe type-conversion.
71              */
72             if (toc_entry.size > UINT32_MAX) {
73                 return TFM_PLAT_ERR_FIP_TOC_ENTRY_INVALID_SIZE;
74             }
75 
76             *size = (uint32_t)toc_entry.size;
77 
78             return TFM_PLAT_ERR_SUCCESS;
79         }
80 
81         idx += sizeof(toc_entry);
82         /* The FIP's TOC ends in an entry with a NULL UUID. This entry's size is
83          * the size of the whole FIP. */
84     } while (memcmp(&null_uuid, &toc_entry.uuid, sizeof(uuid_t)));
85 
86     /* UUID not found, return error. */
87     return TFM_PLAT_ERR_GPT_TOC_ENTRY_NOT_FOUND;
88 }
89