blob: 9ada780636200917d989dd45c0d53d1b6e479d11 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 NXP
*/
#include <asm/mach-imx/sys_proto.h>
#include <fb_fsl.h>
#include <fastboot.h>
#include <mmc.h>
#include <android_image.h>
#include <asm/bootm.h>
#include <nand.h>
#include <part.h>
#include <sparse_format.h>
#include <image-sparse.h>
#include <image.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/arch/sys_proto.h>
#include <asm/setup.h>
#include <environment.h>
#ifdef CONFIG_SATA
#include <sata.h>
#endif
#if defined(CONFIG_FASTBOOT_LOCK)
#include "fastboot_lock_unlock.h"
#endif
#ifdef CONFIG_IMX_TRUSTY_OS
#include "u-boot/sha256.h"
#include <trusty/libtipc.h>
#endif
#ifndef TRUSTY_OS_MMC_BLKS
#define TRUSTY_OS_MMC_BLKS 0x7FF
#endif
#define MEK_8QM_EMMC 0
enum {
PTN_GPT_INDEX = 0,
PTN_TEE_INDEX,
#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT
PTN_M4_OS_INDEX,
#endif
PTN_ALL_INDEX,
PTN_BOOTLOADER_INDEX,
};
struct fastboot_ptentry g_ptable[MAX_PTN];
unsigned int g_pcount;
static ulong bootloader_mmc_offset(void)
{
if (is_imx8m() || (is_imx8() && is_soc_rev(CHIP_REV_A)))
return 0x8400;
else if (is_imx8qm()) {
if (MEK_8QM_EMMC == fastboot_devinfo.dev_id)
/* target device is eMMC boot0 partition, bootloader offset is 0x0 */
return 0x0;
else
/* target device is SD card, bootloader offset is 0x8000 */
return 0x8000;
}
else if (is_imx8())
return 0x8000;
else
return 0x400;
}
bool bootloader_gpt_overlay(void)
{
return (g_ptable[PTN_GPT_INDEX].partition_id == g_ptable[PTN_BOOTLOADER_INDEX].partition_id &&
bootloader_mmc_offset() < ANDROID_GPT_END);
}
/**
@mmc_dos_partition_index: the partition index in mbr.
@mmc_partition_index: the boot partition or user partition index,
not related to the partition table.
*/
static int _fastboot_parts_add_ptable_entry(int ptable_index,
int mmc_dos_partition_index,
int mmc_partition_index,
const char *name,
const char *fstype,
struct blk_desc *dev_desc,
struct fastboot_ptentry *ptable)
{
disk_partition_t info;
if (part_get_info(dev_desc,
mmc_dos_partition_index, &info)) {
debug("Bad partition index:%d for partition:%s\n",
mmc_dos_partition_index, name);
return -1;
}
ptable[ptable_index].start = info.start;
ptable[ptable_index].length = info.size;
ptable[ptable_index].partition_id = mmc_partition_index;
ptable[ptable_index].partition_index = mmc_dos_partition_index;
strncpy(ptable[ptable_index].name, (const char *)info.name,
sizeof(ptable[ptable_index].name) - 1);
#ifdef CONFIG_PARTITION_UUIDS
strcpy(ptable[ptable_index].uuid, (const char *)info.uuid);
#endif
#ifdef CONFIG_ANDROID_AB_SUPPORT
if (!strcmp((const char *)info.name, FASTBOOT_PARTITION_SYSTEM_A) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_SYSTEM_B) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_OEM_A) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_VENDOR_A) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_OEM_B) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_VENDOR_B) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_DATA))
#else
if (!strcmp((const char *)info.name, FASTBOOT_PARTITION_SYSTEM) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_DATA) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_DEVICE) ||
!strcmp((const char *)info.name, FASTBOOT_PARTITION_CACHE))
#endif
strcpy(ptable[ptable_index].fstype, "ext4");
else
strcpy(ptable[ptable_index].fstype, "raw");
return 0;
}
static int _fastboot_parts_load_from_ptable(void)
{
int i;
/* mmc boot partition: -1 means no partition, 0 user part., 1 boot part.
* default is no partition, for emmc default user part, except emmc*/
int boot_partition = FASTBOOT_MMC_NONE_PARTITION_ID;
int user_partition = FASTBOOT_MMC_NONE_PARTITION_ID;
struct mmc *mmc;
struct blk_desc *dev_desc;
struct fastboot_ptentry ptable[MAX_PTN];
/* sata case in env */
if (fastboot_devinfo.type == DEV_SATA) {
#ifdef CONFIG_SATA
int sata_device_no = fastboot_devinfo.dev_id;
puts("flash target is SATA\n");
if (sata_initialize())
return -1;
if (sata_device_no >= CONFIG_SYS_SATA_MAX_DEVICE) {
printf("Unknown SATA(%d) device for fastboot\n",
sata_device_no);
return -1;
}
dev_desc = sata_get_dev(sata_device_no);
#else /*! CONFIG_SATA*/
puts("SATA isn't buildin\n");
return -1;
#endif /*! CONFIG_SATA*/
} else if (fastboot_devinfo.type == DEV_MMC) {
int mmc_no = fastboot_devinfo.dev_id;
printf("flash target is MMC:%d\n", mmc_no);
mmc = find_mmc_device(mmc_no);
if (mmc == NULL) {
printf("invalid mmc device %d\n", mmc_no);
return -1;
}
/* Force to init mmc */
mmc->has_init = 0;
if (mmc_init(mmc))
printf("MMC card init failed!\n");
dev_desc = blk_get_dev("mmc", mmc_no);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
printf("** Block device MMC %d not supported\n",
mmc_no);
return -1;
}
/* multiple boot paritions for eMMC 4.3 later */
if (mmc->part_config != MMCPART_NOAVAILABLE) {
boot_partition = FASTBOOT_MMC_BOOT_PARTITION_ID;
user_partition = FASTBOOT_MMC_USER_PARTITION_ID;
}
} else {
printf("Can't setup partition table on this device %d\n",
fastboot_devinfo.type);
return -1;
}
memset((char *)ptable, 0,
sizeof(struct fastboot_ptentry) * (MAX_PTN));
/* GPT */
strcpy(ptable[PTN_GPT_INDEX].name, FASTBOOT_PARTITION_GPT);
ptable[PTN_GPT_INDEX].start = ANDROID_GPT_OFFSET / dev_desc->blksz;
ptable[PTN_GPT_INDEX].length = ANDROID_GPT_SIZE / dev_desc->blksz;
ptable[PTN_GPT_INDEX].partition_id = user_partition;
ptable[PTN_GPT_INDEX].flags = FASTBOOT_PTENTRY_FLAGS_UNERASEABLE;
strcpy(ptable[PTN_GPT_INDEX].fstype, "raw");
#ifndef CONFIG_ARM64
/* Trusty OS */
strcpy(ptable[PTN_TEE_INDEX].name, FASTBOOT_PARTITION_TEE);
ptable[PTN_TEE_INDEX].start = 0;
ptable[PTN_TEE_INDEX].length = TRUSTY_OS_MMC_BLKS;
ptable[PTN_TEE_INDEX].partition_id = TEE_HWPARTITION_ID;
strcpy(ptable[PTN_TEE_INDEX].fstype, "raw");
#endif
/* Add m4_os partition if we support mcu firmware image flash */
#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT
strcpy(ptable[PTN_M4_OS_INDEX].name, FASTBOOT_MCU_FIRMWARE_PARTITION);
ptable[PTN_M4_OS_INDEX].start = ANDROID_MCU_FIRMWARE_START / dev_desc->blksz;
ptable[PTN_M4_OS_INDEX].length = ANDROID_MCU_FIRMWARE_SIZE / dev_desc->blksz;
ptable[PTN_M4_OS_INDEX].flags = FASTBOOT_PTENTRY_FLAGS_UNERASEABLE;
ptable[PTN_M4_OS_INDEX].partition_id = user_partition;
strcpy(ptable[PTN_M4_OS_INDEX].fstype, "raw");
#endif
strcpy(ptable[PTN_ALL_INDEX].name, FASTBOOT_PARTITION_ALL);
ptable[PTN_ALL_INDEX].start = 0;
ptable[PTN_ALL_INDEX].length = dev_desc->lba;
ptable[PTN_ALL_INDEX].partition_id = user_partition;
strcpy(ptable[PTN_ALL_INDEX].fstype, "device");
/* Bootloader */
strcpy(ptable[PTN_BOOTLOADER_INDEX].name, FASTBOOT_PARTITION_BOOTLOADER);
ptable[PTN_BOOTLOADER_INDEX].start =
bootloader_mmc_offset() / dev_desc->blksz;
ptable[PTN_BOOTLOADER_INDEX].length =
ANDROID_BOOTLOADER_SIZE / dev_desc->blksz;
ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition;
ptable[PTN_BOOTLOADER_INDEX].flags = FASTBOOT_PTENTRY_FLAGS_UNERASEABLE;
strcpy(ptable[PTN_BOOTLOADER_INDEX].fstype, "raw");
int tbl_idx;
int part_idx = 1;
int ret;
for (tbl_idx = PTN_BOOTLOADER_INDEX + 1; tbl_idx < MAX_PTN; tbl_idx++) {
ret = _fastboot_parts_add_ptable_entry(tbl_idx,
part_idx++,
user_partition,
NULL,
NULL,
dev_desc, ptable);
if (ret)
break;
}
for (i = 0; i < tbl_idx; i++)
fastboot_flash_add_ptn(&ptable[i]);
return 0;
}
void fastboot_load_partitions(void)
{
g_pcount = 0;
_fastboot_parts_load_from_ptable();
}
/*
* Android style flash utilties */
void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn)
{
if (g_pcount < MAX_PTN) {
memcpy(g_ptable + g_pcount, ptn, sizeof(struct fastboot_ptentry));
g_pcount++;
}
}
void fastboot_flash_dump_ptn(void)
{
unsigned int n;
for (n = 0; n < g_pcount; n++) {
struct fastboot_ptentry *ptn = g_ptable + n;
printf("idx %d, ptn %d name='%s' start=%d len=%d\n",
n, ptn->partition_index, ptn->name, ptn->start, ptn->length);
}
}
struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name)
{
unsigned int n;
for (n = 0; n < g_pcount; n++) {
/* Make sure a substring is not accepted */
if (strlen(name) == strlen(g_ptable[n].name)) {
if (0 == strcmp(g_ptable[n].name, name))
return g_ptable + n;
}
}
return 0;
}
int fastboot_flash_find_index(const char *name)
{
struct fastboot_ptentry *ptentry = fastboot_flash_find_ptn(name);
if (ptentry == NULL) {
printf("cannot get the partion info for %s\n",name);
fastboot_flash_dump_ptn();
return -1;
}
return ptentry->partition_index;
}
struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned int n)
{
if (n < g_pcount)
return g_ptable + n;
else
return 0;
}
unsigned int fastboot_flash_get_ptn_count(void)
{
return g_pcount;
}
bool fastboot_parts_is_raw(struct fastboot_ptentry *ptn)
{
if (ptn) {
if (!strncmp(ptn->name, FASTBOOT_PARTITION_BOOTLOADER,
strlen(FASTBOOT_PARTITION_BOOTLOADER)))
return true;
#ifdef CONFIG_ANDROID_AB_SUPPORT
else if (!strncmp(ptn->name, FASTBOOT_PARTITION_GPT,
strlen(FASTBOOT_PARTITION_GPT)) ||
!strncmp(ptn->name, FASTBOOT_PARTITION_BOOT_A,
strlen(FASTBOOT_PARTITION_BOOT_A)) ||
!strncmp(ptn->name, FASTBOOT_PARTITION_BOOT_B,
strlen(FASTBOOT_PARTITION_BOOT_B)))
return true;
#else
else if (!strncmp(ptn->name, FASTBOOT_PARTITION_BOOT,
strlen(FASTBOOT_PARTITION_BOOT)))
return true;
#endif
#if defined(CONFIG_FASTBOOT_LOCK)
else if (!strncmp(ptn->name, FASTBOOT_PARTITION_FBMISC,
strlen(FASTBOOT_PARTITION_FBMISC)))
return true;
#endif
else if (!strncmp(ptn->name, FASTBOOT_PARTITION_MISC,
strlen(FASTBOOT_PARTITION_MISC)))
return true;
}
return false;
}
static bool is_exist(char (*partition_base_name)[16], char *buffer, int count)
{
int n;
for (n = 0; n < count; n++) {
if (!strcmp(partition_base_name[n],buffer))
return true;
}
return false;
}
/*get partition base name from gpt without "_a/_b"*/
int fastboot_parts_get_name(char (*partition_base_name)[16])
{
int n = 0;
int count = 0;
char *ptr1, *ptr2;
char buffer[20];
for (n = 0; n < g_pcount; n++) {
strcpy(buffer,g_ptable[n].name);
ptr1 = strstr(buffer, "_a");
ptr2 = strstr(buffer, "_b");
if (ptr1 != NULL) {
*ptr1 = '\0';
if (!is_exist(partition_base_name,buffer,count)) {
strcpy(partition_base_name[count++],buffer);
}
} else if (ptr2 != NULL) {
*ptr2 = '\0';
if (!is_exist(partition_base_name,buffer,count)) {
strcpy(partition_base_name[count++],buffer);
}
} else {
strcpy(partition_base_name[count++],buffer);
}
}
return count;
}
bool fastboot_parts_is_slot(void)
{
char slot_suffix[2][5] = {"_a","_b"};
int n;
for (n = 0; n < g_pcount; n++) {
if (strstr(g_ptable[n].name, slot_suffix[0]) ||
strstr(g_ptable[n].name, slot_suffix[1]))
return true;
}
return false;
}