xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/fit.c (revision d2517c63c2c4e7d90ca8335f9af5c8308bf3a28a)
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(const void *fit)
24 {
25 	return fdt_totalsize(fit) < FIT_FDT_MAX_SIZE;
26 }
27 
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 
33 static inline int fit_image_addr_is_placeholder(ulong addr)
34 {
35 	return (addr & 0xffffff00) == FIT_PLACEHOLDER_ADDR;
36 }
37 
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 
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 
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 
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 
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 
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 
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 
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 
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_ARM64) && 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 subimage node\n");
289 		return -ENOENT;
290 	}
291 
292 	/* get image data address and length */
293 	if (fit_image_get_data(fit, noffset, &buf, &size)) {
294 		printf("Could not find %s subimage data!\n", FIT_KERNEL_PROP);
295 		return -ENOENT;
296 	}
297 
298 	if (!bootz_setup((ulong)buf, &start, &end))
299 		ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
300 					    "kernel_addr_c", MEM_KERNEL);
301 	else
302 #endif
303 		ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
304 					    "kernel_addr_r", MEM_KERNEL);
305 	if (ret < 0)
306 		return ret;
307 
308 	return fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP,
309 				     "ramdisk_addr_r", MEM_RAMDISK);
310 }
311 
312 int fit_image_fail_process(const void *fit)
313 {
314 	ulong raddr, kaddr, faddr;
315 
316 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
317 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
318 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
319 
320 	sysmem_free((phys_addr_t)fit);
321 	sysmem_free((phys_addr_t)raddr);
322 	sysmem_free((phys_addr_t)kaddr);
323 	sysmem_free((phys_addr_t)faddr);
324 
325 	return 0;
326 }
327 
328 static int fit_image_get_subnode(const void *fit, int noffset, const char *name)
329 {
330 	int sub_noffset;
331 
332 	fdt_for_each_subnode(sub_noffset, fit, noffset) {
333 		if (!strncmp(fit_get_name(fit, sub_noffset, NULL),
334 			     name, strlen(name)))
335 			return sub_noffset;
336 	}
337 
338 	return -ENOENT;
339 }
340 
341 static int fit_image_load_one(const void *fit, struct blk_desc *dev_desc,
342 			      disk_partition_t *part, char *prop_name,
343 			      void *data, int check_hash)
344 {
345 	u32 blk_num, blk_off;
346 	int offset, size;
347 	int noffset, ret;
348 	char *msg = "";
349 
350 	ret = fdt_image_get_offset_size(fit, prop_name, &offset, &size);
351 	if (ret)
352 		return ret;
353 
354 	blk_off = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz;
355 	blk_num = DIV_ROUND_UP(size, dev_desc->blksz);
356 	if (blk_dread(dev_desc, part->start + blk_off, blk_num, data) != blk_num)
357 		return -EIO;
358 
359 	if (check_hash) {
360 		int hash_noffset;
361 
362 		noffset = fit_default_conf_get_node(fit, prop_name);
363 		if (noffset < 0)
364 			return noffset;
365 
366 		hash_noffset = fit_image_get_subnode(fit, noffset,
367 						     FIT_HASH_NODENAME);
368 		if (hash_noffset < 0)
369 			return hash_noffset;
370 
371 		printf("%s: ", fdt_get_name(fit, noffset, NULL));
372 		ret = fit_image_check_hash(fit, hash_noffset, data, size, &msg);
373 		if (ret)
374 			return ret;
375 
376 		puts("+\n");
377 	}
378 
379 	return 0;
380 }
381 
382 /* Calculate what we really need */
383 ulong fit_image_get_bootables_size(const void *fit)
384 {
385 	ulong off[3] = { 0, 0, 0 };
386 	ulong max_off, load;
387 	int offset, size;
388 
389 #if 0
390 	if (!fit_get_totalsize(fit, &size))
391 		return size;
392 #endif
393 
394 	if (!fit_image_get_param(fit, FIT_FDT_PROP, &load, &offset, &size))
395 		off[0] = offset + FIT_ALIGN(size);
396 
397 	if (!fit_image_get_param(fit, FIT_KERNEL_PROP, &load, &offset, &size))
398 		off[1] = offset + FIT_ALIGN(size);
399 
400 	if (!fit_image_get_param(fit, FIT_RAMDISK_PROP, &load, &offset, &size))
401 		off[2] = offset + FIT_ALIGN(size);
402 
403 	max_off = max(off[0],  off[1]);
404 	max_off = max(max_off, off[2]);
405 
406 	return FIT_ALIGN(fdt_totalsize(fit)) + max_off;
407 }
408 
409 void *fit_image_load_bootables(ulong *size)
410 {
411 	struct blk_desc *dev_desc;
412 	disk_partition_t part;
413 	int blk_num;
414 	void *fit;
415 
416 	dev_desc = rockchip_get_bootdev();
417 	if (!dev_desc)
418 		return NULL;
419 
420 	fit = fit_get_blob(dev_desc, &part, false);
421 	if (!fit) {
422 		FIT_I("No fit blob\n");
423 		return NULL;
424 	}
425 
426 	*size = fit_image_get_bootables_size(fit);
427 	if (*size == 0) {
428 		FIT_I("No bootable image\n");
429 		return NULL;
430 	}
431 
432 	blk_num = DIV_ROUND_UP(*size, dev_desc->blksz);
433 	fit = sysmem_alloc(MEM_FIT, blk_num * dev_desc->blksz);
434 	if (!fit)
435 		return NULL;
436 
437 	if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) {
438 		FIT_I("Failed to load bootable images\n");
439 		return NULL;
440 	}
441 
442 	return fit;
443 }
444 
445 static void fit_msg(const void *fit)
446 {
447 	FIT_I("%ssigned, %sconf required\n",
448 	      fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ",
449 	      fit_sig_require_conf(fit, gd_fdt_blob()) ? "" : "no ");
450 }
451 
452 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
453 ulong fit_image_init_resource(struct blk_desc *dev_desc)
454 {
455 	disk_partition_t part;
456 	void *fit, *buf;
457 	int offset, size;
458 	int ret = 0;
459 
460 	if (!dev_desc)
461 		return -ENODEV;
462 
463 	fit = fit_get_blob(dev_desc, &part, true);
464 	if (!fit)
465 		return -EAGAIN;
466 
467 	ret = fdt_image_get_offset_size(fit, FIT_MULTI_PROP, &offset, &size);
468 	if (ret)
469 		return -EINVAL;
470 
471 	buf = memalign(ARCH_DMA_MINALIGN, ALIGN(size, dev_desc->blksz));
472 	if (!buf)
473 		return -ENOMEM;
474 
475 	printf("RESC: '%s', blk@0x%08lx\n", part.name,
476 	       part.start + ((FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz));
477 	ret = fit_image_load_one(fit, dev_desc, &part, FIT_MULTI_PROP, buf, 1);
478 	if (ret)
479 		return ret;
480 
481 	ret = resource_setup_ram_list(dev_desc, buf);
482 	if (ret) {
483 		FIT_I("Failed to setup resource ram list, ret=%d\n", ret);
484 		free(fit);
485 		return ret;
486 	}
487 
488 	fit_msg(fit);
489 	free(fit);
490 
491 	return 0;
492 }
493 #else
494 int fit_image_read_dtb(void *fdt_addr)
495 {
496 	struct blk_desc *dev_desc;
497 	disk_partition_t part;
498 	void *fit;
499 
500 	dev_desc = rockchip_get_bootdev();
501 	if (!dev_desc) {
502 		FIT_I("No dev_desc!\n");
503 		return -ENODEV;;
504 	}
505 
506 	fit = fit_get_blob(dev_desc, &part, true);
507 	if (!fit)
508 		return -EINVAL;
509 
510 	fit_msg(fit);
511 
512 	return fit_image_load_one(fit, dev_desc, &part, FIT_FDT_PROP,
513 				  (void *)fdt_addr, 1);
514 }
515 #endif
516