xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/fit.c (revision 008ec9b4bc06f98dd7efdc7d2f44eb066be036e6)
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		0xffffffff
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 
23 static int fit_is_ext_type(void *fit)
24 {
25 	return fdt_totalsize(fit) < FIT_FDT_MAX_SIZE;
26 }
27 
28 static int fit_is_signed(void *fit, const void *sig_blob)
29 {
30 	return fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME) < 0 ? 0 : 1;
31 }
32 
33 static int fit_is_required(void *fit, const void *sig_blob)
34 {
35 	int sig_node;
36 	int noffset;
37 
38 	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
39 	if (sig_node < 0)
40 		return 0;
41 
42 	fdt_for_each_subnode(noffset, sig_blob, sig_node) {
43 		const char *required;
44 
45 		required = fdt_getprop(sig_blob, noffset, "required", NULL);
46 		if (required && !strcmp(required, "conf"))
47 			return 1;
48 	}
49 
50 	return 0;
51 }
52 
53 static int fit_get_image_defconf_node(void *fit, int *images, int *defconf)
54 {
55 	int images_node, confs_node, defconf_node;
56 	const char *def_name;
57 
58 	images_node = fdt_path_offset(fit, FIT_IMAGES_PATH);
59 	if (images_node < 0)
60 		return images_node;
61 
62 	confs_node = fdt_path_offset(fit, FIT_CONFS_PATH);
63 	if (confs_node < 0)
64 		return confs_node;
65 
66 	def_name = fdt_getprop(fit, confs_node, FIT_DEFAULT_PROP, NULL);
67 	if (!def_name)
68 		return -ENOENT;
69 
70 	defconf_node = fdt_subnode_offset(fit, confs_node, def_name);
71 	if (defconf_node < 0)
72 		return defconf_node;
73 
74 	*images = images_node;
75 	*defconf = defconf_node;
76 
77 	return 0;
78 }
79 
80 int fit_fixup_load_entry(void *fit, int images, int defconf,
81 			 char *name, ulong *load, ulong new_addr)
82 {
83 	const char *uname;
84 	int uname_cfg;
85 	int err;
86 
87 	if ((*load != FIT_PLACEHOLDER_ADDR) ||
88 		fit_is_required(fit, gd_fdt_blob()))
89 		return 0;
90 
91 	*load = new_addr;
92 
93 	uname = fdt_getprop(fit, defconf, name, NULL);
94 	if (!uname)
95 		return -ENODEV;
96 
97 	uname_cfg = fdt_subnode_offset(fit, images, uname);
98 	if (uname_cfg < 0)
99 		return -ENODEV;
100 
101 	err = fit_image_set_load(fit, uname_cfg, new_addr);
102 	if (err)
103 		return err;
104 
105 	fit_image_set_entry(fit, uname_cfg, new_addr);
106 
107 	return 0;
108 }
109 
110 static int fit_get_load_and_data(void *fit, int images, int defconf,
111 				 const char *name, ulong *load,
112 				 int *offset, int *size)
113 {
114 	const char *uname;
115 	int uname_cfg;
116 	int off, sz;
117 	int err;
118 
119 	uname = fdt_getprop(fit, defconf, name, NULL);
120 	if (!uname)
121 		return -ENODEV;
122 
123 	uname_cfg = fdt_subnode_offset(fit, images, uname);
124 	if (uname_cfg < 0)
125 		return -ENODEV;
126 
127 	err = fit_image_get_data_size(fit, uname_cfg, &sz);
128 	if (err)
129 		return err;
130 
131 	err = fit_image_get_data_position(fit, uname_cfg, &off);
132 	if (!err) {
133 		off -= fdt_totalsize(fit);
134 	} else {
135 		err = fit_image_get_data_offset(fit, uname_cfg, &off);
136 		if (err)
137 			return err;
138 	}
139 
140 	/* optional */
141 	if (load) {
142 		err = fit_image_get_load(fit, uname_cfg, load);
143 		if (err)
144 			return err;
145 	}
146 
147 	*offset = off;
148 	*size = sz;
149 
150 	return 0;
151 }
152 
153 int fit_image_fixup_and_sysmem_rsv(void *fit)
154 {
155 	ulong load, kaddr, faddr, raddr;
156 	int images, defconf;
157 	int offset, size;
158 	int err;
159 
160 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
161 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
162 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
163 
164 	if (!faddr || !kaddr || !raddr)
165 		return -EINVAL;
166 
167 	if (fit_get_image_defconf_node(fit, &images, &defconf)) {
168 		FIT_I("Failed to get default config\n");
169 		return -ENODEV;
170 	}
171 
172 	/* fdt */
173 	if (fit_get_load_and_data(fit, images, defconf, FIT_FDT_PROP,
174 				  &load, &offset, &size)) {
175 		FIT_I("Invalid fdt node\n");
176 		return -ENOENT;
177 	}
178 
179 #ifdef CONFIG_USING_KERNEL_DTB
180 	sysmem_free((phys_addr_t)gd->fdt_blob);
181 #endif
182 	if (fit_fixup_load_entry(fit, images, defconf,
183 				 FIT_FDT_PROP, &load, faddr)) {
184 		FIT_I("Failed to fixup fdt load addr\n");
185 		return -EINVAL;
186 	}
187 
188 	if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)load,
189 			       ALIGN(size, RK_BLK_SIZE)))
190 		return -ENOMEM;
191 
192 	/* kernel */
193 	if (fit_get_load_and_data(fit, images, defconf, FIT_KERNEL_PROP,
194 				  &load, &offset, &size)) {
195 		FIT_I("Invalid kernel node\n");
196 		return -EINVAL;
197 	}
198 
199 	if (fit_fixup_load_entry(fit, images, defconf,
200 				 FIT_KERNEL_PROP, &load, kaddr)) {
201 		FIT_I("Failed to fixup kernel load addr\n");
202 		return -EINVAL;
203 	}
204 
205 	if (!sysmem_alloc_base(MEM_KERNEL, (phys_addr_t)load,
206 			       ALIGN(size, RK_BLK_SIZE)))
207 		return -ENOMEM;
208 
209 	/* ramdisk(optional) */
210 	err = fit_get_load_and_data(fit, images, defconf, FIT_RAMDISK_PROP,
211 				    &load, &offset, &size);
212 	if (err && err != -ENODEV) {
213 		FIT_I("Invalid ramdisk node\n");
214 		return err;
215 	}
216 
217 	if (size) {
218 		if (fit_fixup_load_entry(fit, images, defconf,
219 					 FIT_RAMDISK_PROP, &load, raddr)) {
220 			FIT_I("Failed to fixup ramdisk load addr\n");
221 			return -EINVAL;
222 		}
223 
224 		if (!sysmem_alloc_base(MEM_RAMDISK, (phys_addr_t)load,
225 				       ALIGN(size, RK_BLK_SIZE)))
226 			return -ENOMEM;
227 	}
228 
229 	return 0;
230 }
231 
232 int fit_sysmem_free_each(void *fit)
233 {
234 	ulong raddr, kaddr, faddr;
235 
236 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
237 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
238 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
239 
240 	sysmem_free((phys_addr_t)fit);
241 	sysmem_free((phys_addr_t)raddr);
242 	sysmem_free((phys_addr_t)kaddr);
243 	sysmem_free((phys_addr_t)faddr);
244 
245 	return 0;
246 }
247 
248 static int fit_image_load_one(void *fit, struct blk_desc *dev_desc,
249 			      disk_partition_t *part, int images,
250 			      int defconf, char *name, void *dst)
251 {
252 	u32 blknum, blkoff;
253 	int offset, size;
254 
255 	if (fit_get_load_and_data(fit, images, defconf, name,
256 				  NULL, &offset, &size))
257 		return -EINVAL;
258 
259 	blkoff = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz;
260 	blknum = DIV_ROUND_UP(size, dev_desc->blksz);
261 
262 	if (blk_dread(dev_desc, part->start + blkoff, blknum, dst) != blknum)
263 		return -EIO;
264 
265 	return 0;
266 }
267 
268 static int fit_image_load_fdt(void *fit, struct blk_desc *dev_desc,
269 			      disk_partition_t *part, int images,
270 			      int defconf, void *dst)
271 {
272 	return fit_image_load_one(fit, dev_desc, part, images,
273 				  defconf, FIT_FDT_PROP, dst);
274 }
275 
276 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
277 static int fit_image_load_resource(void *fit, struct blk_desc *dev_desc,
278 				   disk_partition_t *part, int images,
279 				   int defconf, ulong *addr)
280 {
281 	ulong fdt_addr_r, dst;
282 	int offset, size;
283 	int err;
284 
285 	err = fit_get_load_and_data(fit, images, defconf, FIT_MULTI_PROP,
286 				    NULL, &offset, &size);
287 	if (err)
288 		return err;
289 
290 	fdt_addr_r = env_get_ulong("fdt_addr_r", 16, 0);
291 	if (!fdt_addr_r)
292 		return -EINVAL;
293 
294 	/* reserve enough space before fdt */
295 	dst = fdt_addr_r -
296 		ALIGN(size, dev_desc->blksz) - CONFIG_SYS_FDT_PAD;
297 
298 	if (!sysmem_alloc_base(MEM_RESOURCE, (phys_addr_t)dst,
299 			       ALIGN(size, dev_desc->blksz)))
300 		return -ENOMEM;
301 
302 	*addr = dst;
303 
304 	return fit_image_load_one(fit, dev_desc, part, images, defconf,
305 				  FIT_MULTI_PROP, (void *)dst);
306 }
307 #endif
308 
309 static void *fit_get_blob(struct blk_desc *dev_desc, disk_partition_t *part)
310 {
311 	void *fit, *fdt;
312 	int blknum;
313 
314 	blknum = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz);
315 	fdt = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz);
316 	if (!fdt)
317 		return NULL;
318 
319 	if (blk_dread(dev_desc, part->start, blknum, fdt) != blknum) {
320 		FIT_I("Failed to read fdt header\n");
321 		goto fail;
322 	}
323 
324 	if (fdt_check_header(fdt)) {
325 		FIT_I("Invalid fdt header\n");
326 		goto fail;
327 	}
328 
329 	if (!fit_is_ext_type(fdt)) {
330 		FIT_I("Not external type\n");
331 		goto fail;
332 	}
333 
334 	blknum = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz);
335 	fit = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz);
336 	if (!fit) {
337 		FIT_I("No memory\n");
338 		goto fail;
339 	}
340 
341 	if (blk_dread(dev_desc, part->start, blknum, fit) != blknum) {
342 		free(fit);
343 		FIT_I("Failed to read fit\n");
344 		goto fail;
345 	}
346 
347 	return fit;
348 
349 fail:
350 	free(fdt);
351 	return NULL;
352 }
353 
354 static int fit_image_get_fdt_hash(void *fit, int images, int defconf,
355 				  char **hash, int *hash_size)
356 {
357 	const char *fdt_name;
358 	const char *name;
359 	uint8_t *fit_value2;
360 	uint8_t *fit_value;
361 	int fit_value_len;
362 	int hash_off;
363 	int fdt_off;
364 	int found = 0;
365 	char *algo;
366 
367 	fdt_name = fdt_getprop(fit, defconf, FIT_FDT_PROP, NULL);
368 	if (!fdt_name)
369 		return -EBADF;
370 
371 	fdt_off = fdt_subnode_offset(fit, images, fdt_name);
372 	if (fdt_off < 0)
373 		return -EBADF;
374 
375 	fdt_for_each_subnode(hash_off, fit, fdt_off) {
376 		name = fit_get_name(fit, hash_off, NULL);
377 		if (!strncmp(name, FIT_HASH_NODENAME,
378 			     strlen(FIT_HASH_NODENAME))) {
379 			found = 1;
380 			break;
381 		}
382 	}
383 
384 	if (!found)
385 		return -ENODEV;
386 
387 	if (fit_image_hash_get_algo(fit, hash_off, &algo))
388 		return -EINVAL;
389 
390 	if (fit_image_hash_get_value(fit, hash_off, &fit_value,
391 				     &fit_value_len))
392 		return -EINVAL;
393 
394 	if (!strcmp(algo, "sha1"))
395 		*hash_size = 20;
396 	else if (!strcmp(algo, "sha256"))
397 		*hash_size = 32;
398 	else
399 		return -EINVAL;
400 
401 	/* avoid freed */
402 	fit_value2 = malloc(fit_value_len);
403 	if (!fit_value2)
404 		return -ENOMEM;
405 
406 	memcpy(fit_value2, fit_value, fit_value_len);
407 	*hash = (char *)fit_value2;
408 
409 	return 0;
410 }
411 
412 ulong fit_image_get_bootable_size(void *fit)
413 {
414 	ulong off[3] = { 0, 0, 0 };
415 	ulong max_off, load;
416 	int images, defconf;
417 	int offset, size;
418 
419 	if (fit_get_image_defconf_node(fit, &images, &defconf))
420 		return -ENODEV;
421 
422 	if (!fit_get_load_and_data(fit, images, defconf, FIT_FDT_PROP,
423 				   &load, &offset, &size))
424 		off[0] = offset + FIT_ALIGN(size);
425 
426 	if (!fit_get_load_and_data(fit, images, defconf, FIT_KERNEL_PROP,
427 				   &load, &offset, &size))
428 		off[1] = offset + FIT_ALIGN(size);
429 
430 	if (!fit_get_load_and_data(fit, images, defconf, FIT_RAMDISK_PROP,
431 				   &load, &offset, &size))
432 		off[2] = offset + FIT_ALIGN(size);
433 
434 	max_off = max(off[0],  off[1]);
435 	max_off = max(max_off, off[2]);
436 
437 	return FIT_ALIGN(fdt_totalsize(fit)) + max_off;
438 }
439 
440 void *fit_image_load_bootables(ulong *size)
441 {
442 	struct blk_desc *dev_desc;
443 	disk_partition_t part;
444 	char *part_name;
445 	int blknum;
446 	void *fit;
447 
448 	dev_desc = rockchip_get_bootdev();
449 	if (!dev_desc) {
450 		FIT_I("No dev_desc\n");
451 		return NULL;
452 	}
453 
454 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
455 		part_name = PART_RECOVERY;
456 	else
457 		part_name = PART_BOOT;
458 
459 	if (part_get_info_by_name(dev_desc, part_name, &part) < 0) {
460 		FIT_I("No %s partition\n", part_name);
461 		return NULL;
462 	}
463 
464 	fit = fit_get_blob(dev_desc, &part);
465 	if (!fit) {
466 		FIT_I("No fit blob\n");
467 		return NULL;
468 	}
469 
470 	*size = fit_image_get_bootable_size(fit);
471 	if (*size == 0) {
472 		FIT_I("No bootable image size\n");
473 		return NULL;
474 	}
475 
476 	blknum = DIV_ROUND_UP(*size, dev_desc->blksz);
477 	fit = sysmem_alloc(MEM_FIT, blknum * dev_desc->blksz);
478 	if (!fit)
479 		return NULL;
480 
481 	if (blk_dread(dev_desc, part.start, blknum, fit) != blknum) {
482 		FIT_I("Failed to load bootable images\n");
483 		return NULL;
484 	}
485 
486 	return fit;
487 }
488 
489 static void verbose_msg(void *fit, int defconf)
490 {
491 	FIT_I("%ssigned, %srequired\n",
492 	      fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ",
493 	      fit_is_required(fit, gd_fdt_blob()) ? "" : "no ");
494 
495 	printf("DTB: %s\n",
496 	       (char *)fdt_getprop(fit, defconf, FIT_FDT_PROP, NULL));
497 }
498 
499 int rockchip_read_fit_dtb(void *fdt_addr, char **hash, int *hash_size)
500 {
501 	struct blk_desc *dev_desc;
502 	disk_partition_t part;
503 	char *part_name;
504 	void *fit;
505 	ulong rsce;
506 	int images;
507 	int defconf;
508 	int err;
509 
510 	dev_desc = rockchip_get_bootdev();
511 	if (!dev_desc) {
512 		FIT_I("No dev_desc!\n");
513 		return -ENODEV;
514 	}
515 
516 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
517 		part_name = PART_RECOVERY;
518 	else
519 		part_name = PART_BOOT;
520 
521 	err = part_get_info_by_name(dev_desc, part_name, &part);
522 	if (err < 0) {
523 		FIT_I("No %s partition\n", part_name);
524 		return err;
525 	}
526 
527 	fit = fit_get_blob(dev_desc, &part);
528 	if (!fit) {
529 		FIT_I("No fdt description\n");
530 		return -EINVAL;
531 	}
532 
533 	if (fit_get_image_defconf_node(fit, &images, &defconf)) {
534 		FIT_I("Failed to get /images and /configures default\n");
535 		err = -ENODEV;
536 		goto out;
537 	}
538 
539 	if (fit_image_load_fdt(fit, dev_desc, &part,
540 			       images, defconf, fdt_addr)) {
541 		FIT_I("Failed to load fdt\n");
542 		err = -EINVAL;
543 		goto out;
544 	}
545 
546 	err = fit_image_get_fdt_hash(fit, images, defconf, hash, hash_size);
547 	if (err && err != -ENODEV) {
548 		FIT_I("Failed to get fdt hash\n");
549 		err = -EINVAL;
550 		goto out;
551 	}
552 
553 	verbose_msg(fit, defconf);
554 
555 	/* load resource file */
556 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
557 	err = fit_image_load_resource(fit, dev_desc, &part,
558 				      images, defconf, &rsce);
559 	if (!err) {
560 		if (resource_create_ram_list(dev_desc, (void *)rsce))
561 			FIT_I("Failed to create resource list\n");
562 	} else if (err == -ENODEV) {
563 		FIT_I("No resource file\n");
564 	} else {
565 		FIT_I("Failed to load resource file\n");
566 	}
567 #endif
568 out:
569 	free(fit);
570 
571 	return err;
572 }
573