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