xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/fit_misc.c (revision d1e7b9e1d9259b6a26a1dc310b724936b8d5e55e)
1 /*
2  * (C) Copyright 2020 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <boot_rkimg.h>
9 #include <malloc.h>
10 #include <misc.h>
11 #ifdef CONFIG_SPL_BUILD
12 #include <spl.h>
13 #endif
14 #include <lzma/LzmaTools.h>
15 #include <optee_include/OpteeClientInterface.h>
16 #include <optee_include/tee_api_defines.h>
17 #include <asm/arch/rk_atags.h>
18 
19 DECLARE_GLOBAL_DATA_PTR;
20 
21 #if CONFIG_IS_ENABLED(FIT)
22 
23 /*
24  * Override __weak board_fit_image_post_process() for SPL & U-Boot proper.
25  */
26 #if CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS)
27 
28 __weak void rk_board_fit_image_post_process(void *fit, int node, ulong *load_addr,
29 					    ulong **src_addr, size_t *src_len)
30 {
31 }
32 
33 #define FIT_UNCOMP_HASH_NODENAME	"digest"
34 #if CONFIG_IS_ENABLED(MISC_DECOMPRESS) || CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZMA)
35 static int fit_image_get_uncomp_digest(const void *fit, int parent_noffset)
36 {
37 	const char *name;
38 	int noffset;
39 
40 	fdt_for_each_subnode(noffset, fit, parent_noffset) {
41 		name = fit_get_name(fit, noffset, NULL);
42 		if (!strncmp(name, FIT_UNCOMP_HASH_NODENAME,
43 			     strlen(FIT_UNCOMP_HASH_NODENAME))) {
44 			return noffset;
45 		}
46 	}
47 
48 	return -EINVAL;
49 }
50 
51 static int fit_image_check_uncomp_hash(const void *fit, int parent_noffset,
52 				       const void *data, size_t size)
53 {
54 	char *err_msgp;
55 	int noffset;
56 
57 	noffset = fit_image_get_uncomp_digest(fit, parent_noffset);
58 	if (noffset > 0)
59 		return fit_image_check_hash(fit, noffset, data, size, &err_msgp);
60 
61 	return 0;
62 }
63 
64 static int fit_decomp_image(void *fit, int node, ulong *load_addr,
65 			    ulong **src_addr, size_t *src_len, void *spec)
66 {
67 	u64 len = *src_len;
68 	int ret = -ENOSYS;
69 	u8 comp;
70 #if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
71 	u32 flags = 0;
72 #endif
73 
74 	if (fit_image_get_comp(fit, node, &comp))
75 		return 0;
76 
77 	if (comp != IH_COMP_GZIP && comp != IH_COMP_LZMA)
78 		return 0;
79 
80 #ifndef CONFIG_SPL_BUILD
81 	/*
82 	 * U-Boot:
83 	 *	handled late in bootm_decomp_image()
84 	 */
85 	if (fit_image_check_type(fit, node, IH_TYPE_KERNEL))
86 		return 0;
87 #elif defined(CONFIG_SPL_MTD_SUPPORT) && defined(CONFIG_SPL_MISC_DECOMPRESS) && \
88       defined(CONFIG_SPL_KERNEL_BOOT)
89 	/*
90 	 * SPL Thunder-boot policty on spi-nand:
91 	 *	enable and use interrupt status as a sync signal for
92 	 *	kernel to poll that whether ramdisk decompress is done.
93 	 */
94 	struct spl_load_info *info = spec;
95 	struct blk_desc *desc;
96 
97 	if (info && info->dev) {
98 		desc = info->dev;
99 		if ((desc->if_type == IF_TYPE_MTD) &&
100 		    (desc->devnum == BLK_MTD_SPI_NAND) &&
101 		    fit_image_check_type(fit, node, IH_TYPE_RAMDISK)) {
102 			flags |= DCOMP_FLG_IRQ_ONESHOT;
103 		}
104 	}
105 #endif
106 	if (comp == IH_COMP_LZMA) {
107 #if CONFIG_IS_ENABLED(LZMA)
108 		SizeT lzma_len = ALIGN(len, FIT_MAX_SPL_IMAGE_SZ);
109 		ret = lzmaBuffToBuffDecompress((uchar *)(*load_addr), &lzma_len,
110 					       (uchar *)(*src_addr), *src_len);
111 		len = lzma_len;
112 #endif
113 	} else if (comp == IH_COMP_GZIP) {
114 		/*
115 		 * For smaller spl size, we don't use misc_decompress_process()
116 		 * inside the gunzip().
117 		 */
118 #if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
119 		const void *prop;
120 		bool sync = true;
121 
122 		if (fit_image_get_uncomp_digest(fit, node) < 0)
123 			sync = false;
124 
125 		ret = misc_decompress_process((ulong)(*load_addr),
126 					      (ulong)(*src_addr), (ulong)(*src_len),
127 					      DECOM_GZIP, sync, &len, flags);
128 		/* mark for misc_decompress_cleanup() */
129 		prop = fdt_getprop(fit, node, "decomp-async", NULL);
130 		if (prop)
131 			misc_decompress_async(comp);
132 		else
133 			misc_decompress_sync(comp);
134 #else
135 #if CONFIG_IS_ENABLED(GZIP)
136 		ret = gunzip((void *)(*load_addr), ALIGN(len, FIT_MAX_SPL_IMAGE_SZ),
137 			     (void *)(*src_addr), (void *)(&len));
138 #endif
139 #endif
140 	}
141 
142 	if (ret) {
143 		printf("%s: decompress error, ret=%d\n",
144 		       fdt_get_name(fit, node, NULL), ret);
145 		return ret;
146 	}
147 
148 	/* check uncompressed data hash */
149 	ret = fit_image_check_uncomp_hash(fit, node, (void *)(*load_addr), len);
150 	if (!ret)
151 		puts("+ ");
152 	else
153 		return ret;
154 
155 	*src_addr = (ulong *)*load_addr;
156 	*src_len = len;
157 
158 	return 0;
159 }
160 #endif
161 
162 void board_fit_image_post_process(void *fit, int node, ulong *load_addr,
163 				  ulong **src_addr, size_t *src_len, void *spec)
164 {
165 #if CONFIG_IS_ENABLED(MISC_DECOMPRESS) || CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZMA)
166 	fit_decomp_image(fit, node, load_addr, src_addr, src_len, spec);
167 #endif
168 
169 #if CONFIG_IS_ENABLED(USING_KERNEL_DTB)
170 	/* Avoid overriding processed(overlay, hw-dtb, ...) kernel dtb */
171 	if (fit_image_check_type(fit, node, IH_TYPE_FLATDT)) {
172 		if ((gd->flags & GD_FLG_KDTB_READY) && !gd->fdt_blob_kern) {
173 			*src_addr = (void *)gd->fdt_blob;
174 			*src_len = (size_t)fdt_totalsize(gd->fdt_blob);
175 		} else {
176 			printf("   Using fdt from load-in fdt\n");
177 		}
178 	}
179 #endif
180 
181 #ifndef CONFIG_SPL_BUILD
182 	if (fit_image_check_type(fit, node, IH_TYPE_FIRMWARE)) {
183 		const char *uname;
184 		char *old, *new;
185 		size_t len;
186 
187 		uname = fdt_get_name(fit, node, NULL);
188 		if (strcmp("bootargs", uname))
189 			return;
190 
191 		old = env_get("bootargs");
192 		if (!old)
193 			return;
194 
195 		len = strlen(old) + (*src_len) + 2;
196 		new = calloc(1, len);
197 		if (new) {
198 			strcpy(new, old);
199 			strcat(new, " ");
200 			strcat(new, (char *)(*src_addr));
201 			env_set("bootargs", new);
202 			free(new);
203 		}
204 
205 	}
206 #endif
207 	rk_board_fit_image_post_process(fit, node, load_addr, src_addr, src_len);
208 }
209 #endif /* FIT_IMAGE_POST_PROCESS */
210 /*
211  * Override __weak fit_rollback_index_verify() for SPL & U-Boot proper.
212  */
213 #if CONFIG_IS_ENABLED(FIT_ROLLBACK_PROTECT)
214 int fit_rollback_index_verify(const void *fit, uint32_t rollback_fd,
215 			      uint32_t *fit_index, uint32_t *otp_index)
216 {
217 	int conf_noffset, ret;
218 
219 	conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
220 	if (conf_noffset < 0)
221 		return conf_noffset;
222 
223 	ret = fit_image_get_rollback_index(fit, conf_noffset, fit_index);
224 	if (ret) {
225 		printf("Failed to get rollback-index from FIT, ret=%d\n", ret);
226 		return ret;
227 	}
228 
229 	ret = fit_read_otp_rollback_index(*fit_index, otp_index);
230 	if (ret) {
231 		printf("Failed to get rollback-index from otp, ret=%d\n", ret);
232 		return ret;
233 	}
234 
235 	/* Should update rollback index to otp ! */
236 	if (*otp_index < *fit_index)
237 		gd->rollback_index = *fit_index;
238 
239 	return 0;
240 }
241 #endif
242 
243 /*
244  * Override __weak fit_board_verify_required_sigs() for SPL & U-Boot proper.
245  */
246 int fit_board_verify_required_sigs(void)
247 {
248 	uint8_t vboot = 0;
249 
250 #ifdef CONFIG_SPL_BUILD
251 #if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
252 	struct udevice *dev;
253 
254 	dev = misc_otp_get_device(OTP_S);
255 	if (!dev)
256 		return 1;
257 
258 	if (misc_otp_read(dev, OTP_SECURE_BOOT_ENABLE_ADDR, &vboot, 1)) {
259 		printf("Can't read verified-boot flag\n");
260 		return 1;
261 	}
262 
263 	vboot = (vboot == 0xff);
264 #endif
265 #else /* !CONFIG_SPL_BUILD */
266 #if defined(CONFIG_OPTEE_CLIENT)
267 	int ret;
268 
269 	ret = trusty_read_vbootkey_enable_flag(&vboot);
270 	if (ret) {
271 		printf("Can't read verified-boot flag, ret=%d\n", ret);
272 		return 1;
273 	}
274 #elif defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
275 	struct tag *t;
276 
277 	t = atags_get_tag(ATAG_PUB_KEY);
278 	if (t && t->u.pub_key.flag == PUBKEY_FUSE_PROGRAMMED)
279 		vboot = 1;
280 #endif
281 #endif /* CONFIG_SPL_BUILD*/
282 
283 	printf("## Verified-boot: %d\n", vboot);
284 
285 	return vboot;
286 }
287 
288 #endif /* CONFIG_IS_ENABLED(FIT) */
289