You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
6.7 KiB
283 lines
6.7 KiB
/*
|
|
* (C) Copyright 2020 Rockchip Electronics Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <boot_rkimg.h>
|
|
#include <malloc.h>
|
|
#include <misc.h>
|
|
#ifdef CONFIG_SPL_BUILD
|
|
#include <spl.h>
|
|
#endif
|
|
#include <lzma/LzmaTools.h>
|
|
#include <optee_include/OpteeClientInterface.h>
|
|
#include <optee_include/tee_api_defines.h>
|
|
#include <asm/arch/rk_atags.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#if CONFIG_IS_ENABLED(FIT)
|
|
|
|
/*
|
|
* Override __weak board_fit_image_post_process() for SPL & U-Boot proper.
|
|
*/
|
|
#if CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS)
|
|
|
|
#define FIT_UNCOMP_HASH_NODENAME "digest"
|
|
#if CONFIG_IS_ENABLED(MISC_DECOMPRESS) || CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZMA)
|
|
static int fit_image_get_uncomp_digest(const void *fit, int parent_noffset)
|
|
{
|
|
const char *name;
|
|
int noffset;
|
|
|
|
fdt_for_each_subnode(noffset, fit, parent_noffset) {
|
|
name = fit_get_name(fit, noffset, NULL);
|
|
if (!strncmp(name, FIT_UNCOMP_HASH_NODENAME,
|
|
strlen(FIT_UNCOMP_HASH_NODENAME))) {
|
|
return noffset;
|
|
}
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int fit_image_check_uncomp_hash(const void *fit, int parent_noffset,
|
|
const void *data, size_t size)
|
|
{
|
|
char *err_msgp;
|
|
int noffset;
|
|
|
|
noffset = fit_image_get_uncomp_digest(fit, parent_noffset);
|
|
if (noffset > 0)
|
|
return fit_image_check_hash(fit, noffset, data, size, &err_msgp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fit_decomp_image(void *fit, int node, ulong *load_addr,
|
|
ulong **src_addr, size_t *src_len, void *spec)
|
|
{
|
|
u64 len = *src_len;
|
|
int ret = -ENOSYS;
|
|
u8 comp;
|
|
#if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
|
|
u32 flags = 0;
|
|
#endif
|
|
|
|
if (fit_image_get_comp(fit, node, &comp))
|
|
return 0;
|
|
|
|
if (comp != IH_COMP_GZIP && comp != IH_COMP_LZMA)
|
|
return 0;
|
|
|
|
#ifndef CONFIG_SPL_BUILD
|
|
/*
|
|
* U-Boot:
|
|
* handled late in bootm_decomp_image()
|
|
*/
|
|
if (fit_image_check_type(fit, node, IH_TYPE_KERNEL))
|
|
return 0;
|
|
#elif defined(CONFIG_SPL_MTD_SUPPORT) && defined(CONFIG_SPL_MISC_DECOMPRESS) && \
|
|
defined(CONFIG_SPL_KERNEL_BOOT)
|
|
/*
|
|
* SPL Thunder-boot policty on spi-nand:
|
|
* enable and use interrupt status as a sync signal for
|
|
* kernel to poll that whether ramdisk decompress is done.
|
|
*/
|
|
struct spl_load_info *info = spec;
|
|
struct blk_desc *desc;
|
|
|
|
if (info && info->dev) {
|
|
desc = info->dev;
|
|
if ((desc->if_type == IF_TYPE_MTD) &&
|
|
(desc->devnum == BLK_MTD_SPI_NAND) &&
|
|
fit_image_check_type(fit, node, IH_TYPE_RAMDISK)) {
|
|
flags |= DCOMP_FLG_IRQ_ONESHOT;
|
|
}
|
|
}
|
|
#endif
|
|
if (comp == IH_COMP_LZMA) {
|
|
#if CONFIG_IS_ENABLED(LZMA)
|
|
SizeT lzma_len = ALIGN(len, FIT_MAX_SPL_IMAGE_SZ);
|
|
ret = lzmaBuffToBuffDecompress((uchar *)(*load_addr), &lzma_len,
|
|
(uchar *)(*src_addr), *src_len);
|
|
len = lzma_len;
|
|
#endif
|
|
} else if (comp == IH_COMP_GZIP) {
|
|
/*
|
|
* For smaller spl size, we don't use misc_decompress_process()
|
|
* inside the gunzip().
|
|
*/
|
|
#if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
|
|
const void *prop;
|
|
bool sync = true;
|
|
|
|
if (fit_image_get_uncomp_digest(fit, node) < 0)
|
|
sync = false;
|
|
|
|
ret = misc_decompress_process((ulong)(*load_addr),
|
|
(ulong)(*src_addr), (ulong)(*src_len),
|
|
DECOM_GZIP, sync, &len, flags);
|
|
/* mark for misc_decompress_cleanup() */
|
|
prop = fdt_getprop(fit, node, "decomp-async", NULL);
|
|
if (prop)
|
|
misc_decompress_async(comp);
|
|
else
|
|
misc_decompress_sync(comp);
|
|
#else
|
|
#if CONFIG_IS_ENABLED(GZIP)
|
|
ret = gunzip((void *)(*load_addr), ALIGN(len, FIT_MAX_SPL_IMAGE_SZ),
|
|
(void *)(*src_addr), (void *)(&len));
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
if (ret) {
|
|
printf("%s: decompress error, ret=%d\n",
|
|
fdt_get_name(fit, node, NULL), ret);
|
|
return ret;
|
|
}
|
|
|
|
/* check uncompressed data hash */
|
|
ret = fit_image_check_uncomp_hash(fit, node, (void *)(*load_addr), len);
|
|
if (!ret)
|
|
puts("+ ");
|
|
else
|
|
return ret;
|
|
|
|
*src_addr = (ulong *)*load_addr;
|
|
*src_len = len;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void board_fit_image_post_process(void *fit, int node, ulong *load_addr,
|
|
ulong **src_addr, size_t *src_len, void *spec)
|
|
{
|
|
#if CONFIG_IS_ENABLED(MISC_DECOMPRESS) || CONFIG_IS_ENABLED(GZIP) || CONFIG_IS_ENABLED(LZMA)
|
|
fit_decomp_image(fit, node, load_addr, src_addr, src_len, spec);
|
|
#endif
|
|
|
|
#if CONFIG_IS_ENABLED(USING_KERNEL_DTB)
|
|
/* Avoid overriding processed(overlay, hw-dtb, ...) kernel dtb */
|
|
if (fit_image_check_type(fit, node, IH_TYPE_FLATDT)) {
|
|
if ((gd->flags & GD_FLG_KDTB_READY) && !gd->fdt_blob_kern) {
|
|
*src_addr = (void *)gd->fdt_blob;
|
|
*src_len = (size_t)fdt_totalsize(gd->fdt_blob);
|
|
} else {
|
|
printf(" Using fdt from load-in fdt\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef CONFIG_SPL_BUILD
|
|
if (fit_image_check_type(fit, node, IH_TYPE_FIRMWARE)) {
|
|
const char *uname;
|
|
char *old, *new;
|
|
size_t len;
|
|
|
|
uname = fdt_get_name(fit, node, NULL);
|
|
if (strcmp("bootargs", uname))
|
|
return;
|
|
|
|
old = env_get("bootargs");
|
|
if (!old)
|
|
return;
|
|
|
|
len = strlen(old) + (*src_len) + 2;
|
|
new = calloc(1, len);
|
|
if (new) {
|
|
strcpy(new, old);
|
|
strcat(new, " ");
|
|
strcat(new, (char *)(*src_addr));
|
|
env_set("bootargs", new);
|
|
free(new);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
#endif /* FIT_IMAGE_POST_PROCESS */
|
|
/*
|
|
* Override __weak fit_rollback_index_verify() for SPL & U-Boot proper.
|
|
*/
|
|
#if CONFIG_IS_ENABLED(FIT_ROLLBACK_PROTECT)
|
|
int fit_rollback_index_verify(const void *fit, uint32_t rollback_fd,
|
|
uint32_t *fit_index, uint32_t *otp_index)
|
|
{
|
|
int conf_noffset, ret;
|
|
|
|
conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
|
|
if (conf_noffset < 0)
|
|
return conf_noffset;
|
|
|
|
ret = fit_image_get_rollback_index(fit, conf_noffset, fit_index);
|
|
if (ret) {
|
|
printf("Failed to get rollback-index from FIT, ret=%d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = fit_read_otp_rollback_index(*fit_index, otp_index);
|
|
if (ret) {
|
|
printf("Failed to get rollback-index from otp, ret=%d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Should update rollback index to otp ! */
|
|
if (*otp_index < *fit_index)
|
|
gd->rollback_index = *fit_index;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Override __weak fit_board_verify_required_sigs() for SPL & U-Boot proper.
|
|
*/
|
|
int fit_board_verify_required_sigs(void)
|
|
{
|
|
uint8_t vboot = 0;
|
|
|
|
#ifdef CONFIG_SPL_BUILD
|
|
#if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
|
|
struct udevice *dev;
|
|
|
|
dev = misc_otp_get_device(OTP_S);
|
|
if (!dev)
|
|
return 1;
|
|
|
|
if (misc_otp_read(dev, OTP_SECURE_BOOT_ENABLE_ADDR, &vboot, 1)) {
|
|
printf("Can't read verified-boot flag\n");
|
|
return 1;
|
|
}
|
|
|
|
vboot = (vboot == 0xff);
|
|
#endif
|
|
#else /* !CONFIG_SPL_BUILD */
|
|
#if defined(CONFIG_OPTEE_CLIENT)
|
|
int ret;
|
|
|
|
ret = trusty_read_vbootkey_enable_flag(&vboot);
|
|
if (ret) {
|
|
printf("Can't read verified-boot flag, ret=%d\n", ret);
|
|
return 1;
|
|
}
|
|
#elif defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
|
|
struct tag *t;
|
|
|
|
t = atags_get_tag(ATAG_PUB_KEY);
|
|
if (t && t->u.pub_key.flag == PUBKEY_FUSE_PROGRAMMED)
|
|
vboot = 1;
|
|
#endif
|
|
#endif /* CONFIG_SPL_BUILD*/
|
|
|
|
printf("## Verified-boot: %d\n", vboot);
|
|
|
|
return vboot;
|
|
}
|
|
|
|
#endif /* CONFIG_IS_ENABLED(FIT) */
|