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