1562 lines
50 KiB
C
1562 lines
50 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* common/cmd_imgread.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <common.h>
|
|
#include <amlogic/storage_if.h>
|
|
#include <image.h>
|
|
#include <android_image.h>
|
|
#include <zircon/image.h>
|
|
#include <asm/arch/bl31_apis.h>
|
|
#include <asm/arch/secure_apb.h>
|
|
#include <libfdt.h>
|
|
#include <linux/compat.h>
|
|
#include <partition_table.h>
|
|
#include <malloc.h>
|
|
#include <emmc_partitions.h>
|
|
#include <fs.h>
|
|
#ifdef CONFIG_AVB2
|
|
#include <libavb.h>
|
|
#endif
|
|
|
|
#include <amlogic/aml_efuse.h>
|
|
#if defined(CONFIG_AML_NAND) || defined (CONFIG_AML_MTD)
|
|
#include <nand.h>
|
|
#endif
|
|
|
|
#define debugP(fmt...) //printf("[Dbg imgread]L%d:", __LINE__), printf(fmt)
|
|
#define errorP(fmt...) printf("Err imgread(L%d):", __LINE__),printf(fmt)
|
|
#define wrnP(fmt...) printf("wrn:"fmt)
|
|
#define MsgP(fmt...) printf("[imgread]"fmt)
|
|
|
|
#define IMG_PRELOAD_SZ (1U<<20) //Total read 1M at first to read the image header
|
|
#define PIC_PRELOAD_SZ (8U<<10) //Total read 4k at first to read the image header
|
|
#define RES_OLD_FMT_READ_SZ (8U<<20)
|
|
|
|
#define MAX_RAMDISK_SIZE SZ_64M
|
|
#define MAX_KERNEL_SIZE SZ_64M
|
|
#define MAX_DTB_SIZE SZ_16M
|
|
|
|
typedef struct __aml_enc_blk{
|
|
unsigned int nOffset;
|
|
unsigned int nRawLength;
|
|
unsigned int nSigLength;
|
|
unsigned int nAlignment;
|
|
unsigned int nTotalLength;
|
|
unsigned char szPad[12];
|
|
unsigned char szSHA2IMG[32];
|
|
unsigned char szSHA2KeyID[32];
|
|
}t_aml_enc_blk;
|
|
|
|
#define AML_SECU_BOOT_IMG_HDR_MAGIC "AMLSECU!"
|
|
#define AML_SECU_BOOT_IMG_HDR_MAGIC_SIZE (8)
|
|
#define AML_SECU_BOOT_IMG_HDR_VESRION (0x0905)
|
|
#define AML_BOOT_IMAGE_MAGIC (('@' << 0) | ('A' << 8) | ('M' << 16) | ('L' << 24))
|
|
|
|
#define VENFOR_BOOT_BUFFER_ADDR (0xA000000)
|
|
|
|
typedef struct {
|
|
|
|
unsigned char magic[AML_SECU_BOOT_IMG_HDR_MAGIC_SIZE];//magic to identify whether it is a encrypted boot image
|
|
|
|
unsigned int version; //ersion for this header struct
|
|
unsigned int nBlkCnt;
|
|
|
|
unsigned char szTimeStamp[16];
|
|
|
|
t_aml_enc_blk amlKernel;
|
|
t_aml_enc_blk amlRamdisk;
|
|
t_aml_enc_blk amlDTB;
|
|
|
|
}AmlEncryptBootImgInfo;
|
|
|
|
typedef struct _boot_img_hdr_secure_boot
|
|
{
|
|
unsigned char reserve4ImgHdr[1024];
|
|
|
|
AmlEncryptBootImgInfo encrypteImgInfo;
|
|
|
|
}AmlSecureBootImgHeader;
|
|
|
|
typedef struct{
|
|
unsigned char reserve4ImgHdr[2048];
|
|
|
|
AmlEncryptBootImgInfo encrypteImgInfo;
|
|
|
|
}AmlSecureBootImg9Header;
|
|
|
|
|
|
#define COMPILE_TYPE_ASSERT(expr, t) typedef char t[(expr) ? 1 : -1]
|
|
COMPILE_TYPE_ASSERT(2048 >= sizeof(AmlSecureBootImgHeader), _cc);
|
|
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
static int is_andr_9_image(void* pBuffer)
|
|
{
|
|
int nReturn = 0;
|
|
p_boot_img_hdr_t pAHdr = NULL;
|
|
|
|
if (!pBuffer)
|
|
goto exit;
|
|
|
|
pAHdr = (p_boot_img_hdr_t)pBuffer;
|
|
|
|
if (android_image_check_header(pAHdr))
|
|
goto exit;
|
|
|
|
if (pAHdr->header_version == 1 || pAHdr->header_version == 2)
|
|
nReturn = 1;
|
|
|
|
exit:
|
|
|
|
return nReturn;
|
|
}
|
|
#endif
|
|
|
|
typedef struct {
|
|
uint32_t magic;
|
|
uint32_t version;
|
|
uint32_t flags;
|
|
uint32_t img_version;
|
|
uint32_t img_size;
|
|
uint32_t img_offset;
|
|
uint8_t img_hash[32];
|
|
uint8_t reserved[200];
|
|
uint8_t rsa_sig[256];
|
|
} aml_boot_header_t;
|
|
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
int _aml_get_secure_boot_kernel_size(const void* pLoadaddr, unsigned* pTotalEncKernelSz)
|
|
{
|
|
const AmlEncryptBootImgInfo* amlEncrypteBootimgInfo = 0;
|
|
int rc = 0;
|
|
unsigned secureKernelImgSz = 0;
|
|
unsigned int nBlkCnt = 0;
|
|
const t_aml_enc_blk* pBlkInf = NULL;
|
|
unsigned char *pAndHead = (unsigned char *)pLoadaddr;
|
|
unsigned int isSecure = IS_FEAT_BOOT_VERIFY();
|
|
|
|
rc = __LINE__;
|
|
|
|
if (!pLoadaddr || !pTotalEncKernelSz)
|
|
return rc;
|
|
|
|
if (isSecure)
|
|
{
|
|
ulong nCheckOffset = 0;
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
nCheckOffset = aml_sec_boot_check(AML_D_Q_IMG_SIG_HDR_SIZE,GXB_IMG_LOAD_ADDR,GXB_EFUSE_PATTERN_SIZE,GXB_IMG_DEC_ALL);
|
|
#endif /*CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK*/
|
|
if (AML_D_Q_IMG_SIG_HDR_SIZE == (nCheckOffset & 0xFFFF)) {
|
|
if (is_andr_9_image(pAndHead))
|
|
secureKernelImgSz = BOOT_IMG_HDR_SIZE;
|
|
else if (is_android_v3_header_image(pAndHead)
|
|
|| vendor_boot_image_check_header((vendor_boot_img_hdr_t *)pAndHead))
|
|
secureKernelImgSz = BOOT_IMG_V3_HDR_SIZE;
|
|
|
|
if (((aml_boot_header_t *)(pAndHead+secureKernelImgSz))->magic == AML_BOOT_IMAGE_MAGIC) {
|
|
*pTotalEncKernelSz = (((aml_boot_header_t *)(pAndHead+secureKernelImgSz))->img_size)
|
|
+ secureKernelImgSz + sizeof(aml_boot_header_t);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (is_andr_9_image(pAndHead))
|
|
{
|
|
secureKernelImgSz = 4096;
|
|
}
|
|
|
|
amlEncrypteBootimgInfo = (AmlEncryptBootImgInfo*)(pAndHead + (secureKernelImgSz>>1));
|
|
|
|
nBlkCnt = amlEncrypteBootimgInfo->nBlkCnt;
|
|
|
|
*pTotalEncKernelSz = 0;
|
|
|
|
rc = memcmp(AML_SECU_BOOT_IMG_HDR_MAGIC, amlEncrypteBootimgInfo->magic, AML_SECU_BOOT_IMG_HDR_MAGIC_SIZE);
|
|
if (rc) { // img NOT singed
|
|
if (isSecure) {
|
|
errorP("img NOT signed but secure boot enabled\n");
|
|
return __LINE__;
|
|
}
|
|
*pTotalEncKernelSz = 0;
|
|
return 0;
|
|
} else { //img signed
|
|
if (!isSecure) {
|
|
errorP("Img signed but secure boot NOT enabled\n");
|
|
return __LINE__;
|
|
}
|
|
}
|
|
if (AML_SECU_BOOT_IMG_HDR_VESRION != amlEncrypteBootimgInfo->version) {
|
|
errorP("magic ok but version err, err ver=0x%x\n", amlEncrypteBootimgInfo->version);
|
|
return __LINE__;
|
|
}
|
|
MsgP("szTimeStamp[%s]\n", (char*)&amlEncrypteBootimgInfo->szTimeStamp);
|
|
debugP("nBlkCnt=%d\n", nBlkCnt);
|
|
|
|
for (pBlkInf = &amlEncrypteBootimgInfo->amlKernel;nBlkCnt--; ++pBlkInf)
|
|
{
|
|
const unsigned int thisBlkLen = pBlkInf->nTotalLength;
|
|
debugP("thisBlkLen=0x%x\n", thisBlkLen);
|
|
secureKernelImgSz += thisBlkLen;
|
|
}
|
|
|
|
*pTotalEncKernelSz = secureKernelImgSz;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int do_image_read_dtb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
boot_img_hdr_t *hdr_addr = NULL;
|
|
const char *partName = argv[1];
|
|
unsigned char *loadaddr = 0;
|
|
int nReturn = __LINE__;
|
|
uint64_t lflashReadOff = 0;
|
|
uint64_t lflashreadinitoff = 0;
|
|
unsigned int nFlashLoadLen = 0;
|
|
unsigned secureKernelImgSz = 0;
|
|
const int preloadSz = 4096;
|
|
unsigned int pageSz = 0;
|
|
bool dtb_in_vendor_boot = false;
|
|
bool cache_flag = false;
|
|
unsigned char *pbuffpreload = NULL;
|
|
char *upgrade_step_s = getenv("upgrade_step");
|
|
unsigned long dtb_size_v3 = 0;
|
|
#ifdef CONFIG_AVB2
|
|
u64 original_size = 0;
|
|
bool vendor_boot_preload = true;
|
|
#endif
|
|
|
|
pbuffpreload = (unsigned char *)malloc(preloadSz);
|
|
if (!pbuffpreload) {
|
|
printf("aml log : Fail to allocate memory for %s!\n", partName);
|
|
return __LINE__;
|
|
}
|
|
memset(pbuffpreload, 0, preloadSz);
|
|
hdr_addr = (boot_img_hdr_t *)pbuffpreload;
|
|
|
|
if (argc > 2)
|
|
loadaddr = (unsigned char *)simple_strtoul(argv[2], NULL, 16);
|
|
else
|
|
loadaddr = (unsigned char *)getenv_hex("loadaddr", 0);
|
|
|
|
if (argc > 3)
|
|
lflashreadinitoff = simple_strtoull(argv[3], NULL, 0);
|
|
lflashReadOff = lflashreadinitoff;
|
|
nFlashLoadLen = preloadSz;//head info is one page size == 2k
|
|
debugP("sizeof preloadSz=%u\n", nFlashLoadLen);
|
|
nReturn = store_read_ops((unsigned char *)partName,
|
|
pbuffpreload, lflashReadOff, nFlashLoadLen);
|
|
if (nReturn) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0\n", nFlashLoadLen, partName);
|
|
return __LINE__;
|
|
}
|
|
|
|
if (IMAGE_FORMAT_ANDROID != genimg_get_format(hdr_addr)) {
|
|
errorP("Fmt unsupported! only support 0x%x\n", IMAGE_FORMAT_ANDROID);
|
|
return __LINE__;
|
|
}
|
|
|
|
if (is_android_v3_header_image((void *)hdr_addr)) {
|
|
char *slot_name;
|
|
unsigned long ramdisk_size_v3;
|
|
unsigned long ramdisk_table_size;
|
|
unsigned long totalsize;
|
|
|
|
dtb_in_vendor_boot = true;
|
|
slot_name = getenv("slot-suffixes");
|
|
if (strcmp(slot_name, "0") == 0)
|
|
strcpy((char *)partName, "vendor_boot_a");
|
|
else if (strcmp(slot_name, "1") == 0)
|
|
strcpy((char *)partName, "vendor_boot_b");
|
|
else
|
|
strcpy((char *)partName, "vendor_boot");
|
|
|
|
MsgP("partName = %s\n", partName);
|
|
nReturn = store_read_ops((unsigned char *)partName, pbuffpreload,
|
|
lflashReadOff, nFlashLoadLen);
|
|
if (nReturn) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0\n",
|
|
nFlashLoadLen, partName);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
p_vendor_boot_img_hdr_t pvendorimghdr = (p_vendor_boot_img_hdr_t)pbuffpreload;
|
|
|
|
nReturn = vendor_boot_image_check_header(pvendorimghdr);
|
|
if (!nReturn) {
|
|
pageSz = pvendorimghdr->page_size;
|
|
ramdisk_size_v3 = ALIGN(pvendorimghdr->vendor_ramdisk_size, pageSz);
|
|
dtb_size_v3 = ALIGN(pvendorimghdr->dtb_size, pageSz);
|
|
nFlashLoadLen = dtb_size_v3;
|
|
lflashReadOff = ramdisk_size_v3 + VENDOR_BOOT_IMG_HDR_SIZE;
|
|
|
|
debugP("ramdisk_size_v3 0x%x, totalSz 0x%lx\n",
|
|
pvendorimghdr->vendor_ramdisk_size, ramdisk_size_v3);
|
|
debugP("dtb_size_v3 0x%x, totalSz 0x%lx\n",
|
|
pvendorimghdr->dtb_size, dtb_size_v3);
|
|
debugP("lflashReadOff=0x%llx\n", lflashReadOff);
|
|
debugP("nFlashLoadLen=0x%x\n", nFlashLoadLen);
|
|
totalsize = nFlashLoadLen + lflashReadOff;
|
|
|
|
if (pvendorimghdr->header_version > 3) {
|
|
MsgP("vendor_ramdisk_table_size: 0x%x\n",
|
|
pvendorimghdr->vendor_ramdisk_table_size);
|
|
MsgP("vendor_ramdisk_table_entry_num: 0x%x\n",
|
|
pvendorimghdr->vendor_ramdisk_table_entry_num);
|
|
MsgP("vendor_ramdisk_table_entry_size: 0x%x\n",
|
|
pvendorimghdr->vendor_ramdisk_table_entry_size);
|
|
MsgP("vendor_bootconfig_size: 0x%x\n",
|
|
pvendorimghdr->vendor_bootconfig_size);
|
|
ramdisk_table_size =
|
|
ALIGN(pvendorimghdr->vendor_ramdisk_table_size,
|
|
pageSz);
|
|
totalsize += ramdisk_table_size;
|
|
MsgP("ramdisk table offset 0x%llx, totalsize 0x%lx\n",
|
|
nFlashLoadLen + lflashReadOff, totalsize);
|
|
}
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
//Check if encrypted image
|
|
nReturn = _aml_get_secure_boot_kernel_size(pbuffpreload,
|
|
&secureKernelImgSz);
|
|
if (nReturn) {
|
|
errorP("Fail in get_secure_boot_kernel_size, nReturn = %d\n",
|
|
nReturn);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
if (secureKernelImgSz) {
|
|
totalsize = secureKernelImgSz;
|
|
MsgP("secureKernelImgSz=0x%lx\n", totalsize);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_AVB2
|
|
if (!(upgrade_step_s && !(strcmp(upgrade_step_s, "3")))) {
|
|
original_size = totalsize;
|
|
totalsize = get_size_avb_footer(partName);
|
|
if (!totalsize || totalsize < original_size) {
|
|
totalsize = original_size;
|
|
vendor_boot_preload = false;
|
|
wrnP("part: %s footer not at correct location\n",
|
|
partName);
|
|
}
|
|
}
|
|
#endif
|
|
free(pbuffpreload);
|
|
pbuffpreload = 0;
|
|
pbuffpreload = malloc(totalsize);
|
|
if (!pbuffpreload) {
|
|
errorP("Fail alloc vendor image buffer\n");
|
|
return __LINE__;
|
|
}
|
|
memset(pbuffpreload, 0, totalsize);
|
|
if (upgrade_step_s && (strcmp(upgrade_step_s, "3") == 0) &&
|
|
(strcmp(partName, "vendor_boot") == 0)) {
|
|
loff_t len_read;
|
|
|
|
MsgP("recovery mode, read vendor_boot from cache\n");
|
|
nReturn = fs_set_blk_dev("mmc", "1:2", FS_TYPE_EXT);
|
|
if (nReturn) {
|
|
errorP("Fail to set blk dev cache\n");
|
|
cache_flag = false;
|
|
} else {
|
|
fs_read("/recovery/vendor_boot.img",
|
|
(unsigned long)pbuffpreload,
|
|
0, totalsize,
|
|
&len_read);
|
|
if (totalsize != len_read) {
|
|
errorP("Fail to read from cache\n");
|
|
cache_flag = false;
|
|
} else {
|
|
cache_flag = true;
|
|
pvendorimghdr = (p_vendor_boot_img_hdr_t)pbuffpreload;
|
|
ramdisk_size_v3 = ALIGN(pvendorimghdr->vendor_ramdisk_size, pvendorimghdr->page_size);
|
|
dtb_size_v3 = ALIGN(pvendorimghdr->dtb_size, pvendorimghdr->page_size);
|
|
nFlashLoadLen = dtb_size_v3;
|
|
lflashReadOff = ramdisk_size_v3 + VENDOR_BOOT_IMG_HDR_SIZE;
|
|
}
|
|
}
|
|
}
|
|
if (!cache_flag) {
|
|
MsgP("read from part: %s\n", partName);
|
|
nReturn = store_read_ops((unsigned char *)partName,
|
|
pbuffpreload, 0, totalsize);
|
|
if (nReturn) {
|
|
errorP("Fail to read 0x%xB from part[%s]\n",
|
|
(unsigned int)totalsize, partName);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
}
|
|
#ifdef CONFIG_AVB2
|
|
if (!nReturn && !(upgrade_step_s && !(strcmp(upgrade_step_s, "3"))) &&
|
|
vendor_boot_preload)
|
|
set_avb_parts(partName, (void *)pbuffpreload, totalsize);
|
|
if (avb_verify_single(partName)) {
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
#endif
|
|
flush_cache((unsigned long)pbuffpreload, totalsize);
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
if (IS_FEAT_BOOT_VERIFY()) {
|
|
#ifndef CONFIG_IMAGE_CHECK
|
|
nReturn = aml_sec_boot_check(AML_D_P_IMG_DECRYPT,
|
|
(unsigned long)pbuffpreload,
|
|
GXB_IMG_SIZE, GXB_IMG_DEC_DTB);
|
|
#else
|
|
nReturn = secure_image_check((uint8_t *)(unsigned long)
|
|
pbuffpreload, GXB_IMG_SIZE, GXB_IMG_DEC_DTB);
|
|
/*pbuffpreload += android_image_check_offset();*/
|
|
memmove(pbuffpreload, pbuffpreload + android_image_check_offset(),
|
|
totalsize - android_image_check_offset());
|
|
#endif
|
|
if (nReturn) {
|
|
errorP("\n[vendor_boot]aml log : Sig Check is %d\n",
|
|
nReturn);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
MsgP("vendor_boot decrypt at 0x%p\n", pbuffpreload);
|
|
}
|
|
#endif /* CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK */
|
|
p_vender_boot_img = (p_vendor_boot_img_t)pbuffpreload;
|
|
} else {
|
|
errorP("verndor boot magic error, %s, %d\n", __func__, __LINE__);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
pageSz = hdr_addr->page_size;
|
|
/*lflashReadOff += secureKernelImgSz ? sizeof(AmlSecureBootImgHeader) : pageSz;*/
|
|
lflashReadOff += pageSz;
|
|
lflashReadOff += ALIGN(hdr_addr->kernel_size, pageSz);
|
|
lflashReadOff += ALIGN(hdr_addr->ramdisk_size, pageSz);
|
|
nFlashLoadLen = ALIGN(hdr_addr->second_size, pageSz);
|
|
}
|
|
debugP("lflashReadOff=0x%llx, nFlashLoadLen=0x%x\n", lflashReadOff, nFlashLoadLen);
|
|
debugP("page sz %u\n", hdr_addr->page_size);
|
|
|
|
if (pageSz > PAGE_SIZE) {
|
|
errorP("Wrong pageSz:%d\n", pageSz);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
|
|
if (!nFlashLoadLen || nFlashLoadLen > MAX_DTB_SIZE) {
|
|
errorP("Wrong nFlashLoadLen:%d\n", nFlashLoadLen);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
|
|
if (lflashReadOff > (MAX_RAMDISK_SIZE + MAX_KERNEL_SIZE)) {
|
|
errorP("Wrong lflashReadOff:%lld\n", lflashReadOff);
|
|
nReturn = __LINE__;
|
|
goto exit;
|
|
}
|
|
|
|
unsigned char *dtImgAddr = (unsigned char *)loadaddr + lflashReadOff;
|
|
|
|
if (!dtb_in_vendor_boot) {
|
|
dtImgAddr = (unsigned char *)loadaddr + lflashReadOff;
|
|
unsigned long rdOffAlign = lflashReadOff;
|
|
#ifdef CONFIG_AML_MTD
|
|
if (device_boot_flag == NAND_BOOT_FLAG) {
|
|
const nand_info_t *mtdPartInf = get_mtd_device_nm(partName);
|
|
|
|
if (IS_ERR(mtdPartInf)) {
|
|
errorP("device(%s) is err\n", partName);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
const unsigned pageShift = mtdPartInf->writesize_shift;
|
|
const unsigned writesz = mtdPartInf->writesize;
|
|
|
|
MsgP("MTD pageShift %d, writesz 0x%x\n", pageShift, writesz);
|
|
//align 4k page for mtd nand, 512 for emmc
|
|
rdOffAlign = (lflashReadOff >> pageShift) << pageShift;
|
|
nFlashLoadLen += writesz;
|
|
dtImgAddr = (unsigned char *)loadaddr + rdOffAlign;
|
|
}
|
|
#endif//#ifdef CONFIG_AML_MTD
|
|
|
|
loff_t wroff = rdOffAlign;
|
|
size_t wrsz = nFlashLoadLen;
|
|
unsigned char *wraddr = dtImgAddr;
|
|
|
|
memcpy((void *)loadaddr, (void *)pbuffpreload, preloadSz);
|
|
free(pbuffpreload);
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
nReturn = _aml_get_secure_boot_kernel_size(loadaddr, &secureKernelImgSz);
|
|
if (nReturn) {
|
|
errorP("Fail in _aml_get_secure_boot_kernel_size, rc=%d\n", nReturn);
|
|
return __LINE__;
|
|
}
|
|
|
|
if (secureKernelImgSz) {
|
|
debugP("secure kernel sz 0x%x\n", secureKernelImgSz);
|
|
wrsz = secureKernelImgSz - preloadSz;
|
|
wroff = lflashreadinitoff + preloadSz;
|
|
wraddr = (unsigned char *)loadaddr + preloadSz;
|
|
}
|
|
#endif
|
|
|
|
nReturn = store_read_ops((unsigned char *)partName, wraddr, wroff, wrsz);
|
|
if (nReturn) {
|
|
errorP("Fail to read 0x%lxB from part[%s] at offset 0x%x\n",
|
|
wrsz, partName, (unsigned int)wroff);
|
|
return __LINE__;
|
|
}
|
|
|
|
#ifdef CONFIG_AML_MTD
|
|
if (device_boot_flag == NAND_BOOT_FLAG)
|
|
flush_cache((unsigned long)wraddr, (unsigned long)wrsz);
|
|
#endif
|
|
|
|
dtImgAddr = (unsigned char *)loadaddr + lflashReadOff;
|
|
if (secureKernelImgSz) {
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
//GXB_IMG_DEC_DTB GXB_IMG_DEC_ALL
|
|
nReturn = aml_sec_boot_check(AML_D_P_IMG_DECRYPT,
|
|
(unsigned long)loadaddr, GXB_IMG_SIZE, GXB_IMG_DEC_DTB);
|
|
if (nReturn) {
|
|
errorP("\n[dtb]aml log : Sig Check is %d\n", nReturn);
|
|
return __LINE__;
|
|
}
|
|
#ifdef AML_D_Q_IMG_SIG_HDR_SIZE
|
|
ulong nCheckOffset = aml_sec_boot_check(AML_D_Q_IMG_SIG_HDR_SIZE,
|
|
GXB_IMG_LOAD_ADDR, GXB_EFUSE_PATTERN_SIZE, GXB_IMG_DEC_ALL);
|
|
if (AML_D_Q_IMG_SIG_HDR_SIZE == (nCheckOffset & 0xFFFF))
|
|
nCheckOffset = (nCheckOffset >> 16) & 0xFFFF;
|
|
else
|
|
nCheckOffset = 0;
|
|
dtImgAddr += nCheckOffset;
|
|
#endif
|
|
#endif /*CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK*/
|
|
MsgP("Enc dtb sz 0x%x\n", nFlashLoadLen);
|
|
}
|
|
} else {
|
|
memmove(dtImgAddr, (pbuffpreload + lflashReadOff), dtb_size_v3);
|
|
}
|
|
|
|
char *dtDestAddr = (char *)loadaddr; //simple_strtoull(getenv("dtb_mem_addr"), NULL, 0);
|
|
unsigned long fdtAddr = (unsigned long)dtImgAddr;
|
|
#ifdef CONFIG_MULTI_DTB
|
|
extern unsigned long get_multi_dt_entry(unsigned long fdt_addr);
|
|
fdtAddr = get_multi_dt_entry((unsigned long)dtImgAddr);
|
|
if (!fdtAddr) {
|
|
errorP("Fail in fdt chk\n");
|
|
return __LINE__;
|
|
}
|
|
#endif// #ifdef CONFIG_MULTI_DTB
|
|
nReturn = fdt_check_header((char *)fdtAddr);
|
|
if (nReturn) {
|
|
errorP("Fail in fdt check header\n");
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
const unsigned int fdtsz = fdt_totalsize((char *)fdtAddr);
|
|
|
|
if (fdtsz >= SZ_1M) {
|
|
errorP("bad fdt size:%d\n", fdtsz);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
memmove(dtDestAddr, (char *)fdtAddr, fdtsz);
|
|
|
|
exit:
|
|
|
|
if (nReturn)
|
|
free(pbuffpreload);
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
#if defined(CONFIG_FIT)
|
|
static int _fit_img_get_img_sz(void* hdr, unsigned* imgSz)
|
|
{
|
|
debugP("hdr 0x%p\n", hdr);
|
|
if (fdt_path_offset(hdr, FIT_IMAGES_PATH) < 0) {
|
|
errorP("Wrong FIT format: no images parent node\n");
|
|
return 0;
|
|
}
|
|
*imgSz = fdt_totalsize(hdr);
|
|
MsgP("fit img sz 0x%x\n", *imgSz);
|
|
|
|
return 0;
|
|
}
|
|
#endif//#if defined(CONFIG_FIT)
|
|
|
|
static int do_image_read_kernel(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int kernel_size = 0;
|
|
unsigned int ramdisk_size = 0;
|
|
boot_img_hdr_t * hdr_addr = NULL;
|
|
int genFmt = 0;
|
|
unsigned actualBootImgSz = 0;
|
|
const char* const partName = argv[1];
|
|
unsigned char* loadaddr = 0;
|
|
int rc = 0;
|
|
uint64_t flashReadOff = 0;
|
|
unsigned secureKernelImgSz = 0;
|
|
char *upgrade_step_s = NULL;
|
|
bool cache_flag = false;
|
|
unsigned int dtbSz = 0;
|
|
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
|
|
image_header_t *hdr;
|
|
#endif
|
|
#ifdef CONFIG_AVB2
|
|
u64 original_size = 0;
|
|
bool kernel_preload = true;
|
|
bool init_boot_preload = true;
|
|
#endif
|
|
|
|
ulong kernelEndAddr = 0;
|
|
ulong kernelLoadAddr = 0;
|
|
ulong dtbLoadAddr = 0;
|
|
char strAddr[128] = {0};
|
|
|
|
if (argc > 2) {
|
|
loadaddr = (unsigned char *)simple_strtoul(argv[2], NULL, 16);
|
|
setenv("loadaddr", (const char *)argv[2]);
|
|
} else {
|
|
loadaddr = (unsigned char *)getenv_hex("loadaddr", 0);
|
|
}
|
|
|
|
hdr_addr = (boot_img_hdr_t*)loadaddr;
|
|
|
|
if (3 < argc) flashReadOff = simple_strtoull(argv[3], NULL, 0);
|
|
|
|
upgrade_step_s = getenv("upgrade_step");
|
|
if (upgrade_step_s && (strcmp(upgrade_step_s, "3") == 0) &&
|
|
(strcmp(partName, "recovery") == 0)) {
|
|
loff_t len_read;
|
|
|
|
MsgP("read recovery.img from cache\n");
|
|
rc = fs_set_blk_dev("mmc", "1:2", FS_TYPE_EXT);
|
|
if (rc) {
|
|
errorP("Fail to set blk dev cache\n");
|
|
cache_flag = false;
|
|
}
|
|
if (rc == 0) {
|
|
rc = fs_read("/recovery/recovery.img", (unsigned long)loadaddr,
|
|
flashReadOff, IMG_PRELOAD_SZ, &len_read);
|
|
if (rc < 0 || IMG_PRELOAD_SZ != len_read) {
|
|
errorP("Fail to read recovery.img from cache\n");
|
|
cache_flag = false;
|
|
} else {
|
|
cache_flag = true;
|
|
}
|
|
}
|
|
}
|
|
if (!cache_flag) {
|
|
MsgP("read from part: %s\n", partName);
|
|
rc = store_read_ops((unsigned char *)partName, loadaddr,
|
|
flashReadOff, IMG_PRELOAD_SZ);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0\n",
|
|
IMG_PRELOAD_SZ, partName);
|
|
return __LINE__;
|
|
}
|
|
}
|
|
flashReadOff += IMG_PRELOAD_SZ;
|
|
|
|
genFmt = genimg_get_format(hdr_addr);
|
|
#if defined(CONFIG_FIT)
|
|
if (IMAGE_FORMAT_FIT == genFmt) {
|
|
rc = _fit_img_get_img_sz(hdr_addr, &actualBootImgSz);
|
|
if (rc) {
|
|
errorP("Fail in check fit image header\n"); return -1;
|
|
}
|
|
goto load_left;
|
|
}
|
|
#endif//#if defined(CONFIG_FIT)
|
|
|
|
#if defined(CONFIG_ZIRCON_BOOT_IMAGE)
|
|
if (genFmt == IMAGE_FORMAT_ZIRCON) {
|
|
const zbi_header_t *zbi = (zbi_header_t *)hdr_addr;
|
|
|
|
actualBootImgSz = zbi->length + sizeof(*zbi);
|
|
goto load_left;
|
|
}
|
|
#endif//#if defined(CONFIG_ZIRCON_BOOT_IMAGE)
|
|
if (is_android_v3_header_image((void *)hdr_addr)) {
|
|
p_boot_img_hdr_v3_t hdr_addr_v3 = NULL;
|
|
char partname_init[32] = {0};
|
|
u64 rc_init;
|
|
char *slot_name;
|
|
u64 size;
|
|
|
|
init_boot_ramdisk_size = 0;
|
|
slot_name = getenv("slot-suffixes");
|
|
if (slot_name && (strcmp(slot_name, "0") == 0))
|
|
strcpy((char *)partname_init, "init_boot_a");
|
|
else if (slot_name && (strcmp(slot_name, "1") == 0))
|
|
strcpy((char *)partname_init, "init_boot_b");
|
|
else
|
|
strcpy((char *)partname_init, "init_boot");
|
|
|
|
rc_init = store_get_partition_size((unsigned char *)partname_init, &size);
|
|
|
|
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
|
|
//check image format for rtos
|
|
hdr = (image_header_t *)loadaddr;
|
|
if (genFmt == IMAGE_FORMAT_LEGACY
|
|
&& image_check_type(hdr, IH_TYPE_STANDALONE) ) {
|
|
actualBootImgSz = image_get_image_size(hdr);
|
|
goto load_left_r;
|
|
}
|
|
#endif /* CONFIG_IMAGE_FORMAT_LEGACY */
|
|
|
|
if (IMAGE_FORMAT_ANDROID != genFmt) {
|
|
errorP("Fmt unsupported!genFmt 0x%x != 0x%x\n", genFmt, IMAGE_FORMAT_ANDROID);
|
|
return __LINE__;
|
|
}
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
//Check if encrypted image
|
|
rc = _aml_get_secure_boot_kernel_size(loadaddr, &secureKernelImgSz);
|
|
if (rc) {
|
|
errorP("Fail in _aml_get_secure_boot_kernel_size, rc=%d\n", rc);
|
|
return __LINE__;
|
|
}
|
|
#endif
|
|
hdr_addr_v3 = (p_boot_img_hdr_v3_t)hdr_addr;
|
|
kernel_size = ALIGN(hdr_addr_v3->kernel_size,0x1000);
|
|
ramdisk_size = ALIGN(hdr_addr_v3->ramdisk_size,0x1000);
|
|
MsgP("kernel_size 0x%x, totalSz 0x%x\n", hdr_addr_v3->kernel_size, kernel_size);
|
|
MsgP("ramdisk_size 0x%x, totalSz 0x%x\n", hdr_addr_v3->ramdisk_size, ramdisk_size);
|
|
if (kernel_size > MAX_KERNEL_SIZE) {
|
|
errorP("kernel size limit 0x%x,0x%x\n", kernel_size,
|
|
MAX_KERNEL_SIZE);
|
|
return __LINE__;
|
|
}
|
|
if (ramdisk_size > MAX_RAMDISK_SIZE) {
|
|
errorP("ramdisk size limit 0x%x,0x%x\n", ramdisk_size,
|
|
MAX_RAMDISK_SIZE);
|
|
return __LINE__;
|
|
}
|
|
|
|
if (secureKernelImgSz) {
|
|
actualBootImgSz = secureKernelImgSz;
|
|
MsgP("secureKernelImgSz=0x%x\n", actualBootImgSz);
|
|
} else {
|
|
actualBootImgSz = kernel_size + ramdisk_size + 0x1000;
|
|
}
|
|
#ifdef CONFIG_AVB2
|
|
original_size = actualBootImgSz;
|
|
actualBootImgSz = get_size_avb_footer(partName);
|
|
if (!actualBootImgSz || actualBootImgSz < original_size) {
|
|
actualBootImgSz = original_size;
|
|
kernel_preload = false;
|
|
printf("part: %s footer not at correct location\n", partName);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
|
|
load_left_r:
|
|
#endif
|
|
if (actualBootImgSz > IMG_PRELOAD_SZ) {
|
|
const unsigned leftSz = actualBootImgSz - IMG_PRELOAD_SZ;
|
|
|
|
/* auto adjust kernel image load address avoid
|
|
* touch iotrace data and secureOS memory space
|
|
*/
|
|
kernelLoadAddr =
|
|
getenv_ulong("loadaddr", 16, KERNEL_DEFAULT_LOAD_ADDR);
|
|
kernelEndAddr = kernelLoadAddr + actualBootImgSz;
|
|
dtbLoadAddr = getenv_ulong("dtb_mem_addr", 16, DTB_LOAD_ADDR);
|
|
|
|
if (kernelEndAddr > IOTRACE_LOAD_ADDR) {
|
|
if (ALIGN(actualBootImgSz, LOAD_ADDR_ALIGN_LENGTH) >=
|
|
(IOTRACE_LOAD_ADDR - dtbLoadAddr - LOAD_ADDR_ALIGN_LENGTH))
|
|
kernelLoadAddr = KERNEL_LOAD_HIGH_ADDR;
|
|
else
|
|
kernelLoadAddr = dtbLoadAddr + LOAD_ADDR_ALIGN_LENGTH;
|
|
|
|
sprintf(strAddr, "%lx", kernelLoadAddr);
|
|
memmove((void *)kernelLoadAddr, (void *)loadaddr, IMG_PRELOAD_SZ);
|
|
setenv("loadaddr", strAddr);
|
|
loadaddr = (unsigned char *)
|
|
getenv_ulong("loadaddr", 16, kernelLoadAddr);
|
|
printf("kernel overlap iotrace, reset kernelLoadAddr = 0x%lx\n",
|
|
kernelLoadAddr);
|
|
}
|
|
|
|
debugP("Left sz 0x%x\n", leftSz);
|
|
if (upgrade_step_s && (strcmp(upgrade_step_s, "3") == 0) &&
|
|
(strcmp(partName, "recovery") == 0)) {
|
|
loff_t len_read;
|
|
|
|
MsgP("read recovery.img from cache\n");
|
|
rc = fs_set_blk_dev("mmc", "1:2", FS_TYPE_EXT);
|
|
if (rc) {
|
|
errorP("Fail to set blk dev cache\n");
|
|
cache_flag = false;
|
|
}
|
|
if (rc == 0) {
|
|
rc = fs_read("/recovery/recovery.img",
|
|
(unsigned long)loadaddr,
|
|
0, actualBootImgSz, &len_read);
|
|
if (rc < 0 || actualBootImgSz != len_read) {
|
|
errorP("Fail to read recovery.img from cache\n");
|
|
cache_flag = false;
|
|
} else {
|
|
cache_flag = true;
|
|
}
|
|
}
|
|
}
|
|
if (!cache_flag) {
|
|
MsgP("read from part: %s\n", partName);
|
|
rc = store_read_ops((unsigned char *)partName,
|
|
loadaddr + IMG_PRELOAD_SZ, flashReadOff, leftSz);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0x%x\n",
|
|
leftSz, partName, IMG_PRELOAD_SZ);
|
|
return __LINE__;
|
|
}
|
|
#ifdef CONFIG_AVB2
|
|
if (kernel_preload)
|
|
set_avb_parts(partName, loadaddr, leftSz + IMG_PRELOAD_SZ);
|
|
#endif
|
|
if (rc_init == 0) {
|
|
MsgP("read from part: %s\n", partname_init);
|
|
unsigned int nflashloadlen_init = 0;
|
|
const int preloadsz_init = 0x1000 * 2;
|
|
unsigned char *pbuffpreload_init = 0;
|
|
#ifdef CONFIG_AVB2
|
|
u8 *init_boot_buf = 0;
|
|
#endif
|
|
|
|
nflashloadlen_init = preloadsz_init;
|
|
MsgP("sizeof preloadSz=%u\n", nflashloadlen_init);
|
|
|
|
pbuffpreload_init = malloc(preloadsz_init);
|
|
|
|
if (!pbuffpreload_init) {
|
|
printf("Fail to allocate memory for %s!\n",
|
|
partname_init);
|
|
return __LINE__;
|
|
}
|
|
|
|
rc = store_read_ops((unsigned char *)partname_init,
|
|
pbuffpreload_init, 0,
|
|
nflashloadlen_init);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s]\n",
|
|
nflashloadlen_init, partname_init);
|
|
free(pbuffpreload_init);
|
|
pbuffpreload_init = 0;
|
|
return __LINE__;
|
|
}
|
|
|
|
p_boot_img_hdr_v3_t pinitbootimghdr;
|
|
|
|
pinitbootimghdr = (p_boot_img_hdr_v3_t)pbuffpreload_init;
|
|
|
|
ramdisk_size = ALIGN(pinitbootimghdr->ramdisk_size,
|
|
0x1000);
|
|
MsgP("ramdisk_size 0x%x, totalSz 0x%x\n",
|
|
pinitbootimghdr->ramdisk_size, ramdisk_size);
|
|
MsgP("init_boot header_version = %d\n",
|
|
pinitbootimghdr->header_version);
|
|
init_boot_ramdisk_size = pinitbootimghdr->ramdisk_size;
|
|
#ifdef CONFIG_AVB2
|
|
original_size = ramdisk_size;
|
|
ramdisk_size = get_size_avb_footer(partname_init);
|
|
if (!ramdisk_size || ramdisk_size < original_size) {
|
|
ramdisk_size = original_size;
|
|
init_boot_preload = false;
|
|
printf("part: %s footer not at correct location\n",
|
|
partname_init);
|
|
}
|
|
if (init_boot_preload) {
|
|
init_boot_buf = malloc(ramdisk_size);
|
|
if (!init_boot_buf) {
|
|
printf("Fail to allocate memory for %s!\n",
|
|
partname_init);
|
|
free(pbuffpreload_init);
|
|
pbuffpreload_init = 0;
|
|
return __LINE__;
|
|
}
|
|
memcpy(init_boot_buf, pbuffpreload_init,
|
|
nflashloadlen_init);
|
|
ramdisk_size -= BOOT_IMG_V3_HDR_SIZE;
|
|
}
|
|
#endif
|
|
if (init_boot_ramdisk_size != 0) {
|
|
MsgP("read ramdisk from part: %s\n", partname_init);
|
|
rc = store_read_ops((unsigned char *)partname_init,
|
|
loadaddr + kernel_size + BOOT_IMG_V3_HDR_SIZE,
|
|
BOOT_IMG_V3_HDR_SIZE,
|
|
ramdisk_size);
|
|
#ifdef CONFIG_AVB2
|
|
if (init_boot_preload)
|
|
memcpy(init_boot_buf + BOOT_IMG_V3_HDR_SIZE,
|
|
loadaddr + kernel_size +
|
|
BOOT_IMG_V3_HDR_SIZE,
|
|
ramdisk_size);
|
|
#endif
|
|
}
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s]\n",
|
|
ramdisk_size, partname_init);
|
|
free(pbuffpreload_init);
|
|
pbuffpreload_init = 0;
|
|
#ifdef CONFIG_AVB2
|
|
free(init_boot_buf);
|
|
#endif
|
|
return __LINE__;
|
|
}
|
|
#ifdef CONFIG_AVB2
|
|
if (init_boot_ramdisk_size != 0 && init_boot_preload)
|
|
set_avb_parts(partname_init, init_boot_buf,
|
|
ramdisk_size + BOOT_IMG_V3_HDR_SIZE);
|
|
if (init_boot_preload)
|
|
free(init_boot_buf);
|
|
#endif
|
|
free(pbuffpreload_init);
|
|
pbuffpreload_init = 0;
|
|
}
|
|
}
|
|
}
|
|
debugP("totalSz=0x%x\n", actualBootImgSz);
|
|
|
|
/*
|
|
because secure boot will use DMA which need disable MMU temp
|
|
here must update the cache, otherwise nand will fail (eMMC is OK)
|
|
*/
|
|
flush_cache((unsigned long)loadaddr,(unsigned long)actualBootImgSz);
|
|
} /*ANDROID R and above version */
|
|
else {
|
|
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
|
|
//check image format for rtos
|
|
genFmt = genimg_get_format(loadaddr);
|
|
hdr = (image_header_t *)loadaddr;
|
|
if (genFmt == IMAGE_FORMAT_LEGACY
|
|
&& image_check_type(hdr, IH_TYPE_STANDALONE) ) {
|
|
actualBootImgSz = image_get_image_size(hdr);
|
|
goto load_left;
|
|
}
|
|
#endif /* CONFIG_IMAGE_FORMAT_LEGACY */
|
|
|
|
ulong nCheckOffset = 0;
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
nCheckOffset = aml_sec_boot_check(AML_D_Q_IMG_SIG_HDR_SIZE,GXB_IMG_LOAD_ADDR,GXB_EFUSE_PATTERN_SIZE,GXB_IMG_DEC_ALL);
|
|
if (AML_D_Q_IMG_SIG_HDR_SIZE == (nCheckOffset & 0xFFFF))
|
|
nCheckOffset = (nCheckOffset >> 16) & 0xFFFF;
|
|
else
|
|
nCheckOffset = 0;
|
|
debugP("nCheckOffset 0x%lx\n", nCheckOffset);
|
|
#endif /*CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK*/
|
|
|
|
if (!nCheckOffset)
|
|
{
|
|
genFmt = genimg_get_format(hdr_addr);
|
|
if (IMAGE_FORMAT_ANDROID != genFmt) {
|
|
errorP("Fmt unsupported!genFmt 0x%x != 0x%x\n", genFmt, IMAGE_FORMAT_ANDROID);
|
|
return __LINE__;
|
|
}
|
|
}
|
|
|
|
//Check if encrypted image
|
|
#ifndef CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK
|
|
rc = _aml_get_secure_boot_kernel_size(loadaddr, &secureKernelImgSz);
|
|
if (rc) {
|
|
errorP("Fail in _aml_get_secure_boot_kernel_size, rc=%d\n", rc);
|
|
return __LINE__;
|
|
}
|
|
#endif /* CONFIG_SKIP_KERNEL_DTB_SECBOOT_CHECK */
|
|
if (secureKernelImgSz)
|
|
{
|
|
actualBootImgSz = secureKernelImgSz;
|
|
MsgP("secureKernelImgSz=0x%x\n", actualBootImgSz);
|
|
}
|
|
else
|
|
{
|
|
kernel_size = (hdr_addr->kernel_size + (hdr_addr->page_size-1)+hdr_addr->page_size)&(~(hdr_addr->page_size -1));
|
|
ramdisk_size = (hdr_addr->ramdisk_size + (hdr_addr->page_size-1))&(~(hdr_addr->page_size -1));
|
|
dtbSz = hdr_addr->second_size;
|
|
actualBootImgSz = kernel_size + ramdisk_size + dtbSz;
|
|
#ifdef CONFIG_AVB2
|
|
original_size = actualBootImgSz;
|
|
actualBootImgSz = get_size_avb_footer(partName);
|
|
if (!actualBootImgSz || actualBootImgSz < original_size) {
|
|
kernel_preload = false;
|
|
actualBootImgSz = original_size;
|
|
printf("part: %s footer not at correct location\n", partName);
|
|
}
|
|
#endif
|
|
debugP("kernel_size 0x%x, page_size 0x%x, totalSz 0x%x\n", hdr_addr->kernel_size, hdr_addr->page_size, kernel_size);
|
|
debugP("ramdisk_size 0x%x, totalSz 0x%x\n", hdr_addr->ramdisk_size, ramdisk_size);
|
|
debugP("dtbSz 0x%x, Total actualBootImgSz 0x%x\n", dtbSz, actualBootImgSz);
|
|
if (kernel_size > MAX_KERNEL_SIZE) {
|
|
errorP("kernel size limit 0x%x,0x%x\n", kernel_size,
|
|
MAX_KERNEL_SIZE);
|
|
return __LINE__;
|
|
}
|
|
if (ramdisk_size > MAX_RAMDISK_SIZE) {
|
|
errorP("ramdisk size limit 0x%x,0x%x\n", ramdisk_size,
|
|
MAX_RAMDISK_SIZE);
|
|
return __LINE__;
|
|
}
|
|
if (dtbSz > MAX_DTB_SIZE) {
|
|
errorP("dtb size limit 0x%x,0x%x\n", dtbSz, MAX_DTB_SIZE);
|
|
return __LINE__;
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_IMAGE_FORMAT_LEGACY) || defined(CONFIG_FIT)
|
|
load_left:
|
|
#endif
|
|
if (actualBootImgSz > IMG_PRELOAD_SZ)
|
|
{
|
|
const unsigned leftSz = actualBootImgSz - IMG_PRELOAD_SZ;
|
|
|
|
/* auto adjust kernel image load address avoid
|
|
* touch iotrace data and secureOS memory space
|
|
*/
|
|
kernelLoadAddr =
|
|
getenv_ulong("loadaddr", 16, KERNEL_DEFAULT_LOAD_ADDR);
|
|
kernelEndAddr = kernelLoadAddr + actualBootImgSz;
|
|
dtbLoadAddr = getenv_ulong("dtb_mem_addr", 16, DTB_LOAD_ADDR);
|
|
|
|
if (kernelEndAddr > IOTRACE_LOAD_ADDR) {
|
|
if (ALIGN(actualBootImgSz, LOAD_ADDR_ALIGN_LENGTH) >=
|
|
(IOTRACE_LOAD_ADDR - dtbLoadAddr -
|
|
ALIGN(dtbSz, LOAD_ADDR_ALIGN_LENGTH)))
|
|
kernelLoadAddr = KERNEL_LOAD_HIGH_ADDR;
|
|
else
|
|
kernelLoadAddr = dtbLoadAddr +
|
|
ALIGN(dtbSz, LOAD_ADDR_ALIGN_LENGTH);
|
|
|
|
sprintf(strAddr, "%lx", kernelLoadAddr);
|
|
memmove((void *)kernelLoadAddr, (void *)loadaddr, IMG_PRELOAD_SZ);
|
|
setenv("loadaddr", strAddr);
|
|
loadaddr = (unsigned char *)
|
|
getenv_ulong("loadaddr", 16, kernelLoadAddr);
|
|
printf("kernel overlap iotrace, reset kernelLoadAddr = 0x%lx\n",
|
|
kernelLoadAddr);
|
|
}
|
|
|
|
debugP("Left sz 0x%x\n", leftSz);
|
|
rc = store_read_ops((unsigned char*)partName, loadaddr + IMG_PRELOAD_SZ, flashReadOff, leftSz);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0x%x\n", leftSz, partName, IMG_PRELOAD_SZ);
|
|
return __LINE__;
|
|
}
|
|
#ifdef CONFIG_AVB2
|
|
if (kernel_preload)
|
|
set_avb_parts(partName, loadaddr, leftSz + IMG_PRELOAD_SZ);
|
|
#endif
|
|
}
|
|
debugP("totalSz=0x%x\n", actualBootImgSz);
|
|
|
|
//because secure boot will use DMA which need disable MMU temp
|
|
//here must update the cache, otherwise nand will fail (eMMC is OK)
|
|
flush_cache((unsigned long)loadaddr,(unsigned long)actualBootImgSz);
|
|
|
|
}
|
|
#if defined(CONFIG_FIT)
|
|
if (IMAGE_FORMAT_FIT == genFmt) {
|
|
//fit_print_contents(hdr_addr);
|
|
if (!fit_all_image_verify(hdr_addr)) {
|
|
errorP("Bad hash in FIT image!\n");
|
|
return -__LINE__;
|
|
}
|
|
}
|
|
#endif// #if defined(CONFIG_FIT)
|
|
return 0;
|
|
}
|
|
|
|
#define AML_RES_IMG_VERSION_V1 (0x01)
|
|
#define AML_RES_IMG_VERSION_V2 (0x02)
|
|
#define AML_RES_IMG_V1_MAGIC_LEN 8
|
|
#define AML_RES_IMG_V1_MAGIC "AML_RES!"//8 chars
|
|
#define AML_RES_IMG_ITEM_ALIGN_SZ 16
|
|
#define AML_RES_IMG_HEAD_SZ (AML_RES_IMG_ITEM_ALIGN_SZ * 4)//64
|
|
#define AML_RES_ITEM_HEAD_SZ (AML_RES_IMG_ITEM_ALIGN_SZ * 4)//64
|
|
|
|
//typedef for amlogic resource image
|
|
#pragma pack(push, 4)
|
|
typedef struct {
|
|
__u32 crc; //crc32 value for the resouces image
|
|
__s32 version;//current version is 0x01
|
|
|
|
__u8 magic[AML_RES_IMG_V1_MAGIC_LEN]; //resources images magic
|
|
|
|
__u32 imgSz; //total image size in byte
|
|
__u32 imgItemNum;//total item packed in the image
|
|
|
|
__u32 alignSz;//AML_RES_IMG_ITEM_ALIGN_SZ
|
|
__u8 reserv[AML_RES_IMG_HEAD_SZ - 8 * 3 - 4];
|
|
|
|
}AmlResImgHead_t;
|
|
#pragma pack(pop)
|
|
|
|
#define LOGO_OLD_FMT_READ_SZ (8U<<20)//if logo format old, read 8M
|
|
#define LOGO_TOTAL_ITEM (16)
|
|
|
|
static int img_res_check_log_header(const AmlResImgHead_t* pResImgHead)
|
|
{
|
|
int rc = 0;
|
|
|
|
rc = memcmp(pResImgHead->magic, AML_RES_IMG_V1_MAGIC, AML_RES_IMG_V1_MAGIC_LEN);
|
|
if (rc) {
|
|
debugP("Magic error for res\n");
|
|
return 1;
|
|
}
|
|
if (AML_RES_IMG_VERSION_V2 != pResImgHead->version) {
|
|
errorP("res version 0x%x != 0x%x\n", pResImgHead->version, AML_RES_IMG_VERSION_V2);
|
|
return 2;
|
|
}
|
|
if (pResImgHead->imgItemNum > LOGO_TOTAL_ITEM) {
|
|
errorP("logo size err 0x%x != 0x%x\n", pResImgHead->imgItemNum,
|
|
LOGO_TOTAL_ITEM);
|
|
return 3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_image_read_res(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
const char* const partName = argv[1];
|
|
unsigned char* loadaddr = 0;
|
|
int rc = 0;
|
|
AmlResImgHead_t* pResImgHead = NULL;
|
|
unsigned totalSz = 0;
|
|
uint64_t flashReadOff = 0;
|
|
|
|
if (2 < argc) {
|
|
loadaddr = (unsigned char*)simple_strtoul(argv[2], NULL, 16);
|
|
}
|
|
else{
|
|
loadaddr = (unsigned char *)getenv_hex("loadaddr", 0);
|
|
}
|
|
pResImgHead = (AmlResImgHead_t*)loadaddr;
|
|
|
|
rc = store_read_ops((unsigned char*)partName, loadaddr, flashReadOff, IMG_PRELOAD_SZ);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0\n", IMG_PRELOAD_SZ, partName);
|
|
return __LINE__;
|
|
}
|
|
flashReadOff = IMG_PRELOAD_SZ;
|
|
|
|
if (img_res_check_log_header(pResImgHead)) {
|
|
errorP("Logo header err.\n");
|
|
return __LINE__;
|
|
}
|
|
|
|
//Read the actual size of the new version res image
|
|
totalSz = pResImgHead->imgSz;
|
|
if (totalSz > IMG_PRELOAD_SZ )
|
|
{
|
|
const unsigned leftSz = totalSz - flashReadOff;
|
|
|
|
rc = store_read_ops((unsigned char*)partName, loadaddr + (unsigned)flashReadOff, flashReadOff, leftSz);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0x%x\n", leftSz, partName, IMG_PRELOAD_SZ);
|
|
return __LINE__;
|
|
}
|
|
}
|
|
debugP("totalSz=0x%x\n", totalSz);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define IH_MAGIC 0x27051956 /* Image Magic Number */
|
|
#define IH_NMLEN 32 /* Image Name Length */
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct pack_header{
|
|
unsigned int magic; /* Image Header Magic Number */
|
|
unsigned int hcrc; /* Image Header CRC Checksum */
|
|
unsigned int size; /* Image Data Size */
|
|
unsigned int start; /* item data offset in the image*/
|
|
unsigned int end; /* Entry Point Address */
|
|
unsigned int next; /* Next item head offset in the image*/
|
|
unsigned int dcrc; /* Image Data CRC Checksum */
|
|
unsigned char index; /* Operating System */
|
|
unsigned char nums; /* CPU architecture */
|
|
unsigned char type; /* Image Type */
|
|
unsigned char comp; /* Compression Type */
|
|
char name[IH_NMLEN]; /* Image Name */
|
|
}AmlResItemHead_t;
|
|
#pragma pack(pop)
|
|
|
|
#define CONFIG_MAX_PIC_LEN (12 << 20)
|
|
static const unsigned char gzip_magic[] = { 0x1f, 0x8b };
|
|
|
|
//uncompress known format for 'imgread pic'
|
|
static int imgread_uncomp_pic(unsigned char* srcAddr, const unsigned srcSz,
|
|
unsigned char* dstAddr, const unsigned dstBufSz, unsigned long* dstDatSz)
|
|
{
|
|
/*debugP("srcAddr[%x, %x]\n", srcAddr[0], srcAddr[1]);*/
|
|
if (!memcmp(srcAddr, gzip_magic, sizeof(gzip_magic)))
|
|
{
|
|
if (dstDatSz) *dstDatSz = srcSz;
|
|
else return -__LINE__; //need dstDatSz to check src sz in gunzip
|
|
return gunzip(dstAddr, dstBufSz, srcAddr, dstDatSz);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//[imgread pic] logo $pictureName $loadaddr_misc
|
|
//if $pictureName=bootup,
|
|
// first try find $board_defined_bootup
|
|
// last try find bootup
|
|
static int do_image_read_pic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
const char* const partName = argv[1];
|
|
unsigned char* loadaddr = 0;
|
|
int rc = 0;
|
|
const AmlResImgHead_t* pResImgHead = NULL;
|
|
uint64_t flashReadOff = 0;
|
|
const unsigned PreloadSz = PIC_PRELOAD_SZ;//preload 8k, 124-1 pic header, If you need pack more than 123 items, fix this
|
|
unsigned itemIndex = 0;
|
|
const AmlResItemHead_t* pItem = NULL;
|
|
const char* defPic = argv[2];
|
|
const AmlResItemHead_t* itemFound = NULL;
|
|
char cmdBuf[256];
|
|
const char* bootupOutmode[4] = {NULL, NULL, NULL, NULL};//${bootup_board}_720, ${bootup_board}, bootup_720, bootup
|
|
|
|
if (argc > 3)
|
|
loadaddr = (unsigned char *)simple_strtoul(argv[3], NULL, 16);
|
|
else
|
|
loadaddr = (unsigned char *)getenv_hex("loadaddr_misc", 0);
|
|
|
|
pResImgHead = (AmlResImgHead_t*)loadaddr;
|
|
|
|
debugP("to read pic (%s)\n", defPic);
|
|
rc = store_read_ops((unsigned char*)partName, loadaddr, flashReadOff, PreloadSz);
|
|
if (rc) {
|
|
errorP("Fail to read 0x%xB from part[%s] at offset 0\n", PreloadSz, partName);
|
|
return __LINE__;
|
|
}
|
|
flashReadOff = PreloadSz;
|
|
debugP("end read pic sz %d\n", PreloadSz);
|
|
|
|
if (img_res_check_log_header(pResImgHead)) {
|
|
errorP("Logo header err.\n");
|
|
return __LINE__;
|
|
}
|
|
|
|
bootupOutmode[3] = defPic;//try it last
|
|
//correct bootup
|
|
while (!strcmp("bootup", defPic))
|
|
{
|
|
const char* picName = NULL;
|
|
if (getenv("board_defined_bootup")) {//set bootup name is board
|
|
bootupOutmode[1] = picName = getenv("board_defined_bootup");
|
|
}
|
|
|
|
char* outputmode = getenv("outputmode");
|
|
if (!outputmode)break;//not env outputmode
|
|
|
|
rc = !strncmp("720", outputmode, 3) || !strncmp("576", outputmode, 3) || !strncmp("480", outputmode, 3);
|
|
if (rc) {
|
|
bootupOutmode[2] = "bootup_720";
|
|
if (picName) {
|
|
if (strnlen(picName, sizeof(cmdBuf)/2 + 8) > sizeof(cmdBuf)/2) {
|
|
errorP("picName too long\n");
|
|
return __LINE__;
|
|
}
|
|
/*sprintf(cmdBuf, "%s_720", picName);*/
|
|
memcpy(cmdBuf, picName, strnlen(picName, sizeof(cmdBuf)/2));
|
|
strncpy(&cmdBuf[strlen(cmdBuf)], "_720", 4+1);
|
|
bootupOutmode[0] = cmdBuf;
|
|
}
|
|
break;
|
|
}
|
|
|
|
bootupOutmode[2] = "bootup_1080";
|
|
if (picName) {
|
|
/*sprintf(cmdBuf, "%s_1080", picName);*/
|
|
memcpy(cmdBuf, picName, strnlen(picName, sizeof(cmdBuf)/2));
|
|
strncpy(&cmdBuf[strlen(cmdBuf)], "_1080", 5+1);
|
|
bootupOutmode[0] = cmdBuf;
|
|
}
|
|
break;
|
|
}
|
|
debugP("bootupOutmode %s,%s, %s, %s\n", bootupOutmode[0], bootupOutmode[1], bootupOutmode[2], bootupOutmode[3]);
|
|
|
|
int i = 0;
|
|
for (; i < ARRAY_SIZE(bootupOutmode); ++i) {
|
|
const char* thisName = bootupOutmode[i];
|
|
if (!thisName) continue;
|
|
|
|
pItem = (AmlResItemHead_t*)(pResImgHead + 1);
|
|
for (itemIndex = 0; itemIndex < pResImgHead->imgItemNum; ++itemIndex, ++pItem) {
|
|
if (IH_MAGIC != pItem->magic) {
|
|
errorP("item magic 0x%x != 0x%x\n", pItem->magic, IH_MAGIC);
|
|
return __LINE__;
|
|
}
|
|
|
|
if (pItem->start > CONFIG_MAX_PIC_LEN) {
|
|
errorP("item data offset err 0x%x != 0x%x\n", pItem->start,
|
|
CONFIG_MAX_PIC_LEN);
|
|
return __LINE__;
|
|
}
|
|
|
|
if (pItem->size > CONFIG_MAX_PIC_LEN) {
|
|
errorP("item data size err 0x%x != 0x%x\n", pItem->size,
|
|
CONFIG_MAX_PIC_LEN);
|
|
return __LINE__;
|
|
}
|
|
|
|
const char* itemName = pItem->name;
|
|
if (!strcmp(thisName, itemName)) {
|
|
itemFound = pItem;
|
|
debugP("found itemName %s\n", itemName);
|
|
break;
|
|
}
|
|
}
|
|
if (itemFound) break;
|
|
}
|
|
if (!itemFound) {
|
|
errorP("cannot find pic for cmd[imgread pic %s]\n", defPic);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
{
|
|
char env_name[IH_NMLEN*2];
|
|
char env_data[IH_NMLEN*2];
|
|
unsigned long picLoadAddr = (unsigned long)loadaddr + (unsigned)pItem->start;
|
|
unsigned int itemSz = pItem->size;
|
|
unsigned long uncompSz = 0;
|
|
|
|
if (pItem->start + itemSz > flashReadOff)
|
|
{
|
|
unsigned long rdOff = pItem->start;
|
|
unsigned long rdOffAlign = (rdOff >> 11) << 11;//align 2k page for mtd nand, 512 for emmc
|
|
rc = store_read_ops((unsigned char*)partName, (unsigned char *)((picLoadAddr>>11)<<11),
|
|
rdOffAlign, itemSz + (rdOff & 0x7ff) );
|
|
if (rc) {
|
|
errorP("Fail to read pic at offset 0x%x\n", pItem->start);
|
|
return __LINE__;
|
|
}
|
|
debugP("pic sz 0x%x\n", itemSz);
|
|
}
|
|
|
|
//uncompress supported format
|
|
unsigned long uncompLoadaddr = picLoadAddr + itemSz + 7;
|
|
uncompLoadaddr &= ~(0x7U);
|
|
rc = imgread_uncomp_pic((unsigned char *)picLoadAddr, itemSz,
|
|
(unsigned char *)uncompLoadaddr, CONFIG_MAX_PIC_LEN, &uncompSz);
|
|
if (rc) {
|
|
errorP("Fail in uncomp pic,rc[%d]\n", rc);
|
|
return __LINE__;
|
|
}
|
|
if (uncompSz) {
|
|
itemSz = uncompSz;
|
|
picLoadAddr = uncompLoadaddr;
|
|
}
|
|
|
|
sprintf(env_name, "%s_offset", defPic);//be bootup_offset ,not bootup_720_offset
|
|
sprintf(env_data, "0x%lx", picLoadAddr);
|
|
setenv(env_name, env_data);
|
|
|
|
sprintf(env_name, "%s_size", defPic);
|
|
sprintf(env_data, "0x%x", itemSz);
|
|
setenv(env_name, env_data);
|
|
|
|
debugP("end read pic[%s]\n", defPic);
|
|
return 0;//success
|
|
}
|
|
|
|
return __LINE__;//fail
|
|
}
|
|
|
|
static cmd_tbl_t cmd_imgread_sub[] = {
|
|
U_BOOT_CMD_MKENT(kernel, 4, 0, do_image_read_kernel, "", ""),
|
|
U_BOOT_CMD_MKENT(dtb, 4, 0, do_image_read_dtb, "", ""),
|
|
U_BOOT_CMD_MKENT(res, 3, 0, do_image_read_res, "", ""),
|
|
U_BOOT_CMD_MKENT(pic, 4, 0, do_image_read_pic, "", ""),
|
|
};
|
|
|
|
static int do_image_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
cmd_tbl_t *c;
|
|
|
|
/* Strip off leading 'bmp' command argument */
|
|
argc--;
|
|
argv++;
|
|
|
|
c = find_cmd_tbl(argv[0], &cmd_imgread_sub[0], ARRAY_SIZE(cmd_imgread_sub));
|
|
|
|
if (c) {
|
|
return c->cmd(cmdtp, flag, argc, argv);
|
|
} else {
|
|
cmd_usage(cmdtp);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
U_BOOT_CMD(
|
|
imgread, //command name
|
|
5, //maxargs
|
|
0, //repeatable
|
|
do_image_read, //command function
|
|
"Read the image from internal flash with actual size", //description
|
|
" argv: <imageType> <part_name> <loadaddr> \n" //usage
|
|
" - <image_type> Current support is kernel/res(ource).\n"
|
|
"imgread kernel --- Read image in format IMAGE_FORMAT_ANDROID\n"
|
|
"imgread dtb --- Read dtb in format IMAGE_FORMAT_ANDROID\n"
|
|
"imgread res --- Read image packed by 'Amlogic resource packer'\n"
|
|
"imgread pic --- Read one picture from Amlogic logo"
|
|
" - e.g. \n"
|
|
" to read boot.img from part boot from flash: <imgread kernel boot loadaddr> \n" //usage
|
|
" to read recovery.img from part recovery from flash: <imgread kernel recovery loadaddr $offset> \n" //usage
|
|
" to read logo.img from part logo from flash: <imgread res logo loadaddr> \n" //usage
|
|
" to read one picture named 'bootup' from logo.img from logo: <imgread pic logo bootup loadaddr> \n" //usage
|
|
);
|
|
|
|
//[imgread pic] logo bootup $loadaddr_misc
|
|
static int do_unpackimg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned char* loadaddr = 0;
|
|
const AmlResImgHead_t* pResImgHead = NULL;
|
|
unsigned itemIndex = 0;
|
|
const AmlResItemHead_t* pItem = NULL;
|
|
|
|
if (argc > 1) {
|
|
loadaddr = (unsigned char *)simple_strtoul(argv[1], NULL, 16);
|
|
} else {
|
|
loadaddr = (unsigned char *)getenv_hex("loadaddr_misc", 0);
|
|
}
|
|
|
|
pResImgHead = (AmlResImgHead_t*)loadaddr;
|
|
const int totalSz = pResImgHead->imgSz;
|
|
unsigned char* unCompressBuf = loadaddr + totalSz;
|
|
|
|
if (img_res_check_log_header(pResImgHead)) {
|
|
errorP("Logo header err.\n");
|
|
return __LINE__;
|
|
}
|
|
|
|
pItem = (AmlResItemHead_t*)(pResImgHead + 1);
|
|
for (itemIndex = 0; itemIndex < pResImgHead->imgItemNum; ++itemIndex, ++pItem)
|
|
{
|
|
if (IH_MAGIC != pItem->magic) {
|
|
errorP("item magic 0x%x != 0x%x\n", pItem->magic, IH_MAGIC);
|
|
return __LINE__;
|
|
}
|
|
char env_name[IH_NMLEN*2];
|
|
char env_data[IH_NMLEN*2];
|
|
unsigned long picLoadAddr = (unsigned long)loadaddr + (unsigned)pItem->start;
|
|
|
|
int itemSz = pItem->size;
|
|
unsigned long uncompSz = 0;
|
|
if ((long)unCompressBuf & 0x7U)
|
|
unCompressBuf = (unsigned char*)((((unsigned long)unCompressBuf + 8)>>3) << 3);
|
|
imgread_uncomp_pic((unsigned char*)picLoadAddr, pItem->size,
|
|
unCompressBuf, CONFIG_MAX_PIC_LEN, &uncompSz);
|
|
if (uncompSz) {
|
|
picLoadAddr = (unsigned long)unCompressBuf;
|
|
itemSz = uncompSz;
|
|
unCompressBuf += uncompSz;
|
|
}
|
|
|
|
sprintf(env_name, "%s_offset", pItem->name);//be bootup_offset ,not bootup_720_offset
|
|
sprintf(env_data, "0x%lx", picLoadAddr);
|
|
setenv(env_name, env_data);
|
|
|
|
sprintf(env_name, "%s_size", pItem->name);
|
|
sprintf(env_data, "0x%x", itemSz);
|
|
setenv(env_name, env_data);
|
|
}
|
|
|
|
return 0;//success
|
|
}
|
|
|
|
U_BOOT_CMD(
|
|
unpackimg, //command name
|
|
2, //maxargs
|
|
0, //repeatable
|
|
do_unpackimg, //command function
|
|
"un pack logo image into pictures", //description
|
|
" argv: unpackimg <imgLoadaddr> \n" //usage
|
|
" un pack the logo image, which already loaded at <imgLoadaddr>.\n"
|
|
);
|
|
|
|
#if defined(CONFIG_CMD_EXT4)
|
|
/*"if ext4load mmc 1:x ${dtb_mem_addr} /recovery/dtb.img; then echo cache dtb.img loaded; fi;"\*/
|
|
static int do_load_logo_from_ext4(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
if (3 > argc) {
|
|
errorP("argc(%d) < 3 illegal\n", argc);
|
|
return CMD_RET_USAGE;
|
|
}
|
|
int iRet = 0;
|
|
const char* ext4Part = argv[1];
|
|
void* loadaddr = (void*)simple_strtoul(argv[2], NULL, 16);
|
|
if (argc > 3) {
|
|
setenv("ext4LogoPath", argv[3]);
|
|
} else {
|
|
setenv("ext4LogoPath", "/logo_files/bootup.bmp");
|
|
}
|
|
|
|
if (!loadaddr) {
|
|
errorP("illegal loadaddr %s\n", argv[2]);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
if (EMMC_BOOT_FLAG != device_boot_flag) return CMD_RET_FAILURE;
|
|
|
|
const int partIndex = get_partition_num_by_name((char*)ext4Part);
|
|
if (partIndex < 0) {
|
|
errorP("invalid partition name(%s)\n", ext4Part);
|
|
}
|
|
setenv_hex("logoPart", partIndex);
|
|
setenv_hex("logoLoadAddr", (ulong)loadaddr);
|
|
setenv("ext4logoLoadCmd", "ext4load mmc 1:${logoPart} ${logoLoadAddr} ${ext4LogoPath}");
|
|
iRet = run_command("printenv ext4logoLoadCmd; run ext4logoLoadCmd", 0);
|
|
if (iRet) {
|
|
errorP("Fail in load logo cmd\n"); return CMD_RET_FAILURE;
|
|
}
|
|
MsgP("load bmp from ext4 part okay\n");
|
|
run_command("setenv ext4LogoSz ${filesize}", 0);
|
|
const int bmpSz = getenv_hex("filesize", 0);
|
|
if (bmpSz <= 0) {
|
|
errorP("err bmp sz\n"); return CMD_RET_FAILURE;
|
|
}
|
|
|
|
#if defined(CONFIG_GZIP)
|
|
if (memcmp(loadaddr, gzip_magic, sizeof(gzip_magic))) {
|
|
return CMD_RET_SUCCESS;
|
|
}
|
|
MsgP("gunzip bmp logo\n");
|
|
void* uncompress = (char*)loadaddr + (((bmpSz + 0xf)>>4)<<4);
|
|
unsigned long uncompSz = 0;
|
|
iRet = imgread_uncomp_pic((unsigned char*)loadaddr, bmpSz, (unsigned char*)uncompress,
|
|
CONFIG_MAX_PIC_LEN, (unsigned long*)&uncompSz);
|
|
if (iRet) {
|
|
errorP("Fail in uncomp pic,rc[%d]\n", iRet); return __LINE__;
|
|
}
|
|
if (uncompSz <= 0) {
|
|
errorP("Fail uncompress logo bmp\n"); return CMD_RET_FAILURE;
|
|
}
|
|
memmove(loadaddr, uncompress, uncompSz);
|
|
setenv_hex("ext4LogoSz", uncompSz);
|
|
#endif//#if defined(CONFIG_GZIP)
|
|
|
|
return CMD_RET_SUCCESS;
|
|
}
|
|
|
|
U_BOOT_CMD(
|
|
rdext4pic, //read ext4 picture
|
|
4, //maxargs
|
|
0, //repeatable
|
|
do_load_logo_from_ext4, //command function
|
|
"read logo bmp from ext4 part", //description
|
|
" argv: rdext4pic <partName> <memAddr> <logoPath>\n" //usage
|
|
" load bmp picture from <logoPath> of <partName> to <memAddr>.\n"
|
|
);
|
|
#endif// #if defined(CONFIG_CMD_EXT4)
|
|
|