blob: af7514c8883ab9559bad045b941abb0319d60430 [file] [log] [blame]
/*
* Copyright (c) 2015-2017, 2020 The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <common.h>
#include <command.h>
#include <image.h>
#include <nand.h>
#include <errno.h>
#include <asm/arch-qca-common/scm.h>
#include <part.h>
#include <linux/mtd/ubi.h>
#include <asm/arch-qca-common/smem.h>
#include <mmc.h>
#include <part_efi.h>
#include <fdtdec.h>
#include "fdt_info.h"
#include <asm/errno.h>
#include <asm/arch-qca-common/qca_common.h>
#include <usb.h>
#include <elf.h>
#ifdef CONFIG_ANDROID_BOOT_IMAGE
#include <android_image.h>
#endif
#ifdef CONFIG_ANDROID_AB_BOOT
#include <android_ab_boot.h>
#endif
#define SEC_AUTH_SW_ID 0x17
#define ROOTFS_IMAGE_TYPE 0x13
#define NO_OF_PROGRAM_HDRS 3
#define ELF_HDR_PLUS_PHDR_SIZE sizeof(Elf32_Ehdr) + \
(NO_OF_PROGRAM_HDRS * sizeof(Elf32_Phdr))
unsigned long __stack_chk_guard = 0x000a0dff;
static int debug = 0;
static char mtdids[256];
DECLARE_GLOBAL_DATA_PTR;
static qca_smem_flash_info_t *sfi = &qca_smem_flash_info;
static int ipq_fs_on_nand = 0;
extern int nand_env_device;
extern qca_mmc mmc_host;
#ifdef CONFIG_QCA_MMC
static qca_mmc *host = &mmc_host;
#endif
/* boot.img source for bootipq command */
#define QCA_BOOT_FROM_FLASH 0
#define QCA_BOOT_FROM_USB 1
#define QCA_BOOT_FROM_MEM 2
#ifndef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
typedef struct {
unsigned int image_type;
unsigned int header_vsn_num;
unsigned int image_src;
unsigned char *image_dest_ptr;
unsigned int image_size;
unsigned int code_size;
unsigned char *signature_ptr;
unsigned int signature_size;
unsigned char *cert_chain_ptr;
unsigned int cert_chain_size;
} mbn_header_t;
typedef struct {
unsigned int kernel_load_addr;
unsigned int kernel_load_size;
} kernel_img_info_t;
kernel_img_info_t kernel_img_info;
char dtb_config_name[64];
char kernelpart[ALT_PART_NAME_LENGTH];
char rootfspart[ALT_PART_NAME_LENGTH];
#ifdef CONFIG_IPQ_ELF_AUTH
typedef struct {
unsigned int img_offset;
unsigned int img_load_addr;
unsigned int img_size;
} image_info;
#endif
void __stack_chk_fail(void)
{
printf("stack-protector: U-boot stack is corrupted.\n");
bad_mode ();
}
/*
* Memory layout:
*
* CONFIG_SYS_SDRAM_BASE - CONFIG_IPQ_FDT_HIGH (can be used by uboot)
* CONFIG_IPQ_FDT_HIGH - CONFIG_TZ_END_ADDR (reserved, can not be used by uboot)
* CONFIG_TZ_END_ADDR - CONFIG_SYS_SDRAM_END (can be used by uboot)
*
* This function checks if the memory between start_addr and start_addr+size
* resides in areas which can be used by uboot
*/
bool validate_bootimg_memory(unsigned int start_addr, unsigned int size)
{
if (((start_addr >= CONFIG_SYS_SDRAM_BASE) &&
(start_addr + size < CONFIG_IPQ_FDT_HIGH)) ||
((start_addr >= CONFIG_TZ_END_ADDR) &&
(start_addr + size < CONFIG_SYS_SDRAM_END)))
return true;
return false;
}
#ifndef CONFIG_ANDROID_AB_BOOT
/*
* Set the root device and bootargs for mounting root filesystem.
*/
static int set_fs_bootargs(int *fs_on_nand)
{
char *bootargs;
unsigned int active_part = 0;
int ret = 0;
char boot_args[MAX_BOOT_ARGS_SIZE] = {'\0'};
#define nand_rootfs "ubi.mtd=" QCA_ROOT_FS_PART_NAME " root=mtd:ubi_rootfs rootfstype=squashfs"
if (sfi->flash_type == SMEM_BOOT_SPI_FLASH) {
if (get_which_flash_param("rootfs") ||
((sfi->flash_secondary_type == SMEM_BOOT_NAND_FLASH) ||
(sfi->flash_secondary_type == SMEM_BOOT_QSPI_NAND_FLASH))) {
bootargs = nand_rootfs;
*fs_on_nand = 1;
if (sfi->rootfs.offset == 0xBAD0FF5E) {
if(smem_bootconfig_info() == 0)
active_part = get_rootfs_active_partition();
sfi->rootfs.offset = active_part * IPQ_NAND_ROOTFS_SIZE;
sfi->rootfs.size = IPQ_NAND_ROOTFS_SIZE;
}
fdt_setprop((void *)gd->fdt_blob, 0, "nor_nand_available",
fs_on_nand, sizeof(int));
snprintf(mtdids, sizeof(mtdids),
"nand%d=nand%d,nand%d=" QCA_SPI_NOR_DEVICE,
is_spi_nand_available(),
is_spi_nand_available(),
CONFIG_SPI_FLASH_INFO_IDX
);
if (getenv("fsbootargs") == NULL)
setenv("fsbootargs", bootargs);
} else {
bootargs = boot_args;
if (smem_bootconfig_info() == 0) {
active_part = get_rootfs_active_partition();
if (active_part) {
strlcpy(bootargs, "rootfsname=rootfs_1", sizeof(boot_args));
if (sfi->rootfs.offset == 0xBAD0FF5E)
ret = set_uuid_bootargs(bootargs, "rootfs_1", sizeof(boot_args), false);
} else {
strlcpy(bootargs, "rootfsname=rootfs", sizeof(boot_args));
if (sfi->rootfs.offset == 0xBAD0FF5E)
ret = set_uuid_bootargs(bootargs, "rootfs", sizeof(boot_args), false);
}
} else {
strlcpy(bootargs, "rootfsname=rootfs", sizeof(boot_args));
if (sfi->rootfs.offset == 0xBAD0FF5E)
ret = set_uuid_bootargs(bootargs, "rootfs", sizeof(boot_args), false);
}
if (ret)
return ret;
*fs_on_nand = 0;
snprintf(mtdids, sizeof(mtdids), "nand%d="
QCA_SPI_NOR_DEVICE, CONFIG_SPI_FLASH_INFO_IDX);
if (getenv("fsbootargs") == NULL)
setenv("fsbootargs", bootargs);
}
} else if (((sfi->flash_type == SMEM_BOOT_NAND_FLASH) ||
(sfi->flash_type == SMEM_BOOT_QSPI_NAND_FLASH))) {
bootargs = nand_rootfs;
if (getenv("fsbootargs") == NULL)
setenv("fsbootargs", bootargs);
*fs_on_nand = 1;
snprintf(mtdids, sizeof(mtdids), "nand0=nand0");
#ifdef CONFIG_QCA_MMC
} else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH) {
bootargs = boot_args;
if (smem_bootconfig_info() == 0) {
active_part = get_rootfs_active_partition();
snprintf(bootargs, sizeof(boot_args), "rootfsname=%s gpt", rootfspart);
ret = set_uuid_bootargs(bootargs, rootfspart, sizeof(boot_args), true);
} else {
strlcpy(bootargs, "rootfsname=rootfs gpt", sizeof(boot_args));
ret = set_uuid_bootargs(bootargs, "rootfs", sizeof(boot_args), true);
if (ret) {
strlcpy(bootargs, "rootfsname=system_a gpt", sizeof(boot_args));
ret = set_uuid_bootargs(bootargs, "system_a", sizeof(boot_args), true);
}
}
if (ret)
return ret;
*fs_on_nand = 0;
if (getenv("fsbootargs") == NULL)
setenv("fsbootargs", bootargs);
#endif
} else {
printf("bootipq: unsupported boot flash type\n");
return -EINVAL;
}
return run_command("setenv bootargs ${bootargs} ${fsbootargs} rootwait", 0);
}
#endif
int config_select(unsigned int addr, char *rcmd, int rcmd_size)
{
/* Selecting a config name from the list of available
* config names by passing them to the fit_conf_get_node()
* function which is used to get the node_offset with the
* config name passed. Based on the return value index based
* or board name based config is used.
*/
#ifdef CONFIG_ARCH_IPQ806x
int soc_version = 0;
#endif
int i, strings_count;
const char *config = getenv("config_name");
if (config) {
printf("Manual device tree config selected!\n");
strlcpy(dtb_config_name, config, sizeof(dtb_config_name));
if (fit_conf_get_node((void *)addr, dtb_config_name) >= 0) {
snprintf(rcmd, rcmd_size, "bootm 0x%x#%s\n",
addr, dtb_config_name);
return 0;
}
} else {
strings_count = fdt_count_strings(gd->fdt_blob, 0, "config_name");
if (!strings_count) {
printf("Failed to get config_name\n");
return -1;
}
for (i = 0; i < strings_count; i++) {
fdt_get_string_index(gd->fdt_blob, 0, "config_name",
i, &config);
snprintf((char *)dtb_config_name,
sizeof(dtb_config_name), "%s", config);
#ifdef CONFIG_ARCH_IPQ806x
ipq_smem_get_socinfo_version((uint32_t *)&soc_version);
if(SOCINFO_VERSION_MAJOR(soc_version) >= 2) {
snprintf(dtb_config_name + strlen("config@"),
sizeof(dtb_config_name) - strlen("config@"),
"v%d.0-%s",
SOCINFO_VERSION_MAJOR(soc_version),
config + strlen("config@"));
}
#endif
if (fit_conf_get_node((void *)addr, dtb_config_name) >= 0) {
snprintf(rcmd, rcmd_size, "bootm 0x%x#%s\n",
addr, dtb_config_name);
return 0;
}
}
}
printf("Config not available\n");
return -1;
}
__weak int switch_ce_channel_buf(unsigned int channel_id)
{
return 0;
}
#ifdef CONFIG_IPQ_ELF_AUTH
static int parse_elf_image_phdr(image_info *img_info, unsigned int addr)
{
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
Elf32_Phdr *phdr; /* Program header structure pointer */
int i;
ehdr = (Elf32_Ehdr *)addr;
phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
if (!IS_ELF(*ehdr)) {
printf("It is not a elf image \n");
return -EINVAL;
}
if (ehdr->e_type != ET_EXEC) {
printf("Not a valid elf image\n");
return -EINVAL;
}
/* Load each program header */
for (i = 0; i < NO_OF_PROGRAM_HDRS; ++i) {
printf("Parsing phdr load addr 0x%x offset 0x%x size 0x%x type 0x%x\n",
phdr->p_paddr, phdr->p_offset, phdr->p_filesz, phdr->p_type);
if(phdr->p_type == PT_LOAD) {
img_info->img_offset = phdr->p_offset;
img_info->img_load_addr = phdr->p_paddr;
img_info->img_size = phdr->p_filesz;
return 0;
}
++phdr;
}
return -EINVAL;
}
#endif
#ifdef CONFIG_IPQ_ROOTFS_AUTH
static int copy_rootfs(unsigned int request, uint32_t size)
{
int ret;
char runcmd[256] = {0};
#ifdef CONFIG_QCA_MMC
block_dev_desc_t *blk_dev;
disk_partition_t disk_info;
#endif
if (ipq_fs_on_nand) {
snprintf(runcmd, sizeof(runcmd),
"ubi read 0x%x ubi_rootfs &&", request);
#ifdef CONFIG_QCA_MMC
} else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH ||
((sfi->flash_type == SMEM_BOOT_SPI_FLASH) &&
(sfi->rootfs.offset == 0xBAD0FF5E))) {
blk_dev = mmc_get_dev(host->dev_num);
if (smem_bootconfig_info() == 0) {
get_rootfs_active_partition();
ret = get_partition_info_efi_by_name(blk_dev,
rootfspart, &disk_info);
}else {
ret = get_partition_info_efi_by_name(blk_dev,
"rootfs", &disk_info);
if (ret)
ret = get_partition_info_efi_by_name(blk_dev,
"system_a", &disk_info);
}
if(ret == 0)
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%X 0x%X &&",
request, (uint)disk_info.start,
(uint)(size / disk_info.blksz) + 1);
else
return CMD_RET_FAILURE;
#endif
} else {
snprintf(runcmd, sizeof(runcmd),
"sf read 0x%x 0x%x 0x%x && ",
request, (uint)sfi->rootfs.offset, (uint)sfi->rootfs.size);
}
if (debug)
printf("runcmd: %s\n", runcmd);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
return 0;
}
#ifndef CONFIG_IPQ_ELF_AUTH
static int authenticate_rootfs(unsigned int kernel_addr)
{
unsigned int kernel_imgsize;
unsigned int request;
int ret;
mbn_header_t *mbn_ptr;
struct {
unsigned long type;
unsigned long size;
unsigned long addr;
} rootfs_img_info;
request = CONFIG_ROOTFS_LOAD_ADDR;
rootfs_img_info.addr = CONFIG_ROOTFS_LOAD_ADDR;
rootfs_img_info.type = SEC_AUTH_SW_ID;
request += sizeof(mbn_header_t);/* space for mbn header */
/* get , kernel size = header + kernel + certificate */
mbn_ptr = (mbn_header_t *) kernel_addr;
kernel_imgsize = mbn_ptr->image_size + sizeof(mbn_header_t);
/* get rootfs MBN header and validate it */
mbn_ptr = (mbn_header_t *)((uint32_t)mbn_ptr + kernel_imgsize);
if (mbn_ptr->image_type != ROOTFS_IMAGE_TYPE &&
(mbn_ptr->code_size + mbn_ptr->signature_size +
mbn_ptr->cert_chain_size != mbn_ptr->image_size))
return CMD_RET_FAILURE;
/* pack, MBN header + rootfs + certificate */
/* copy rootfs from the boot device */
copy_rootfs(request, mbn_ptr->code_size);
/* copy rootfs MBN header */
memcpy((void *)CONFIG_ROOTFS_LOAD_ADDR, (void *)kernel_addr + kernel_imgsize,
sizeof(mbn_header_t));
/* copy rootfs certificate */
memcpy((void *)request + mbn_ptr->code_size,
(void *)kernel_addr + kernel_imgsize + sizeof(mbn_header_t),
mbn_ptr->signature_size + mbn_ptr->cert_chain_size);
/* copy rootfs size */
rootfs_img_info.size = sizeof(mbn_header_t) + mbn_ptr->image_size;
ret = qca_scm_secure_authenticate(&rootfs_img_info, sizeof(rootfs_img_info));
if (ret)
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}
#else
static int authenticate_rootfs_elf(unsigned int rootfs_hdr)
{
int ret;
unsigned int request;
image_info img_info;
struct {
unsigned long type;
unsigned long size;
unsigned long addr;
} rootfs_img_info;
request = CONFIG_ROOTFS_LOAD_ADDR;
rootfs_img_info.addr = request;
rootfs_img_info.type = SEC_AUTH_SW_ID;
if (parse_elf_image_phdr(&img_info, rootfs_hdr))
return CMD_RET_FAILURE;
memcpy((void*)request, (void*)rootfs_hdr, img_info.img_offset);
request += img_info.img_offset;
/* copy rootfs from the boot device */
copy_rootfs(request, img_info.img_size);
rootfs_img_info.size = img_info.img_offset + img_info.img_size;
ret = qca_scm_secure_authenticate(&rootfs_img_info, sizeof(rootfs_img_info));
if (ret)
return CMD_RET_FAILURE;
return CMD_RET_SUCCESS;
}
#endif
#endif
#ifdef CONFIG_ANDROID_AB_BOOT
static bool bootimage_startswith_android_header(disk_partition_t *disk_info)
{
char runcmd[256] = {0};
uint bootimg_start = (uint)disk_info->start;
/* Load the first sector of boot.img
* and check if boot.img is signed or not.
* There is no mbn header for unsigned boot.img
* so we can use boot.img magic number at the beginning of
* the image to check if boot.img is signed or not.
* */
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%x 0x%x",
CONFIG_SYS_LOAD_ADDR, bootimg_start, 1);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return false;
}
return (android_image_check_header((const struct andr_img_hdr *)CONFIG_SYS_LOAD_ADDR) == 0);
}
static int load_bootimg(disk_partition_t *disk_info, bool bootimg_is_signed)
{
#ifdef CONFIG_ANDROID_BOOT_IMAGE
char runcmd[256] = {0};
const struct andr_img_hdr *hdr;
mbn_header_t *mbn_hdr=(mbn_header_t *)CONFIG_SYS_LOAD_ADDR;
uint total_img_size;
uint bootimg_start = (uint)disk_info->start;
if (bootimg_is_signed) {
/* load signed boot.img */
/* load mbn header first */
/* 1 sector (512B) is enough for mbn header */
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%x 0x%x",
CONFIG_SYS_LOAD_ADDR, bootimg_start, 1);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
/* check if this is valid signed boot.img with mbn header,
* mbn header doesn't have magic number, so we use a tricky way
* here */
if (mbn_hdr->image_size !=
(mbn_hdr->code_size + mbn_hdr->signature_size + mbn_hdr->cert_chain_size)) {
return CMD_RET_FAILURE;
}
/* calculate the remaining image size to read */
total_img_size = sizeof(mbn_header_t) +
mbn_hdr->image_size;
/* calculate image size in # of sectors */
total_img_size = (total_img_size + MMC_MAX_BLOCK_LEN - 1) / MMC_MAX_BLOCK_LEN;
if ((total_img_size > (uint)disk_info->size) ||
(total_img_size <= 1)) {
return CMD_RET_FAILURE;
}
/* read remaining boot.img */
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%x 0x%x",
CONFIG_SYS_LOAD_ADDR + MMC_MAX_BLOCK_LEN,
bootimg_start + 1,
total_img_size - 1);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
} else {
/* load unsigned boot.img */
/* load boot.img header first */
/* 1 sector (512B) is enough for boot.img header */
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%x 0x%x",
CONFIG_SYS_LOAD_ADDR, bootimg_start, 1);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
/* check the magic number of android boot.img */
hdr = (const struct andr_img_hdr *)CONFIG_SYS_LOAD_ADDR;
if (android_image_check_header(hdr) != 0) {
return CMD_RET_FAILURE;
}
/* calculate the remaining boot.img size to read */
total_img_size = hdr->page_size +
ALIGN(hdr->kernel_size, hdr->page_size) +
ALIGN(hdr->ramdisk_size, hdr->page_size) +
ALIGN(hdr->second_size, hdr->page_size);
/* calculate image size in # of sectors */
total_img_size = (total_img_size + MMC_MAX_BLOCK_LEN - 1) / MMC_MAX_BLOCK_LEN;
if ((total_img_size > (uint)disk_info->size) ||
(total_img_size <= 1)) {
return CMD_RET_FAILURE;
}
/* read remaining boot.img */
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%x 0x%x",
CONFIG_SYS_LOAD_ADDR + MMC_MAX_BLOCK_LEN,
bootimg_start + 1,
total_img_size - 1);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
}
return CMD_RET_SUCCESS;
#else
return CMD_RET_FAILURE;
#endif // CONFIG_ANDROID_BOOT_IMAGE
}
#endif // CONFIG_ANDROID_AB_BOOT
static int do_boot_signedimg(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char runcmd[256] = {0};
int ret;
int boot_src = QCA_BOOT_FROM_FLASH; /* default boot from flash */
unsigned int request;
#ifdef CONFIG_QCA_MMC
block_dev_desc_t *blk_dev;
disk_partition_t disk_info;
#ifdef CONFIG_ANDROID_AB_BOOT
char boot_part_name[20]={0};
#endif // CONFIG_ANDROID_AB_BOOT
#endif
#ifdef CONFIG_IPQ_ELF_AUTH
image_info img_info;
#endif
if (argc == 2 && strncmp(argv[1], "debug", 5) == 0) {
debug = 1;
} else if (argc == 3 && strncmp(argv[1], "mem", 3) == 0) {
boot_src = QCA_BOOT_FROM_MEM;
} else if (argc == 4 && strncmp(argv[1], "usb", 3) == 0) {
boot_src = QCA_BOOT_FROM_USB;
}
#ifndef CONFIG_ANDROID_AB_BOOT
if ((ret = set_fs_bootargs(&ipq_fs_on_nand)))
return ret;
#endif
switch (boot_src) {
case QCA_BOOT_FROM_FLASH:
/* check the smem info to see which flash used for booting */
if (sfi->flash_type == SMEM_BOOT_SPI_FLASH) {
if (debug) {
printf("Using nand device %d\n", CONFIG_SPI_FLASH_INFO_IDX);
}
} else if (((sfi->flash_type == SMEM_BOOT_NAND_FLASH) ||
(sfi->flash_type == SMEM_BOOT_QSPI_NAND_FLASH))) {
if (debug) {
printf("Using nand device 0\n");
}
} else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH) {
if (debug) {
printf("Using MMC device\n");
}
} else {
printf("Unsupported BOOT flash type\n");
return -1;
}
if (debug) {
run_command("printenv bootargs", 0);
printf("Booting from flash\n");
}
request = CONFIG_SYS_LOAD_ADDR;
break;
case QCA_BOOT_FROM_USB:
printf("Boot from USB device\n");
request = CONFIG_SYS_LOAD_ADDR;
break;
case QCA_BOOT_FROM_MEM:
printf("Boot from memory\n");
request = simple_strtoul(argv[2], NULL, 16);
break;
default:
printf("Unsupported BOOT source\n");
return -1;
}
kernel_img_info.kernel_load_addr = request;
switch (boot_src) {
case QCA_BOOT_FROM_FLASH:
if (ipq_fs_on_nand) {
#ifdef CONFIG_CMD_UBI
/*
* The kernel will be available inside a UBI volume
*/
snprintf(runcmd, sizeof(runcmd),
"nand device %d && "
"setenv mtdids nand%d=nand%d && "
"setenv mtdparts mtdparts=nand%d:0x%llx@0x%llx(fs),${msmparts} && "
"ubi part fs && ", is_spi_nand_available(),
is_spi_nand_available(),
is_spi_nand_available(),
is_spi_nand_available(),
sfi->rootfs.size, sfi->rootfs.offset);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
#ifdef CONFIG_IPQ_ELF_AUTH
snprintf(runcmd, sizeof(runcmd),
"ubi read 0x%x kernel 0x%x && ",
request, ELF_HDR_PLUS_PHDR_SIZE);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
if (parse_elf_image_phdr(&img_info, request))
return CMD_RET_FAILURE;
request = img_info.img_load_addr - img_info.img_offset;
#endif
snprintf(runcmd, sizeof(runcmd),
"ubi read 0x%x kernel && ", request);
if (debug)
printf("%s", runcmd);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
kernel_img_info.kernel_load_size =
(unsigned int)ubi_get_volume_size("kernel");
#endif
#ifdef CONFIG_QCA_MMC
} else if (sfi->flash_type == SMEM_BOOT_MMC_FLASH ||
((sfi->flash_type == SMEM_BOOT_SPI_FLASH) &&
(sfi->rootfs.offset == 0xBAD0FF5E))) {
blk_dev = mmc_get_dev(host->dev_num);
#ifdef CONFIG_ANDROID_AB_BOOT
if (smem_bootconfig_info() != 0)
return -1;
snprintf(boot_part_name, sizeof(boot_part_name),
"boot%s", android_get_active_slot());
ret = get_partition_info_efi_by_name(blk_dev,
boot_part_name, &disk_info);
if (load_bootimg(&disk_info, true) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
#else
if (smem_bootconfig_info() == 0) {
get_rootfs_active_partition();
ret = get_partition_info_efi_by_name(blk_dev,
kernelpart, &disk_info);
} else {
ret = get_partition_info_efi_by_name(blk_dev,
"0:HLOS", &disk_info);
if (ret)
ret = get_partition_info_efi_by_name(blk_dev,
"boot_a", &disk_info);
}
if (ret == 0) {
#ifdef CONFIG_IPQ_ELF_AUTH
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%X 0x%X",
CONFIG_SYS_LOAD_ADDR,
(uint)disk_info.start, ELF_HDR_PLUS_PHDR_SIZE);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
if (parse_elf_image_phdr(&img_info, request))
return CMD_RET_FAILURE;
request = img_info.img_load_addr - img_info.img_offset;
#endif
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%X 0x%X",
request,
(uint)disk_info.start, (uint)disk_info.size);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
kernel_img_info.kernel_load_size = disk_info.size * disk_info.blksz;
}
#endif // CONFIG_ANDROID_AB_BOOT
#endif
} else {
/*
* Kernel is in a separate partition
*/
snprintf(runcmd, sizeof(runcmd), "sf probe &&");
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
#ifdef CONFIG_IPQ_ELF_AUTH
snprintf(runcmd, sizeof(runcmd),
"sf read 0x%x 0x%x 0x%x && ",
CONFIG_SYS_LOAD_ADDR,
(uint)sfi->hlos.offset, ELF_HDR_PLUS_PHDR_SIZE);
if (debug)
printf("%s", runcmd);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
if (parse_elf_image_phdr(&img_info, request))
return CMD_RET_FAILURE;
request = img_info.img_load_addr - img_info.img_offset;
#endif
snprintf(runcmd, sizeof(runcmd),
"sf read 0x%x 0x%x 0x%x && ",
request,
(uint)sfi->hlos.offset, (uint)sfi->hlos.size);
if (debug)
printf("%s", runcmd);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS)
return CMD_RET_FAILURE;
kernel_img_info.kernel_load_size = sfi->hlos.size;
}
break;
case QCA_BOOT_FROM_USB:
snprintf(runcmd, sizeof(runcmd), "fatsize usb %s %s", argv[2], argv[3]);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
kernel_img_info.kernel_load_size = MIN(getenv_hex("filesize", 0), CONFIG_BOOGIMG_SIZE_MAX);
if (validate_bootimg_memory(kernel_img_info.kernel_load_addr, kernel_img_info.kernel_load_size)) {
snprintf(runcmd, sizeof(runcmd), "fatload usb %s %x %s %x", argv[2], kernel_img_info.kernel_load_addr, argv[3], kernel_img_info.kernel_load_size);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
} else {
printf("file size too large\n");
return CMD_RET_FAILURE;
}
break;
}
setenv("mtdids", mtdids);
#ifndef CONFIG_IPQ_ELF_AUTH
request += sizeof(mbn_header_t);
#else
kernel_img_info.kernel_load_addr = request;
request = img_info.img_load_addr;
#endif
/* This sys call will switch the CE1 channel to register usage */
ret = switch_ce_channel_buf(0);
if (ret)
return CMD_RET_FAILURE;
ret = qca_scm_auth_kernel(&kernel_img_info,
sizeof(kernel_img_info));
if (ret) {
printf("Kernel image authentication failed \n");
BUG();
}
#ifdef CONFIG_IPQ_ROOTFS_AUTH
#ifdef CONFIG_IPQ_ELF_AUTH
if (authenticate_rootfs_elf(img_info.img_load_addr +
img_info.img_size) != CMD_RET_SUCCESS) {
printf("Rootfs elf image authentication failed\n");
BUG();
}
#else
/* Rootfs's header and certificate at end of kernel image, copy from
* there and pack with rootfs image and authenticate rootfs */
if (authenticate_rootfs(CONFIG_SYS_LOAD_ADDR) != CMD_RET_SUCCESS) {
printf("Rootfs image authentication failed\n");
BUG();
}
#endif
#endif
/*
* This sys call will switch the CE1 channel to ADM usage
* so that HLOS can use it.
*/
ret = switch_ce_channel_buf(1);
if (ret)
return CMD_RET_FAILURE;
dcache_enable();
ret = genimg_get_format((void *)request);
if (ret == IMAGE_FORMAT_FIT) {
ret = config_select(request, runcmd, sizeof(runcmd));
} else if ((ret == IMAGE_FORMAT_LEGACY)
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|| (ret == IMAGE_FORMAT_ANDROID)
#endif
) {
snprintf(runcmd, sizeof(runcmd),
"bootm 0x%x\n", request);
} else {
printf("Image Format not supported \n");
ret = -1;
}
if (debug)
printf("%s", runcmd);
if (ret < 0 || run_command(runcmd, 0) != CMD_RET_SUCCESS) {
#ifdef CONFIG_QCA_MMC
mmc_initialize(gd->bd);
#endif
#ifdef CONFIG_USB_XHCI_IPQ
ipq_board_usb_init();
#endif
dcache_disable();
return CMD_RET_FAILURE;
}
#ifndef CONFIG_QCA_APPSBL_DLOAD
reset_crashdump();
#endif
return CMD_RET_SUCCESS;
}
static int do_boot_unsignedimg(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
int boot_src = QCA_BOOT_FROM_FLASH; /* default boot from flash */
unsigned int request;
char runcmd[256] = {0};
#ifdef CONFIG_QCA_MMC
block_dev_desc_t *blk_dev;
disk_partition_t disk_info;
#ifdef CONFIG_ANDROID_AB_BOOT
char boot_part_name[20]={0};
bool image_is_unsigned;
#endif // CONFIG_ANDROID_AB_BOOT
#endif // CONFIG_QCA_MMC
if (argc == 2 && strncmp(argv[1], "debug", 5) == 0) {
debug = 1;
} else if (argc == 3 && strncmp(argv[1], "mem", 3) == 0) {
boot_src = QCA_BOOT_FROM_MEM;
} else if (argc == 4 && strncmp(argv[1], "usb", 3) == 0) {
boot_src = QCA_BOOT_FROM_USB;
}
#ifndef CONFIG_ANDROID_AB_BOOT
if ((ret = set_fs_bootargs(&ipq_fs_on_nand)))
return ret;
#endif // !CONFIG_ANDROID_AB_BOOT
request = CONFIG_SYS_LOAD_ADDR;
switch (boot_src) {
case QCA_BOOT_FROM_FLASH:
if (debug) {
run_command("printenv bootargs", 0);
printf("Booting from flash\n");
}
if (((sfi->flash_type == SMEM_BOOT_NAND_FLASH) ||
(sfi->flash_type == SMEM_BOOT_QSPI_NAND_FLASH))) {
if (debug) {
printf("Using nand device 0\n");
}
/*
* The kernel is in seperate partition
*/
if (sfi->rootfs.offset == 0xBAD0FF5E) {
printf(" bad offset of hlos");
return -1;
}
snprintf(runcmd, sizeof(runcmd),
"setenv mtdids nand0=nand0 && "
"setenv mtdparts mtdparts=nand0:0x%llx@0x%llx(fs),${msmparts} && "
"ubi part fs && "
"ubi read 0x%x kernel && ",
sfi->rootfs.size, sfi->rootfs.offset,
CONFIG_SYS_LOAD_ADDR);
} else if (((sfi->flash_type == SMEM_BOOT_SPI_FLASH) &&
(sfi->rootfs.offset != 0xBAD0FF5E)) ||
ipq_fs_on_nand) {
if (get_which_flash_param("rootfs") || ipq_fs_on_nand) {
snprintf(runcmd, sizeof(runcmd),
"nand device %d && "
"setenv mtdids nand%d=nand%d && "
"setenv mtdparts mtdparts=nand%d:0x%llx@0x%llx(fs),${msmparts} && "
"ubi part fs && "
"ubi read 0x%x kernel && ",
is_spi_nand_available(),
is_spi_nand_available(),
is_spi_nand_available(),
is_spi_nand_available(),
sfi->rootfs.size, sfi->rootfs.offset,
CONFIG_SYS_LOAD_ADDR);
} else {
/*
* Kernel is in a separate partition
*/
snprintf(runcmd, sizeof(runcmd),
"sf probe &&"
"sf read 0x%x 0x%x 0x%x && ",
CONFIG_SYS_LOAD_ADDR, (uint)sfi->hlos.offset, (uint)sfi->hlos.size);
}
#ifdef CONFIG_QCA_MMC
} else if ((sfi->flash_type == SMEM_BOOT_MMC_FLASH) ||
((sfi->flash_type == SMEM_BOOT_SPI_FLASH) &&
(sfi->rootfs.offset == 0xBAD0FF5E))) {
if (debug) {
printf("Using MMC device\n");
}
blk_dev = mmc_get_dev(host->dev_num);
#ifdef CONFIG_ANDROID_AB_BOOT
if (smem_bootconfig_info() != 0)
return -1;
snprintf(boot_part_name, sizeof(boot_part_name),
"boot%s", android_get_active_slot());
ret = get_partition_info_efi_by_name(blk_dev,
boot_part_name, &disk_info);
image_is_unsigned = bootimage_startswith_android_header(&disk_info);
if (load_bootimg(&disk_info, !image_is_unsigned) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
#else
if (smem_bootconfig_info() == 0) {
get_rootfs_active_partition();
ret = get_partition_info_efi_by_name(blk_dev,
kernelpart, &disk_info);
} else {
ret = get_partition_info_efi_by_name(blk_dev,
"0:HLOS", &disk_info);
if (ret)
ret = get_partition_info_efi_by_name(blk_dev,
"boot_a", &disk_info);
}
if (ret == 0) {
snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%x 0x%x",
CONFIG_SYS_LOAD_ADDR,
(uint)disk_info.start, (uint)disk_info.size);
}
#endif // CONFIG_ANDROID_AB_BOOT
#endif /* CONFIG_QCA_MMC */
} else {
printf("Unsupported BOOT flash type\n");
return -1;
}
break;
case QCA_BOOT_FROM_USB:
printf("Boot from USB device\n");
snprintf(runcmd, sizeof(runcmd), "fatsize usb %s %s", argv[2], argv[3]);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
kernel_img_info.kernel_load_size = MIN(getenv_hex("filesize", 0), CONFIG_BOOGIMG_SIZE_MAX);
kernel_img_info.kernel_load_addr = CONFIG_SYS_LOAD_ADDR;
if (validate_bootimg_memory(kernel_img_info.kernel_load_addr, kernel_img_info.kernel_load_size)) {
snprintf(runcmd, sizeof(runcmd), "fatload usb %s %x %s %x", argv[2], CONFIG_SYS_LOAD_ADDR, argv[3], kernel_img_info.kernel_load_size);
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
} else {
printf("file size too large\n");
return CMD_RET_FAILURE;
}
break;
case QCA_BOOT_FROM_MEM:
request = simple_strtoul(argv[2], NULL, 16);
printf("Boot from memory\n");
break;
}
#ifndef CONFIG_ANDROID_AB_BOOT
if (run_command(runcmd, 0) != CMD_RET_SUCCESS) {
#ifdef CONFIG_QCA_MMC
mmc_initialize(gd->bd);
#endif
return CMD_RET_FAILURE;
}
#endif
dcache_enable();
setenv("mtdids", mtdids);
ret = genimg_get_format((void *)request);
if (ret == IMAGE_FORMAT_FIT) {
ret = config_select(request,
runcmd, sizeof(runcmd));
} else if ((ret == IMAGE_FORMAT_LEGACY)
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|| (ret == IMAGE_FORMAT_ANDROID)
#endif
) {
snprintf(runcmd, sizeof(runcmd),
"bootm 0x%x\n", request);
} else {
ret = genimg_get_format((void *)request +
sizeof(mbn_header_t));
if (ret == IMAGE_FORMAT_FIT) {
ret = config_select((request
+ sizeof(mbn_header_t)),
runcmd, sizeof(runcmd));
} else if ((ret == IMAGE_FORMAT_LEGACY)
#ifdef CONFIG_ANDROID_BOOT_IMAGE
|| (ret == IMAGE_FORMAT_ANDROID)
#endif
) {
snprintf(runcmd, sizeof(runcmd),
"bootm 0x%x\n", (request +
sizeof(mbn_header_t)));
} else {
dcache_disable();
return CMD_RET_FAILURE;
}
}
if (ret < 0 || run_command(runcmd, 0) != CMD_RET_SUCCESS) {
#ifdef CONFIG_USB_XHCI_IPQ
ipq_board_usb_init();
#endif
dcache_disable();
return CMD_RET_FAILURE;
}
#ifndef CONFIG_QCA_APPSBL_DLOAD
reset_crashdump();
#endif
return CMD_RET_SUCCESS;
}
int do_bootipq(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
char buf = 0;
/*
* set fdt_high parameter so that u-boot will not load
* dtb above CONFIG_IPQ40XX_FDT_HIGH region.
*/
if (run_command("setenv fdt_high " MK_STR(CONFIG_IPQ_FDT_HIGH) "\n", 0)
!= CMD_RET_SUCCESS) {
return CMD_RET_FAILURE;
}
ret = qca_scm_call(SCM_SVC_FUSE, QFPROM_IS_AUTHENTICATE_CMD, &buf, sizeof(char));
aquantia_phy_reset_init_done();
/*
|| if atf is enable in env ,do_boot_signedimg is skip.
|| Note: This features currently support in ipq50XX.
*/
if (ret == 0 && buf == 1 && !getenv("atf")) {
printf("%s: boot signed image\n", __func__);
ret = do_boot_signedimg(cmdtp, flag, argc, argv);
} else if (ret == 0 || ret == -EOPNOTSUPP) {
printf("%s: boot unsigned image\n", __func__);
ret = do_boot_unsignedimg(cmdtp, flag, argc, argv);
}
if (ret == CMD_RET_FAILURE) {
#ifdef CONFIG_IPQ_ETH_INIT_DEFER
puts("\nNet: ");
eth_initialize();
#endif
}
return ret;
}
U_BOOT_CMD(bootipq, 4, 0, do_bootipq,
"bootipq from flash device",
"bootipq [debug] - Load image(s) and boots the kernel\n");