1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Firmware Image Package (FIP) parser support.
9  */
10 
11 #include <mod_fip.h>
12 
13 #include <fwk_id.h>
14 #include <fwk_log.h>
15 #include <fwk_module.h>
16 #include <fwk_status.h>
17 #include <fwk_string.h>
18 
19 #include <inttypes.h>
20 #include <string.h>
21 
22 static const struct fip_uuid_desc fip_uuid_desc_arr[3] = {
23     FIP_UUID_NULL,
24     FIP_UUID_SCP_BL2,
25     FIP_UUID_TFA_BL31,
26 };
27 
28 /*
29  * Static helpers
30  */
fip_entry_type_to_uuid(enum mod_fip_toc_entry_type type,uint8_t * uuid)31 static int fip_entry_type_to_uuid(
32     enum mod_fip_toc_entry_type type,
33     uint8_t *uuid)
34 {
35     const struct mod_fip_module_config *module_config;
36     size_t i;
37 
38     module_config = fwk_module_get_data(fwk_module_id_fip);
39     size_t desc_arr_size =
40         sizeof(fip_uuid_desc_arr) / sizeof(fip_uuid_desc_arr[0]);
41 
42     if (type < MOD_FIP_TOC_ENTRY_COUNT) {
43         for (i = 0; i < desc_arr_size; i++) {
44             if (fip_uuid_desc_arr[i].image_type == type) {
45                 fwk_str_memcpy(
46                     uuid, fip_uuid_desc_arr[i].uuid, FIP_UUID_ENTRY_SIZE);
47                 return FWK_SUCCESS;
48             }
49         }
50     }
51 
52     if (type >= MOD_FIP_TOC_ENTRY_COUNT &&
53         module_config->custom_fip_uuid_desc_arr != NULL) {
54         for (i = 0; i < module_config->custom_uuid_desc_count; i++) {
55             if (module_config->custom_fip_uuid_desc_arr[i].image_type == type) {
56                 fwk_str_memcpy(
57                     uuid,
58                     module_config->custom_fip_uuid_desc_arr[i].uuid,
59                     FIP_UUID_ENTRY_SIZE);
60                 return FWK_SUCCESS;
61             }
62         }
63     }
64 
65     return FWK_E_PARAM;
66 }
67 
uuid_cmp(const uint8_t * a,const uint8_t * b)68 static inline bool uuid_cmp(const uint8_t *a, const uint8_t *b)
69 {
70     int match = 0;
71 
72     for (unsigned int i = 0; i < FIP_UUID_ENTRY_SIZE; i++) {
73         if (a[i] == b[i]) {
74             match++;
75         } else {
76             match--;
77         }
78     }
79 
80     return (match == FIP_UUID_ENTRY_SIZE);
81 }
82 
uuid_is_null(const uint8_t * uuid)83 static bool uuid_is_null(const uint8_t *uuid)
84 {
85     static const struct fip_uuid_desc uuid_null = FIP_UUID_NULL;
86     return uuid_cmp(uuid, uuid_null.uuid);
87 }
88 
validate_fip_toc(const struct fip_toc * const toc)89 static bool validate_fip_toc(const struct fip_toc *const toc)
90 {
91     return toc->header.name == FIP_TOC_HEADER_NAME;
92 }
93 
94 /*
95  * Module API functions
96  */
fip_get_entry(enum mod_fip_toc_entry_type image_type,struct mod_fip_entry_data * const entry_data,uintptr_t base,size_t limit)97 static int fip_get_entry(
98     enum mod_fip_toc_entry_type image_type,
99     struct mod_fip_entry_data *const entry_data,
100     uintptr_t base,
101     size_t limit)
102 {
103     uintptr_t address;
104     uint8_t target_uuid[FIP_UUID_ENTRY_SIZE];
105     struct fip_toc_entry *toc_entry;
106     int status;
107     struct fip_toc *toc = (void *)base;
108 
109     if (!validate_fip_toc(toc)) {
110         /*
111          * The error log message here requires the platform to enable an
112          * always-on logging mechanism in order to detect this failure in
113          * early stages, such as in ROM code.
114          */
115         FWK_LOG_ERR(
116             "[FIP] Invalid FIP ToC header name: [0x%08" PRIX32 "]",
117             toc->header.name);
118         return FWK_E_PARAM;
119     }
120 
121     toc_entry = toc->entry;
122 
123     /* Updates target_uuid field with UUID of corresponding image_type passed */
124     status = fip_entry_type_to_uuid(image_type, target_uuid);
125     if (status != FWK_SUCCESS)
126         return status;
127 
128     /*
129      * Traverse all FIP ToC entries until the desired entry is found or ToC
130      * End Marker is reached
131      */
132     while (!uuid_cmp(toc_entry->uuid, target_uuid)) {
133         if (uuid_is_null(toc_entry->uuid))
134             return FWK_E_RANGE;
135         toc_entry++;
136     }
137 
138     /* Sanity checks of the retrieved entry data */
139     if (__builtin_add_overflow(
140             (uintptr_t)toc, (uintptr_t)toc_entry->offset_address, &address)) {
141         return FWK_E_DATA;
142     }
143 
144     if ((uintptr_t)toc_entry->offset_address + toc_entry->size > limit)
145         return FWK_E_SIZE;
146 
147     entry_data->base = (void *)address;
148     entry_data->size = toc_entry->size;
149     entry_data->flags = toc_entry->flags;
150     return FWK_SUCCESS;
151 }
152 
153 static const struct mod_fip_api fip_api = {
154     .get_entry = fip_get_entry,
155 };
156 
157 /*
158  * Framework handler functions
159  */
fip_init(fwk_id_t module_id,unsigned int element_count,const void * data)160 static int fip_init(
161     fwk_id_t module_id,
162     unsigned int element_count,
163     const void *data)
164 {
165     return FWK_SUCCESS;
166 }
167 
fip_process_bind_request(fwk_id_t requester_id,fwk_id_t id,fwk_id_t api_id,const void ** api)168 static int fip_process_bind_request(
169     fwk_id_t requester_id,
170     fwk_id_t id,
171     fwk_id_t api_id,
172     const void **api)
173 {
174     *api = &fip_api;
175     return FWK_SUCCESS;
176 }
177 
178 const struct fwk_module module_fip = {
179     .type = FWK_MODULE_TYPE_SERVICE,
180     .api_count = 1,
181     .init = fip_init,
182     .process_bind_request = fip_process_bind_request,
183 };
184