blob: b56ea785c506bed17f7677a5aa625f9a63edd410 [file] [log] [blame]
Hou Zhiqiang505d7352016-06-28 20:18:13 +08001/*
2 * Copyright 2016 NXP Semiconductor, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
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)
Hou Zhiqiang9c2eca12016-09-06 14:23:07 +080022/*
23 * Secure firmware load addr
24 * Flags used: 0x1 secure firmware has been loaded to secure memory
25 * 0x2 secure firmware is running
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
Andre Przywarae0c4ded2017-12-04 02:05:13 +000033#define SEC_FIRMEWARE_FIT_CNF_NAME "config-1"
Hou Zhiqiang9c2eca12016-09-06 14:23:07 +080034#endif
35#ifndef SEC_FIRMWARE_TARGET_EL
36#define SEC_FIRMWARE_TARGET_EL 2
37#endif
Hou Zhiqiang505d7352016-06-28 20:18:13 +080038
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 /* Verify secure firmware image */
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 * SEC Firmware FIT image parser checks if the image is in FIT
86 * format, verifies integrity of the image and calculates raw
87 * image address and size values.
88 *
89 * Returns 0 on success and a negative errno on error task fail.
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
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530108/*
109 * SEC Firmware FIT image parser to check if any loadable is
110 * present. If present, verify integrity of the loadable and
111 * copy loadable to address provided in (loadable_h, loadable_l).
112 *
113 * Returns 0 on success and a negative errno on error task fail.
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 /* Verify secure firmware image */
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 /* Get load address, treated as load offset to secure memory */
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 /* Compute load address for loadable in secure memory */
158 sec_firmware_loadable_addr = (sec_firmware_addr -
159 gd->arch.tlb_size) + load;
160
161 /* Copy loadable to secure memory and flush dcache */
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 /* Populate address ptrs for loadable image with loadbale addr */
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
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800176static 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 * This function will parse the SEC Firmware image, and then load it
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530188 * to secure memory. Also load any loadable if present along with SEC
189 * Firmware image.
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800190 */
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530191static int sec_firmware_load_image(const void *sec_firmware_img,
192 u32 *loadable_l, u32 *loadable_h)
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800193{
194 const void *raw_image_addr;
195 size_t raw_image_size = 0;
196 int ret;
197
198 /*
199 * The Excetpion Level must be EL3 to load and initialize
200 * the SEC Firmware.
201 */
202 if (current_el() != 3) {
203 ret = -EACCES;
204 goto out;
205 }
206
207#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
208 /*
209 * The SEC Firmware must be stored in secure memory.
210 * Append SEC Firmware to secure mmu table.
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 /* Align SEC Firmware base address to 4K */
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 /* TODO:
234 * Check if the end addr of SEC Firmware has been extend the secure
235 * memory.
236 */
237
238 /* Copy the secure firmware to secure memory */
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
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530245 /*
246 * Check if any loadable are present along with firmware image, if
247 * present load them.
248 */
249 ret = sec_firmware_check_copy_loadable(sec_firmware_img, loadable_l,
250 loadable_h);
251 if (ret)
252 goto out;
253
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800254 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/* Check the secure firmware FIT image */
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
Hou Zhiqiang6be115d2017-01-16 17:31:48 +0800291#ifdef CONFIG_SEC_FIRMWARE_ARMV8_PSCI
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800292/*
293 * The PSCI_VERSION function is added from PSCI v0.2. When the PSCI
294 * v0.1 received this function, the NOT_SUPPORTED (0xffff_ffff) error
295 * number will be returned according to SMC Calling Conventions. But
296 * when getting the NOT_SUPPORTED error number, we cannot ensure if
297 * the PSCI version is v0.1 or other error occurred. So, PSCI v0.1
298 * won't be supported by this framework.
299 * And if the secure firmware isn't running, return NOT_SUPPORTED.
300 *
301 * The return value on success is PSCI version in format
302 * major[31:16]:minor[15:0].
303 */
304unsigned int sec_firmware_support_psci_version(void)
305{
York Sune6b871e2017-05-15 08:51:59 -0700306 if (current_el() == SEC_FIRMWARE_TARGET_EL)
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800307 return _sec_firmware_support_psci_version();
308
Yuantian Tangaec3b142017-04-19 13:27:39 +0800309 return PSCI_INVALID_VER;
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800310}
311#endif
312
313/*
Ruchika Guptadb204d72017-08-16 15:58:10 +0530314 * Check with sec_firmware if it supports random number generation
315 * via HW RNG
316 *
317 * The return value will be true if it is supported
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 * sec_firmware_get_random - Get a random number from SEC Firmware
332 * @rand: random number buffer to be filled
333 * @bytes: Number of bytes of random number to be supported
334 * @eret: -1 in case of error, 0 for success
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(&regs);
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/*
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800367 * sec_firmware_init - Initialize the SEC Firmware
368 * @sec_firmware_img: the SEC Firmware image address
369 * @eret_hold_l: the address to hold exception return address low
370 * @eret_hold_h: the address to hold exception return address high
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530371 * @loadable_l: the address to hold loadable address low
372 * @loadable_h: the address to hold loadable address high
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800373 */
374int sec_firmware_init(const void *sec_firmware_img,
375 u32 *eret_hold_l,
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530376 u32 *eret_hold_h,
377 u32 *loadable_l,
378 u32 *loadable_h)
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800379{
380 int ret;
381
382 if (!sec_firmware_is_valid(sec_firmware_img))
383 return -EINVAL;
384
Sumit Gargb6fa55e2017-09-01 13:55:01 +0530385 ret = sec_firmware_load_image(sec_firmware_img, loadable_l,
386 loadable_h);
Hou Zhiqiang505d7352016-06-28 20:18:13 +0800387 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 * The PE will be turned into target EL when returned from
403 * SEC Firmware.
404 */
405 if (current_el() != SEC_FIRMWARE_TARGET_EL)
406 return -EACCES;
407
408 sec_firmware_addr |= SEC_FIRMWARE_RUNNING;
409
410 /* Set exception table and enable caches if it isn't EL3 */
411 if (current_el() != 3) {
412 c_runtime_cpu_setup();
413 enable_caches();
414 }
415
416 return 0;
417}
Ruchika Guptadb204d72017-08-16 15:58:10 +0530418
419/*
420 * fdt_fix_kaslr - Add kalsr-seed node in Device tree
421 * @fdt: Device tree
422 * @eret: 0 in case of error, 1 for success
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 /* Check if random seed generation is supported */
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 /* find or create "/chosen" node. */
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}