1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <mod_bootloader.h>
9 
10 #include <fwk_id.h>
11 #include <fwk_interrupt.h>
12 #include <fwk_log.h>
13 #include <fwk_module.h>
14 #include <fwk_module_idx.h>
15 #include <fwk_noreturn.h>
16 #include <fwk_status.h>
17 
18 #include <fmw_cmsis.h>
19 
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <string.h>
23 
24 #ifdef BUILD_HAS_MOD_SDS
25 #    include <mod_sds.h>
26 
27 /* Offset within the SDS structure where the valid flag is located. */
28 #    define BOOTLOADER_STRUCT_VALID_POS 0
29 
30 /* Offset within the SDS structure where the image offset is located. */
31 #    define BOOTLOADER_STRUCT_IMAGE_OFFSET_POS 4
32 
33 /* Offset within the SDS structure where the image size is located. */
34 #    define BOOTLOADER_STRUCT_IMAGE_SIZE_POS 8
35 
36 #    define IMAGE_FLAGS_VALID_MASK 0x1
37 #endif
38 
39 /* Module context */
40 struct bootloader_ctx {
41     const struct mod_bootloader_config *module_config;
42 
43 #ifdef BUILD_HAS_MOD_SDS
44     const struct mod_sds_api *sds_api;
45 #endif
46 };
47 
48 static struct bootloader_ctx mod_bootloader_ctx;
49 
50 /*
51  * Module API
52  */
53 
load_image(void)54 static int load_image(void)
55 {
56     extern noreturn void mod_bootloader_boot(
57         uint8_t * destination,
58         const uint8_t *source,
59         size_t size,
60         volatile uint32_t *vtor);
61 
62 #ifdef BUILD_HAS_MOD_SDS
63     int status;
64 
65     uint32_t image_flags;
66     uint32_t image_offset;
67     uint32_t zero_flag = 0;
68 #endif
69 
70     const uint8_t *image_base;
71     uint32_t image_size;
72 
73     bool sds = false;
74 
75     if (mod_bootloader_ctx.module_config == NULL) {
76         return FWK_E_PARAM;
77     }
78     if (mod_bootloader_ctx.module_config->source_base == 0) {
79         return FWK_E_PARAM;
80     }
81     if (mod_bootloader_ctx.module_config->destination_base == 0) {
82         return FWK_E_PARAM;
83     }
84     if (mod_bootloader_ctx.module_config->source_size == 0) {
85         return FWK_E_PARAM;
86     }
87 
88 #ifdef BUILD_HAS_MOD_SDS
89     sds = mod_bootloader_ctx.module_config->sds_struct_id != 0;
90 #endif
91 
92     if (sds) {
93 #ifdef BUILD_HAS_MOD_SDS
94         /*
95          * Wait until Trusted Firmware writes the image metadata and sets the
96          * data valid flag.
97          */
98         while (true) {
99             status = mod_bootloader_ctx.sds_api->struct_read(
100                 mod_bootloader_ctx.module_config->sds_struct_id,
101                 BOOTLOADER_STRUCT_VALID_POS,
102                 &image_flags,
103                 sizeof(image_flags));
104 
105             if (status != FWK_SUCCESS) {
106                 return status;
107             }
108             if ((image_flags & (uint32_t)IMAGE_FLAGS_VALID_MASK) !=
109                 (uint32_t)0) {
110                 break;
111             }
112         }
113         /*
114          * Clear the image flag, so that at reboot if the RAM contents are
115          * retained, then it would need to be set again by AP.
116          */
117         status = mod_bootloader_ctx.sds_api->struct_write(
118             mod_bootloader_ctx.module_config->sds_struct_id,
119             BOOTLOADER_STRUCT_VALID_POS,
120             &zero_flag,
121             sizeof(zero_flag));
122 
123         if (status != FWK_SUCCESS) {
124             return status;
125         }
126         /*
127          * The image metadata from Trusted Firmware can now be read and
128          * validated.
129          */
130         status = mod_bootloader_ctx.sds_api->struct_read(
131             mod_bootloader_ctx.module_config->sds_struct_id,
132             BOOTLOADER_STRUCT_IMAGE_OFFSET_POS,
133             &image_offset,
134             sizeof(image_offset));
135 
136         if (status != FWK_SUCCESS) {
137             return status;
138         }
139         status = mod_bootloader_ctx.sds_api->struct_read(
140             mod_bootloader_ctx.module_config->sds_struct_id,
141             BOOTLOADER_STRUCT_IMAGE_SIZE_POS,
142             &image_size,
143             sizeof(image_size));
144 
145         if (status != FWK_SUCCESS) {
146             return status;
147         }
148 
149         if (image_size == 0) {
150             return FWK_E_SIZE;
151         }
152         if ((image_offset % 4) != 0) {
153             return FWK_E_ALIGN;
154         }
155         if (image_offset > mod_bootloader_ctx.module_config->source_size) {
156             return FWK_E_SIZE;
157         }
158 
159         /* Read the image header now that its base address is known */
160         image_base =
161             (const uint8_t *)mod_bootloader_ctx.module_config->source_base +
162             image_offset;
163 #endif
164     } else {
165         image_base =
166             (const uint8_t *)mod_bootloader_ctx.module_config->source_base;
167         image_size = mod_bootloader_ctx.module_config->source_size;
168     }
169 
170     if (mod_bootloader_ctx.module_config->destination_size > 0) {
171         if (image_size > mod_bootloader_ctx.module_config->destination_size) {
172             return FWK_E_SIZE;
173         }
174     }
175 
176     (void)
177         fwk_interrupt_global_disable(); /* We are relocating the vector table */
178 
179     FWK_LOG_INFO("[BOOTLOADER] Booting RAM firmware...");
180     FWK_LOG_FLUSH();
181 
182     mod_bootloader_boot(
183         (uint8_t *)mod_bootloader_ctx.module_config->destination_base,
184         image_base,
185         image_size,
186         &SCB->VTOR);
187 }
188 
189 static const struct mod_bootloader_api bootloader_api = {
190     .load_image = load_image,
191 };
192 
193 /*
194  * Framework handlers
195  */
196 
bootloader_init(fwk_id_t module_id,unsigned int element_count,const void * data)197 static int bootloader_init(fwk_id_t module_id, unsigned int element_count,
198     const void *data)
199 {
200     /* Store a pointer to the module config within the module context */
201     mod_bootloader_ctx.module_config = data;
202 
203     return FWK_SUCCESS;
204 }
205 
206 #ifdef BUILD_HAS_MOD_SDS
bootloader_bind(fwk_id_t id,unsigned int call_number)207 static int bootloader_bind(fwk_id_t id, unsigned int call_number)
208 {
209     int status;
210 
211     /* Only the first round of binding is used (round number is zero-indexed) */
212     if (call_number == 1) {
213         return FWK_SUCCESS;
214     }
215 
216     if (fwk_module_is_valid_element_id(id)) {
217         /* No element-level binding required */
218         return FWK_SUCCESS;
219     }
220 
221     status = fwk_module_bind(
222         FWK_ID_MODULE(FWK_MODULE_IDX_SDS),
223         FWK_ID_API(FWK_MODULE_IDX_SDS, 0),
224         &mod_bootloader_ctx.sds_api);
225 
226     return status;
227 }
228 #endif
229 
bootloader_process_bind_request(fwk_id_t requester_id,fwk_id_t id,fwk_id_t api_id,const void ** api)230 static int bootloader_process_bind_request(fwk_id_t requester_id, fwk_id_t id,
231     fwk_id_t api_id, const void **api)
232 {
233     if (api == NULL) {
234         return FWK_E_PARAM;
235     }
236 
237     if (!fwk_module_is_valid_module_id(id)) {
238         return FWK_E_PARAM;
239     }
240 
241     *api = &bootloader_api;
242     return FWK_SUCCESS;
243 }
244 
245 const struct fwk_module module_bootloader = {
246     .type = FWK_MODULE_TYPE_SERVICE,
247     .api_count = 1,
248     .event_count = 0,
249     .init = bootloader_init,
250     .process_bind_request = bootloader_process_bind_request,
251 
252 #ifdef BUILD_HAS_MOD_SDS
253     .bind = bootloader_bind,
254 #endif
255 };
256