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