1 /*
2 * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6 #include <common.h>
7 #include <boot_rkimg.h>
8 #include <image.h>
9 #include <malloc.h>
10 #include <sysmem.h>
11 #include <asm/arch/fit.h>
12 #include <asm/arch/resource_img.h>
13
14 DECLARE_GLOBAL_DATA_PTR;
15
16 #define FIT_PLACEHOLDER_ADDR 0xffffff00
17
18 /*
19 * Must use args '-E -p' for mkimage to generate FIT image, 4K as max assumption.
20 */
21 #define FIT_FDT_MAX_SIZE SZ_4K
22
fit_is_ext_type(const void * fit)23 static int fit_is_ext_type(const void *fit)
24 {
25 return fdt_totalsize(fit) < FIT_FDT_MAX_SIZE;
26 }
27
fit_is_signed(const void * fit,const void * sig_blob)28 static int fit_is_signed(const void *fit, const void *sig_blob)
29 {
30 return fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME) < 0 ? 0 : 1;
31 }
32
fit_image_addr_is_placeholder(ulong addr)33 static inline int fit_image_addr_is_placeholder(ulong addr)
34 {
35 return (addr & 0xffffff00) == FIT_PLACEHOLDER_ADDR;
36 }
37
fit_sig_require_conf(const void * fit,const void * sig_blob)38 static int fit_sig_require_conf(const void *fit, const void *sig_blob)
39 {
40 const char *required;
41 int sig_node;
42 int noffset;
43
44 sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
45 if (sig_node < 0)
46 return 0;
47
48 fdt_for_each_subnode(noffset, sig_blob, sig_node) {
49 required = fdt_getprop(sig_blob, noffset, "required", NULL);
50 if (required && !strcmp(required, "conf"))
51 return 1;
52 }
53
54 return 0;
55 }
56
fit_default_conf_get_node(const void * fit,const char * prop_name)57 int fit_default_conf_get_node(const void *fit, const char *prop_name)
58 {
59 int conf_noffset;
60
61 conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
62 if (conf_noffset < 0)
63 return conf_noffset;
64
65 return fit_conf_get_prop_node(fit, conf_noffset, prop_name);
66 }
67
fix_image_set_addr(const void * fit,const char * prop_name,ulong old,ulong new)68 int fix_image_set_addr(const void *fit, const char *prop_name,
69 ulong old, ulong new)
70 {
71 int noffset;
72
73 /* do not fix if verified-boot */
74 if (!fit_image_addr_is_placeholder(old) ||
75 fit_sig_require_conf(fit, gd_fdt_blob()))
76 return 0;
77
78 noffset = fit_default_conf_get_node(fit, prop_name);
79 if (noffset < 0)
80 return noffset;
81
82 /* optional */
83 fit_image_set_entry(fit, noffset, new);
84
85 return fit_image_set_load(fit, noffset, new);
86 }
87
fdt_image_get_offset_size(const void * fit,const char * prop_name,int * offset,int * size)88 static int fdt_image_get_offset_size(const void *fit, const char *prop_name,
89 int *offset, int *size)
90 {
91 int sz, offs;
92 int noffset;
93 int ret;
94
95 noffset = fit_default_conf_get_node(fit, prop_name);
96 if (noffset < 0)
97 return noffset;
98
99 ret = fit_image_get_data_size(fit, noffset, &sz);
100 if (ret)
101 return ret;
102
103 ret = fit_image_get_data_position(fit, noffset, &offs);
104 if (!ret)
105 offs -= fdt_totalsize(fit);
106 else
107 ret = fit_image_get_data_offset(fit, noffset, &offs);
108
109 *offset = offs;
110 *size = sz;
111
112 return ret;
113 }
114
fdt_image_get_load(const void * fit,const char * prop_name,ulong * load)115 static int fdt_image_get_load(const void *fit, const char *prop_name,
116 ulong *load)
117 {
118 int noffset;
119
120 noffset = fit_default_conf_get_node(fit, prop_name);
121 if (noffset < 0)
122 return noffset;
123
124 return fit_image_get_load(fit, noffset, load);
125 }
126
fit_image_get_param(const void * fit,const char * prop_name,ulong * load,int * offset,int * size)127 static int fit_image_get_param(const void *fit, const char *prop_name,
128 ulong *load, int *offset, int *size)
129 {
130 int ret;
131
132 ret = fdt_image_get_offset_size(fit, prop_name, offset, size);
133 if (ret < 0)
134 return ret;
135
136 return fdt_image_get_load(fit, prop_name, load);
137 }
138
fit_get_blob(struct blk_desc * dev_desc,disk_partition_t * out_part,bool verify)139 static void *fit_get_blob(struct blk_desc *dev_desc,
140 disk_partition_t *out_part,
141 bool verify)
142 {
143 __maybe_unused int conf_noffset;
144 disk_partition_t part;
145 char *part_name = PART_BOOT;
146 void *fit, *fdt;
147 int blk_num;
148
149 #ifndef CONFIG_ANDROID_AB
150 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
151 part_name = PART_RECOVERY;
152 #endif
153
154 if (part_get_info_by_name(dev_desc, part_name, &part) < 0) {
155 FIT_I("No %s partition\n", part_name);
156 return NULL;
157 }
158
159 *out_part = part;
160 blk_num = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz);
161 fdt = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
162 if (!fdt)
163 return NULL;
164
165 if (blk_dread(dev_desc, part.start, blk_num, fdt) != blk_num) {
166 debug("Failed to read fdt header\n");
167 goto fail;
168 }
169
170 if (fdt_check_header(fdt)) {
171 debug("No fdt header\n");
172 goto fail;
173 }
174
175 if (!fit_is_ext_type(fdt)) {
176 debug("Not external type\n");
177 goto fail;
178 }
179
180 blk_num = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz);
181 fit = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
182 if (!fit) {
183 debug("No memory\n");
184 goto fail;
185 }
186
187 if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) {
188 free(fit);
189 debug("Failed to read fit blob\n");
190 goto fail;
191 }
192
193 #ifdef CONFIG_FIT_SIGNATURE
194 if (!verify)
195 return fit;
196
197 conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
198 if (conf_noffset < 0)
199 goto fail;
200
201 printf("%s: ", fdt_get_name(fit, conf_noffset, NULL));
202 if (fit_config_verify(fit, conf_noffset)) {
203 puts("\n");
204 /* don't remove this failure handle */
205 run_command("download", 0);
206 hang();
207 }
208 puts("\n");
209 #endif
210 return fit;
211
212 fail:
213 free(fdt);
214 return NULL;
215 }
216
fit_image_fixup_alloc(const void * fit,const char * prop_name,const char * addr_name,enum memblk_id mem)217 static int fit_image_fixup_alloc(const void *fit, const char *prop_name,
218 const char *addr_name, enum memblk_id mem)
219 {
220 ulong load, addr;
221 int offset, size = 0;
222 int ret;
223
224 addr = env_get_ulong(addr_name, 16, 0);
225 if (!addr)
226 return -EINVAL;
227
228 ret = fit_image_get_param(fit, prop_name, &load, &offset, &size);
229 if (ret)
230 return (ret == -FDT_ERR_NOTFOUND) ? 0 : ret;
231
232 if (!size)
233 return 0;
234
235 ret = fix_image_set_addr(fit, prop_name, load, addr);
236 if (ret)
237 return ret;
238
239 /*
240 * 1. When need load HWID dtb, gd->fdt_blob points to HWID dtb
241 * and U-Boot will re-alloc MEM_FDT based on fdt node in
242 * ITB instead of resource. So alloc the larger size to
243 * avoid fail in sysmem. It will already skip load DTB in fdt node.
244 *
245 * 2. Additionally increase size with CONFIG_SYS_FDT_PAD to reserve
246 * some space for adding more props to dtb afterwards.
247 */
248 if (!strcmp(prop_name, FIT_FDT_PROP) && !fdt_check_header(gd->fdt_blob))
249 size = ((size > fdt_totalsize(gd->fdt_blob)) ?
250 size : fdt_totalsize(gd->fdt_blob)) +
251 CONFIG_SYS_FDT_PAD;
252
253 if (!sysmem_alloc_base(mem, (phys_addr_t)addr,
254 ALIGN(size, RK_BLK_SIZE)))
255 return -ENOMEM;
256
257 return 0;
258 }
259
fit_image_pre_process(const void * fit)260 int fit_image_pre_process(const void *fit)
261 {
262 int ret;
263
264 /* free for fit_image_fixup_alloc(FIT_FDT_PROP) to re-alloc */
265 if ((gd->flags & GD_FLG_KDTB_READY) && !gd->fdt_blob_kern)
266 sysmem_free((phys_addr_t)gd->fdt_blob);
267
268 ret = fit_image_fixup_alloc(fit, FIT_FDT_PROP,
269 "fdt_addr_r", MEM_FDT);
270 if (ret < 0) {
271 return ret;
272 }
273
274 #if defined(CONFIG_CMD_BOOTZ)
275 int cfg_noffset, noffset;
276 const void *buf;
277 ulong start, end;
278 size_t size;
279
280 cfg_noffset = fit_conf_get_node(fit, NULL);
281 if (cfg_noffset < 0) {
282 printf("Could not find configuration node\n");
283 return -ENOENT;
284 }
285
286 noffset = fit_conf_get_prop_node_index(fit, cfg_noffset, FIT_KERNEL_PROP, 0);
287 if (noffset < 0) {
288 printf("Could not find kernel node\n");
289 return -ENOENT;
290 }
291
292 /*
293 * "kernel_addr_r" is for 64-bit kernel Image by default.
294 * Here in case of 64-bit U-Boot load 32-bit kenrel Image.
295 */
296 #ifdef CONFIG_ARM64
297 char *kernel_addr_r;
298
299 if (fit_image_check_arch(fit, noffset, IH_ARCH_ARM)) {
300 kernel_addr_r = env_get("kernel_addr_aarch32_r");
301 if (kernel_addr_r)
302 env_set("kernel_addr_r", kernel_addr_r);
303 }
304 #endif
305 /* get image data address and length */
306 if (fit_image_get_data(fit, noffset, &buf, &size)) {
307 printf("Could not find %s subimage data!\n", FIT_KERNEL_PROP);
308 return -ENOENT;
309 }
310
311 if (!bootz_setup((ulong)buf, &start, &end))
312 ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
313 "kernel_addr_c", MEM_KERNEL);
314 else
315 #endif
316 ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
317 "kernel_addr_r", MEM_KERNEL);
318 if (ret < 0)
319 return ret;
320
321 return fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP,
322 "ramdisk_addr_r", MEM_RAMDISK);
323 }
324
fit_image_fail_process(const void * fit)325 int fit_image_fail_process(const void *fit)
326 {
327 ulong raddr, kaddr, faddr;
328
329 raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
330 kaddr = env_get_ulong("kernel_addr_r", 16, 0);
331 faddr = env_get_ulong("fdt_addr_r", 16, 0);
332
333 sysmem_free((phys_addr_t)fit);
334 sysmem_free((phys_addr_t)raddr);
335 sysmem_free((phys_addr_t)kaddr);
336 sysmem_free((phys_addr_t)faddr);
337
338 return 0;
339 }
340
fit_image_get_subnode(const void * fit,int noffset,const char * name)341 static int fit_image_get_subnode(const void *fit, int noffset, const char *name)
342 {
343 int sub_noffset;
344
345 fdt_for_each_subnode(sub_noffset, fit, noffset) {
346 if (!strncmp(fit_get_name(fit, sub_noffset, NULL),
347 name, strlen(name)))
348 return sub_noffset;
349 }
350
351 return -ENOENT;
352 }
353
fit_image_load_one(const void * fit,struct blk_desc * dev_desc,disk_partition_t * part,char * prop_name,void * data,int check_hash)354 static int fit_image_load_one(const void *fit, struct blk_desc *dev_desc,
355 disk_partition_t *part, char *prop_name,
356 void *data, int check_hash)
357 {
358 u32 blk_num, blk_off;
359 int offset, size;
360 int noffset, ret;
361 char *msg = "";
362
363 ret = fdt_image_get_offset_size(fit, prop_name, &offset, &size);
364 if (ret)
365 return ret;
366
367 blk_off = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz;
368 blk_num = DIV_ROUND_UP(size, dev_desc->blksz);
369 if (blk_dread(dev_desc, part->start + blk_off, blk_num, data) != blk_num)
370 return -EIO;
371
372 if (check_hash) {
373 int hash_noffset;
374
375 noffset = fit_default_conf_get_node(fit, prop_name);
376 if (noffset < 0)
377 return noffset;
378
379 hash_noffset = fit_image_get_subnode(fit, noffset,
380 FIT_HASH_NODENAME);
381 if (hash_noffset < 0)
382 return hash_noffset;
383
384 printf("%s: ", fdt_get_name(fit, noffset, NULL));
385 ret = fit_image_check_hash(fit, hash_noffset, data, size, &msg);
386 if (ret)
387 return ret;
388
389 puts("+\n");
390 }
391
392 return 0;
393 }
394
395 /* Calculate what we really need */
fit_image_get_bootables_size(const void * fit)396 ulong fit_image_get_bootables_size(const void *fit)
397 {
398 ulong off[3] = { 0, 0, 0 };
399 ulong max_off, load;
400 int offset, size;
401
402 #if 0
403 if (!fit_get_totalsize(fit, &size))
404 return size;
405 #endif
406
407 if (!fit_image_get_param(fit, FIT_FDT_PROP, &load, &offset, &size))
408 off[0] = offset + FIT_ALIGN(size);
409
410 if (!fit_image_get_param(fit, FIT_KERNEL_PROP, &load, &offset, &size))
411 off[1] = offset + FIT_ALIGN(size);
412
413 if (!fit_image_get_param(fit, FIT_RAMDISK_PROP, &load, &offset, &size))
414 off[2] = offset + FIT_ALIGN(size);
415
416 max_off = max(off[0], off[1]);
417 max_off = max(max_off, off[2]);
418
419 return FIT_ALIGN(fdt_totalsize(fit)) + max_off;
420 }
421
fit_image_load_bootables(ulong * size)422 void *fit_image_load_bootables(ulong *size)
423 {
424 struct blk_desc *dev_desc;
425 disk_partition_t part;
426 int blk_num;
427 void *fit;
428
429 dev_desc = rockchip_get_bootdev();
430 if (!dev_desc)
431 return NULL;
432
433 fit = fit_get_blob(dev_desc, &part, false);
434 if (!fit) {
435 FIT_I("No fit blob\n");
436 return NULL;
437 }
438
439 *size = fit_image_get_bootables_size(fit);
440 if (*size == 0) {
441 FIT_I("No bootable image\n");
442 return NULL;
443 }
444
445 blk_num = DIV_ROUND_UP(*size, dev_desc->blksz);
446 fit = sysmem_alloc(MEM_FIT, blk_num * dev_desc->blksz);
447 if (!fit)
448 return NULL;
449
450 if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) {
451 FIT_I("Failed to load bootable images\n");
452 return NULL;
453 }
454
455 return fit;
456 }
457
fit_msg(const void * fit)458 static void fit_msg(const void *fit)
459 {
460 FIT_I("%ssigned, %sconf required\n",
461 fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ",
462 fit_sig_require_conf(fit, gd_fdt_blob()) ? "" : "no ");
463 }
464
465 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
fit_image_init_resource(struct blk_desc * dev_desc)466 ulong fit_image_init_resource(struct blk_desc *dev_desc)
467 {
468 disk_partition_t part;
469 void *fit, *buf;
470 int offset, size;
471 int ret = 0;
472
473 if (!dev_desc)
474 return -ENODEV;
475
476 fit = fit_get_blob(dev_desc, &part, true);
477 if (!fit)
478 return -EAGAIN;
479
480 ret = fdt_image_get_offset_size(fit, FIT_MULTI_PROP, &offset, &size);
481 if (ret)
482 return -EINVAL;
483
484 buf = memalign(ARCH_DMA_MINALIGN, ALIGN(size, dev_desc->blksz));
485 if (!buf)
486 return -ENOMEM;
487
488 printf("RESC: '%s', blk@0x%08lx\n", part.name,
489 part.start + ((FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz));
490 ret = fit_image_load_one(fit, dev_desc, &part, FIT_MULTI_PROP, buf, 1);
491 if (ret)
492 return ret;
493
494 ret = resource_setup_ram_list(dev_desc, buf);
495 if (ret) {
496 FIT_I("Failed to setup resource ram list, ret=%d\n", ret);
497 free(fit);
498 return ret;
499 }
500
501 fit_msg(fit);
502 free(fit);
503
504 return 0;
505 }
506 #else
fit_image_read_dtb(void * fdt_addr)507 int fit_image_read_dtb(void *fdt_addr)
508 {
509 struct blk_desc *dev_desc;
510 disk_partition_t part;
511 void *fit;
512
513 dev_desc = rockchip_get_bootdev();
514 if (!dev_desc) {
515 FIT_I("No dev_desc!\n");
516 return -ENODEV;;
517 }
518
519 fit = fit_get_blob(dev_desc, &part, true);
520 if (!fit)
521 return -EINVAL;
522
523 fit_msg(fit);
524
525 return fit_image_load_one(fit, dev_desc, &part, FIT_FDT_PROP,
526 (void *)fdt_addr, 1);
527 }
528 #endif
529