xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/fit_misc.c (revision 8dbfe4155a4a9c5479263ed74b085e9b69eb1dc2)
1aa8e825bSJoseph Chen /*
2aa8e825bSJoseph Chen  * (C) Copyright 2020 Rockchip Electronics Co., Ltd
3aa8e825bSJoseph Chen  *
4aa8e825bSJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5aa8e825bSJoseph Chen  */
6aa8e825bSJoseph Chen 
7aa8e825bSJoseph Chen #include <common.h>
8aa8e825bSJoseph Chen #include <boot_rkimg.h>
925f6240eSJoseph Chen #include <malloc.h>
10aa8e825bSJoseph Chen #include <misc.h>
11aa8e825bSJoseph Chen #ifdef CONFIG_SPL_BUILD
12aa8e825bSJoseph Chen #include <spl.h>
13aa8e825bSJoseph Chen #endif
14ade0ccd7SJoseph Chen #include <lzma/LzmaTools.h>
15aa8e825bSJoseph Chen #include <optee_include/OpteeClientInterface.h>
16aa8e825bSJoseph Chen #include <optee_include/tee_api_defines.h>
175c822578SJoseph Chen #include <asm/arch/rk_atags.h>
18aa8e825bSJoseph Chen 
19aa8e825bSJoseph Chen DECLARE_GLOBAL_DATA_PTR;
20aa8e825bSJoseph Chen 
21aa8e825bSJoseph Chen #if CONFIG_IS_ENABLED(FIT)
22aa8e825bSJoseph Chen 
23aa8e825bSJoseph Chen /*
24aa8e825bSJoseph Chen  * Override __weak board_fit_image_post_process() for SPL & U-Boot proper.
25aa8e825bSJoseph Chen  */
26aa8e825bSJoseph Chen #if CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS)
27aa8e825bSJoseph Chen 
rk_board_fit_image_post_process(void * fit,int node,ulong * load_addr,ulong ** src_addr,size_t * src_len)28ebb7c7ecSXuhui Lin __weak int rk_board_fit_image_post_process(void *fit, int node, ulong *load_addr,
29f9d8fee0SXuhui Lin 					    ulong **src_addr, size_t *src_len)
30f9d8fee0SXuhui Lin {
31ebb7c7ecSXuhui Lin 	return 0;
32f9d8fee0SXuhui Lin }
33f9d8fee0SXuhui Lin 
34aa8e825bSJoseph Chen #define FIT_UNCOMP_HASH_NODENAME	"digest"
357d03fc8bSXuhui Lin #if CONFIG_IS_ENABLED(MISC_DECOMPRESS) || CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZMA)
fit_image_get_uncomp_digest(const void * fit,int parent_noffset)36ad180a17SJoseph Chen static int fit_image_get_uncomp_digest(const void *fit, int parent_noffset)
37aa8e825bSJoseph Chen {
38aa8e825bSJoseph Chen 	const char *name;
39aa8e825bSJoseph Chen 	int noffset;
40aa8e825bSJoseph Chen 
41aa8e825bSJoseph Chen 	fdt_for_each_subnode(noffset, fit, parent_noffset) {
42aa8e825bSJoseph Chen 		name = fit_get_name(fit, noffset, NULL);
43aa8e825bSJoseph Chen 		if (!strncmp(name, FIT_UNCOMP_HASH_NODENAME,
44aa8e825bSJoseph Chen 			     strlen(FIT_UNCOMP_HASH_NODENAME))) {
45ad180a17SJoseph Chen 			return noffset;
46aa8e825bSJoseph Chen 		}
47aa8e825bSJoseph Chen 	}
48aa8e825bSJoseph Chen 
49ad180a17SJoseph Chen 	return -EINVAL;
50ad180a17SJoseph Chen }
51ad180a17SJoseph Chen 
fit_image_check_uncomp_hash(const void * fit,int parent_noffset,const void * data,size_t size)52ad180a17SJoseph Chen static int fit_image_check_uncomp_hash(const void *fit, int parent_noffset,
53ad180a17SJoseph Chen 				       const void *data, size_t size)
54ad180a17SJoseph Chen {
55ad180a17SJoseph Chen 	char *err_msgp;
56ad180a17SJoseph Chen 	int noffset;
57ad180a17SJoseph Chen 
58ad180a17SJoseph Chen 	noffset = fit_image_get_uncomp_digest(fit, parent_noffset);
59ad180a17SJoseph Chen 	if (noffset > 0)
60ad180a17SJoseph Chen 		return fit_image_check_hash(fit, noffset, data, size, &err_msgp);
61ad180a17SJoseph Chen 
62aa8e825bSJoseph Chen 	return 0;
63aa8e825bSJoseph Chen }
64aa8e825bSJoseph Chen 
fit_decomp_image(void * fit,int node,ulong * load_addr,ulong ** src_addr,size_t * src_len,void * spec)65ade0ccd7SJoseph Chen static int fit_decomp_image(void *fit, int node, ulong *load_addr,
669bb8411cSJoseph Chen 			    ulong **src_addr, size_t *src_len, void *spec)
67aa8e825bSJoseph Chen {
68aa8e825bSJoseph Chen 	u64 len = *src_len;
69ade0ccd7SJoseph Chen 	int ret = -ENOSYS;
70aa8e825bSJoseph Chen 	u8 comp;
7186b1f5c1SJason Zhu #if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
7286b1f5c1SJason Zhu 	u32 flags = 0;
7386b1f5c1SJason Zhu #endif
74aa8e825bSJoseph Chen 
75aa8e825bSJoseph Chen 	if (fit_image_get_comp(fit, node, &comp))
76aa8e825bSJoseph Chen 		return 0;
77aa8e825bSJoseph Chen 
78ade0ccd7SJoseph Chen 	if (comp != IH_COMP_GZIP && comp != IH_COMP_LZMA)
79aa8e825bSJoseph Chen 		return 0;
80aa8e825bSJoseph Chen 
81aa8e825bSJoseph Chen #ifndef CONFIG_SPL_BUILD
829bb8411cSJoseph Chen 	/*
839bb8411cSJoseph Chen 	 * U-Boot:
849bb8411cSJoseph Chen 	 *	handled late in bootm_decomp_image()
859bb8411cSJoseph Chen 	 */
86aa8e825bSJoseph Chen 	if (fit_image_check_type(fit, node, IH_TYPE_KERNEL))
87aa8e825bSJoseph Chen 		return 0;
889bb8411cSJoseph Chen #elif defined(CONFIG_SPL_MTD_SUPPORT) && defined(CONFIG_SPL_MISC_DECOMPRESS) && \
899bb8411cSJoseph Chen       defined(CONFIG_SPL_KERNEL_BOOT)
909bb8411cSJoseph Chen 	/*
919bb8411cSJoseph Chen 	 * SPL Thunder-boot policty on spi-nand:
929bb8411cSJoseph Chen 	 *	enable and use interrupt status as a sync signal for
939bb8411cSJoseph Chen 	 *	kernel to poll that whether ramdisk decompress is done.
949bb8411cSJoseph Chen 	 */
959bb8411cSJoseph Chen 	struct spl_load_info *info = spec;
969bb8411cSJoseph Chen 	struct blk_desc *desc;
979bb8411cSJoseph Chen 
989bb8411cSJoseph Chen 	if (info && info->dev) {
999bb8411cSJoseph Chen 		desc = info->dev;
1009bb8411cSJoseph Chen 		if ((desc->if_type == IF_TYPE_MTD) &&
1019bb8411cSJoseph Chen 		    (desc->devnum == BLK_MTD_SPI_NAND) &&
1029bb8411cSJoseph Chen 		    fit_image_check_type(fit, node, IH_TYPE_RAMDISK)) {
1039bb8411cSJoseph Chen 			flags |= DCOMP_FLG_IRQ_ONESHOT;
1049bb8411cSJoseph Chen 		}
1059bb8411cSJoseph Chen 	}
106aa8e825bSJoseph Chen #endif
107ade0ccd7SJoseph Chen 	if (comp == IH_COMP_LZMA) {
108ade0ccd7SJoseph Chen #if CONFIG_IS_ENABLED(LZMA)
109ade0ccd7SJoseph Chen 		SizeT lzma_len = ALIGN(len, FIT_MAX_SPL_IMAGE_SZ);
110ade0ccd7SJoseph Chen 		ret = lzmaBuffToBuffDecompress((uchar *)(*load_addr), &lzma_len,
111ea098e48SJoseph Chen 					       (uchar *)(*src_addr), *src_len);
112ade0ccd7SJoseph Chen 		len = lzma_len;
113ade0ccd7SJoseph Chen #endif
114ade0ccd7SJoseph Chen 	} else if (comp == IH_COMP_GZIP) {
115aa8e825bSJoseph Chen 		/*
116aa8e825bSJoseph Chen 		 * For smaller spl size, we don't use misc_decompress_process()
117aa8e825bSJoseph Chen 		 * inside the gunzip().
118aa8e825bSJoseph Chen 		 */
119aa8e825bSJoseph Chen #if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
120ade0ccd7SJoseph Chen 		const void *prop;
121ad180a17SJoseph Chen 		bool sync = true;
122ad180a17SJoseph Chen 
123ad180a17SJoseph Chen 		if (fit_image_get_uncomp_digest(fit, node) < 0)
124ad180a17SJoseph Chen 			sync = false;
125ade0ccd7SJoseph Chen 
126aa8e825bSJoseph Chen 		ret = misc_decompress_process((ulong)(*load_addr),
127aa8e825bSJoseph Chen 					      (ulong)(*src_addr), (ulong)(*src_len),
128ad180a17SJoseph Chen 					      DECOM_GZIP, sync, &len, flags);
129ade0ccd7SJoseph Chen 		/* mark for misc_decompress_cleanup() */
130ade0ccd7SJoseph Chen 		prop = fdt_getprop(fit, node, "decomp-async", NULL);
131ade0ccd7SJoseph Chen 		if (prop)
132ade0ccd7SJoseph Chen 			misc_decompress_async(comp);
133ade0ccd7SJoseph Chen 		else
134ade0ccd7SJoseph Chen 			misc_decompress_sync(comp);
135aa8e825bSJoseph Chen #else
1367d03fc8bSXuhui Lin #if CONFIG_IS_ENABLED(GZIP)
1372708ed29SJoseph Chen 		ret = gunzip((void *)(*load_addr), ALIGN(len, FIT_MAX_SPL_IMAGE_SZ),
138aa8e825bSJoseph Chen 			     (void *)(*src_addr), (void *)(&len));
139aa8e825bSJoseph Chen #endif
1407d03fc8bSXuhui Lin #endif
141ade0ccd7SJoseph Chen 	}
142ade0ccd7SJoseph Chen 
143aa8e825bSJoseph Chen 	if (ret) {
144aa8e825bSJoseph Chen 		printf("%s: decompress error, ret=%d\n",
145aa8e825bSJoseph Chen 		       fdt_get_name(fit, node, NULL), ret);
146aa8e825bSJoseph Chen 		return ret;
147aa8e825bSJoseph Chen 	}
148aa8e825bSJoseph Chen 
149aa8e825bSJoseph Chen 	/* check uncompressed data hash */
150aa8e825bSJoseph Chen 	ret = fit_image_check_uncomp_hash(fit, node, (void *)(*load_addr), len);
151aa8e825bSJoseph Chen 	if (!ret)
152aa8e825bSJoseph Chen 		puts("+ ");
153aa8e825bSJoseph Chen 	else
154aa8e825bSJoseph Chen 		return ret;
155aa8e825bSJoseph Chen 
156aa8e825bSJoseph Chen 	*src_addr = (ulong *)*load_addr;
157aa8e825bSJoseph Chen 	*src_len = len;
158aa8e825bSJoseph Chen 
159aa8e825bSJoseph Chen 	return 0;
160aa8e825bSJoseph Chen }
161aa8e825bSJoseph Chen #endif
162aa8e825bSJoseph Chen 
board_fit_image_post_process(void * fit,int node,ulong * load_addr,ulong ** src_addr,size_t * src_len,void * spec)1636da15b9fSXuhui Lin int board_fit_image_post_process(void *fit, int node, ulong *load_addr,
1649bb8411cSJoseph Chen 				  ulong **src_addr, size_t *src_len, void *spec)
165aa8e825bSJoseph Chen {
1667d03fc8bSXuhui Lin #if CONFIG_IS_ENABLED(MISC_DECOMPRESS) || CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZMA)
1676da15b9fSXuhui Lin 	int ret = 0;
1686da15b9fSXuhui Lin 
1696da15b9fSXuhui Lin 	ret = fit_decomp_image(fit, node, load_addr, src_addr, src_len, spec);
1706da15b9fSXuhui Lin 	if (ret)
1716da15b9fSXuhui Lin 		return ret;
172aa8e825bSJoseph Chen #endif
173aa8e825bSJoseph Chen 
174aa8e825bSJoseph Chen #if CONFIG_IS_ENABLED(USING_KERNEL_DTB)
175aa8e825bSJoseph Chen 	/* Avoid overriding processed(overlay, hw-dtb, ...) kernel dtb */
176d94316bfSJoseph Chen 	if (fit_image_check_type(fit, node, IH_TYPE_FLATDT)) {
177d94316bfSJoseph Chen 		if ((gd->flags & GD_FLG_KDTB_READY) && !gd->fdt_blob_kern) {
178aa8e825bSJoseph Chen 			*src_addr = (void *)gd->fdt_blob;
179aa8e825bSJoseph Chen 			*src_len = (size_t)fdt_totalsize(gd->fdt_blob);
180d94316bfSJoseph Chen 		} else {
181d94316bfSJoseph Chen 			printf("   Using fdt from load-in fdt\n");
182d94316bfSJoseph Chen 		}
183aa8e825bSJoseph Chen 	}
184aa8e825bSJoseph Chen #endif
18525f6240eSJoseph Chen 
18625f6240eSJoseph Chen #ifndef CONFIG_SPL_BUILD
18725f6240eSJoseph Chen 	if (fit_image_check_type(fit, node, IH_TYPE_FIRMWARE)) {
18825f6240eSJoseph Chen 		const char *uname;
18925f6240eSJoseph Chen 		char *old, *new;
19025f6240eSJoseph Chen 		size_t len;
19125f6240eSJoseph Chen 
19225f6240eSJoseph Chen 		uname = fdt_get_name(fit, node, NULL);
19325f6240eSJoseph Chen 		if (strcmp("bootargs", uname))
194*8dbfe415SJoseph Chen 			return 0;
19525f6240eSJoseph Chen 
19625f6240eSJoseph Chen 		old = env_get("bootargs");
19725f6240eSJoseph Chen 		if (!old)
1986da15b9fSXuhui Lin 			return -EIO;
19925f6240eSJoseph Chen 
20025f6240eSJoseph Chen 		len = strlen(old) + (*src_len) + 2;
20125f6240eSJoseph Chen 		new = calloc(1, len);
20225f6240eSJoseph Chen 		if (new) {
20325f6240eSJoseph Chen 			strcpy(new, old);
20425f6240eSJoseph Chen 			strcat(new, " ");
20525f6240eSJoseph Chen 			strcat(new, (char *)(*src_addr));
20625f6240eSJoseph Chen 			env_set("bootargs", new);
20725f6240eSJoseph Chen 			free(new);
20825f6240eSJoseph Chen 		}
20925f6240eSJoseph Chen 
21025f6240eSJoseph Chen 	}
21125f6240eSJoseph Chen #endif
2126da15b9fSXuhui Lin 
2136da15b9fSXuhui Lin 	return rk_board_fit_image_post_process(fit, node, load_addr, src_addr, src_len);
214aa8e825bSJoseph Chen }
215aa8e825bSJoseph Chen #endif /* FIT_IMAGE_POST_PROCESS */
216aa8e825bSJoseph Chen /*
217aa8e825bSJoseph Chen  * Override __weak fit_rollback_index_verify() for SPL & U-Boot proper.
218aa8e825bSJoseph Chen  */
219aa8e825bSJoseph Chen #if CONFIG_IS_ENABLED(FIT_ROLLBACK_PROTECT)
fit_rollback_index_verify(const void * fit,uint32_t rollback_fd,uint32_t * fit_index,uint32_t * otp_index)220aa8e825bSJoseph Chen int fit_rollback_index_verify(const void *fit, uint32_t rollback_fd,
221aa8e825bSJoseph Chen 			      uint32_t *fit_index, uint32_t *otp_index)
222aa8e825bSJoseph Chen {
223aa8e825bSJoseph Chen 	int conf_noffset, ret;
224aa8e825bSJoseph Chen 
225aa8e825bSJoseph Chen 	conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
226aa8e825bSJoseph Chen 	if (conf_noffset < 0)
227aa8e825bSJoseph Chen 		return conf_noffset;
228aa8e825bSJoseph Chen 
229aa8e825bSJoseph Chen 	ret = fit_image_get_rollback_index(fit, conf_noffset, fit_index);
230aa8e825bSJoseph Chen 	if (ret) {
231aa8e825bSJoseph Chen 		printf("Failed to get rollback-index from FIT, ret=%d\n", ret);
232aa8e825bSJoseph Chen 		return ret;
233aa8e825bSJoseph Chen 	}
234aa8e825bSJoseph Chen 
235aa8e825bSJoseph Chen 	ret = fit_read_otp_rollback_index(*fit_index, otp_index);
236aa8e825bSJoseph Chen 	if (ret) {
237aa8e825bSJoseph Chen 		printf("Failed to get rollback-index from otp, ret=%d\n", ret);
238aa8e825bSJoseph Chen 		return ret;
239aa8e825bSJoseph Chen 	}
240aa8e825bSJoseph Chen 
241aa8e825bSJoseph Chen 	/* Should update rollback index to otp ! */
242aa8e825bSJoseph Chen 	if (*otp_index < *fit_index)
243aa8e825bSJoseph Chen 		gd->rollback_index = *fit_index;
244aa8e825bSJoseph Chen 
245aa8e825bSJoseph Chen 	return 0;
246aa8e825bSJoseph Chen }
247aa8e825bSJoseph Chen #endif
248aa8e825bSJoseph Chen 
249aa8e825bSJoseph Chen /*
250aa8e825bSJoseph Chen  * Override __weak fit_board_verify_required_sigs() for SPL & U-Boot proper.
251aa8e825bSJoseph Chen  */
fit_board_verify_required_sigs(void)252aa8e825bSJoseph Chen int fit_board_verify_required_sigs(void)
253aa8e825bSJoseph Chen {
254aa8e825bSJoseph Chen 	uint8_t vboot = 0;
255aa8e825bSJoseph Chen 
256aa8e825bSJoseph Chen #ifdef CONFIG_SPL_BUILD
257299f09a0SJason Zhu #if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
258aa8e825bSJoseph Chen 	struct udevice *dev;
259aa8e825bSJoseph Chen 
260aa8e825bSJoseph Chen 	dev = misc_otp_get_device(OTP_S);
261aa8e825bSJoseph Chen 	if (!dev)
262aa8e825bSJoseph Chen 		return 1;
263aa8e825bSJoseph Chen 
264a31e24f3SJason Zhu 	if (misc_otp_read(dev, OTP_SECURE_BOOT_ENABLE_ADDR, &vboot, 1)) {
265aa8e825bSJoseph Chen 		printf("Can't read verified-boot flag\n");
266aa8e825bSJoseph Chen 		return 1;
267aa8e825bSJoseph Chen 	}
268aa8e825bSJoseph Chen 
269aa8e825bSJoseph Chen 	vboot = (vboot == 0xff);
270aa8e825bSJoseph Chen #endif
271aa8e825bSJoseph Chen #else /* !CONFIG_SPL_BUILD */
2725c822578SJoseph Chen #if defined(CONFIG_OPTEE_CLIENT)
273aa8e825bSJoseph Chen 	int ret;
274aa8e825bSJoseph Chen 
275aa8e825bSJoseph Chen 	ret = trusty_read_vbootkey_enable_flag(&vboot);
276aa8e825bSJoseph Chen 	if (ret) {
277aa8e825bSJoseph Chen 		printf("Can't read verified-boot flag, ret=%d\n", ret);
278aa8e825bSJoseph Chen 		return 1;
279aa8e825bSJoseph Chen 	}
2805c822578SJoseph Chen #elif defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
2815c822578SJoseph Chen 	struct tag *t;
2825c822578SJoseph Chen 
2835c822578SJoseph Chen 	t = atags_get_tag(ATAG_PUB_KEY);
2845c822578SJoseph Chen 	if (t && t->u.pub_key.flag == PUBKEY_FUSE_PROGRAMMED)
2855c822578SJoseph Chen 		vboot = 1;
286aa8e825bSJoseph Chen #endif
287aa8e825bSJoseph Chen #endif /* CONFIG_SPL_BUILD*/
288aa8e825bSJoseph Chen 
289aa8e825bSJoseph Chen 	printf("## Verified-boot: %d\n", vboot);
290aa8e825bSJoseph Chen 
291aa8e825bSJoseph Chen 	return vboot;
292aa8e825bSJoseph Chen }
293aa8e825bSJoseph Chen 
294aa8e825bSJoseph Chen #endif /* CONFIG_IS_ENABLED(FIT) */
295