1
2
3
4
5
6
7#include <common.h>
8#include <errno.h>
9#include <linux/kernel.h>
10#include <asm/io.h>
11#include <asm/system.h>
12#include <asm/types.h>
13#include <asm/macro.h>
14#include <asm/armv8/sec_firmware.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17extern void c_runtime_cpu_setup(void);
18
19#define SEC_FIRMWARE_LOADED 0x1
20#define SEC_FIRMWARE_RUNNING 0x2
21#define SEC_FIRMWARE_ADDR_MASK (~0x3)
22
23
24
25
26
27phys_addr_t sec_firmware_addr;
28
29#ifndef SEC_FIRMWARE_FIT_IMAGE
30#define SEC_FIRMWARE_FIT_IMAGE "firmware"
31#endif
32#ifndef SEC_FIRMEWARE_FIT_CNF_NAME
33#define SEC_FIRMEWARE_FIT_CNF_NAME "config@1"
34#endif
35#ifndef SEC_FIRMWARE_TARGET_EL
36#define SEC_FIRMWARE_TARGET_EL 2
37#endif
38
39static int sec_firmware_get_data(const void *sec_firmware_img,
40 const void **data, size_t *size)
41{
42 int conf_node_off, fw_node_off;
43 char *conf_node_name = NULL;
44 char *desc;
45 int ret;
46
47 conf_node_name = SEC_FIRMEWARE_FIT_CNF_NAME;
48
49 conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
50 if (conf_node_off < 0) {
51 printf("SEC Firmware: %s: no such config\n", conf_node_name);
52 return -ENOENT;
53 }
54
55 fw_node_off = fit_conf_get_prop_node(sec_firmware_img, conf_node_off,
56 SEC_FIRMWARE_FIT_IMAGE);
57 if (fw_node_off < 0) {
58 printf("SEC Firmware: No '%s' in config\n",
59 SEC_FIRMWARE_FIT_IMAGE);
60 return -ENOLINK;
61 }
62
63
64 if (!(fit_image_verify(sec_firmware_img, fw_node_off))) {
65 printf("SEC Firmware: Bad firmware image (bad CRC)\n");
66 return -EINVAL;
67 }
68
69 if (fit_image_get_data(sec_firmware_img, fw_node_off, data, size)) {
70 printf("SEC Firmware: Can't get %s subimage data/size",
71 SEC_FIRMWARE_FIT_IMAGE);
72 return -ENOENT;
73 }
74
75 ret = fit_get_desc(sec_firmware_img, fw_node_off, &desc);
76 if (ret)
77 printf("SEC Firmware: Can't get description\n");
78 else
79 printf("%s\n", desc);
80
81 return ret;
82}
83
84
85
86
87
88
89
90
91static int sec_firmware_parse_image(const void *sec_firmware_img,
92 const void **raw_image_addr,
93 size_t *raw_image_size)
94{
95 int ret;
96
97 ret = sec_firmware_get_data(sec_firmware_img, raw_image_addr,
98 raw_image_size);
99 if (ret)
100 return ret;
101
102 debug("SEC Firmware: raw_image_addr = 0x%p, raw_image_size = 0x%lx\n",
103 *raw_image_addr, *raw_image_size);
104
105 return 0;
106}
107
108
109
110
111
112
113
114
115static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
116 u32 *loadable_l, u32 *loadable_h)
117{
118 phys_addr_t sec_firmware_loadable_addr = 0;
119 int conf_node_off, ld_node_off;
120 char *conf_node_name = NULL;
121 const void *data;
122 size_t size;
123 ulong load;
124
125 conf_node_name = SEC_FIRMEWARE_FIT_CNF_NAME;
126
127 conf_node_off = fit_conf_get_node(sec_firmware_img, conf_node_name);
128 if (conf_node_off < 0) {
129 printf("SEC Firmware: %s: no such config\n", conf_node_name);
130 return -ENOENT;
131 }
132
133 ld_node_off = fit_conf_get_prop_node(sec_firmware_img, conf_node_off,
134 FIT_LOADABLE_PROP);
135 if (ld_node_off >= 0) {
136 printf("SEC Firmware: '%s' present in config\n",
137 FIT_LOADABLE_PROP);
138
139
140 if (!(fit_image_verify(sec_firmware_img, ld_node_off))) {
141 printf("SEC Loadable: Bad loadable image (bad CRC)\n");
142 return -EINVAL;
143 }
144
145 if (fit_image_get_data(sec_firmware_img, ld_node_off,
146 &data, &size)) {
147 printf("SEC Loadable: Can't get subimage data/size");
148 return -ENOENT;
149 }
150
151
152 if (fit_image_get_load(sec_firmware_img, ld_node_off, &load)) {
153 printf("SEC Loadable: Can't get subimage load");
154 return -ENOENT;
155 }
156
157
158 sec_firmware_loadable_addr = (sec_firmware_addr -
159 gd->arch.tlb_size) + load;
160
161
162 debug("%s copied to address 0x%p\n",
163 FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr);
164 memcpy((void *)sec_firmware_loadable_addr, data, size);
165 flush_dcache_range(sec_firmware_loadable_addr,
166 sec_firmware_loadable_addr + size);
167 }
168
169
170 out_le32(loadable_l, (sec_firmware_loadable_addr & WORD_MASK));
171 out_le32(loadable_h, (sec_firmware_loadable_addr >> WORD_SHIFT));
172
173 return 0;
174}
175
176static int sec_firmware_copy_image(const char *title,
177 u64 image_addr, u32 image_size, u64 sec_firmware)
178{
179 debug("%s copied to address 0x%p\n", title, (void *)sec_firmware);
180 memcpy((void *)sec_firmware, (void *)image_addr, image_size);
181 flush_dcache_range(sec_firmware, sec_firmware + image_size);
182
183 return 0;
184}
185
186
187
188
189
190
191static int sec_firmware_load_image(const void *sec_firmware_img,
192 u32 *loadable_l, u32 *loadable_h)
193{
194 const void *raw_image_addr;
195 size_t raw_image_size = 0;
196 int ret;
197
198
199
200
201
202 if (current_el() != 3) {
203 ret = -EACCES;
204 goto out;
205 }
206
207#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
208
209
210
211
212 if (!(gd->arch.secure_ram & MEM_RESERVE_SECURE_MAINTAINED)) {
213 ret = -ENXIO;
214 goto out;
215 }
216
217 sec_firmware_addr = (gd->arch.secure_ram & MEM_RESERVE_SECURE_ADDR_MASK) +
218 gd->arch.tlb_size;
219#else
220#error "The CONFIG_SYS_MEM_RESERVE_SECURE must be defined when enabled SEC Firmware support"
221#endif
222
223
224 sec_firmware_addr = (sec_firmware_addr + 0xfff) & ~0xfff;
225 debug("SEC Firmware: Load address: 0x%llx\n",
226 sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
227
228 ret = sec_firmware_parse_image(sec_firmware_img, &raw_image_addr,
229 &raw_image_size);
230 if (ret)
231 goto out;
232
233
234
235
236
237
238
239 ret = sec_firmware_copy_image("SEC Firmware", (u64)raw_image_addr,
240 raw_image_size, sec_firmware_addr &
241 SEC_FIRMWARE_ADDR_MASK);
242 if (ret)
243 goto out;
244
245
246
247
248
249 ret = sec_firmware_check_copy_loadable(sec_firmware_img, loadable_l,
250 loadable_h);
251 if (ret)
252 goto out;
253
254 sec_firmware_addr |= SEC_FIRMWARE_LOADED;
255 debug("SEC Firmware: Entry point: 0x%llx\n",
256 sec_firmware_addr & SEC_FIRMWARE_ADDR_MASK);
257
258 return 0;
259
260out:
261 printf("SEC Firmware: error (%d)\n", ret);
262 sec_firmware_addr = 0;
263
264 return ret;
265}
266
267static int sec_firmware_entry(u32 *eret_hold_l, u32 *eret_hold_h)
268{
269 const void *entry = (void *)(sec_firmware_addr &
270 SEC_FIRMWARE_ADDR_MASK);
271
272 return _sec_firmware_entry(entry, eret_hold_l, eret_hold_h);
273}
274
275
276__weak bool sec_firmware_is_valid(const void *sec_firmware_img)
277{
278 if (fdt_check_header(sec_firmware_img)) {
279 printf("SEC Firmware: Bad firmware image (not a FIT image)\n");
280 return false;
281 }
282
283 if (!fit_check_format(sec_firmware_img)) {
284 printf("SEC Firmware: Bad firmware image (bad FIT header)\n");
285 return false;
286 }
287
288 return true;
289}
290
291#ifdef CONFIG_SEC_FIRMWARE_ARMV8_PSCI
292
293
294
295
296
297
298
299
300
301
302
303
304unsigned int sec_firmware_support_psci_version(void)
305{
306 if (current_el() == SEC_FIRMWARE_TARGET_EL)
307 return _sec_firmware_support_psci_version();
308
309 return PSCI_INVALID_VER;
310}
311#endif
312
313
314
315
316
317
318
319bool sec_firmware_support_hwrng(void)
320{
321 uint8_t rand[8];
322 if (sec_firmware_addr & SEC_FIRMWARE_RUNNING) {
323 if (!sec_firmware_get_random(rand, 8))
324 return true;
325 }
326
327 return false;
328}
329
330
331
332
333
334
335
336int sec_firmware_get_random(uint8_t *rand, int bytes)
337{
338 unsigned long long num;
339 struct pt_regs regs;
340 int param1;
341
342 if (!bytes || bytes > 8) {
343 printf("Max Random bytes genration supported is 8\n");
344 return -1;
345 }
346#define SIP_RNG_64 0xC200FF11
347 regs.regs[0] = SIP_RNG_64;
348
349 if (bytes <= 4)
350 param1 = 0;
351 else
352 param1 = 1;
353 regs.regs[1] = param1;
354
355 smc_call(®s);
356
357 if (regs.regs[0])
358 return -1;
359
360 num = regs.regs[1];
361 memcpy(rand, &num, bytes);
362
363 return 0;
364}
365
366
367
368
369
370
371
372
373
374int sec_firmware_init(const void *sec_firmware_img,
375 u32 *eret_hold_l,
376 u32 *eret_hold_h,
377 u32 *loadable_l,
378 u32 *loadable_h)
379{
380 int ret;
381
382 if (!sec_firmware_is_valid(sec_firmware_img))
383 return -EINVAL;
384
385 ret = sec_firmware_load_image(sec_firmware_img, loadable_l,
386 loadable_h);
387 if (ret) {
388 printf("SEC Firmware: Failed to load image\n");
389 return ret;
390 } else if (sec_firmware_addr & SEC_FIRMWARE_LOADED) {
391 ret = sec_firmware_entry(eret_hold_l, eret_hold_h);
392 if (ret) {
393 printf("SEC Firmware: Failed to initialize\n");
394 return ret;
395 }
396 }
397
398 debug("SEC Firmware: Return from SEC Firmware: current_el = %d\n",
399 current_el());
400
401
402
403
404
405 if (current_el() != SEC_FIRMWARE_TARGET_EL)
406 return -EACCES;
407
408 sec_firmware_addr |= SEC_FIRMWARE_RUNNING;
409
410
411 if (current_el() != 3) {
412 c_runtime_cpu_setup();
413 enable_caches();
414 }
415
416 return 0;
417}
418
419
420
421
422
423
424int fdt_fixup_kaslr(void *fdt)
425{
426 int nodeoffset;
427 int err, ret = 0;
428 u8 rand[8];
429
430#if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
431
432 if (sec_firmware_support_hwrng() == false)
433 return 0;
434
435 ret = sec_firmware_get_random(rand, 8);
436 if (ret < 0) {
437 printf("WARNING: No random number to set kaslr-seed\n");
438 return 0;
439 }
440
441 err = fdt_check_header(fdt);
442 if (err < 0) {
443 printf("fdt_chosen: %s\n", fdt_strerror(err));
444 return 0;
445 }
446
447
448 nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
449 if (nodeoffset < 0)
450 return 0;
451
452 err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
453 sizeof(rand));
454 if (err < 0) {
455 printf("WARNING: can't set kaslr-seed %s.\n",
456 fdt_strerror(err));
457 return 0;
458 }
459 ret = 1;
460#endif
461
462 return ret;
463}
464