xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/fit.c (revision a1daefc8e61099cd3e2c89eba707e5fa507c749b)
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 static int fit_image_get_subnode(const void *fit, int noffset, const char *name)
58 {
59 	int sub_noffset;
60 
61 	fdt_for_each_subnode(sub_noffset, fit, noffset) {
62 		if (!strncmp(fit_get_name(fit, sub_noffset, NULL),
63 			     name, strlen(name)))
64 			return sub_noffset;
65 	}
66 
67 	return -ENOENT;
68 }
69 
70 int fit_default_conf_get_node(const void *fit, const char *prop_name)
71 {
72 	int conf_noffset;
73 
74 	conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
75 	if (conf_noffset < 0)
76 		return conf_noffset;
77 
78 	return fit_conf_get_prop_node(fit, conf_noffset, prop_name);
79 }
80 
81 int fix_image_set_addr(const void *fit, const char *prop_name,
82 		       ulong old, ulong new)
83 {
84 	int noffset;
85 
86 	/* do not fix if verified-boot */
87 	if (!fit_image_addr_is_placeholder(old) ||
88 	     fit_sig_require_conf(fit, gd_fdt_blob()))
89 		return 0;
90 
91 	noffset = fit_default_conf_get_node(fit, prop_name);
92 	if (noffset < 0)
93 		return noffset;
94 
95 	/* optional */
96 	fit_image_set_entry(fit, noffset, new);
97 
98 	return fit_image_set_load(fit, noffset, new);
99 }
100 
101 static int fdt_image_get_offset_size(const void *fit, const char *prop_name,
102 				     int *offset, int *size)
103 {
104 	int sz, offs;
105 	int noffset;
106 	int ret;
107 
108 	noffset = fit_default_conf_get_node(fit, prop_name);
109 	if (noffset < 0)
110 		return noffset;
111 
112 	ret = fit_image_get_data_size(fit, noffset, &sz);
113 	if (ret)
114 		return ret;
115 
116 	ret = fit_image_get_data_position(fit, noffset, &offs);
117 	if (!ret)
118 		offs -= fdt_totalsize(fit);
119 	else
120 		ret = fit_image_get_data_offset(fit, noffset, &offs);
121 
122 	*offset = offs;
123 	*size = sz;
124 
125 	return ret;
126 }
127 
128 static int fdt_image_get_load(const void *fit, const char *prop_name,
129 			      ulong *load)
130 {
131 	int noffset;
132 
133 	noffset = fit_default_conf_get_node(fit, prop_name);
134 	if (noffset < 0)
135 		return noffset;
136 
137 	return fit_image_get_load(fit, noffset, load);
138 }
139 
140 static int fit_image_get_param(const void *fit, const char *prop_name,
141 			       ulong *load, int *offset, int *size)
142 {
143 	int ret;
144 
145 	ret = fdt_image_get_offset_size(fit, prop_name, offset, size);
146 	if (ret < 0)
147 		return ret;
148 
149 	return fdt_image_get_load(fit, prop_name, load);
150 }
151 
152 static void *fit_get_blob(struct blk_desc *dev_desc, disk_partition_t *part)
153 {
154 	void *fit, *fdt;
155 	int blk_num;
156 
157 	blk_num = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz);
158 	fdt = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
159 	if (!fdt)
160 		return NULL;
161 
162 	if (blk_dread(dev_desc, part->start, blk_num, fdt) != blk_num) {
163 		debug("Failed to read fdt header\n");
164 		goto fail;
165 	}
166 
167 	if (fdt_check_header(fdt)) {
168 		debug("No fdt header\n");
169 		goto fail;
170 	}
171 
172 	if (!fit_is_ext_type(fdt)) {
173 		debug("Not external type\n");
174 		goto fail;
175 	}
176 
177 	blk_num = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz);
178 	fit = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
179 	if (!fit) {
180 		debug("No memory\n");
181 		goto fail;
182 	}
183 
184 	if (blk_dread(dev_desc, part->start, blk_num, fit) != blk_num) {
185 		free(fit);
186 		debug("Failed to read fit blob\n");
187 		goto fail;
188 	}
189 
190 	return fit;
191 
192 fail:
193 	free(fdt);
194 	return NULL;
195 }
196 
197 static int fit_image_fixup_alloc(const void *fit, const char *prop_name,
198 				 const char *addr_name, enum memblk_id mem)
199 {
200 	ulong load, addr;
201 	int offset, size = 0;
202 	int ret;
203 
204 	addr = env_get_ulong(addr_name, 16, 0);
205 	if (!addr)
206 		return -EINVAL;
207 
208 	ret = fit_image_get_param(fit, prop_name, &load, &offset, &size);
209 	if (ret)
210 		return (ret == -FDT_ERR_NOTFOUND) ? 0 : ret;
211 
212 	if (!size)
213 		return 0;
214 
215 	ret = fix_image_set_addr(fit, prop_name, load, addr);
216 	if (ret)
217 		return ret;
218 
219 	if (!sysmem_alloc_base(mem, (phys_addr_t)addr,
220 			       ALIGN(size, RK_BLK_SIZE)))
221 		return -ENOMEM;
222 
223 	return 0;
224 }
225 
226 int fit_image_pre_process(const void *fit)
227 {
228 	int ret;
229 
230 #ifdef CONFIG_USING_KERNEL_DTB
231 	sysmem_free((phys_addr_t)gd->fdt_blob);
232 #endif
233 	ret = fit_image_fixup_alloc(fit, FIT_FDT_PROP,
234 				    "fdt_addr_r", MEM_FDT);
235 	if (ret < 0)
236 		return ret;
237 
238 	ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
239 				    "kernel_addr_r", MEM_KERNEL);
240 	if (ret < 0)
241 		return ret;
242 
243 	return fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP,
244 				     "ramdisk_addr_r", MEM_RAMDISK);
245 }
246 
247 int fit_image_fail_process(const void *fit)
248 {
249 	ulong raddr, kaddr, faddr;
250 
251 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
252 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
253 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
254 
255 	sysmem_free((phys_addr_t)fit);
256 	sysmem_free((phys_addr_t)raddr);
257 	sysmem_free((phys_addr_t)kaddr);
258 	sysmem_free((phys_addr_t)faddr);
259 
260 	return 0;
261 }
262 
263 static int fit_image_load_one(const void *fit, struct blk_desc *dev_desc,
264 			      disk_partition_t *part, char *prop_name,
265 			      void *data, int check_hash)
266 {
267 	u32 blk_num, blk_off;
268 	int offset, size;
269 	int noffset, ret;
270 	char *msg = "";
271 
272 	ret = fdt_image_get_offset_size(fit, prop_name, &offset, &size);
273 	if (ret)
274 		return ret;
275 
276 	blk_off = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz;
277 	blk_num = DIV_ROUND_UP(size, dev_desc->blksz);
278 	if (blk_dread(dev_desc, part->start + blk_off, blk_num, data) != blk_num)
279 		return -EIO;
280 
281 	if (check_hash) {
282 		int hash_noffset;
283 
284 		noffset = fit_default_conf_get_node(fit, prop_name);
285 		if (noffset < 0)
286 			return noffset;
287 
288 		hash_noffset = fit_image_get_subnode(fit, noffset,
289 						     FIT_HASH_NODENAME);
290 		if (hash_noffset < 0)
291 			return hash_noffset;
292 
293 		printf("%s: ", fdt_get_name(fit, noffset, NULL));
294 		ret = fit_image_check_hash(fit, hash_noffset, data, size, &msg);
295 		if (ret)
296 			return ret;
297 
298 		puts("+\n");
299 	}
300 
301 	return 0;
302 }
303 
304 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
305 static int fit_image_load_resource(const void *fit, struct blk_desc *dev_desc,
306 				   disk_partition_t *part, ulong *addr)
307 {
308 	int offset, size;
309 	int ret;
310 	void *data;
311 
312 	ret = fdt_image_get_offset_size(fit, FIT_MULTI_PROP, &offset, &size);
313 	if (ret)
314 		return ret;
315 
316 	data = malloc(ALIGN(size, dev_desc->blksz));
317 	if (!data)
318 		return -ENOMEM;
319 
320 	*addr = (ulong)data;
321 
322 	return fit_image_load_one(fit, dev_desc, part, FIT_MULTI_PROP, data, 1);
323 }
324 
325 #else
326 static int fit_image_load_fdt(const void *fit, struct blk_desc *dev_desc,
327 			      disk_partition_t *part, void *data)
328 {
329 	return fit_image_load_one(fit, dev_desc, part, FIT_FDT_PROP, data, 1);
330 }
331 #endif
332 
333 /* Calculate what we really need */
334 ulong fit_image_get_bootables_size(const void *fit)
335 {
336 	ulong off[3] = { 0, 0, 0 };
337 	ulong max_off, load;
338 	int offset, size;
339 
340 	if (!fit_image_get_param(fit, FIT_FDT_PROP, &load, &offset, &size))
341 		off[0] = offset + FIT_ALIGN(size);
342 
343 	if (!fit_image_get_param(fit, FIT_KERNEL_PROP, &load, &offset, &size))
344 		off[1] = offset + FIT_ALIGN(size);
345 
346 	if (!fit_image_get_param(fit, FIT_RAMDISK_PROP, &load, &offset, &size))
347 		off[2] = offset + FIT_ALIGN(size);
348 
349 	max_off = max(off[0],  off[1]);
350 	max_off = max(max_off, off[2]);
351 
352 	return FIT_ALIGN(fdt_totalsize(fit)) + max_off;
353 }
354 
355 void *fit_image_load_bootables(ulong *size)
356 {
357 	struct blk_desc *dev_desc;
358 	disk_partition_t part;
359 	char *part_name;
360 	int blk_num;
361 	void *fit;
362 
363 	dev_desc = rockchip_get_bootdev();
364 	if (!dev_desc)
365 		return NULL;
366 
367 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
368 		part_name = PART_RECOVERY;
369 	else
370 		part_name = PART_BOOT;
371 
372 	if (part_get_info_by_name(dev_desc, part_name, &part) < 0) {
373 		FIT_I("No %s partition\n", part_name);
374 		return NULL;
375 	}
376 
377 	fit = fit_get_blob(dev_desc, &part);
378 	if (!fit) {
379 		FIT_I("No fit blob\n");
380 		return NULL;
381 	}
382 
383 	*size = fit_image_get_bootables_size(fit);
384 	if (*size == 0) {
385 		FIT_I("No bootable image\n");
386 		return NULL;
387 	}
388 
389 	blk_num = DIV_ROUND_UP(*size, dev_desc->blksz);
390 	fit = sysmem_alloc(MEM_FIT, blk_num * dev_desc->blksz);
391 	if (!fit)
392 		return NULL;
393 
394 	if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) {
395 		FIT_I("Failed to load bootable images\n");
396 		return NULL;
397 	}
398 
399 	return fit;
400 }
401 
402 static void fit_msg(const void *fit)
403 {
404 	FIT_I("%ssigned, %sconf required\n",
405 	      fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ",
406 	      fit_sig_require_conf(fit, gd_fdt_blob()) ? "" : "no ");
407 
408 #ifndef CONFIG_ROCKCHIP_RESOURCE_IMAGE
409 	int noffset;
410 
411 	noffset = fit_default_conf_get_node(fit, FIT_FDT_PROP);
412 	printf("DTB: %s\n", fdt_get_name(fit, noffset, NULL));
413 #endif
414 }
415 
416 int rockchip_read_fit_dtb(void *fdt_addr, char **hash, int *hash_size)
417 {
418 	int conf_noffset __maybe_unused;
419 	ulong rsce __maybe_unused;
420 	struct blk_desc *dev_desc;
421 	disk_partition_t part;
422 	char *part_name;
423 	void *fit;
424 	int ret;
425 
426 	dev_desc = rockchip_get_bootdev();
427 	if (!dev_desc) {
428 		FIT_I("No dev_desc!\n");
429 		return -ENODEV;
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 	ret = part_get_info_by_name(dev_desc, part_name, &part);
438 	if (ret < 0) {
439 		FIT_I("No %s partition\n", part_name);
440 		return ret;
441 	}
442 
443 	fit = fit_get_blob(dev_desc, &part);
444 	if (!fit) {
445 		FIT_I("No fdt blob\n");
446 		return -EINVAL;
447 	}
448 
449 #ifdef CONFIG_FIT_SIGNATURE
450 	conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
451 	if (conf_noffset < 0)
452 		return conf_noffset;
453 
454 	printf("%s: ", fdt_get_name(fit, conf_noffset, NULL));
455 	if (fit_config_verify(fit, conf_noffset))
456 		return -EACCES;
457 
458 	puts("\n");
459 #endif
460 
461 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
462 	ret = fit_image_load_resource(fit, dev_desc, &part, &rsce);
463 	if (ret) {
464 		FIT_I("Failed to load resource\n");
465 		goto out;
466 	}
467 
468 	ret = resource_create_ram_list(dev_desc, (void *)rsce);
469 	if (ret) {
470 		FIT_I("Failed to create resource list\n");
471 		goto out;
472 	}
473 
474 	ret = rockchip_read_resource_dtb(fdt_addr, hash, hash_size);
475 #else
476 	ret = fit_image_load_fdt(fit, dev_desc, &part, fdt_addr);
477 	if (ret) {
478 		FIT_I("Failed to load fdt\n");
479 		goto out;
480 	}
481 #endif
482 
483 	fit_msg(fit);
484 out:
485 	free(fit);
486 
487 	return ret;
488 }
489