diff options
author | Ye Li <ye.li@nxp.com> | 2018-06-05 01:34:41 -0700 |
---|---|---|
committer | Ye Li <ye.li@nxp.com> | 2018-06-13 03:06:25 -0700 |
commit | 2c840c82b3558267650b98735790ac7151644ae1 (patch) | |
tree | b62bd46f634e8a76ec122085113a92a967db6288 | |
parent | 4ec81a0b075d8d853ac696172660a7771064405d (diff) |
MLK-18591-3 android: Add FSL android fastboot support
Porting the FSL android fastboot features from imx u-boot v2017.03 to
support all SoCs: imx6/imx7/imx7ulp/imx8/imx8m
Signed-off-by: Ye Li <ye.li@nxp.com>
34 files changed, 4446 insertions, 108 deletions
diff --git a/arch/arm/include/asm/arch-imx8/sys_proto.h b/arch/arm/include/asm/arch-imx8/sys_proto.h index 816040c5e92..26078fcfc14 100644 --- a/arch/arm/include/asm/arch-imx8/sys_proto.h +++ b/arch/arm/include/asm/arch-imx8/sys_proto.h @@ -19,3 +19,4 @@ struct pass_over_info_t { int print_bootinfo(void); int init_otg_power(void); void power_off_pd_devices(const char* permanent_on_devices[], int size); +enum boot_device get_boot_device(void); diff --git a/arch/arm/include/asm/arch-mx6/sys_proto.h b/arch/arm/include/asm/arch-mx6/sys_proto.h index 75159a140c9..ebb52f8388a 100644 --- a/arch/arm/include/asm/arch-mx6/sys_proto.h +++ b/arch/arm/include/asm/arch-mx6/sys_proto.h @@ -35,6 +35,7 @@ static inline void iomuxc_set_rgmii_io_voltage(int io_vol) } void set_wdog_reset(struct wdog_regs *wdog); +enum boot_device get_boot_device(void); #ifdef CONFIG_LDO_BYPASS_CHECK int check_ldo_bypass(void); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 34707001370..16bcdea0892 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -100,3 +100,9 @@ config NXP_BOARD_REVISION NXP boards based on i.MX6/7 contain the board revision information stored in the fuses. Select this option if you want to be able to retrieve the board revision information. + +config FLASH_MCUFIRMWARE_SUPPORT + bool "Enable mcu firmware flash support" + depends on ARCH_MX7ULP || ARCH_IMX8M + help + This enables the mcu firmware flash support for some SOCs. diff --git a/arch/arm/mach-imx/imx8/cpu.c b/arch/arm/mach-imx/imx8/cpu.c index 3630d9f006e..fdaa30c3ca1 100644 --- a/arch/arm/mach-imx/imx8/cpu.c +++ b/arch/arm/mach-imx/imx8/cpu.c @@ -26,6 +26,7 @@ #include <fdtdec.h> #include <asm/arch/cpu.h> #include <generated/version_autogenerated.h> +#include <asm/setup.h> DECLARE_GLOBAL_DATA_PTR; @@ -1392,4 +1393,4 @@ void disconnect_from_pc(void) printf("conn_usb0 finding failed!\n"); return; } -}
\ No newline at end of file +} diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c index c31f75b1e92..d507584faf9 100644 --- a/arch/arm/mach-imx/imx8m/soc.c +++ b/arch/arm/mach-imx/imx8m/soc.c @@ -20,6 +20,7 @@ #include <fsl_wdog.h> #include <imx_sip.h> #include <generated/version_autogenerated.h> +#include <asm/setup.h> DECLARE_GLOBAL_DATA_PTR; @@ -196,6 +197,18 @@ bool is_usb_boot(void) { return get_boot_device() == USB_BOOT; } +#ifdef CONFIG_SERIAL_TAG +void get_board_serial(struct tag_serialnr *serialnr) +{ + struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; + struct fuse_bank *bank = &ocotp->bank[0]; + struct fuse_bank0_regs *fuse = + (struct fuse_bank0_regs *)bank->fuse_regs; + + serialnr->low = fuse->uid_low; + serialnr->high = fuse->uid_high; +} +#endif #ifdef CONFIG_OF_SYSTEM_SETUP static int ft_add_optee_node(void *fdt, bd_t *bd) diff --git a/arch/arm/mach-imx/mx6/soc.c b/arch/arm/mach-imx/mx6/soc.c index 72cde0eeb79..4dd14d7a200 100644 --- a/arch/arm/mach-imx/mx6/soc.c +++ b/arch/arm/mach-imx/mx6/soc.c @@ -23,6 +23,7 @@ #include <dm.h> #include <imx_thermal.h> #include <mmc.h> +#include <asm/setup.h> enum ldo_reg { LDO_ARM, @@ -805,6 +806,10 @@ void s_init(void) u32 mask528; u32 reg, periph1, periph2; +#if defined(CONFIG_ANDROID_SUPPORT) + /* Enable RTC */ + writel(0x21, 0x020cc038); +#endif if (is_mx6sx() || is_mx6ul() || is_mx6ull() || is_mx6sll()) return; diff --git a/arch/arm/mach-imx/mx7/soc.c b/arch/arm/mach-imx/mx7/soc.c index 96eb782ed92..f9deb3c2729 100644 --- a/arch/arm/mach-imx/mx7/soc.c +++ b/arch/arm/mach-imx/mx7/soc.c @@ -20,6 +20,7 @@ #include <imx_thermal.h> #include <fsl_sec.h> #include <fsl_wdog.h> +#include <asm/setup.h> #if defined(CONFIG_IMX_THERMAL) static const struct imx_thermal_plat imx7_thermal_plat = { @@ -293,6 +294,10 @@ void s_init(void) /* clock configuration. */ clock_init(); +#if defined(CONFIG_ANDROID_SUPPORT) + /* Enable RTC */ + writel(0x21, 0x30370038); +#endif return; } diff --git a/arch/arm/mach-imx/mx7ulp/soc.c b/arch/arm/mach-imx/mx7ulp/soc.c index 1cf783aa358..d04f91de249 100644 --- a/arch/arm/mach-imx/mx7ulp/soc.c +++ b/arch/arm/mach-imx/mx7ulp/soc.c @@ -12,6 +12,7 @@ #include <asm/mach-imx/hab.h> #include <asm/mach-imx/boot_mode.h> #include <fdt_support.h> +#include <asm/setup.h> static char *get_reset_cause(char *); @@ -155,6 +156,11 @@ void s_init(void) if (soc_rev() < CHIP_REV_2_0) { /* enable dumb pmic */ writel((readl(SNVS_LP_LPCR) | SNVS_LPCR_DPEN), SNVS_LP_LPCR); + +#if defined(CONFIG_ANDROID_SUPPORT) + /* Enable RTC */ + writel((readl(SNVS_LP_LPCR) | SNVS_LPCR_SRTC_ENV), SNVS_LP_LPCR); +#endif } return; } @@ -370,3 +376,18 @@ enum boot_device get_boot_device(void) return boot_dev; } + +#ifdef CONFIG_FSL_FASTBOOT +#ifdef CONFIG_SERIAL_TAG +void get_board_serial(struct tag_serialnr *serialnr) +{ + + struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; + struct fuse_bank *bank = &ocotp->bank[1]; + struct fuse_bank1_regs *fuse = + (struct fuse_bank1_regs *)bank->fuse_regs; + serialnr->low = (fuse->cfg0 & 0xFFFF) + ((fuse->cfg1 & 0xFFFF) << 16); + serialnr->high = (fuse->cfg2 & 0xFFFF) + ((fuse->cfg3 & 0xFFFF) << 16); +} +#endif /*CONFIG_SERIAL_TAG*/ +#endif /*CONFIG_FSL_FASTBOOT*/ diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile index b659ed3bae1..dfe4ac6cf9b 100644 --- a/board/freescale/common/Makefile +++ b/board/freescale/common/Makefile @@ -65,6 +65,9 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze.o obj-$(CONFIG_POWER_MC34VR500) += mc34vr500.o obj-$(CONFIG_MXC_EPDC) += epdc_setup.o obj-y += mmc.o +ifdef CONFIG_FSL_FASTBOOT +obj-${CONFIG_ANDROID_RECOVERY} += recovery_keypad.o +endif obj-$(CONFIG_LS102XA_STREAM_ID) += ls102xa_stream_id.o diff --git a/board/freescale/common/recovery_keypad.c b/board/freescale/common/recovery_keypad.c new file mode 100644 index 00000000000..fb15626b030 --- /dev/null +++ b/board/freescale/common/recovery_keypad.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <malloc.h> +#include <recovery.h> +#ifdef CONFIG_MXC_KPD +#include <mxc_keyb.h> +#endif +#include <asm/mach-imx/boot_mode.h> + +#ifdef CONFIG_MXC_KPD +#define PRESSED_VOL_DOWN 0x01 +#define PRESSED_POWER 0x02 +#define RECOVERY_KEY_MASK (PRESSED_VOL_DOWN | PRESSED_POWER) + +inline int test_key(int value, struct kpp_key_info *ki) +{ + return (ki->val == value) && (ki->evt == KDepress); +} + +int is_recovery_keypad_pressing(void) +{ + struct kpp_key_info *key_info = NULL; + int state = 0, keys, i; + + int ret = 0; + + mxc_kpp_init(); + /* due to glitch suppression circuit, + wait sometime to let all keys scanned. */ + udelay(1000); + keys = mxc_kpp_getc(&key_info); + + printf("Detecting VOL_DOWN+POWER key for recovery(%d:%d) ...\n", + keys, keys ? key_info->val : 0); + if (keys > 1) { + for (i = 0; i < keys; i++) { + if (test_key(CONFIG_POWER_KEY, &key_info[i])) + state |= PRESSED_POWER; + else if (test_key(CONFIG_VOL_DOWN_KEY, &key_info[i])) + state |= PRESSED_VOL_DOWN; + } + } + if ((state & RECOVERY_KEY_MASK) == RECOVERY_KEY_MASK) + ret = 1; + if (key_info) + free(key_info); + return ret; +} +#else +/* If not using mxc keypad, currently we will detect power key on board */ +int is_recovery_keypad_pressing(void) +{ + return 0; +} +#endif diff --git a/board/freescale/common/recovery_keypad.h b/board/freescale/common/recovery_keypad.h new file mode 100644 index 00000000000..d315cea780b --- /dev/null +++ b/board/freescale/common/recovery_keypad.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RECOVERY_KEYPAD_H_ +#define __RECOVERY_KEYPAD_H_ + +int is_recovery_keypad_pressing(void); + +#endif diff --git a/cmd/fastboot.c b/cmd/fastboot.c index 8adcca592d5..be4a11f9b7d 100644 --- a/cmd/fastboot.c +++ b/cmd/fastboot.c @@ -23,7 +23,11 @@ static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_USAGE; usb_controller = argv[1]; +#ifdef CONFIG_FASTBOOT_USB_DEV + controller_index = CONFIG_FASTBOOT_USB_DEV; +#else controller_index = simple_strtoul(usb_controller, NULL, 0); +#endif ret = board_usb_init(controller_index, USB_INIT_DEVICE); if (ret) { diff --git a/cmd/fastboot/Kconfig b/cmd/fastboot/Kconfig index 0d2c2f131e6..63b65b6ab9d 100644 --- a/cmd/fastboot/Kconfig +++ b/cmd/fastboot/Kconfig @@ -26,6 +26,48 @@ config CMD_FASTBOOT See doc/README.android-fastboot for more information. +config FSL_FASTBOOT + bool "Enable FSL fastboot support" + select BCB_SUPPORT + help + This enables FSL implementation for Android fastboot. + +if FSL_FASTBOOT + +config ANDROID_RECOVERY + bool "Enable the recovery boot function" + help + This enables the Android Recovery boot function. + +config CMD_BOOTA + bool "Enable the boota command" + help + This enables the boota command for booting android images. + +config BCB_SUPPORT + bool + +choice + prompt "Android Image Storage select" + default FASTBOOT_STORAGE_MMC + +config FASTBOOT_STORAGE_MMC + bool "Using eMMC/SD for Android fastboot storage media" + +config FASTBOOT_STORAGE_NAND + bool "Using NAND flash for Android fastboot storage media" + +config FASTBOOT_STORAGE_SATA + bool "Using SATA disk for Android fastboot storage media" + +endchoice + +config FASTBOOT_SATA_NO + int "Sata device index" + depends on FASTBOOT_STORAGE_SATA + +endif #FSL_FASTBOOT + if USB_FUNCTION_FASTBOOT config FASTBOOT_BUF_ADDR diff --git a/cmd/read.c b/cmd/read.c index 82c2d9ad994..7011d2869ef 100644 --- a/cmd/read.c +++ b/cmd/read.c @@ -12,7 +12,7 @@ #include <command.h> #include <part.h> -int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_raw_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *ep; struct blk_desc *dev_desc = NULL; @@ -75,7 +75,7 @@ int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } U_BOOT_CMD( - read, 6, 0, do_read, + read, 6, 0, do_raw_read, "Load binary data from a partition", "<interface> <dev[:part]> addr blk# cnt" ); diff --git a/common/autoboot.c b/common/autoboot.c index 1b52e44939b..0d826e81dfc 100644 --- a/common/autoboot.c +++ b/common/autoboot.c @@ -311,7 +311,7 @@ const char *bootdelay_process(void) s = env_get("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; -#ifdef is_boot_from_usb +#if !defined(CONFIG_FSL_FASTBOOT) && defined(is_boot_from_usb) if (is_boot_from_usb()) { disconnect_from_pc(); printf("Boot from USB for mfgtools\n"); @@ -349,7 +349,7 @@ const char *bootdelay_process(void) #endif /* CONFIG_BOOTCOUNT_LIMIT */ s = env_get("bootcmd"); -#ifdef is_boot_from_usb +#if !defined(CONFIG_FSL_FASTBOOT) && defined(is_boot_from_usb) if (is_boot_from_usb()) { s = env_get("bootcmd_mfg"); printf("Run bootcmd_mfg: %s\n", s); diff --git a/common/board_r.c b/common/board_r.c index 84d2b251f89..6d6adc13a97 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -54,6 +54,9 @@ #include <linux/compiler.h> #include <linux/err.h> #include <efi_loader.h> +#ifdef CONFIG_FSL_FASTBOOT +#include <fsl_fastboot.h> +#endif DECLARE_GLOBAL_DATA_PTR; @@ -659,6 +662,20 @@ static int initr_avbkey(void) } #endif +#ifdef CONFIG_FSL_FASTBOOT +static int initr_fastboot_setup(void) +{ + fastboot_setup(); + return 0; +} + +static int initr_check_fastboot(void) +{ + fastboot_run_bootmode(); + return 0; +} +#endif + static int run_main_loop(void) { #ifdef CONFIG_SANDBOX @@ -831,6 +848,9 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_BOARD_LATE_INIT board_late_init, #endif +#ifdef CONFIG_FSL_FASTBOOT + initr_fastboot_setup, +#endif #if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI) INIT_FUNC_WATCHDOG_RESET initr_scsi, @@ -873,6 +893,9 @@ static init_fnc_t init_sequence_r[] = { #ifdef AVB_RPMB initr_avbkey, #endif +#ifdef CONFIG_FSL_FASTBOOT + initr_check_fastboot, +#endif run_main_loop, }; diff --git a/common/image-android.c b/common/image-android.c index 5ad3a1fa38a..07d82d54593 100644 --- a/common/image-android.c +++ b/common/image-android.c @@ -1,6 +1,9 @@ /* * Copyright (c) 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> * + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * * SPDX-License-Identifier: GPL-2.0+ */ @@ -9,6 +12,11 @@ #include <android_image.h> #include <malloc.h> #include <errno.h> +#include <asm/bootm.h> +#include <asm/mach-imx/boot_mode.h> +#include <asm/arch/sys_proto.h> +#include <fsl_fastboot.h> +#include <asm/setup.h> #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 @@ -51,6 +59,7 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr) int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, ulong *os_data, ulong *os_len) { + extern boot_metric metrics; u32 kernel_addr = android_image_get_kernel_addr(hdr); /* @@ -66,31 +75,110 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, printf("Kernel load addr 0x%08x size %u KiB\n", kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024)); - int len = 0; - if (*hdr->cmdline) { - printf("Kernel command line: %s\n", hdr->cmdline); - len += strlen(hdr->cmdline); + char newbootargs[512] = {0}; + char commandline[2048] = {0}; + char *bootargs = env_get("bootargs"); + + if (bootargs) { + if (strlen(bootargs) + 1 > sizeof(commandline)) { + printf("bootargs is too long!\n"); + return -1; + } + else + strncpy(commandline, bootargs, sizeof(commandline) - 1); + } else if (*hdr->cmdline) { + if (strlen(hdr->cmdline) + 1 > sizeof(commandline)) { + printf("cmdline in bootimg is too long!\n"); + return -1; + } + else + strncpy(commandline, hdr->cmdline, strlen(commandline) - 1); } - char *bootargs = env_get("bootargs"); - if (bootargs) - len += strlen(bootargs); +#ifdef CONFIG_SERIAL_TAG + struct tag_serialnr serialnr; + get_board_serial(&serialnr); - char *newbootargs = malloc(len + 2); - if (!newbootargs) { - puts("Error: malloc in android_image_get_kernel failed!\n"); - return -ENOMEM; + sprintf(newbootargs, + " androidboot.serialno=%08x%08x", + serialnr.high, + serialnr.low); + strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline)); +#endif + + /* append soc type into bootargs */ + char *soc_type = env_get("soc_type"); + if (soc_type) { + sprintf(newbootargs, + " androidboot.soc_type=%s", + soc_type); + strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline)); } - *newbootargs = '\0'; - if (bootargs) { - strcpy(newbootargs, bootargs); - strcat(newbootargs, " "); + int bootdev = get_boot_device(); + if (bootdev == SD1_BOOT || bootdev == SD2_BOOT || + bootdev == SD3_BOOT || bootdev == SD4_BOOT) { + sprintf(newbootargs, + " androidboot.storage_type=sd"); + } else if (bootdev == MMC1_BOOT || bootdev == MMC2_BOOT || + bootdev == MMC3_BOOT || bootdev == MMC4_BOOT) { + sprintf(newbootargs, + " androidboot.storage_type=emmc"); + } else if (bootdev == NAND_BOOT) { + sprintf(newbootargs, + " androidboot.storage_type=nand"); + } else + printf("boot device type is incorrect.\n"); + strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline)); + if (bootloader_gpt_overlay()) { + sprintf(newbootargs, " gpt"); + strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline)); } - if (*hdr->cmdline) - strcat(newbootargs, hdr->cmdline); - env_set("bootargs", newbootargs); + /* boot metric variables */ + metrics.ble_1 = get_timer(0); + sprintf(newbootargs, + " androidboot.boottime=1BLL:%d,1BLE:%d,KL:%d,KD:%d,AVB:%d,ODT:%d,SW:%d", + metrics.bll_1, metrics.ble_1, metrics.kl, metrics.kd, metrics.avb, + metrics.odt, metrics.sw); + strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline)); + +#ifdef CONFIG_AVB_SUPPORT + /* secondary cmdline added by avb */ + char *bootargs_sec = env_get("bootargs_sec"); + if (bootargs_sec) { + strncat(commandline, " ", sizeof(commandline) - strlen(commandline)); + strncat(commandline, bootargs_sec, sizeof(commandline) - strlen(commandline)); + } +#endif +#ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT + /* Normal boot: + * cmdline to bypass ramdisk in boot.img, but use the system.img + * Recovery boot: + * Use the ramdisk in boot.img + */ + char *bootargs_3rd = env_get("bootargs_3rd"); + if (bootargs_3rd) { + strncat(commandline, " ", sizeof(commandline) - strlen(commandline)); + strncat(commandline, bootargs_3rd, sizeof(commandline) - strlen(commandline)); + } +#endif + + /* Add 'append_bootargs' to hold some paramemters which need to be appended + * to bootargs */ + char *append_bootargs = env_get("append_bootargs"); + if (append_bootargs) { + if (strlen(append_bootargs) + 2 > + (sizeof(commandline) - strlen(commandline))) { + printf("The 'append_bootargs' is too long to be appended to bootargs\n"); + } else { + strncat(commandline, " ", sizeof(commandline) - strlen(commandline)); + strncat(commandline, append_bootargs, sizeof(commandline) - strlen(commandline)); + } + } + + printf("Kernel command line: %s\n", commandline); + env_set("bootargs", commandline); if (os_data) { *os_data = (ulong)hdr; @@ -202,3 +290,15 @@ void android_print_contents(const struct andr_img_hdr *hdr) printf("%scmdline: %s\n", p, hdr->cmdline); } #endif + +#define ARM64_IMAGE_MAGIC 0x644d5241 +bool image_arm64(void *images) +{ + struct header_image *ih; + + ih = (struct header_image *)images; + debug("image magic: %x\n", ih->magic); + if (ih->magic == le32_to_cpu(ARM64_IMAGE_MAGIC)) + return true; + return false; +} diff --git a/common/image-fdt.c b/common/image-fdt.c index 25103ba3b5d..5691e964f5b 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -6,6 +6,8 @@ * (C) Copyright 2000-2006 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * * SPDX-License-Identifier: GPL-2.0+ */ @@ -413,7 +415,34 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch, debug("## No Flattened Device Tree\n"); goto no_fdt; } - } else { + } +#ifdef CONFIG_ANDROID_BOOT_IMAGE + else if (genimg_get_format((void *)images->os.start) == + IMAGE_FORMAT_ANDROID) { + ulong fdt_data, fdt_len; + android_image_get_second((void *)images->os.start, + &fdt_data, &fdt_len); + + if (fdt_len) { + fdt_blob = (char *)fdt_data; + printf(" Booting using the fdt at 0x%p\n", fdt_blob); + + if (fdt_check_header(fdt_blob) != 0) { + fdt_error("image is not a fdt"); + goto error; + } + + if (fdt_totalsize(fdt_blob) != fdt_len) { + fdt_error("fdt size != image size"); + goto error; + } + } else { + debug("## No Flattened Device Tree\n"); + goto no_fdt; + } + } +#endif + else { debug("## No Flattened Device Tree\n"); goto no_fdt; } diff --git a/disk/part_efi.c b/disk/part_efi.c index fb221eec090..ee9d64703dd 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -135,6 +135,25 @@ static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba, return 0; } +static void prepare_last_lba_gpt_header(struct blk_desc *dev_desc, gpt_header *gpt_h) +{ + uint32_t calc_crc32; + uint64_t val; + + /* recalculate the values for the Backup GPT Header */ + val = le64_to_cpu(gpt_h->my_lba); + gpt_h->my_lba = cpu_to_le64(dev_desc->lba - 1);; + gpt_h->alternate_lba = cpu_to_le64(val); + gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34); + gpt_h->partition_entry_lba = + cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1); + gpt_h->header_crc32 = 0; + + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, + le32_to_cpu(gpt_h->header_size)); + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); +} + static int validate_gpt_entries(gpt_header *gpt_h, gpt_entry *gpt_e) { uint32_t calc_crc32; @@ -145,7 +164,7 @@ static int validate_gpt_entries(gpt_header *gpt_h, gpt_entry *gpt_e) le32_to_cpu(gpt_h->sizeof_partition_entry)); if (calc_crc32 != le32_to_cpu(gpt_h->partition_entry_array_crc32)) { - printf("%s: 0x%x != 0x%x\n", + debug("%s: 0x%x != 0x%x\n", "GUID Partition Table Entry Array CRC is wrong", le32_to_cpu(gpt_h->partition_entry_array_crc32), calc_crc32); @@ -281,14 +300,14 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part, /* This function validates AND fills in the GPT header and PTE */ if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA, gpt_head, &gpt_pte) != 1) { - printf("%s: *** ERROR: Invalid GPT ***\n", __func__); + debug("%s: *** ERROR: Invalid GPT ***\n", __func__); if (is_gpt_valid(dev_desc, (dev_desc->lba - 1), gpt_head, &gpt_pte) != 1) { printf("%s: *** ERROR: Invalid Backup GPT ***\n", __func__); return -1; } else { - printf("%s: *** Using Backup GPT ***\n", + debug("%s: *** Using Backup GPT ***\n", __func__); } } @@ -869,6 +888,58 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf) return 0; } +int write_backup_gpt_partitions(struct blk_desc *dev_desc, void *buf) +{ + gpt_header *gpt_h; + gpt_entry *gpt_e; + int gpt_e_blk_cnt; + lbaint_t lba; + int cnt; + + if (is_valid_gpt_buf(dev_desc, buf)) + return -1; + + /* determine start of GPT Header in the buffer */ + gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA * + dev_desc->blksz); + + /* determine start of GPT Entries in the buffer */ + gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) * + dev_desc->blksz); + gpt_e_blk_cnt = BLOCK_CNT((le32_to_cpu(gpt_h->num_partition_entries) * + le32_to_cpu(gpt_h->sizeof_partition_entry)), + dev_desc); + + /* write MBR */ + lba = 0; /* MBR is always at 0 */ + cnt = 1; /* MBR (1 block) */ + if (blk_dwrite(dev_desc, lba, cnt, buf) != cnt) { + printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n", + __func__, "MBR", cnt, lba); + return 1; + } + + prepare_last_lba_gpt_header(dev_desc, gpt_h); + + /* write Backup GPT */ + lba = le64_to_cpu(gpt_h->partition_entry_lba); + cnt = gpt_e_blk_cnt; + if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) { + printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n", + __func__, "Backup GPT Entries", cnt, lba); + return 1; + } + + lba = le64_to_cpu(gpt_h->my_lba); + cnt = 1; /* GPT Header (1 block) */ + if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) { + printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n", + __func__, "Backup GPT Header", cnt, lba); + return 1; + } + + return 0; +} #endif /* diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 748366fb9f0..becdc559abd 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -29,6 +29,8 @@ obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_DFU_OVER_USB) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_FASTBOOT_LOCK) += fastboot_lock_unlock.o +obj-$(CONFIG_BCB_SUPPORT) += command.o bcb.o obj-$(CONFIG_USB_FUNCTION_SDP) += f_sdp.o obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o endif diff --git a/drivers/usb/gadget/bcb.c b/drivers/usb/gadget/bcb.c new file mode 100644 index 00000000000..645bc88a418 --- /dev/null +++ b/drivers/usb/gadget/bcb.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <fsl_fastboot.h> +#include <linux/stat.h> +#include <linux/types.h> +#include <common.h> +#include <g_dnl.h> +#include <mmc.h> +#include "bcb.h" +#define ALIGN_BYTES 64 /*armv7 cache line need 64 bytes aligned */ + +static ulong get_block_size(char *ifname, int dev) +{ + struct blk_desc *dev_desc = NULL; + + dev_desc = blk_get_dev(ifname, dev); + if (dev_desc == NULL) { + printf("Block device %s %d not supported\n", ifname, dev); + return 0; + } + + return dev_desc->blksz; +} + +static int do_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *ep; + struct blk_desc *dev_desc = NULL; + int dev; + int part = 0; + disk_partition_t part_info; + ulong offset = 0u; + ulong limit = 0u; + void *addr; + uint blk; + uint cnt; + + if (argc != 6) { + cmd_usage(cmdtp); + return 1; + } + + dev = (int)simple_strtoul(argv[2], &ep, 16); + if (*ep) { + if (*ep != ':') { + printf("Invalid block device %s\n", argv[2]); + return 1; + } + part = (int)simple_strtoul(++ep, NULL, 16); + } + + dev_desc = blk_get_dev(argv[1], dev); + if (dev_desc == NULL) { + printf("Block device %s %d not supported\n", argv[1], dev); + return 1; + } + + addr = (void *)simple_strtoul(argv[3], NULL, 16); + blk = simple_strtoul(argv[4], NULL, 16); + cnt = simple_strtoul(argv[5], NULL, 16); + + if (part != 0) { + if (part_get_info(dev_desc, part, &part_info)) { + printf("Cannot find partition %d\n", part); + return 1; + } + offset = part_info.start; + limit = part_info.size; + } else { + /* Largest address not available in block_dev_desc_t. */ + limit = ~0; + } + + if (cnt + blk > limit) { + printf("Write out of range\n"); + return 1; + } + + if (blk_dwrite(dev_desc, offset + blk, cnt, addr) != cnt) { + printf("Error writing blocks\n"); + return 1; + } + + return 0; +} + +U_BOOT_CMD( + write, 6, 0, do_write, + "write binary data to a partition", + "<interface> <dev[:part]> addr blk# cnt" +); + +int bcb_rw_block(bool bread, char **ppblock, + uint *pblksize, char *pblock_write, uint offset, uint size) +{ + int ret; + char *argv[6]; + char addr_str[20]; + char cnt_str[8]; + char devpart_str[8]; + char block_begin_str[8]; + ulong blk_size = 0; + uint blk_begin = 0; + uint blk_end = 0; + uint block_cnt = 0; + char *p_block = NULL; + unsigned int mmc_id; + + if (bread && ((ppblock == NULL) || (pblksize == NULL))) + return -1; + + if (!bread && (pblock_write == NULL)) + return -1; + + mmc_id = mmc_get_env_dev(); + blk_size = get_block_size("mmc", mmc_id); + if (blk_size == 0) { + printf("bcb_rw_block, get_block_size return 0\n"); + return -1; + } + + blk_begin = offset/blk_size; + blk_end = (offset + size)/blk_size; + block_cnt = 1 + (blk_end - blk_begin); + + sprintf(devpart_str, "0x%x:0x%x", mmc_id, + fastboot_flash_find_index(FASTBOOT_PARTITION_MISC)); + sprintf(block_begin_str, "0x%x", blk_begin); + sprintf(cnt_str, "0x%x", block_cnt); + + argv[0] = "rw"; /* not care */ + argv[1] = "mmc"; + argv[2] = devpart_str; + argv[3] = addr_str; + argv[4] = block_begin_str; + argv[5] = cnt_str; + + if (bread) { + p_block = (char *)memalign(ALIGN_BYTES, blk_size * block_cnt); + if (NULL == p_block) { + printf("bcb_rw_block, memalign %d bytes failed\n", + (int)(blk_size * block_cnt)); + return -1; + } + sprintf(addr_str, "0x%x", (unsigned int)(uintptr_t)p_block); + ret = do_raw_read(NULL, 0, 6, argv); + if (ret) { + free(p_block); + printf("do_raw_read failed, ret %d\n", ret); + return -1; + } + + *ppblock = p_block; + *pblksize = (uint)blk_size; + } else { + sprintf(addr_str, "0x%x", (unsigned int)(uintptr_t)pblock_write); + ret = do_write(NULL, 0, 6, argv); + if (ret) { + printf("do_write failed, ret %d\n", ret); + return -1; + } + } + return 0; +} diff --git a/drivers/usb/gadget/bcb.h b/drivers/usb/gadget/bcb.h new file mode 100644 index 00000000000..b5a2491014a --- /dev/null +++ b/drivers/usb/gadget/bcb.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef BCB_H +#define BCB_H +#include <linux/types.h> +#include <linux/stat.h> + +#define FASTBOOT_BCB_CMD "bootonce-bootloader" +#ifdef CONFIG_ANDROID_RECOVERY +#define RECOVERY_BCB_CMD "boot-recovery" +#endif +/* keep same as bootable/recovery/bootloader.h */ +struct bootloader_message { + char command[32]; + char status[32]; + char recovery[768]; + + /* The 'recovery' field used to be 1024 bytes. It has only ever + been used to store the recovery command line, so 768 bytes + should be plenty. We carve off the last 256 bytes to store the + stage string (for multistage packages) and possible future + expansion. */ + char stage[32]; + + /* The 'reserved' field used to be 224 bytes when it was initially + carved off from the 1024-byte recovery field. Bump it up to + 1184-byte so that the entire bootloader_message struct rounds up + to 2048-byte. + */ + char reserved[1184]; +}; + +struct bootloader_message_ab { + struct bootloader_message message; + char slot_suffix[32]; + + /* Round up the entire struct to 4096-byte. */ + char reserved[2016]; +}; + +/* start from bootloader_message_ab.slot_suffix[BOOTCTRL_IDX] */ +#define BOOTCTRL_IDX 0 +#define MISC_COMMAND_IDX 0 +#define BOOTCTRL_OFFSET \ + (u32)(&(((struct bootloader_message_ab *)0)->slot_suffix[BOOTCTRL_IDX])) +#define MISC_COMMAND \ + (u32)(uintptr_t)(&(((struct bootloader_message *)0)->command[MISC_COMMAND_IDX])) +int bcb_rw_block(bool bread, char **ppblock, + uint *pblksize, char *pblock_write, uint offset, uint size); + +int bcb_write_command(char *bcb_command); +int bcb_read_command(char *command); + +#endif diff --git a/drivers/usb/gadget/command.c b/drivers/usb/gadget/command.c new file mode 100644 index 00000000000..e9f7d291735 --- /dev/null +++ b/drivers/usb/gadget/command.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <g_dnl.h> +#include "bcb.h" + +int bcb_read_command(char *command) +{ + int ret = 0; + char *p_block = NULL; + uint offset_in_block = 0; + uint blk_size = 0; + + if (command == NULL) + return -1; + + ret = bcb_rw_block(true, &p_block, &blk_size, NULL, MISC_COMMAND, 32); + if (ret) { + printf("read_bootctl, bcb_rw_block read failed\n"); + return -1; + } + + offset_in_block = MISC_COMMAND%blk_size; + memcpy(command, p_block + offset_in_block, 32); + free(p_block); + + return 0; +} +int bcb_write_command(char *bcb_command) +{ + int ret = 0; + char *p_block = NULL; + uint offset_in_block = 0; + uint blk_size = 0; + + if (bcb_command == NULL) + return -1; + + + ret = bcb_rw_block(true, &p_block, &blk_size, NULL, MISC_COMMAND, 32); + if (ret) { + printf("write_bootctl, bcb_rw_block read failed\n"); + return -1; + } + + offset_in_block = MISC_COMMAND%blk_size; + memcpy(p_block + offset_in_block, bcb_command, 32); + + ret = bcb_rw_block(false, NULL, NULL, p_block, MISC_COMMAND, 32); + if (ret) { + free(p_block); + printf("write_bootctl, bcb_rw_block write failed\n"); + return -1; + } + + free(p_block); + return 0; +} diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 7acffb6c87e..9d91ab93b8a 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -8,11 +8,15 @@ * Copyright 2014 Linaro, Ltd. * Rob Herring <robh@kernel.org> * + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * * SPDX-License-Identifier: GPL-2.0+ */ #include <config.h> #include <common.h> #include <errno.h> +#include <stdlib.h> #include <fastboot.h> #include <malloc.h> #include <linux/usb/ch9.h> @@ -21,6 +25,7 @@ #include <linux/compiler.h> #include <version.h> #include <g_dnl.h> +#include "../lib/avb/fsl/utils.h" #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV #include <fb_mmc.h> #endif @@ -28,8 +33,43 @@ #include <fb_nand.h> #endif +#ifdef CONFIG_FSL_FASTBOOT +#include <asm/mach-imx/sys_proto.h> +#include <fsl_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_ANDROID_RECOVERY +#include <recovery.h> +#endif + +#ifdef CONFIG_BCB_SUPPORT +#include "bcb.h" +#endif + +#ifdef CONFIG_AVB_SUPPORT +#include <fsl_avb.h> +#endif + +#ifdef CONFIG_FASTBOOT_LOCK +#include "fastboot_lock_unlock.h" +#endif +#endif + #define FASTBOOT_VERSION "0.4" +#define FASTBOOT_COMMON_VAR_NUM 13 +#define FASTBOOT_VAR_YES "yes" +#define FASTBOOT_VAR_NO "no" #define FASTBOOT_INTERFACE_CLASS 0xff #define FASTBOOT_INTERFACE_SUB_CLASS 0x42 #define FASTBOOT_INTERFACE_PROTOCOL 0x03 @@ -39,18 +79,69 @@ #define TX_ENDPOINT_MAXIMUM_PACKET_SIZE (0x0040) #define EP_BUFFER_SIZE 4096 + +#ifdef CONFIG_FSL_FASTBOOT + +#define ANDROID_GPT_OFFSET 0 +#define ANDROID_GPT_SIZE 0x100000 +#define ANDROID_GPT_END 0x4400 + +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT +struct fastboot_device_info fastboot_firmwareinfo; +#endif + +#if defined (CONFIG_ARCH_IMX8) || defined (CONFIG_ARCH_IMX8M) +#define DST_DECOMPRESS_LEN 1024*1024*32 +#endif + +#endif /* * EP_BUFFER_SIZE must always be an integral multiple of maxpacket size * (64 or 512 or 1024), else we break on certain controllers like DWC3 * that expect bulk OUT requests to be divisible by maxpacket size. */ +/* common variables of fastboot getvar command */ +char *fastboot_common_var[FASTBOOT_COMMON_VAR_NUM] = { + "version", + "version-bootloader", + "version-baseband", + "product", + "secure", + "max-download-size", + "erase-block-size", + "logical-block-size", + "unlocked", + "off-mode-charge", + "battery-voltage", + "variant", + "battery-soc-ok" +}; + +/* Boot metric variables */ +boot_metric metrics = { + .bll_1 = 0, + .ble_1 = 0, + .kl = 0, + .kd = 0, + .avb = 0, + .odt = 0, + .sw = 0 +}; + +typedef struct usb_req usb_req; +struct usb_req { + struct usb_request *in_req; + usb_req *next; +}; + struct f_fastboot { struct usb_function usb_function; /* IN/OUT EP's and corresponding requests */ struct usb_ep *in_ep, *out_ep; struct usb_request *in_req, *out_req; + usb_req *front, *rear; }; static inline struct f_fastboot *func_to_fastboot(struct usb_function *f) @@ -153,6 +244,1960 @@ static int strcmp_l1(const char *s1, const char *s2); static char *fb_response_str; +#ifdef CONFIG_FSL_FASTBOOT + +#define ANDROID_MBR_OFFSET 0 +#define ANDROID_MBR_SIZE 0x200 +#ifdef CONFIG_BOOTLOADER_OFFSET_33K +#define ANDROID_BOOTLOADER_OFFSET 0x8400 +/* The Bootloader offset of imx8qxp B0 board is set to 32K */ +#elif defined(CONFIG_BOOTLOADER_OFFSET_32K) +#define ANDROID_BOOTLOADER_OFFSET 0x8000 +#else +#define ANDROID_BOOTLOADER_OFFSET 0x400 +#endif +#define ANDROID_BOOTLOADER_SIZE 0x1FFC00 + +#define MMC_SATA_BLOCK_SIZE 512 +#define FASTBOOT_FBPARTS_ENV_MAX_LEN 1024 +/* To support the Android-style naming of flash */ +#define MAX_PTN 32 +struct fastboot_ptentry g_ptable[MAX_PTN]; +unsigned int g_pcount; +struct fastboot_device_info fastboot_devinfo; + + +enum { + PTN_GPT_INDEX = 0, +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT + PTN_M4_OS_INDEX, +#endif + PTN_BOOTLOADER_INDEX, +}; +static unsigned int download_bytes_unpadded; + +static struct cmd_fastboot_interface interface = { + .rx_handler = NULL, + .reset_handler = NULL, + .product_name = NULL, + .serial_no = NULL, + .nand_block_size = 0, + .transfer_buffer = (unsigned char *)0xffffffff, + .transfer_buffer_size = 0, +}; + +int read_from_partition_multi(const char* partition, + int64_t offset, size_t num_bytes, void* buffer, size_t* out_num_read) +{ + struct fastboot_ptentry *pte; + unsigned char *bdata; + unsigned char *out_buf = (unsigned char *)buffer; + unsigned char *dst, *dst64 = NULL; + unsigned long blksz; + unsigned long s, cnt; + size_t num_read = 0; + lbaint_t part_start, part_end, bs, be, bm, blk_num; + margin_pos_t margin; + struct blk_desc *fs_dev_desc = NULL; + int dev_no; + int ret; + + assert(buffer != NULL && out_num_read != NULL); + + dev_no = mmc_get_env_dev(); + if ((fs_dev_desc = blk_get_dev("mmc", dev_no)) == NULL) { + printf("mmc device not found\n"); + return -1; + } + + pte = fastboot_flash_find_ptn(partition); + if (!pte) { + printf("no %s partition\n", partition); + return -1; + } + + blksz = fs_dev_desc->blksz; + part_start = pte->start; + part_end = pte->start + pte->length - 1; + + if (get_margin_pos((uint64_t)part_start, (uint64_t)part_end, blksz, + &margin, offset, num_bytes, true)) + return -1; + + bs = (lbaint_t)margin.blk_start; + be = (lbaint_t)margin.blk_end; + s = margin.start; + bm = margin.multi; + + /* alloc a blksz mem */ + bdata = (unsigned char *)memalign(ALIGN_BYTES, blksz); + if (bdata == NULL) { + printf("Failed to allocate memory!\n"); + return -1; + } + + /* support multi blk read */ + while (bs <= be) { + if (!s && bm > 1) { + dst = out_buf; + dst64 = PTR_ALIGN(out_buf, 64); /* for mmc blk read alignment */ + if (dst64 != dst) { + dst = dst64; + bm--; + } + blk_num = bm; + cnt = bm * blksz; + bm = 0; /* no more multi blk */ + } else { + blk_num = 1; + cnt = blksz - s; + if (num_read + cnt > num_bytes) + cnt = num_bytes - num_read; + dst = bdata; + } + if (blk_dread(fs_dev_desc, bs, blk_num, dst) != blk_num) { + ret = -1; + goto fail; + } + + if (dst == bdata) + memcpy(out_buf, bdata + s, cnt); + else if (dst == dst64) + memcpy(out_buf, dst, cnt); /* internal copy */ + + s = 0; + bs += blk_num; + num_read += cnt; + out_buf += cnt; + } + *out_num_read = num_read; + ret = 0; + +fail: + free(bdata); + return ret; +} + +static void save_env(struct fastboot_ptentry *ptn, + char *var, char *val) +{ + env_set(var, val); + env_save(); +} + +/* When save = 0, just parse. The input is unchanged + When save = 1, parse and do the save. The input is changed */ +static int parse_env(void *ptn, char *err_string, int save, int debug) +{ + int ret = 1; + unsigned int sets = 0; + unsigned int comment_start = 0; + char *var = NULL; + char *var_end = NULL; + char *val = NULL; + char *val_end = NULL; + unsigned int i; + + char *buff = (char *)interface.transfer_buffer; + unsigned int size = download_bytes_unpadded; + + /* The input does not have to be null terminated. + This will cause a problem in the corner case + where the last line does not have a new line. + Put a null after the end of the input. + + WARNING : Input buffer is assumed to be bigger + than the size of the input */ + if (save) + buff[size] = 0; + + for (i = 0; i < size; i++) { + + if (NULL == var) { + + /* + * Check for comments, comment ok only on + * mostly empty lines + */ + if (buff[i] == '#') + comment_start = 1; + + if (comment_start) { + if ((buff[i] == '\r') || + (buff[i] == '\n')) { + comment_start = 0; + } + } else { + if (!((buff[i] == ' ') || + (buff[i] == '\t') || + (buff[i] == '\r') || + (buff[i] == '\n'))) { + /* + * Normal whitespace before the + * variable + */ + var = &buff[i]; + } + } + + } else if (((NULL == var_end) || (NULL == val)) && + ((buff[i] == '\r') || (buff[i] == '\n'))) { + + /* This is the case when a variable + is unset. */ + + if (save) { + /* Set the var end to null so the + normal string routines will work + + WARNING : This changes the input */ + buff[i] = '\0'; + + save_env(ptn, var, val); + + if (debug) + printf("Unsetting %s\n", var); + } + + /* Clear the variable so state is parse is back + to initial. */ + var = NULL; + var_end = NULL; + sets++; + } else if (NULL == var_end) { + if ((buff[i] == ' ') || + (buff[i] == '\t')) + var_end = &buff[i]; + } else if (NULL == val) { + if (!((buff[i] == ' ') || + (buff[i] == '\t'))) + val = &buff[i]; + } else if (NULL == val_end) { + if ((buff[i] == '\r') || + (buff[i] == '\n')) { + /* look for escaped cr or ln */ + if ('\\' == buff[i - 1]) { + /* check for dos */ + if ((buff[i] == '\r') && + (buff[i+1] == '\n')) + buff[i + 1] = ' '; + buff[i - 1] = buff[i] = ' '; + } else { + val_end = &buff[i]; + } + } + } else { + sprintf(err_string, "Internal Error"); + + if (debug) + printf("Internal error at %s %d\n", + __FILE__, __LINE__); + return 1; + } + /* Check if a var / val pair is ready */ + if (NULL != val_end) { + if (save) { + /* Set the end's with nulls so + normal string routines will + work. + + WARNING : This changes the input */ + *var_end = '\0'; + *val_end = '\0'; + + save_env(ptn, var, val); + + if (debug) + printf("Setting %s %s\n", var, val); + } + + /* Clear the variable so state is parse is back + to initial. */ + var = NULL; + var_end = NULL; + val = NULL; + val_end = NULL; + + sets++; + } + } + + /* Corner case + Check for the case that no newline at end of the input */ + if ((NULL != var) && + (NULL == val_end)) { + if (save) { + /* case of val / val pair */ + if (var_end) + *var_end = '\0'; + /* else case handled by setting 0 past + the end of buffer. + Similar for val_end being null */ + save_env(ptn, var, val); + + if (debug) { + if (var_end) + printf("Trailing Setting %s %s\n", var, val); + else + printf("Trailing Unsetting %s\n", var); + } + } + sets++; + } + /* Did we set anything ? */ + if (0 == sets) + sprintf(err_string, "No variables set"); + else + ret = 0; + + return ret; +} + +static int saveenv_to_ptn(struct fastboot_ptentry *ptn, char *err_string) +{ + int ret = 1; + int save = 0; + int debug = 0; + + /* err_string is only 32 bytes + Initialize with a generic error message. */ + sprintf(err_string, "%s", "Unknown Error"); + + /* Parse the input twice. + Only save to the enviroment if the entire input if correct */ + save = 0; + if (0 == parse_env(ptn, err_string, save, debug)) { + save = 1; + ret = parse_env(ptn, err_string, save, debug); + } + return ret; +} + +static int get_block_size(void); +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT +static void process_flash_sf(const char *cmdbuf) +{ + int blksz = 0; + blksz = get_block_size(); + + if (download_bytes) { + struct fastboot_ptentry *ptn; + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == 0) { + fastboot_fail("partition does not exist"); + } else if ((download_bytes > ptn->length * blksz)) { + fastboot_fail("image too large for partition"); + /* TODO : Improve check for yaffs write */ + } else { + int ret; + char sf_command[128]; + /* Normal case */ + /* Probe device */ + sprintf(sf_command, "sf probe"); + ret = run_command(sf_command, 0); + if (ret){ + fastboot_fail("Probe sf failed"); + return; + } + /* Erase */ + sprintf(sf_command, "sf erase 0x%x 0x%x", ptn->start * blksz, /*start*/ + ptn->length * blksz /*size*/); + ret = run_command(sf_command, 0); + if (ret) { + fastboot_fail("Erasing sf failed"); + return; + } + /* Write image */ + sprintf(sf_command, "sf write 0x%x 0x%x 0x%x", + (unsigned int)(ulong)interface.transfer_buffer, /* source */ + ptn->start * blksz, /* start */ + download_bytes /*size*/); + printf("sf write '%s'\n", ptn->name); + ret = run_command(sf_command, 0); + if (ret){ + fastboot_fail("Writing sf failed"); + return; + } + printf("sf write finished '%s'\n", ptn->name); + fastboot_okay(""); + } + } else { + fastboot_fail("no image downloaded"); + } +} + +#ifdef CONFIG_ARCH_IMX8M +/* Check if the mcu image is built for running from TCM */ +static bool is_tcm_image(unsigned char *image_addr) +{ + u32 stack; + + stack = *(u32 *)image_addr; + + if ((stack != (u32)ANDROID_MCU_FIRMWARE_HEADER_STACK)) { + printf("Please flash mcu firmware images for running from TCM\n"); + return false; + } else + return true; +} + +static int do_bootmcu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret; + size_t out_num_read; + void *m4_base_addr = (void *)M4_BOOTROM_BASE_ADDR; + char command[32]; + + ret = read_from_partition_multi(FASTBOOT_MCU_FIRMWARE_PARTITION, + 0, ANDROID_MCU_FIRMWARE_SIZE, (void *)m4_base_addr, &out_num_read); + if ((ret != 0) || (out_num_read != ANDROID_MCU_FIRMWARE_SIZE)) { + printf("Read M4 images failed!\n"); + return 1; + } else { + printf("run command: 'bootaux 0x%x'\n",(unsigned int)(ulong)m4_base_addr); + + sprintf(command, "bootaux 0x%x", (unsigned int)(ulong)m4_base_addr); + ret = run_command(command, 0); + if (ret) { + printf("run 'bootaux' command failed!\n"); + return 1; + } + } + return 0; +} + +U_BOOT_CMD( + bootmcu, 1, 0, do_bootmcu, + "boot mcu images\n", + "boot mcu images from 'm4_os' partition, only support images run from TCM" +); +#endif +#endif /* CONFIG_FLASH_MCUFIRMWARE_SUPPORT */ + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) +static void process_flash_sata(const char *cmdbuf) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; + + /* Next is the partition name */ + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == NULL) { + fastboot_fail("partition does not exist"); + } else if ((download_bytes > + ptn->length * MMC_SATA_BLOCK_SIZE) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + printf("Image too large for the partition\n"); + fastboot_fail("image too large for partition"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", ptn->name, err_string); + fastboot_fail(err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + fastboot_okay(""); + } + } else { + unsigned int temp; + char sata_write[128]; + + /* block count */ + temp = (download_bytes + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + + sprintf(sata_write, "sata write 0x%x 0x%x 0x%x", + (unsigned int)interface.transfer_buffer, + ptn->start, + temp); + + if (run_command(sata_write, 0)) { + printf("Writing '%s' FAILED!\n", + ptn->name); + fastboot_fail("Write partition failed"); + } else { + printf("Writing '%s' DONE!\n", + ptn->name); + fastboot_okay(""); + } + } + } else { + fastboot_fail("no image downloaded"); + } + +} +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) +static int is_raw_partition(struct fastboot_ptentry *ptn) +{ +#ifdef CONFIG_ANDROID_AB_SUPPORT + if (ptn && (!strncmp(ptn->name, FASTBOOT_PARTITION_BOOTLOADER, + strlen(FASTBOOT_PARTITION_BOOTLOADER)) || + !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)) || +#ifdef CONFIG_FASTBOOT_LOCK + !strncmp(ptn->name, FASTBOOT_PARTITION_FBMISC, + strlen(FASTBOOT_PARTITION_FBMISC)) || +#endif + !strncmp(ptn->name, FASTBOOT_PARTITION_MISC, + strlen(FASTBOOT_PARTITION_MISC)))) { +#else + if (ptn && (!strncmp(ptn->name, FASTBOOT_PARTITION_BOOTLOADER, + strlen(FASTBOOT_PARTITION_BOOTLOADER)) || + !strncmp(ptn->name, FASTBOOT_PARTITION_BOOT, + strlen(FASTBOOT_PARTITION_BOOT)) || +#ifdef CONFIG_FASTBOOT_LOCK + !strncmp(ptn->name, FASTBOOT_PARTITION_FBMISC, + strlen(FASTBOOT_PARTITION_FBMISC)) || +#endif + !strncmp(ptn->name, FASTBOOT_PARTITION_MISC, + strlen(FASTBOOT_PARTITION_MISC)))) { +#endif + printf("support sparse flash partition for %s\n", ptn->name); + return 1; + } else + return 0; +} + +static lbaint_t mmc_sparse_write(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt, const void *buffer) +{ +#define SPARSE_FILL_BUF_SIZE (2 * 1024 * 1024) + + struct blk_desc *dev_desc = (struct blk_desc *)info->priv; + ulong ret = 0; + void *data; + int fill_buf_num_blks, cnt; + + if ((unsigned long)buffer & (CONFIG_SYS_CACHELINE_SIZE - 1)) { + + fill_buf_num_blks = SPARSE_FILL_BUF_SIZE / info->blksz; + + data = memalign(CONFIG_SYS_CACHELINE_SIZE, fill_buf_num_blks * info->blksz); + + while (blkcnt) { + + if (blkcnt > fill_buf_num_blks) + cnt = fill_buf_num_blks; + else + cnt = blkcnt; + + memcpy(data, buffer, cnt * info->blksz); + + ret += blk_dwrite(dev_desc, blk, cnt, data); + + blk += cnt; + blkcnt -= cnt; + buffer = (void *)((unsigned long)buffer + cnt * info->blksz); + + } + + free(data); + } else { + ret = blk_dwrite(dev_desc, blk, blkcnt, buffer); + } + + return ret; +} + +static lbaint_t mmc_sparse_reserve(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt) +{ + return blkcnt; +} + +/*judge wether the gpt image and bootloader image are overlay*/ +bool bootloader_gpt_overlay(void) +{ + return (g_ptable[PTN_GPT_INDEX].partition_id == g_ptable[PTN_BOOTLOADER_INDEX].partition_id && + ANDROID_BOOTLOADER_OFFSET < ANDROID_GPT_END); +} + +int write_backup_gpt(void) +{ + int mmc_no = 0; + struct mmc *mmc; + struct blk_desc *dev_desc; + + mmc_no = fastboot_devinfo.dev_id; + mmc = find_mmc_device(mmc_no); + if (mmc == NULL) { + printf("invalid mmc device\n"); + return -1; + } + dev_desc = blk_get_dev("mmc", mmc_no); + + /* write backup get partition */ + if (write_backup_gpt_partitions(dev_desc, interface.transfer_buffer)) { + printf("writing GPT image fail\n"); + return -1; + } + + printf("flash backup gpt image successfully\n"); + return 0; +} + +static void process_flash_mmc(const char *cmdbuf) +{ + if (download_bytes) { + struct fastboot_ptentry *ptn; +#ifdef CONFIG_AVB_SUPPORT + if (!strcmp_l1(FASTBOOT_PARTITION_AVBKEY, cmdbuf)) { + printf("pubkey len %d\n", download_bytes); + if (avbkey_init(interface.transfer_buffer, download_bytes) != 0) { + fastboot_fail("fail to Write partition"); + } else { + printf("init 'avbkey' DONE!\n"); + fastboot_okay("OKAY"); + } + return; + } +#endif + + /* Next is the partition name */ + ptn = fastboot_flash_find_ptn(cmdbuf); + if (ptn == NULL) { + fastboot_fail("partition does not exist"); + } else if ((download_bytes > + ptn->length * MMC_SATA_BLOCK_SIZE) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + printf("Image too large for the partition\n"); + fastboot_fail("image too large for partition"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { + /* Since the response can only be 64 bytes, + there is no point in having a large error message. */ + char err_string[32]; + if (saveenv_to_ptn(ptn, &err_string[0])) { + printf("savenv '%s' failed : %s\n", ptn->name, err_string); + fastboot_fail(err_string); + } else { + printf("partition '%s' saveenv-ed\n", ptn->name); + fastboot_okay(""); + } + } else { + unsigned int temp; + + char mmc_dev[128]; + char mmc_write[128]; + int mmcret; + + printf("writing to partition '%s'\n", ptn->name); + + if (ptn->partition_id != FASTBOOT_MMC_NONE_PARTITION_ID) + sprintf(mmc_dev, "mmc dev %x %x", + fastboot_devinfo.dev_id, /*slot no*/ + ptn->partition_id /*part no*/); + else + sprintf(mmc_dev, "mmc dev %x", + fastboot_devinfo.dev_id /*slot no*/); + + if (!is_raw_partition(ptn) && + is_sparse_image(interface.transfer_buffer)) { + int mmc_no = 0; + struct mmc *mmc; + struct blk_desc *dev_desc; + disk_partition_t info; + struct sparse_storage sparse; + + mmc_no = fastboot_devinfo.dev_id; + + printf("sparse flash target is MMC:%d\n", mmc_no); + mmc = find_mmc_device(mmc_no); + if (mmc && 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; + } + + if (part_get_info(dev_desc, + ptn->partition_index, &info)) { + printf("Bad partition index:%d for partition:%s\n", + ptn->partition_index, ptn->name); + return; + } + + printf("writing to partition '%s' for sparse, buffer size %d\n", + ptn->name, download_bytes); + + sparse.blksz = info.blksz; + sparse.start = info.start; + sparse.size = info.size; + sparse.write = mmc_sparse_write; + sparse.reserve = mmc_sparse_reserve; + printf("Flashing sparse image at offset " LBAFU "\n", + sparse.start); + + sparse.priv = dev_desc; + write_sparse_image(&sparse, ptn->name, interface.transfer_buffer, + download_bytes); + + } else { + /* Will flash images in below case: + * 1. Is not gpt partition. + * 2. Is gpt partition but no overlay detected. + * */ + if (strncmp(ptn->name, "gpt", 3) || !bootloader_gpt_overlay()) { + /* block count */ + if (strncmp(ptn->name, "gpt", 3) == 0) { + temp = (ANDROID_GPT_END + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + } else { + temp = (download_bytes + + MMC_SATA_BLOCK_SIZE - 1) / + MMC_SATA_BLOCK_SIZE; + } + + sprintf(mmc_write, "mmc write 0x%x 0x%x 0x%x", + (unsigned int)(uintptr_t)interface.transfer_buffer, /*source*/ + ptn->start, /*dest*/ + temp /*length*/); + + printf("Initializing '%s'\n", ptn->name); + + mmcret = run_command(mmc_dev, 0); + if (mmcret) + fastboot_fail("Init of MMC card failed"); + else + fastboot_okay(""); + + printf("Writing '%s'\n", ptn->name); + if (run_command(mmc_write, 0)) { + printf("Writing '%s' FAILED!\n", ptn->name); + fastboot_fail("Write partition failed"); + } else { + printf("Writing '%s' DONE!\n", ptn->name); + fastboot_okay(""); + } + } + /* Write backup gpt image */ + if (strncmp(ptn->name, "gpt", 3) == 0) { + if (write_backup_gpt()) + fastboot_fail("write backup GPT image fail"); + else + fastboot_okay(""); + + /* will force scan the device, + * so dev_desc can be re-inited + * with the latest data */ + run_command(mmc_dev, 0); + } + } + } + } else { + fastboot_fail("no image downloaded"); + } +} + +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) +static void process_erase_mmc(const char *cmdbuf, char *response) +{ + int mmc_no = 0; + lbaint_t blks, blks_start, blks_size, grp_size; + struct mmc *mmc; + struct blk_desc *dev_desc; + struct fastboot_ptentry *ptn; + disk_partition_t info; + + ptn = fastboot_flash_find_ptn(cmdbuf); + if ((ptn == NULL) || (ptn->flags & FASTBOOT_PTENTRY_FLAGS_UNERASEABLE)) { + sprintf(response, "FAILpartition does not exist or uneraseable"); + return; + } + + mmc_no = fastboot_devinfo.dev_id; + printf("erase target is MMC:%d\n", mmc_no); + + mmc = find_mmc_device(mmc_no); + if ((mmc == NULL) || mmc_init(mmc)) { + printf("MMC card init failed!\n"); + return; + } + + dev_desc = blk_get_dev("mmc", mmc_no); + if (NULL == dev_desc) { + printf("Block device MMC %d not supported\n", + mmc_no); + sprintf(response, "FAILnot valid MMC card"); + return; + } + + if (part_get_info(dev_desc, + ptn->partition_index, &info)) { + printf("Bad partition index:%d for partition:%s\n", + ptn->partition_index, ptn->name); + sprintf(response, "FAILerasing of MMC card"); + return; + } + + /* Align blocks to erase group size to avoid erasing other partitions */ + grp_size = mmc->erase_grp_size; + blks_start = (info.start + grp_size - 1) & ~(grp_size - 1); + if (info.size >= grp_size) + blks_size = (info.size - (blks_start - info.start)) & + (~(grp_size - 1)); + else + blks_size = 0; + + printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n", + blks_start, blks_start + blks_size); + + blks = blk_derase(dev_desc, blks_start, blks_size); + if (blks != blks_size) { + printf("failed erasing from device %d", dev_desc->devnum); + sprintf(response, "FAILerasing of MMC card"); + return; + } + + printf("........ erased " LBAFU " bytes from '%s'\n", + blks_size * info.blksz, cmdbuf); + sprintf(response, "OKAY"); + + return; +} +#endif + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) +static void process_erase_sata(const char *cmdbuf, char *response) +{ + return; +} +#endif + +static void rx_process_erase(const char *cmdbuf, char *response) +{ + switch (fastboot_devinfo.type) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case DEV_SATA: + process_erase_sata(cmdbuf, response); + break; +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case DEV_MMC: + process_erase_mmc(cmdbuf, response); + break; +#endif + default: + printf("Not support flash command for current device %d\n", + fastboot_devinfo.type); + sprintf(response, + "FAILfailed to flash device"); + break; + } +} + +static void rx_process_flash(const char *cmdbuf) +{ +/* Check if we need to flash mcu firmware */ +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT + if (!strncmp(cmdbuf, FASTBOOT_MCU_FIRMWARE_PARTITION, + sizeof(FASTBOOT_MCU_FIRMWARE_PARTITION))) { + switch (fastboot_firmwareinfo.type) { + case DEV_SF: + process_flash_sf(cmdbuf); + break; +#ifdef CONFIG_ARCH_IMX8M + case DEV_MMC: + if (is_tcm_image(interface.transfer_buffer)) + process_flash_mmc(cmdbuf); + break; +#endif + default: + printf("Don't support flash firmware\n"); + } + return; + } +#endif + /* Normal case */ + switch (fastboot_devinfo.type) { +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) + case DEV_SATA: + process_flash_sata(cmdbuf); + break; +#endif +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case DEV_MMC: + process_flash_mmc(cmdbuf); + break; +#endif + default: + printf("Not support flash command for current device %d\n", + fastboot_devinfo.type); + fastboot_fail("failed to flash device"); + break; + } +} + + +static void parameters_setup(void) +{ + interface.nand_block_size = 0; + interface.transfer_buffer = + (unsigned char *)CONFIG_FASTBOOT_BUF_ADDR; + interface.transfer_buffer_size = + CONFIG_FASTBOOT_BUF_SIZE; +} + +static int _fastboot_setup_dev(void) +{ + char *fastboot_env; + fastboot_env = env_get("fastboot_dev"); + + if (fastboot_env) { + if (!strcmp(fastboot_env, "sata")) { + fastboot_devinfo.type = DEV_SATA; + fastboot_devinfo.dev_id = 0; +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + } else if (!strncmp(fastboot_env, "mmc", 3)) { + fastboot_devinfo.type = DEV_MMC; + fastboot_devinfo.dev_id = mmc_get_env_dev(); +#endif + } + } else { + return 1; + } +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT + /* For imx7ulp, flash m4 images directly to spi nor-flash, M4 will + * run automatically after powered on. For imx8mq, flash m4 images to + * physical partition 'm4_os', m4 will be kicked off by A core. */ + fastboot_firmwareinfo.type = ANDROID_MCU_FRIMWARE_DEV_TYPE; +#endif + + return 0; +} + +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) +/** + @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_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; +#ifdef CONFIG_CMD_SATA + int sata_device_no; +#endif + + /* 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_CMD_SATA + puts("flash target is SATA\n"); + if (sata_initialize()) + return -1; + sata_device_no = CONFIG_FASTBOOT_SATA_NO; + 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_CMD_SATA*/ + puts("SATA isn't buildin\n"); + return -1; +#endif /*! CONFIG_CMD_SATA*/ + } else if (fastboot_devinfo.type == DEV_MMC) { + int mmc_no = 0; + mmc_no = fastboot_devinfo.dev_id; + + printf("flash target is MMC:%d\n", mmc_no); + mmc = find_mmc_device(mmc_no); + if (mmc && 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"); + + /* 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 + + /* Bootloader */ + strcpy(ptable[PTN_BOOTLOADER_INDEX].name, FASTBOOT_PARTITION_BOOTLOADER); + ptable[PTN_BOOTLOADER_INDEX].start = + ANDROID_BOOTLOADER_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; +} +#endif /*CONFIG_FASTBOOT_STORAGE_SATA || CONFIG_FASTBOOT_STORAGE_MMC*/ + +static void _fastboot_load_partitions(void) +{ + g_pcount = 0; +#if defined(CONFIG_FASTBOOT_STORAGE_SATA) \ + || defined(CONFIG_FASTBOOT_STORAGE_MMC) + _fastboot_parts_load_from_ptable(); +#endif +} + +/* + * 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; + } + } + + printf("can't find partition: %s, dump the partition table\n", name); + fastboot_flash_dump_ptn(); + 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); + 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; +} + +#ifdef CONFIG_FSL_FASTBOOT +void board_fastboot_setup(void) +{ +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + static char boot_dev_part[32]; + u32 dev_no; +#endif + switch (get_boot_device()) { +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD1_BOOT: + case SD2_BOOT: + case SD3_BOOT: + case SD4_BOOT: + case MMC1_BOOT: + case MMC2_BOOT: + case MMC3_BOOT: + case MMC4_BOOT: + dev_no = mmc_get_env_dev(); + sprintf(boot_dev_part,"mmc%d",dev_no); + if (!env_get("fastboot_dev")) + env_set("fastboot_dev", boot_dev_part); + sprintf(boot_dev_part, "boota mmc%d", dev_no); + if (!env_get("bootcmd")) + env_set("bootcmd", boot_dev_part); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ + default: + printf("unsupported boot devices\n"); + break; + } + + /* add soc type into bootargs */ + if (is_mx6dqp()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx6qp"); + } else if (is_mx6dq()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx6q"); + } else if (is_mx6sdl()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx6dl"); + } else if (is_mx6sx()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx6sx"); + } else if (is_mx6sl()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx6sl"); + } else if (is_mx6ul()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx6ul"); + } else if (is_mx7()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx7d"); + } else if (is_mx7ulp()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx7ulp"); + } else if (is_imx8qm()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx8qm"); + } else if (is_imx8qxp()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx8qxp"); + } else if (is_imx8mq()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx8mq"); + } else if (is_imx8mm()) { + if (!env_get("soc_type")) + env_set("soc_type", "imx8mm"); + } +} + +#ifdef CONFIG_ANDROID_RECOVERY +void board_recovery_setup(void) +{ +/* boot from current mmc with avb verify */ +#ifdef CONFIG_AVB_SUPPORT + if (!env_get("bootcmd_android_recovery")) + env_set("bootcmd_android_recovery", "boota recovery"); +#else +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + static char boot_dev_part[32]; + u32 dev_no; +#endif + int bootdev = get_boot_device(); + switch (bootdev) { +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD1_BOOT: + case SD2_BOOT: + case SD3_BOOT: + case SD4_BOOT: + case MMC1_BOOT: + case MMC2_BOOT: + case MMC3_BOOT: + case MMC4_BOOT: + dev_no = mmc_get_env_dev(); + sprintf(boot_dev_part,"boota mmc%d recovery",dev_no); + if (!env_get("bootcmd_android_recovery")) + env_set("bootcmd_android_recovery", boot_dev_part); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ + default: + printf("Unsupported bootup device for recovery: dev: %d\n", + bootdev); + return; + } +#endif /* CONFIG_AVB_SUPPORT */ + printf("setup env for recovery..\n"); + env_set("bootcmd", "run bootcmd_android_recovery"); +} +#endif /*CONFIG_ANDROID_RECOVERY*/ +#endif /*CONFIG_FSL_FASTBOOT*/ + +#if defined(CONFIG_AVB_SUPPORT) && defined(CONFIG_MMC) +static AvbABOps fsl_avb_ab_ops = { + .read_ab_metadata = fsl_read_ab_metadata, + .write_ab_metadata = fsl_write_ab_metadata, + .ops = NULL +}; +#ifdef CONFIG_AVB_ATX +static AvbAtxOps fsl_avb_atx_ops = { + .ops = NULL, + .read_permanent_attributes = fsl_read_permanent_attributes, + .read_permanent_attributes_hash = fsl_read_permanent_attributes_hash +}; +#endif +static AvbOps fsl_avb_ops = { + .ab_ops = &fsl_avb_ab_ops, +#ifdef CONFIG_AVB_ATX + .atx_ops = &fsl_avb_atx_ops, +#endif + .read_from_partition = fsl_read_from_partition_multi, + .write_to_partition = fsl_write_to_partition, +#ifdef CONFIG_AVB_ATX + .validate_vbmeta_public_key = avb_atx_validate_vbmeta_public_key, +#else + .validate_vbmeta_public_key = fsl_validate_vbmeta_public_key_rpmb, +#endif + .read_rollback_index = fsl_read_rollback_index_rpmb, + .write_rollback_index = fsl_write_rollback_index_rpmb, + .read_is_device_unlocked = fsl_read_is_device_unlocked, + .get_unique_guid_for_partition = fsl_get_unique_guid_for_partition, + .get_size_of_partition = fsl_get_size_of_partition +}; +#endif + +void fastboot_setup(void) +{ +#ifdef CONFIG_USB_GADGET + struct tag_serialnr serialnr; + char serial[17]; + + get_board_serial(&serialnr); + sprintf(serial, "%08x%08x", serialnr.high, serialnr.low); + g_dnl_set_serialnumber(serial); +#endif + /*execute board relevant initilizations for preparing fastboot */ + board_fastboot_setup(); + + /*get the fastboot dev*/ + _fastboot_setup_dev(); + + + /*load partitions information for the fastboot dev*/ + _fastboot_load_partitions(); + + parameters_setup(); +#ifdef CONFIG_AVB_SUPPORT + fsl_avb_ab_ops.ops = &fsl_avb_ops; +#ifdef CONFIG_AVB_ATX + fsl_avb_atx_ops.ops = &fsl_avb_ops; +#endif +#endif +} + +/* Write the bcb with fastboot bootloader commands */ +static void enable_fastboot_command(void) +{ + char fastboot_command[32] = {0}; + strncpy(fastboot_command, FASTBOOT_BCB_CMD, 31); + bcb_write_command(fastboot_command); +} + +/* Get the Boot mode from BCB cmd or Key pressed */ +static FbBootMode fastboot_get_bootmode(void) +{ + int ret = 0; + int boot_mode = BOOTMODE_NORMAL; + char command[32]; +#ifdef CONFIG_ANDROID_RECOVERY + if(is_recovery_key_pressing()) { + boot_mode = BOOTMODE_RECOVERY_KEY_PRESSED; + return boot_mode; + } +#endif + ret = bcb_read_command(command); + if (ret < 0) { + printf("read command failed\n"); + return boot_mode; + } + if (!strcmp(command, FASTBOOT_BCB_CMD)) { + boot_mode = BOOTMODE_FASTBOOT_BCB_CMD; + } +#ifdef CONFIG_ANDROID_RECOVERY + else if (!strcmp(command, RECOVERY_BCB_CMD)) { + boot_mode = BOOTMODE_RECOVERY_BCB_CMD; + } +#endif + + /* Clean the mode once its read out, + no matter what in the mode string */ + memset(command, 0, 32); + bcb_write_command(command); + return boot_mode; +} + +#ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT +/* Setup booargs for taking the system parition as ramdisk */ +static void fastboot_setup_system_boot_args(const char *slot, bool append_root) +{ + const char *system_part_name = NULL; + if(slot == NULL) + return; + if(!strncmp(slot, "_a", strlen("_a")) || !strncmp(slot, "boot_a", strlen("boot_a"))) { + system_part_name = FASTBOOT_PARTITION_SYSTEM_A; + } + else if(!strncmp(slot, "_b", strlen("_b")) || !strncmp(slot, "boot_b", strlen("boot_b"))) { + system_part_name = FASTBOOT_PARTITION_SYSTEM_B; + } else { + printf("slot invalid!\n"); + return; + } + struct fastboot_ptentry *ptentry = fastboot_flash_find_ptn(system_part_name); + if(ptentry != NULL) { + char bootargs_3rd[ANDR_BOOT_ARGS_SIZE]; +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + if (append_root) { + u32 dev_no = mmc_map_to_kernel_blk(mmc_get_env_dev()); + sprintf(bootargs_3rd, "skip_initramfs root=/dev/mmcblk%dp%d", + dev_no, + ptentry->partition_index); + } else { + sprintf(bootargs_3rd, "skip_initramfs"); + } + strcat(bootargs_3rd, " rootwait"); + env_set("bootargs_3rd", bootargs_3rd); +#endif + } +} +#endif +/* export to lib_arm/board.c */ +void fastboot_run_bootmode(void) +{ + FbBootMode boot_mode = fastboot_get_bootmode(); + switch(boot_mode){ + case BOOTMODE_FASTBOOT_BCB_CMD: + /* Make the boot into fastboot mode*/ + puts("Fastboot: Got bootloader commands!\n"); + run_command("fastboot 0", 0); + break; +#ifdef CONFIG_ANDROID_RECOVERY + case BOOTMODE_RECOVERY_BCB_CMD: + case BOOTMODE_RECOVERY_KEY_PRESSED: + /* Make the boot into recovery mode */ + puts("Fastboot: Got Recovery key pressing or recovery commands!\n"); + board_recovery_setup(); + break; +#endif + default: + /* skip special mode boot*/ + puts("Fastboot: Normal\n"); + break; + } +} + +#ifdef CONFIG_CMD_BOOTA + /* Section for Android bootimage format support + * Refer: + * http://android.git.kernel.org/?p=platform/system/core.git;a=blob; + * f=mkbootimg/bootimg.h + */ + +void +bootimg_print_image_hdr(struct andr_img_hdr *hdr) +{ +#ifdef DEBUG + int i; + printf(" Image magic: %s\n", hdr->magic); + + printf(" kernel_size: 0x%x\n", hdr->kernel_size); + printf(" kernel_addr: 0x%x\n", hdr->kernel_addr); + + printf(" rdisk_size: 0x%x\n", hdr->ramdisk_size); + printf(" rdisk_addr: 0x%x\n", hdr->ramdisk_addr); + + printf(" second_size: 0x%x\n", hdr->second_size); + printf(" second_addr: 0x%x\n", hdr->second_addr); + + printf(" tags_addr: 0x%x\n", hdr->tags_addr); + printf(" page_size: 0x%x\n", hdr->page_size); + + printf(" name: %s\n", hdr->name); + printf(" cmdline: %s\n", hdr->cmdline); + + for (i = 0; i < 8; i++) + printf(" id[%d]: 0x%x\n", i, hdr->id[i]); +#endif +} + +static struct andr_img_hdr boothdr __aligned(ARCH_DMA_MINALIGN); + +#if defined(CONFIG_AVB_SUPPORT) && defined(CONFIG_MMC) + +int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + + ulong addr = 0; + struct andr_img_hdr *hdr = NULL; + void *boot_buf = NULL; + ulong image_size; + u32 avb_metric; + bool check_image_arm64 = false; + bool is_recovery_mode = false; + +#if defined (CONFIG_ARCH_IMX8) || defined (CONFIG_ARCH_IMX8M) + size_t lz4_len = DST_DECOMPRESS_LEN; +#endif + AvbABFlowResult avb_result; + AvbSlotVerifyData *avb_out_data; + AvbPartitionData *avb_loadpart; + + /* get bootmode, default to boot "boot" */ + if (argc > 1) { + is_recovery_mode = + (strncmp(argv[1], "recovery", sizeof("recovery")) != 0) ? false: true; + } + +#ifdef CONFIG_FASTBOOT_LOCK + /* check lock state */ + FbLockState lock_status = fastboot_get_lock_stat(); + if (lock_status == FASTBOOT_LOCK_ERROR) { + printf("In boota get fastboot lock status error. Set lock status\n"); + fastboot_set_lock_stat(FASTBOOT_LOCK); + lock_status = FASTBOOT_LOCK; + } + bool allow_fail = (lock_status == FASTBOOT_UNLOCK ? true : false); + avb_metric = get_timer(0); + /* For imx6 on Android, we don't have a/b slot and we want to verify + * boot/recovery with AVB. For imx8 and Android Things we don't have + * recovery and support a/b slot for boot */ +#ifdef CONFIG_ANDROID_AB_SUPPORT + /* we can use avb to verify Trusty if we want */ + const char *requested_partitions[] = {"boot", 0}; + avb_result = avb_ab_flow_fast(&fsl_avb_ab_ops, requested_partitions, allow_fail, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_out_data); +#else /* CONFIG_ANDROID_AB_SUPPORT */ + if (!is_recovery_mode) { + const char *requested_partitions[] = {"boot", 0}; + avb_result = avb_single_flow(&fsl_avb_ab_ops, requested_partitions, allow_fail, + AVB_HASHTREE_ERROR_MODE_RESTART, &avb_out_data); + } else { + const char *requested_partitions[] = {"recovery", 0}; + avb_result = avb_single_flow(&fsl_avb_ab_ops, requested_partitions, allow_fail, + AVB_HASHTREE_ERROR_MODE_RESTART, &avb_out_data); + } +#endif /* CONFIG_ANDROID_AB_SUPPORT */ + /* get the duration of avb */ + metrics.avb = get_timer(avb_metric); + + if ((avb_result == AVB_AB_FLOW_RESULT_OK) || + (avb_result == AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR)) { + assert(avb_out_data != NULL); + /* load the first partition */ + avb_loadpart = avb_out_data->loaded_partitions; + assert(avb_loadpart != NULL); + /* we should use avb_part_data->data as boot image */ + /* boot image is already read by avb */ + hdr = (struct andr_img_hdr *)avb_loadpart->data; + if (android_image_check_header(hdr)) { + printf("boota: bad boot image magic\n"); + goto fail; + } + if (avb_result == AVB_AB_FLOW_RESULT_OK) + printf(" verify OK, boot '%s%s'\n", + avb_loadpart->partition_name, avb_out_data->ab_suffix); + else { + printf(" verify FAIL, state: UNLOCK\n"); + printf(" boot '%s%s' still\n", + avb_loadpart->partition_name, avb_out_data->ab_suffix); + } + char bootargs_sec[ANDR_BOOT_ARGS_SIZE]; + if (lock_status == FASTBOOT_LOCK) { + sprintf(bootargs_sec, + "androidboot.verifiedbootstate=green androidboot.slot_suffix=%s %s", + avb_out_data->ab_suffix, avb_out_data->cmdline); + } else { + sprintf(bootargs_sec, + "androidboot.verifiedbootstate=orange androidboot.slot_suffix=%s %s", + avb_out_data->ab_suffix, avb_out_data->cmdline); + } + env_set("bootargs_sec", bootargs_sec); +#ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT + if(!is_recovery_mode) { + if(avb_out_data->cmdline != NULL && strstr(avb_out_data->cmdline, "root=")) + fastboot_setup_system_boot_args(avb_out_data->ab_suffix, false); + else + fastboot_setup_system_boot_args(avb_out_data->ab_suffix, true); + } +#endif /* CONFIG_SYSTEM_RAMDISK_SUPPORT */ + image_size = avb_loadpart->data_size; +#if defined (CONFIG_ARCH_IMX8) || defined (CONFIG_ARCH_IMX8M) + /* If we are using uncompressed kernel image, copy it directly to + * hdr->kernel_addr, if we are using compressed lz4 kernel image, + * we need to decompress the kernel image first. */ + if (image_arm64((void *)((ulong)hdr + hdr->page_size))) { + memcpy((void *)(long)hdr->kernel_addr, + (void *)((ulong)hdr + hdr->page_size), hdr->kernel_size); + } else { +#ifdef CONFIG_LZ4 + if (ulz4fn((void *)((ulong)hdr + hdr->page_size), + hdr->kernel_size, (void *)(ulong)hdr->kernel_addr, &lz4_len) != 0) { + printf("Decompress kernel fail!\n"); + goto fail; + } +#else /* CONFIG_LZ4 */ + printf("please enable CONFIG_LZ4 if we're using compressed lz4 kernel image!\n"); + goto fail; +#endif /* CONFIG_LZ4 */ + } +#else /* CONFIG_ARCH_IMX8 || CONFIG_ARCH_IMX8M */ + /* copy kernel image and boot header to hdr->kernel_addr - hdr->page_size */ + memcpy((void *)(ulong)(hdr->kernel_addr - hdr->page_size), (void *)hdr, + hdr->page_size + ALIGN(hdr->kernel_size, hdr->page_size)); +#endif /* CONFIG_ARCH_IMX8 || CONFIG_ARCH_IMX8M */ + } else if (lock_status == FASTBOOT_LOCK) { /* && verify fail */ + /* if in lock state, verify enforce fail */ + printf(" verify FAIL, state: LOCK\n"); + goto fail; + } else { /* lock_status == FASTBOOT_UNLOCK && get unacceptable verify fail */ + /* if in unlock state, log the verify state */ + printf(" verify FAIL, state: UNLOCK\n"); +#endif + /* if lock/unlock not enabled or verify fail + * in unlock state, will try boot */ + size_t num_read; + hdr = &boothdr; + + char bootimg[10]; + /* we don't have a/b slot for imx6 on normal Android*/ +#ifndef CONFIG_ANDROID_AB_SUPPORT + char *slot = ""; + if (!is_recovery_mode) { + sprintf(bootimg, "boot"); + } else { + sprintf(bootimg, "recovery"); + } + printf("boot '%s' still\n", bootimg); +#else + char *slot = select_slot(&fsl_avb_ab_ops); + if (slot == NULL) { + printf("boota: no bootable slot\n"); + goto fail; + } + sprintf(bootimg, "boot%s", slot); + printf(" boot '%s' still\n", bootimg); +#endif + /* maybe we should use bootctl to select a/b + * but libavb doesn't export a/b select */ + if (fsl_avb_ops.read_from_partition(&fsl_avb_ops, bootimg, + 0, sizeof(boothdr), hdr, &num_read) != AVB_IO_RESULT_OK && + num_read != sizeof(boothdr)) { + printf("boota: read bootimage head error\n"); + goto fail; + } + if (android_image_check_header(hdr)) { + printf("boota: bad boot image magic\n"); + goto fail; + } + image_size = android_image_get_end(hdr) - (ulong)hdr; +#if defined (CONFIG_ARCH_IMX8) || defined (CONFIG_ARCH_IMX8M) + boot_buf = malloc(image_size); + /* Load boot image */ + if (fsl_avb_ops.read_from_partition(&fsl_avb_ops, bootimg, + 0, image_size, boot_buf, &num_read) != AVB_IO_RESULT_OK + && num_read != image_size) { + printf("boota: read boot image error\n"); + goto fail; + } + /* If we are using uncompressed kernel image, copy it directly to + * hdr->kernel_addr, if we are using compressed lz4 kernel image, + * we need to decompress the kernel image first. */ + if (image_arm64((void *)((ulong)boot_buf + hdr->page_size))) { + memcpy((void *)(ulong)hdr->kernel_addr, + (void *)((ulong)boot_buf + hdr->page_size), hdr->kernel_size); + } else { +#ifdef CONFIG_LZ4 + if (ulz4fn((void *)((ulong)boot_buf + hdr->page_size), + hdr->kernel_size, (void *)(ulong)hdr->kernel_addr, &lz4_len) != 0) { + printf("Decompress kernel fail!\n"); + goto fail; + } +#else /* CONFIG_LZ4 */ + printf("please enable CONFIG_LZ4 if we're using compressed lz4 kernel image!\n"); + goto fail; +#endif /* CONFIG_LZ4 */ + } + hdr = (struct andr_img_hdr *)boot_buf; +#else /* CONFIG_ARCH_IMX8 || CONFIG_ARCH_IMX8M */ + if (fsl_avb_ops.read_from_partition(&fsl_avb_ops, bootimg, + 0, image_size, (void *)(ulong)(hdr->kernel_addr - hdr->page_size), &num_read) != AVB_IO_RESULT_OK + && num_read != image_size) { + printf("boota: read boot image error\n"); + goto fail; + } + hdr = (struct andr_img_hdr *)(ulong)(hdr->kernel_addr - hdr->page_size); +#endif /* CONFIG_ARCH_IMX8 || CONFIG_ARCH_IMX8M */ + char bootargs_sec[ANDR_BOOT_ARGS_SIZE]; + sprintf(bootargs_sec, + "androidboot.verifiedbootstate=orange androidboot.slot_suffix=%s", slot); + env_set("bootargs_sec", bootargs_sec); +#ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT + if(!is_recovery_mode) + fastboot_setup_system_boot_args(slot, true); +#endif /* CONFIG_SYSTEM_RAMDISK_SUPPORT */ +#ifdef CONFIG_FASTBOOT_LOCK + } +#endif + + flush_cache((ulong)load_addr, image_size); + check_image_arm64 = image_arm64((void *)(ulong)hdr->kernel_addr); +#ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT + if (is_recovery_mode) + memcpy((void *)(ulong)hdr->ramdisk_addr, (void *)(ulong)hdr + hdr->page_size + + ALIGN(hdr->kernel_size, hdr->page_size), hdr->ramdisk_size); +#else + memcpy((void *)(ulong)hdr->ramdisk_addr, (void *)(ulong)hdr + hdr->page_size + + ALIGN(hdr->kernel_size, hdr->page_size), hdr->ramdisk_size); +#endif +#ifdef CONFIG_OF_LIBFDT + /* load the dtb file */ + if (hdr->second_size && hdr->second_addr) { + memcpy((void *)(ulong)hdr->second_addr, (void *)(ulong)hdr + hdr->page_size + + ALIGN(hdr->kernel_size, hdr->page_size) + + ALIGN(hdr->ramdisk_size, hdr->page_size), hdr->second_size); + } +#endif /*CONFIG_OF_LIBFDT*/ + if (check_image_arm64) { + android_image_get_kernel(hdr, 0, NULL, NULL); + addr = hdr->kernel_addr; + } else { + addr = (ulong)(hdr->kernel_addr - hdr->page_size); + } + printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size); + printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size); +#ifdef CONFIG_OF_LIBFDT + if (hdr->second_size) + printf("fdt @ %08x (%d)\n", hdr->second_addr, hdr->second_size); +#endif /*CONFIG_OF_LIBFDT*/ + + char boot_addr_start[12]; + char ramdisk_addr[25]; + char fdt_addr[12]; + + char *boot_args[] = { NULL, boot_addr_start, ramdisk_addr, fdt_addr}; + if (check_image_arm64) + boot_args[0] = "booti"; + else + boot_args[0] = "bootm"; + + sprintf(boot_addr_start, "0x%lx", addr); + sprintf(ramdisk_addr, "0x%x:0x%x", hdr->ramdisk_addr, hdr->ramdisk_size); + sprintf(fdt_addr, "0x%x", hdr->second_addr); + +/* no need to pass ramdisk addr for normal boot mode when enable CONFIG_SYSTEM_RAMDISK_SUPPORT*/ +#ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT + if (!is_recovery_mode) + boot_args[2] = NULL; +#endif + if (avb_out_data != NULL) + avb_slot_verify_data_free(avb_out_data); + if (boot_buf != NULL) + free(boot_buf); + + if (check_image_arm64) { +#ifdef CONFIG_CMD_BOOTI + do_booti(NULL, 0, 4, boot_args); +#else + debug("please enable CONFIG_CMD_BOOTI when kernel are Image"); +#endif + } else { + do_bootm(NULL, 0, 4, boot_args); + } + + /* This only happens if image is somehow faulty so we start over */ + do_reset(NULL, 0, 0, NULL); + + return 1; + +fail: + /* avb has no recovery */ + if (avb_out_data != NULL) + avb_slot_verify_data_free(avb_out_data); + if (boot_buf != NULL) + free(boot_buf); + + return run_command("fastboot 0", 0); +} + +U_BOOT_CMD( + boota, 2, 1, do_boota, + "boota - boot android bootimg \n", + "boot from current mmc with avb verify\n" +); +#else /* CONFIG_AVB_SUPPORT */ +/* boota <addr> [ mmc0 | mmc1 [ <partition> ] ] */ +int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ulong addr = 0; + char *ptn = "boot"; + int mmcc = -1; + struct andr_img_hdr *hdr = &boothdr; + ulong image_size; + bool check_image_arm64 = false; + int i = 0; + + for (i = 0; i < argc; i++) + printf("%s ", argv[i]); + printf("\n"); + + if (argc < 2) + return -1; + + mmcc = simple_strtoul(argv[1]+3, NULL, 10); + + if (argc > 2) + ptn = argv[2]; + + if (mmcc != -1) { +#ifdef CONFIG_MMC + struct fastboot_ptentry *pte; + struct mmc *mmc; + disk_partition_t info; + struct blk_desc *dev_desc = NULL; + unsigned bootimg_sectors; + + memset((void *)&info, 0 , sizeof(disk_partition_t)); + /* i.MX use MBR as partition table, so this will have + to find the start block and length for the + partition name and register the fastboot pte we + define the partition number of each partition in + config file + */ + mmc = find_mmc_device(mmcc); + if (!mmc) { + printf("boota: cannot find '%d' mmc device\n", mmcc); + goto fail; + } + dev_desc = blk_get_dev("mmc", mmcc); + if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { + printf("** Block device MMC %d not supported\n", mmcc); + goto fail; + } + + /* below was i.MX mmc operation code */ + if (mmc_init(mmc)) { + printf("mmc%d init failed\n", mmcc); + goto fail; + } + + pte = fastboot_flash_find_ptn(ptn); + if (!pte) { + printf("boota: cannot find '%s' partition\n", ptn); + goto fail; + } + + if (blk_dread(dev_desc, pte->start, + 1, (void *)hdr) < 0) { + printf("boota: mmc failed to read bootimg header\n"); + goto fail; + } + + if (android_image_check_header(hdr)) { + printf("boota: bad boot image magic\n"); + goto fail; + } + + image_size = android_image_get_end(hdr) - (ulong)hdr; + bootimg_sectors = image_size/512; + + if (blk_dread(dev_desc, pte->start, + bootimg_sectors, + (void *)(hdr->kernel_addr - hdr->page_size)) < 0) { + printf("boota: mmc failed to read bootimage\n"); + goto fail; + } + check_image_arm64 = image_arm64((void *)hdr->kernel_addr); +#ifdef CONFIG_FASTBOOT_LOCK + int verifyresult = -1; +#endif + +#ifdef CONFIG_FASTBOOT_LOCK + int lock_status = fastboot_get_lock_stat(); + if (lock_status == FASTBOOT_LOCK_ERROR) { + printf("In boota get fastboot lock status error. Set lock status\n"); + fastboot_set_lock_stat(FASTBOOT_LOCK); + } + display_lock(fastboot_get_lock_stat(), verifyresult); +#endif + /* load the ramdisk file */ + memcpy((void *)hdr->ramdisk_addr, (void *)hdr->kernel_addr + + ALIGN(hdr->kernel_size, hdr->page_size), hdr->ramdisk_size); + +#ifdef CONFIG_OF_LIBFDT + /* load the dtb file */ + if (hdr->second_size && hdr->second_addr) { + memcpy((void *)hdr->second_addr, (void *)hdr->kernel_addr + + ALIGN(hdr->kernel_size, hdr->page_size) + + ALIGN(hdr->ramdisk_size, hdr->page_size), hdr->second_size); + } +#endif /*CONFIG_OF_LIBFDT*/ + +#else /*! CONFIG_MMC*/ + return -1; +#endif /*! CONFIG_MMC*/ + } else { + printf("boota: parameters is invalid. only support mmcX device\n"); + return -1; + } + + printf("kernel @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size); + printf("ramdisk @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size); +#ifdef CONFIG_OF_LIBFDT + if (hdr->second_size) + printf("fdt @ %08x (%d)\n", hdr->second_addr, hdr->second_size); +#endif /*CONFIG_OF_LIBFDT*/ + + + char boot_addr_start[12]; + char ramdisk_addr[25]; + char fdt_addr[12]; + char *boot_args[] = { NULL, boot_addr_start, ramdisk_addr, fdt_addr}; + if (check_image_arm64 ) { + addr = hdr->kernel_addr; + boot_args[0] = "booti"; + } else { + addr = hdr->kernel_addr - hdr->page_size; + boot_args[0] = "bootm"; + } + + sprintf(boot_addr_start, "0x%lx", addr); + sprintf(ramdisk_addr, "0x%x:0x%x", hdr->ramdisk_addr, hdr->ramdisk_size); + sprintf(fdt_addr, "0x%x", hdr->second_addr); + if (check_image_arm64) { + android_image_get_kernel(hdr, 0, NULL, NULL); +#ifdef CONFIG_CMD_BOOTI + do_booti(NULL, 0, 4, boot_args); +#else + debug("please enable CONFIG_CMD_BOOTI when kernel are Image"); +#endif + } else { + do_bootm(NULL, 0, 4, boot_args); + } + /* This only happens if image is somehow faulty so we start over */ + do_reset(NULL, 0, 0, NULL); + + return 1; + +fail: +#if defined(CONFIG_FSL_FASTBOOT) + return run_command("fastboot 0", 0); +#else /*! CONFIG_FSL_FASTBOOT*/ + return -1; +#endif /*! CONFIG_FSL_FASTBOOT*/ +} + +U_BOOT_CMD( + boota, 3, 1, do_boota, + "boota - boot android bootimg from memory\n", + "[<addr> | mmc0 | mmc1 | mmc2 | mmcX] [<partition>]\n " + "- boot application image stored in memory or mmc\n" + "\t'addr' should be the address of boot image " + "which is zImage+ramdisk.img\n" + "\t'mmcX' is the mmc device you store your boot.img, " + "which will read the boot.img from 1M offset('/boot' partition)\n" + "\t 'partition' (optional) is the partition id of your device, " + "if no partition give, will going to 'boot' partition\n" +); +#endif /* CONFIG_AVB_SUPPORT */ +#endif /* CONFIG_CMD_BOOTA */ +#endif + void fastboot_fail(const char *reason) { strncpy(fb_response_str, "FAIL\0", 5); @@ -165,6 +2210,24 @@ void fastboot_okay(const char *reason) strncat(fb_response_str, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); } +static void fastboot_fifo_complete(struct usb_ep *ep, struct usb_request *req) +{ + int status = req->status; + usb_req *request; + + if (!status) { + if (fastboot_func->front != NULL) { + request = fastboot_func->front; + fastboot_func->front = fastboot_func->front->next; + usb_ep_free_request(ep, request->in_req); + free(request); + } else { + printf("fail free request\n"); + } + return; + } +} + static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) { int status = req->status; @@ -226,6 +2289,7 @@ static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f) static void fastboot_disable(struct usb_function *f) { + usb_req *req; struct f_fastboot *f_fb = func_to_fastboot(f); usb_ep_disable(f_fb->out_ep); @@ -239,6 +2303,17 @@ static void fastboot_disable(struct usb_function *f) if (f_fb->in_req) { free(f_fb->in_req->buf); usb_ep_free_request(f_fb->in_ep, f_fb->in_req); + + /* disable usb request FIFO */ + while(f_fb->front != NULL) { + req = f_fb->front; + f_fb->front = f_fb->front->next; + free(req->in_req->buf); + usb_ep_free_request(f_fb->in_ep, req->in_req); + free(req); + } + + f_fb->rear = NULL; f_fb->in_req = NULL; } } @@ -302,8 +2377,19 @@ static int fastboot_set_alt(struct usb_function *f, ret = -EINVAL; goto err; } +#ifdef CONFIG_ANDROID_THINGS_SUPPORT + /* + * fastboot host end implement to get data in one bulk package so need + * large buffer for the "fastboot upload" and "fastboot get_staged". + */ + if (f_fb->in_req->buf) + free(f_fb->in_req->buf); + f_fb->in_req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, EP_BUFFER_SIZE * 32); +#endif f_fb->in_req->complete = fastboot_complete; + f_fb->front = f_fb->rear = NULL; + ret = usb_ep_queue(f_fb->out_ep, f_fb->out_req, 0); if (ret) goto err; @@ -340,13 +2426,56 @@ static int fastboot_add(struct usb_configuration *c) status = usb_add_function(c, &f_fb->usb_function); if (status) { free(f_fb); - fastboot_func = f_fb; + fastboot_func = NULL; } return status; } DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add); +static int fastboot_tx_write_more(const char *buffer) +{ + int ret = 0; + + /* alloc usb request FIFO node */ + usb_req *req = (usb_req *)malloc(sizeof(usb_req)); + if (!req) { + printf("failed alloc usb req!\n"); + return -ENOMEM; + } + + /* usb request node FIFO enquene */ + if ((fastboot_func->front == NULL) && (fastboot_func->rear == NULL)) { + fastboot_func->front = fastboot_func->rear = req; + req->next = NULL; + } else { + fastboot_func->rear->next = req; + fastboot_func->rear = req; + req->next = NULL; + } + + /* alloc in request for current node */ + req->in_req = fastboot_start_ep(fastboot_func->in_ep); + if (!req->in_req) { + printf("failed alloc req in\n"); + fastboot_disable(&(fastboot_func->usb_function)); + return -EINVAL; + } + req->in_req->complete = fastboot_fifo_complete; + + memcpy(req->in_req->buf, buffer, strlen(buffer)); + req->in_req->length = strlen(buffer); + + ret = usb_ep_queue(fastboot_func->in_ep, req->in_req, 0); + if (ret) { + printf("Error %d on queue\n", ret); + return -EINVAL; + } + + ret = 0; + return ret; +} + static int fastboot_tx_write(const char *buffer, unsigned int buffer_size) { struct usb_request *in_req = fastboot_func->in_req; @@ -398,6 +2527,608 @@ static int strcmp_l1(const char *s1, const char *s2) return strncmp(s1, s2, strlen(s1)); } +#ifdef CONFIG_FSL_FASTBOOT +static bool is_slotvar(char *cmd) +{ + assert(cmd != NULL); + if (!strcmp_l1("has-slot:", cmd) || + !strcmp_l1("slot-successful:", cmd) || + !strcmp_l1("slot-count", cmd) || + !strcmp_l1("slot-suffixes", cmd) || + !strcmp_l1("current-slot", cmd) || + !strcmp_l1("slot-unbootable:", cmd) || + !strcmp_l1("slot-retry-count:", cmd)) + return true; + return false; +} + +static char *get_serial(void) +{ +#ifdef CONFIG_SERIAL_TAG + struct tag_serialnr serialnr; + static char serial[32]; + get_board_serial(&serialnr); + sprintf(serial, "%08x%08x", serialnr.high, serialnr.low); + return serial; +#else + return NULL; +#endif +} + +#if !defined(PRODUCT_NAME) +#define PRODUCT_NAME "NXP i.MX" +#endif + +#if !defined(VARIANT_NAME) +#define VARIANT_NAME "NXP i.MX" +#endif + +static int get_block_size(void) { + int mmc_no = 0; + struct blk_desc *dev_desc; + mmc_no = fastboot_devinfo.dev_id; + dev_desc = blk_get_dev("mmc", mmc_no); + if (NULL == dev_desc) { + printf("** Block device MMC %d not supported\n", + mmc_no); + return 0; + } + return dev_desc->blksz; +} + +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"*/ +static int get_partition_base_name(char (*partition_base_name)[16]) +{ + int n = 0; + int count = 0; + char *ptr1, *ptr2; + char buffer[16]; + + 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; +} + +static bool 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; +} + +static int get_single_var(char *cmd, char *response) +{ + char *str = cmd; + size_t chars_left; + const char *s; + struct mmc *mmc; + int mmc_dev_no; + int blksz; + + chars_left = FASTBOOT_RESPONSE_LEN - strlen(response) - 1; + + if ((str = strstr(cmd, "partition-size:"))) { + str +=strlen("partition-size:"); + struct fastboot_ptentry* fb_part; + fb_part = fastboot_flash_find_ptn(str); + if (!fb_part) { + strncat(response, "Wrong partition name.", chars_left); + return -1; + } else { + snprintf(response + strlen(response), chars_left, "0x%x", fb_part->length * get_block_size()); + } + } else if ((str = strstr(cmd, "partition-type:"))) { + str +=strlen("partition-type:"); + struct fastboot_ptentry* fb_part; + fb_part = fastboot_flash_find_ptn(str); + if (!fb_part) { + strncat(response, "Wrong partition name.", chars_left); + return -1; + } else { + strncat(response, fb_part->fstype, chars_left); + } + } else if (!strcmp_l1("version-baseband", cmd)) { + strncat(response, "N/A", chars_left); + } else if (!strcmp_l1("version-bootloader", cmd) || + !strcmp_l1("bootloader-version", cmd)) { + strncat(response, U_BOOT_VERSION, chars_left); + } else if (!strcmp_l1("version", cmd)) { + strncat(response, FASTBOOT_VERSION, chars_left); + } else if (!strcmp_l1("battery-voltage", cmd)) { + strncat(response, "0mV", chars_left); + } else if (!strcmp_l1("battery-soc-ok", cmd)) { + strncat(response, "yes", chars_left); + } else if (!strcmp_l1("variant", cmd)) { + strncat(response, VARIANT_NAME, chars_left); + } else if (!strcmp_l1("off-mode-charge", cmd)) { + strncat(response, "1", chars_left); + } else if (!strcmp_l1("downloadsize", cmd) || + !strcmp_l1("max-download-size", cmd)) { + + snprintf(response + strlen(response), chars_left, "0x%x", CONFIG_FASTBOOT_BUF_SIZE); + } else if (!strcmp_l1("erase-block-size", cmd)) { + mmc_dev_no = mmc_get_env_dev(); + mmc = find_mmc_device(mmc_dev_no); + blksz = get_block_size(); + snprintf(response + strlen(response), chars_left, "0x%x", + (blksz * mmc->erase_grp_size)); + } else if (!strcmp_l1("logical-block-size", cmd)) { + blksz = get_block_size(); + snprintf(response + strlen(response), chars_left, "0x%x", blksz); + } else if (!strcmp_l1("serialno", cmd)) { + s = get_serial(); + if (s) + strncat(response, s, chars_left); + else { + strncat(response, "FAILValue not set", chars_left); + return -1; + } + } else if (!strcmp_l1("product", cmd)) { + strncat(response, PRODUCT_NAME, chars_left); + } +#ifdef CONFIG_FASTBOOT_LOCK + else if (!strcmp_l1("secure", cmd)) { + strncat(response, FASTBOOT_VAR_YES, chars_left); + } else if (!strcmp_l1("unlocked",cmd)){ + int status = fastboot_get_lock_stat(); + if (status == FASTBOOT_UNLOCK) { + strncat(response, FASTBOOT_VAR_YES, chars_left); + } else { + strncat(response, FASTBOOT_VAR_NO, chars_left); + } + } +#else + else if (!strcmp_l1("secure", cmd)) { + strncat(response, FASTBOOT_VAR_NO, chars_left); + } else if (!strcmp_l1("unlocked",cmd)) { + strncat(response, FASTBOOT_VAR_NO, chars_left); + } +#endif + else if (is_slotvar(cmd)) { +#ifdef CONFIG_AVB_SUPPORT + if (get_slotvar_avb(&fsl_avb_ab_ops, cmd, + response + strlen(response), chars_left + 1) < 0) + return -1; +#else + strncat(response, FASTBOOT_VAR_NO, chars_left); +#endif + } + else { + char envstr[32]; + + snprintf(envstr, sizeof(envstr) - 1, "fastboot.%s", cmd); + s = env_get(envstr); + if (s) { + strncat(response, s, chars_left); + } else { + sprintf(response,"FAILunknow variable:%s",cmd); + printf("WARNING: unknown variable: %s\n", cmd); + return -1; + } + } + return 0; +} + +static void cb_getvar(struct usb_ep *ep, struct usb_request *req) +{ + int n = 0; + int status = 0; + int count = 0; + char *cmd = req->buf; + char var_name[FASTBOOT_RESPONSE_LEN - 1]; + char partition_base_name[MAX_PTN][16]; + char slot_suffix[2][5] = {"a","b"}; + char response[FASTBOOT_RESPONSE_LEN - 1]; + + strsep(&cmd, ":"); + if (!cmd) { + pr_err("missing variable"); + fastboot_tx_write_str("FAILmissing var"); + return; + } + + if (!strcmp_l1("all", cmd)) { + + memset(response, '\0', FASTBOOT_RESPONSE_LEN - 1); + + + /* get common variables */ + for (n = 0; n < FASTBOOT_COMMON_VAR_NUM; n++) { + snprintf(response, sizeof(response), "INFO%s:", fastboot_common_var[n]); + get_single_var(fastboot_common_var[n], response); + fastboot_tx_write_more(response); + } + + /* get partition type */ + for (n = 0; n < g_pcount; n++) { + snprintf(response, sizeof(response), "INFOpartition-type:%s:", g_ptable[n].name); + snprintf(var_name, sizeof(var_name), "partition-type:%s", g_ptable[n].name); + get_single_var(var_name, response); + fastboot_tx_write_more(response); + } + /* get partition size */ + for (n = 0; n < g_pcount; n++) { + snprintf(response, sizeof(response), "INFOpartition-size:%s:", g_ptable[n].name); + snprintf(var_name, sizeof(var_name), "partition-size:%s", g_ptable[n].name); + get_single_var(var_name,response); + fastboot_tx_write_more(response); + } + /* slot related variables */ + if (is_slot()) { + /* get has-slot variables */ + count = get_partition_base_name(partition_base_name); + for (n = 0; n < count; n++) { + snprintf(response, sizeof(response), "INFOhas-slot:%s:", partition_base_name[n]); + snprintf(var_name, sizeof(var_name), "has-slot:%s", partition_base_name[n]); + get_single_var(var_name,response); + fastboot_tx_write_more(response); + } + /* get current slot */ + strncpy(response, "INFOcurrent-slot:", sizeof(response)); + get_single_var("current-slot", response); + fastboot_tx_write_more(response); + /* get slot count */ + strncpy(response, "INFOslot-count:", sizeof(response)); + get_single_var("slot-count", response); + fastboot_tx_write_more(response); + /* get slot-successful variable */ + for (n = 0; n < 2; n++) { + snprintf(response, sizeof(response), "INFOslot-successful:%s:", slot_suffix[n]); + snprintf(var_name, sizeof(var_name), "slot-successful:%s", slot_suffix[n]); + get_single_var(var_name, response); + fastboot_tx_write_more(response); + } + /*get slot-unbootable variable*/ + for (n = 0; n < 2; n++) { + snprintf(response, sizeof(response), "INFOslot-unbootable:%s:", slot_suffix[n]); + snprintf(var_name, sizeof(var_name), "slot-unbootable:%s", slot_suffix[n]); + get_single_var(var_name, response); + fastboot_tx_write_more(response); + } + /*get slot-retry-count variable*/ + for (n = 0; n < 2; n++) { + snprintf(response, sizeof(response), "INFOslot-retry-count:%s:", slot_suffix[n]); + snprintf(var_name, sizeof(var_name), "slot-retry-count:%s", slot_suffix[n]); + get_single_var(var_name, response); + fastboot_tx_write_more(response); + } + } + + strncpy(response, "OKAYDone!", 10); + fastboot_tx_write_more(response); + + return; + } else { + + strncpy(response, "OKAY", 5); + status = get_single_var(cmd, response); + if (status != 0) { + strncpy(response, "FAIL", 5); + } + fastboot_tx_write_str(response); + return; + } +} + +#ifdef CONFIG_FASTBOOT_LOCK + +int do_lock_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + FbLockState status = fastboot_get_lock_stat(); + if (status != FASTBOOT_LOCK_ERROR) { + if (status == FASTBOOT_LOCK) + printf("fastboot lock status: locked.\n"); + else + printf("fastboot lock status: unlocked.\n"); + } else + printf("fastboot lock status error!\n"); + + display_lock(status, -1); + + return 0; + +} + +U_BOOT_CMD( + lock_status, 2, 1, do_lock_status, + "lock_status", + "lock_status"); + +static FbLockState do_fastboot_unlock(bool force) +{ + int status; + if (force) + set_fastboot_lock_disable(); + if ((fastboot_lock_enable() == FASTBOOT_UL_ENABLE) || force) { + printf("It is able to unlock device. %d\n",fastboot_lock_enable()); + if (fastboot_get_lock_stat() == FASTBOOT_UNLOCK) { + printf("The device is already unlocked\n"); + return FASTBOOT_UNLOCK; + } + status = fastboot_set_lock_stat(FASTBOOT_UNLOCK); + if (status < 0) + return FASTBOOT_LOCK_ERROR; + + printf("Start /data wipe process....\n"); + fastboot_wipe_data_partition(); + printf("Wipe /data completed.\n"); + +#ifdef CONFIG_AVB_SUPPORT + printf("Start stored_rollback_index wipe process....\n"); + rbkidx_erase(); + printf("Wipe stored_rollback_index completed.\n"); +#endif + } else { + printf("It is not able to unlock device."); + return FASTBOOT_LOCK_ERROR; + } + + return FASTBOOT_UNLOCK; +} + +static FbLockState do_fastboot_lock(void) +{ + int status; + if (fastboot_get_lock_stat() == FASTBOOT_LOCK) { + printf("The device is already locked\n"); + return FASTBOOT_LOCK; + } + status = fastboot_set_lock_stat(FASTBOOT_LOCK); + if (status < 0) + return FASTBOOT_LOCK_ERROR; + + printf("Start /data wipe process....\n"); + fastboot_wipe_data_partition(); + printf("Wipe /data completed.\n"); + + return FASTBOOT_LOCK; +} + +static void cb_flashing(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; + char response[FASTBOOT_RESPONSE_LEN]; + unsigned char len = strlen(cmd); + FbLockState status; + FbLockEnableResult result; + +#ifdef CONFIG_ANDROID_THINGS_SUPPORT + if (!strncmp(cmd + len - strlen(FASTBOOT_BOOTLOADER_VBOOT_KEY), + FASTBOOT_BOOTLOADER_VBOOT_KEY, + strlen(FASTBOOT_BOOTLOADER_VBOOT_KEY))) { + strcpy(response, "OKAY"); + } else if (!strncmp(cmd + len - strlen("unlock_critical"), + "unlock_critical", strlen("unlock_critical"))) { +#else + if (!strncmp(cmd + len - strlen("unlock_critical"), + "unlock_critical", strlen("unlock_critical"))) { +#endif + strcpy(response, "OKAY"); + } else if (!strncmp(cmd + len - strlen("lock_critical"), + "lock_critical", strlen("lock_critical"))) { + strcpy(response, "OKAY"); + } else if (!strncmp(cmd + len - strlen("unlock"), + "unlock", strlen("unlock"))) { + printf("flashing unlock.\n"); + status = do_fastboot_unlock(false); + if (status != FASTBOOT_LOCK_ERROR) + strcpy(response, "OKAY"); + else + strcpy(response, "FAIL unlock device failed."); + } else if (!strncmp(cmd + len - strlen("lock"), "lock", strlen("lock"))) { + printf("flashing lock.\n"); + status = do_fastboot_lock(); + if (status != FASTBOOT_LOCK_ERROR) + strcpy(response, "OKAY"); + else + strcpy(response, "FAIL lock device failed."); + } else if (!strncmp(cmd + len - strlen("get_unlock_ability"), + "get_unlock_ability", strlen("get_unlock_ability"))) { + result = fastboot_lock_enable(); + if (result == FASTBOOT_UL_ENABLE) { + fastboot_tx_write_more("INFO1"); + strcpy(response, "OKAY"); + } else if (result == FASTBOOT_UL_DISABLE) { + fastboot_tx_write_more("INFO0"); + strcpy(response, "OKAY"); + } else { + printf("flashing get_unlock_ability fail!\n"); + strcpy(response, "FAIL get unlock ability failed."); + } + } else { + printf("Unknown flashing command:%s\n", cmd); + strcpy(response, "FAIL command not defined"); + } + fastboot_tx_write_more(response); +} + +static int partition_table_valid(void) +{ + int status, mmc_no; + struct blk_desc *dev_desc; + disk_partition_t info; + mmc_no = fastboot_devinfo.dev_id; + dev_desc = blk_get_dev("mmc", mmc_no); + if (dev_desc) + status = part_get_info(dev_desc, 1, &info); + else + status = -1; + return (status == 0); +} + +#endif /* CONFIG_FASTBOOT_LOCK */ + +#ifdef CONFIG_FASTBOOT_FLASH +static void cb_flash(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; + char response[FASTBOOT_RESPONSE_LEN]; + + strsep(&cmd, ":"); + if (!cmd) { + pr_err("missing partition name"); + fastboot_tx_write_str("FAILmissing partition name"); + return; + } + + /* initialize the response buffer */ + fb_response_str = response; + +#ifdef CONFIG_FASTBOOT_LOCK + int status; + status = fastboot_get_lock_stat(); + + if (status == FASTBOOT_LOCK) { + pr_err("device is LOCKed!\n"); + strcpy(response, "FAIL device is locked."); + fastboot_tx_write_str(response); + return; + + } else if (status == FASTBOOT_LOCK_ERROR) { + pr_err("write lock status into device!\n"); + fastboot_set_lock_stat(FASTBOOT_LOCK); + strcpy(response, "FAIL device is locked."); + fastboot_tx_write_str(response); + return; + } +#endif + fastboot_fail("no flash device defined"); + +#ifdef CONFIG_FASTBOOT_LOCK + int gpt_valid_pre = 0; + int gpt_valid_pst = 0; + if (strncmp(cmd, "gpt", 3) == 0) + gpt_valid_pre = partition_table_valid(); +#endif + rx_process_flash(cmd); +#ifdef CONFIG_FASTBOOT_LOCK + if (strncmp(cmd, "gpt", 3) == 0) { + gpt_valid_pst = partition_table_valid(); + /* If gpt is valid, load partitons table into memory. + So if the next command is "fastboot reboot bootloader", + it can find the "misc" partition to r/w. */ + if(gpt_valid_pst) + _fastboot_load_partitions(); + /* If gpt invalid -> valid, write unlock status, also wipe data. */ + if ((gpt_valid_pre == 0) && (gpt_valid_pst == 1)) + do_fastboot_unlock(true); + } + +#endif + fastboot_tx_write_str(response); +} +#endif + +#ifdef CONFIG_FASTBOOT_FLASH +static void cb_erase(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; + char response[FASTBOOT_RESPONSE_LEN]; + + strsep(&cmd, ":"); + if (!cmd) { + pr_err("missing partition name"); + fastboot_tx_write_str("FAILmissing partition name"); + return; + } + + /* initialize the response buffer */ + fb_response_str = response; + +#ifdef CONFIG_FASTBOOT_LOCK + FbLockState status; + status = fastboot_get_lock_stat(); + if (status == FASTBOOT_LOCK) { + pr_err("device is LOCKed!\n"); + strcpy(response, "FAIL device is locked."); + fastboot_tx_write_str(response); + return; + } else if (status == FASTBOOT_LOCK_ERROR) { + pr_err("write lock status into device!\n"); + fastboot_set_lock_stat(FASTBOOT_LOCK); + strcpy(response, "FAIL device is locked."); + fastboot_tx_write_str(response); + return; + } +#endif + rx_process_erase(cmd, response); + fastboot_tx_write_str(response); +} +#endif + +#ifdef CONFIG_AVB_SUPPORT +static void cb_set_active_avb(struct usb_ep *ep, struct usb_request *req) +{ + AvbIOResult ret; + int slot = 0; + char *cmd = req->buf; + + strsep(&cmd, ":"); + if (!cmd) { + pr_err("missing slot suffix\n"); + fastboot_tx_write_str("FAILmissing slot suffix"); + return; + } + + slot = slotidx_from_suffix(cmd); + + if (slot < 0) { + fastboot_tx_write_str("FAILerr slot suffix"); + return; + } + + ret = avb_ab_mark_slot_active(&fsl_avb_ab_ops, slot); + if (ret != AVB_IO_RESULT_OK) + fastboot_tx_write_str("avb IO error"); + else + fastboot_tx_write_str("OKAY"); + + return; +} +#endif /*CONFIG_AVB_SUPPORT*/ + +static void cb_reboot_bootloader(struct usb_ep *ep, struct usb_request *req) +{ + fastboot_tx_write_str("OKAY"); + + udelay(1000000); + enable_fastboot_command(); + do_reset(NULL, 0, 0, NULL); +} + +#else /* CONFIG_FSL_FASTBOOT */ + static void cb_getvar(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; @@ -454,6 +3185,87 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) fastboot_tx_write_str(response); } +#ifdef CONFIG_FASTBOOT_FLASH +static void cb_flash(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; + char response[FASTBOOT_RESPONSE_LEN]; + + strsep(&cmd, ":"); + if (!cmd) { + pr_err("missing partition name"); + fastboot_tx_write_str("FAILmissing partition name"); + return; + } + + /* initialize the response buffer */ + fb_response_str = response; + + fastboot_fail("no flash device defined"); +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV + fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, + download_bytes); +#endif +#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV + fb_nand_flash_write(cmd, + (void *)CONFIG_FASTBOOT_BUF_ADDR, + download_bytes); +#endif + fastboot_tx_write_str(response); +} +#endif + +static void cb_oem(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV + if (strncmp("format", cmd + 4, 6) == 0) { + char cmdbuf[32]; + sprintf(cmdbuf, "gpt write mmc %x $partitions", + CONFIG_FASTBOOT_FLASH_MMC_DEV); + if (run_command(cmdbuf, 0)) + fastboot_tx_write_str("FAIL"); + else + fastboot_tx_write_str("OKAY"); + } else +#endif + if (strncmp("unlock", cmd + 4, 8) == 0) { + fastboot_tx_write_str("FAILnot implemented"); + } + else { + fastboot_tx_write_str("FAILunknown oem command"); + } +} + +#ifdef CONFIG_FASTBOOT_FLASH +static void cb_erase(struct usb_ep *ep, struct usb_request *req) +{ + char *cmd = req->buf; + char response[FASTBOOT_RESPONSE_LEN]; + + strsep(&cmd, ":"); + if (!cmd) { + pr_err("missing partition name"); + fastboot_tx_write_str("FAILmissing partition name"); + return; + } + + /* initialize the response buffer */ + fb_response_str = response; + + fastboot_fail("no flash device defined"); +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV + fb_mmc_erase(cmd); +#endif +#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV + fb_nand_erase(cmd); +#endif + fastboot_tx_write_str(response); +} +#endif + +#endif /* CONFIG_FSL_FASTBOOT*/ + static unsigned int rx_bytes_expected(struct usb_ep *ep) { int rx_remain = download_size - download_bytes; @@ -530,6 +3342,26 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req, 0); } +static void cb_upload(struct usb_ep *ep, struct usb_request *req) +{ + char response[FASTBOOT_RESPONSE_LEN]; + + if (!download_bytes || download_bytes > (EP_BUFFER_SIZE * 32)) { + sprintf(response, "FAIL"); + fastboot_tx_write_str(response); + return; + } + + printf("Will upload %d bytes.\n", download_bytes); + snprintf(response, FASTBOOT_RESPONSE_LEN, "DATA%08x", download_bytes); + fastboot_tx_write_more(response); + + fastboot_tx_write((const char *)(interface.transfer_buffer), download_bytes); + + snprintf(response,FASTBOOT_RESPONSE_LEN, "OKAY"); + fastboot_tx_write_more(response); +} + static void cb_download(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; @@ -557,11 +3389,16 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req) static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) { char boot_addr_start[12]; +#ifdef CONFIG_FSL_FASTBOOT + char *bootm_args[] = { "boota", boot_addr_start, NULL }; + sprintf(boot_addr_start, "0x%lx", load_addr); +#else char *bootm_args[] = { "bootm", boot_addr_start, NULL }; + sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR); +#endif puts("Booting kernel..\n"); - sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR); do_bootm(NULL, 0, 2, bootm_args); /* This only happens if image is somehow faulty so we start over */ @@ -585,91 +3422,38 @@ static void cb_continue(struct usb_ep *ep, struct usb_request *req) fastboot_tx_write_str("OKAY"); } -#ifdef CONFIG_FASTBOOT_FLASH -static void cb_flash(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing partition name"); - fastboot_tx_write_str("FAILmissing partition name"); - return; - } - - /* initialize the response buffer */ - fb_response_str = response; - - fastboot_fail("no flash device defined"); -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV - fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes); -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV - fb_nand_flash_write(cmd, - (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes); -#endif - fastboot_tx_write_str(response); -} -#endif - -static void cb_oem(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV - if (strncmp("format", cmd + 4, 6) == 0) { - char cmdbuf[32]; - sprintf(cmdbuf, "gpt write mmc %x $partitions", - CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (run_command(cmdbuf, 0)) - fastboot_tx_write_str("FAIL"); - else - fastboot_tx_write_str("OKAY"); - } else -#endif - if (strncmp("unlock", cmd + 4, 8) == 0) { - fastboot_tx_write_str("FAILnot implemented"); - } - else { - fastboot_tx_write_str("FAILunknown oem command"); - } -} - -#ifdef CONFIG_FASTBOOT_FLASH -static void cb_erase(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing partition name"); - fastboot_tx_write_str("FAILmissing partition name"); - return; - } - - /* initialize the response buffer */ - fb_response_str = response; - - fastboot_fail("no flash device defined"); -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV - fb_mmc_erase(cmd); -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV - fb_nand_erase(cmd); -#endif - fastboot_tx_write_str(response); -} -#endif - struct cmd_dispatch_info { char *cmd; void (*cb)(struct usb_ep *ep, struct usb_request *req); }; static const struct cmd_dispatch_info cmd_dispatch_info[] = { +#ifdef CONFIG_FSL_FASTBOOT + { + .cmd = "reboot-bootloader", + .cb = cb_reboot_bootloader, + }, + { + .cmd = "upload", + .cb = cb_upload, + }, +#ifdef CONFIG_FASTBOOT_LOCK + { + .cmd = "flashing", + .cb = cb_flashing, + }, + { + .cmd = "oem", + .cb = cb_flashing, + }, +#endif +#ifdef CONFIG_AVB_SUPPORT + { + .cmd = "set_active", + .cb = cb_set_active_avb, + }, +#endif +#endif { .cmd = "reboot", .cb = cb_reboot, @@ -695,10 +3479,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { .cb = cb_erase, }, #endif +#ifndef CONFIG_FSL_FASTBOOT { .cmd = "oem", .cb = cb_oem, }, +#endif }; static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) @@ -707,6 +3493,10 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; int i; + /* init in request FIFO pointer */ + fastboot_func->front = NULL; + fastboot_func->rear = NULL; + if (req->status != 0 || req->length == 0) return; diff --git a/drivers/usb/gadget/fastboot_lock_unlock.c b/drivers/usb/gadget/fastboot_lock_unlock.c new file mode 100644 index 00000000000..230f892f672 --- /dev/null +++ b/drivers/usb/gadget/fastboot_lock_unlock.c @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <common.h> +#include <mapmem.h> +#include <linux/types.h> +#include <part.h> +#include <mmc.h> +#include <ext_common.h> +#include <stdio_dev.h> +#include <stdlib.h> +#include "fastboot_lock_unlock.h" +#include <fsl_fastboot.h> + +#ifdef FASTBOOT_ENCRYPT_LOCK + +#include <hash.h> +#include <fsl_caam.h> + +//Encrypted data is 80bytes length. +#define ENDATA_LEN 80 + +#endif + +int fastboot_flash_find_index(const char *name); + +#ifndef FASTBOOT_ENCRYPT_LOCK + +/* + * This will return FASTBOOT_LOCK, FASTBOOT_UNLOCK or FASTBOOT_ERROR + */ +static FbLockState decrypt_lock_store(unsigned char* bdata) { + if (!strncmp((const char *)bdata, "locked", strlen("locked"))) + return FASTBOOT_LOCK; + else if (!strncmp((const char *)bdata, "unlocked", strlen("unlocked"))) + return FASTBOOT_UNLOCK; + else + return FASTBOOT_LOCK_ERROR; +} + +static inline int encrypt_lock_store(FbLockState lock, unsigned char* bdata) { + if (FASTBOOT_LOCK == lock) + strncpy((char *)bdata, "locked", strlen("locked")); + else if (FASTBOOT_UNLOCK == lock) + strncpy((char *)bdata, "unlocked", strlen("unlocked")); + else + return -1; + return 0; +} +#else + +static int sha1sum(unsigned char* data, int len, unsigned char* output) { + struct hash_algo *algo; + void *buf; + if (hash_lookup_algo("sha1", &algo)) { + printf("error in lookup sha1 algo!\n"); + return -1; + } + buf = map_sysmem((ulong)data, len); + algo->hash_func_ws(buf, len, output, algo->chunk_size); + unmap_sysmem(buf); + + return algo->digest_size; + +} + +static int generate_salt(unsigned char* salt) { + unsigned long time = get_timer(0); + return sha1sum((unsigned char *)&time, sizeof(unsigned long), salt); + +} + +static FbLockState decrypt_lock_store(unsigned char *bdata) { + unsigned char plain_data[ENDATA_LEN]; + int p = 0, ret; + + caam_open(); + ret = caam_decap_blob((uint32_t)plain_data, + (uint32_t)bdata + ENDATA_LEN, ENDATA_LEN); + if (ret != 0) { + printf("Error during blob decap operation: 0x%x\n",ret); + return FASTBOOT_LOCK_ERROR; + } +#ifdef FASTBOOT_LOCK_DEBUG + FB_DEBUG("Decrypt data block are:\n \t=======\t\n"); + for (p = 0; p < ENDATA_LEN; p++) { + FB_DEBUG("0x%2x ", *(bdata + p)); + if (p % 16 == 0) + FB_DEBUG("\n"); + } + FB_DEBUG("\n \t========\t\n"); + for (p = ENDATA_LEN; p < (ENDATA_LEN + ENDATA_LEN + 48 ); p++) { + FB_DEBUG("0x%2x ", *(bdata + p)); + if (p % 16 == 0) + FB_DEBUG("\n"); + } + + FB_DEBUG("\n plain text are:\n"); + for (p = 0; p < ENDATA_LEN; p++) { + FB_DEBUG("0x%2x ", plain_data[p]); + if (p % 16 == 0) + FB_DEBUG("\n"); + } + FB_DEBUG("\n"); +#endif + + for (p = 0; p < ENDATA_LEN-1; p++) { + if (*(bdata+p) != plain_data[p]) { + FB_DEBUG("Verify salt in decrypt error on pointer %d\n", p); + return FASTBOOT_LOCK_ERROR; + } + } + + if (plain_data[ENDATA_LEN - 1] >= FASTBOOT_LOCK_NUM) + return FASTBOOT_LOCK_ERROR; + else + return plain_data[ENDATA_LEN-1]; +} + +static int encrypt_lock_store(FbLockState lock, unsigned char* bdata) { + unsigned int p = 0; + int ret; + int salt_len = generate_salt(bdata); + if (salt_len < 0) + return -1; + + //salt_len cannot be longer than endata block size. + if (salt_len >= ENDATA_LEN) + salt_len = ENDATA_LEN - 1; + + p = ENDATA_LEN - 1; + + //Set lock value + *(bdata + p) = lock; + + caam_open(); + ret = caam_gen_blob((uint32_t)bdata, (uint32_t)(bdata + ENDATA_LEN), ENDATA_LEN); + if (ret != 0) { + printf("error in caam_gen_blob:0x%x\n", ret); + return -1; + } + + +#ifdef FASTBOOT_LOCK_DEBUG + int i = 0; + FB_DEBUG("encrypt plain_text:\n"); + for (i = 0; i < ENDATA_LEN; i++) { + FB_DEBUG("0x%2x\t", *(bdata+i)); + if (i % 16 == 0) + printf("\n"); + } + printf("\nto:\n"); + for (i=0; i < ENDATA_LEN + 48; i++) { + FB_DEBUG("0x%2x\t", *(bdata + ENDATA_LEN + i)); + if (i % 16 == 0) + printf("\n"); + } + printf("\n"); + +#endif + //protect value + *(bdata + p) = 0xff; + return 0; +} + +#endif + +static char mmc_dev_part[16]; +static char* get_mmc_part(int part) { + u32 dev_no = mmc_get_env_dev(); + sprintf(mmc_dev_part,"%x:%x",dev_no, part); + return mmc_dev_part; +} + +static inline void set_lock_disable_data(unsigned char* bdata) { + *(bdata + SECTOR_SIZE -1) = 0; +} + +/* + * The enabling value is stored in the last byte of target partition. + */ +static inline unsigned char lock_enable_parse(unsigned char* bdata) { + FB_DEBUG("lock_enable_parse: 0x%x\n", *(bdata + SECTOR_SIZE -1)); + if (*(bdata + SECTOR_SIZE -1) >= FASTBOOT_UL_NUM) + return FASTBOOT_UL_ERROR; + else + return *(bdata + SECTOR_SIZE -1); +} + +static FbLockState g_lockstat = FASTBOOT_UNLOCK; +/* + * Set status of the lock&unlock to FSL_FASTBOOT_FB_PART + * Currently use the very first Byte of FSL_FASTBOOT_FB_PART + * to store the fastboot lock&unlock status + */ +int fastboot_set_lock_stat(FbLockState lock) { + struct blk_desc *fs_dev_desc; + disk_partition_t fs_partition; + unsigned char *bdata; + int mmc_id; + int status, ret; + + bdata = (unsigned char *)memalign(ALIGN_BYTES, SECTOR_SIZE); + if (bdata == NULL) + goto fail2; + memset(bdata, 0, SECTOR_SIZE); + + mmc_id = fastboot_flash_find_index(FASTBOOT_PARTITION_FBMISC); + if (mmc_id < 0) { + printf("%s: error in get mmc part\n", __FUNCTION__); + ret = -1; + goto fail; + } + status = blk_get_device_part_str(FSL_FASTBOOT_FB_DEV, + get_mmc_part(mmc_id), + &fs_dev_desc, &fs_partition, 1); + if (status < 0) { + printf("%s:error in getdevice partition.\n", __FUNCTION__); + ret = -1; + goto fail; + } + + status = encrypt_lock_store(lock, bdata); + if (status < 0) { + ret = -1; + goto fail; + } + status = blk_dwrite(fs_dev_desc, fs_partition.start, 1, bdata); + if (!status) { + printf("%s:error in block write.\n", __FUNCTION__); + ret = -1; + goto fail; + } + ret = 0; +fail: + free(bdata); + return ret; +fail2: + g_lockstat = lock; + return 0; +} + +FbLockState fastboot_get_lock_stat(void) { + struct blk_desc *fs_dev_desc; + disk_partition_t fs_partition; + unsigned char *bdata; + int mmc_id; + FbLockState ret; + + bdata = (unsigned char *)memalign(ALIGN_BYTES, SECTOR_SIZE); + if (bdata == NULL) + return g_lockstat; + + int status; + mmc_id = fastboot_flash_find_index(FASTBOOT_PARTITION_FBMISC); + if (mmc_id < 0) { + printf("%s: error in get mmc part\n", __FUNCTION__); + ret = g_lockstat; + goto fail; + } + status = blk_get_device_part_str(FSL_FASTBOOT_FB_DEV, + get_mmc_part(mmc_id), + &fs_dev_desc, &fs_partition, 1); + + if (status < 0) { + printf("%s:error in getdevice partition.\n", __FUNCTION__); + ret = g_lockstat; + goto fail; + } + + status = blk_dread(fs_dev_desc, fs_partition.start, 1, bdata); + if (!status) { + printf("%s:error in block read.\n", __FUNCTION__); + ret = FASTBOOT_LOCK_ERROR; + goto fail; + } + + ret = decrypt_lock_store(bdata); +fail: + free(bdata); + return ret; +} + + +/* Return the last byte of of FSL_FASTBOOT_PR_DATA + * which is managed by PresistDataService + */ + +#ifdef CONFIG_ENABLE_LOCKSTATUS_SUPPORT +//Brillo has no presist data partition +FbLockEnableResult fastboot_lock_enable(void) { + return FASTBOOT_UL_ENABLE; +} +void set_fastboot_lock_disable(void) { +} +#else +void set_fastboot_lock_disable(void) { + struct blk_desc *fs_dev_desc; + disk_partition_t fs_partition; + unsigned char *bdata; + int mmc_id; + + bdata = (unsigned char *)memalign(ALIGN_BYTES, SECTOR_SIZE); + if (bdata == NULL) + return; + set_lock_disable_data(bdata); + int status; + mmc_id = fastboot_flash_find_index(FASTBOOT_PARTITION_PRDATA); + if (mmc_id < 0) { + printf("%s: error in get mmc part\n", __FUNCTION__); + goto fail; + } + status = blk_get_device_part_str(FSL_FASTBOOT_FB_DEV, + get_mmc_part(mmc_id), + &fs_dev_desc, &fs_partition, 1); + if (status < 0) { + printf("%s:error in getdevice partition.\n", __FUNCTION__); + goto fail; + } + + lbaint_t target_block = fs_partition.start + fs_partition.size - 1; + status = blk_dwrite(fs_dev_desc, target_block, 1, bdata); + if (!status) { + printf("%s: error in block read\n", __FUNCTION__); + goto fail; + } + +fail: + free(bdata); + return; + +} +FbLockEnableResult fastboot_lock_enable() { + struct blk_desc *fs_dev_desc; + disk_partition_t fs_partition; + unsigned char *bdata; + int mmc_id; + FbLockEnableResult ret; + + bdata = (unsigned char *)memalign(ALIGN_BYTES, SECTOR_SIZE); + if (bdata == NULL) + return FASTBOOT_UL_ERROR; + int status; + mmc_id = fastboot_flash_find_index(FASTBOOT_PARTITION_PRDATA); + if (mmc_id < 0) { + printf("%s: error in get mmc part\n", __FUNCTION__); + ret = FASTBOOT_UL_ERROR; + goto fail; + } + status = blk_get_device_part_str(FSL_FASTBOOT_FB_DEV, + get_mmc_part(mmc_id), + &fs_dev_desc, &fs_partition, 1); + if (status < 0) { + printf("%s:error in getdevice partition.\n", __FUNCTION__); + ret = FASTBOOT_UL_ERROR; + goto fail; + } + + //The data is stored in the last blcok of this partition. + lbaint_t target_block = fs_partition.start + fs_partition.size - 1; + status = blk_dread(fs_dev_desc, target_block, 1, bdata); + if (!status) { + printf("%s: error in block read\n", __FUNCTION__); + ret = FASTBOOT_UL_ERROR; + goto fail; + } + int i = 0; + FB_DEBUG("\n PRIST last sector is:\n"); + for (i = 0; i < SECTOR_SIZE; i++) { + FB_DEBUG("0x%x ", *(bdata + i)); + if (i % 32 == 0) + FB_DEBUG("\n"); + } + FB_DEBUG("\n"); + ret = lock_enable_parse(bdata); +fail: + free(bdata); + return ret; + +} +#endif + +int display_lock(FbLockState lock, int verify) { + struct stdio_dev *disp; + disp = stdio_get_by_name("vga"); + if (disp != NULL) { + if (lock == FASTBOOT_UNLOCK) { + disp->puts(disp, "\n============= NOTICE ============\n"); + disp->puts(disp, "| |\n"); + disp->puts(disp, "| Your device is NOT locked. |\n"); + disp->puts(disp, "| |\n"); + disp->puts(disp, "=================================\n"); + } else { + if (verify == -1) { + disp->puts(disp, "\n============= NOTICE ============\n"); + disp->puts(disp, "| |\n"); + disp->puts(disp, "| Your device is NOT protected. |\n"); + disp->puts(disp, "| |\n"); + disp->puts(disp, "=================================\n"); + } else if (verify == 1) { + disp->puts(disp, "\n============= NOTICE ============\n"); + disp->puts(disp, "| |\n"); + disp->puts(disp, "| Boot verify failed! |\n"); + disp->puts(disp, "| |\n"); + disp->puts(disp, "=================================\n"); + } + } + return 0; + } else + printf("not found VGA disp console.\n"); + + return -1; + +} + +int fastboot_wipe_data_partition(void) +{ + struct blk_desc *fs_dev_desc; + disk_partition_t fs_partition; + int status; + int mmc_id; + mmc_id = fastboot_flash_find_index(FASTBOOT_PARTITION_DATA); + if (mmc_id < 0) { + printf("%s: error in get mmc part\n", __FUNCTION__); + return -1; + } + status = blk_get_device_part_str(FSL_FASTBOOT_FB_DEV, + get_mmc_part(mmc_id), &fs_dev_desc, &fs_partition, 1); + if (status < 0) { + printf("error in get device partition for wipe /data\n"); + return -1; + } + status = blk_derase(fs_dev_desc, fs_partition.start , fs_partition.size ); + if (status != fs_partition.size ) { + printf("erase not complete\n"); + return -1; + } + mdelay(2000); + + return 0; +} diff --git a/drivers/usb/gadget/fastboot_lock_unlock.h b/drivers/usb/gadget/fastboot_lock_unlock.h new file mode 100644 index 00000000000..f08ab269bbd --- /dev/null +++ b/drivers/usb/gadget/fastboot_lock_unlock.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FASTBOOT_LOCK_UNLOCK_H +#define FASTBOOT_LOCK_UNLOCK_H + +#define ALIGN_BYTES 64 /*armv7 cache line need 64 bytes aligned */ + +//#define FASTBOOT_LOCK_DEBUG +#ifdef CONFIG_FSL_CAAM_KB +#define FASTBOOT_ENCRYPT_LOCK +#endif + +#ifdef FASTBOOT_LOCK_DEBUG +#define FB_DEBUG(format, ...) printf(format, ##__VA_ARGS__) +#else +#define FB_DEBUG(format, ...) +#endif + +typedef enum { + FASTBOOT_UNLOCK, + FASTBOOT_LOCK, + FASTBOOT_LOCK_ERROR, + FASTBOOT_LOCK_NUM +}FbLockState; + +typedef enum { + FASTBOOT_UL_DISABLE, + FASTBOOT_UL_ENABLE, + FASTBOOT_UL_ERROR, + FASTBOOT_UL_NUM +}FbLockEnableResult; + +FbLockState fastboot_get_lock_stat(void); + +int fastboot_set_lock_stat(FbLockState lock); + +int fastboot_wipe_data_partition(void); + +FbLockEnableResult fastboot_lock_enable(void); +void set_fastboot_lock_disable(void); + +int display_lock(FbLockState lock, int verify); +#endif diff --git a/include/android_image.h b/include/android_image.h index dfd4d9d72c7..ffe50d3b9db 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -20,6 +20,19 @@ typedef struct andr_img_hdr andr_img_hdr; #define ANDR_BOOT_ARGS_SIZE 512 #define ANDR_BOOT_EXTRA_ARGS_SIZE 1024 +/* Boot metric variables (in millisecond) */ +struct boot_metric +{ + u32 bll_1; /* 1th bootloader load duration */ + u32 ble_1; /* 1th bootloader exec duration */ + u32 kl; /* kernel image load duration */ + u32 kd; /* kernel image decompress duration */ + u32 avb; /* avb verify boot.img duration */ + u32 odt; /* overlay device tree duration */ + u32 sw; /* system wait for UI interaction duration*/ +}; +typedef struct boot_metric boot_metric; + struct andr_img_hdr { char magic[ANDR_BOOT_MAGIC_SIZE]; @@ -80,4 +93,16 @@ struct andr_img_hdr { * 6. if second_size != 0: jump to second_addr * else: jump to kernel_addr */ +struct header_image { + uint32_t code0; /* Executable code */ + uint32_t code1; /* Executable code */ + uint64_t text_offset; /* Image load offset, LE */ + uint64_t image_size; /* Effective Image size, LE */ + uint64_t res1; /* reserved */ + uint64_t res2; /* reserved */ + uint64_t res3; /* reserved */ + uint64_t res4; /* reserved */ + uint32_t magic; /* Magic number */ + uint32_t res5; +}; #endif diff --git a/include/common.h b/include/common.h index 71c2e39f214..eed03c33d5a 100644 --- a/include/common.h +++ b/include/common.h @@ -685,6 +685,10 @@ int cpu_disable(int nr); int cpu_release(int nr, int argc, char * const argv[]); #endif +#ifdef CONFIG_CMD_READ +int do_raw_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +#endif + #else /* __ASSEMBLY__ */ /* Drop a C type modifier (like in 3UL) for constants used in assembly. */ diff --git a/include/fsl_fastboot.h b/include/fsl_fastboot.h new file mode 100644 index 00000000000..8deac211d31 --- /dev/null +++ b/include/fsl_fastboot.h @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef FSL_FASTBOOT_H +#define FSL_FASTBOOT_H +#include <stdbool.h> +#include <linux/types.h> + +#define FASTBOOT_PTENTRY_FLAGS_REPEAT(n) (n & 0x0f) +#define FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK 0x0000000F + +/* Writes happen a block at a time. + If the write fails, go to next block + NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK 0x00000010 + +/* Find a contiguous block big enough for a the whole file + NEXT_GOOD_BLOCK and CONTIGOUS_BLOCK can not both be set */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK 0x00000020 + +/* Write the file with write.i */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_I 0x00000100 + +/* Write the file with write.trimffs */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_TRIMFFS 0x00000200 + +/* Write the file as a series of variable/value pairs + using the setenv and saveenv commands */ +#define FASTBOOT_PTENTRY_FLAGS_WRITE_ENV 0x00000400 + +/* Uneraseable partition */ +#define FASTBOOT_PTENTRY_FLAGS_UNERASEABLE 0x00000800 + +#define FASTBOOT_MMC_BOOT_PARTITION_ID 1 +#define FASTBOOT_MMC_USER_PARTITION_ID 0 +#define FASTBOOT_MMC_NONE_PARTITION_ID -1 + +#define FASTBOOT_PARTITION_PRDATA "presistdata" + +#ifdef CONFIG_AVB_SUPPORT +#define FASTBOOT_PARTITION_AVBKEY "avbkey" +#endif + +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT +#define FASTBOOT_MCU_FIRMWARE_PARTITION "m4_os" +#endif + +#ifdef CONFIG_ANDROID_AB_SUPPORT +#define FASTBOOT_PARTITION_BOOT_A "boot_a" +#define FASTBOOT_PARTITION_RECOVERY "recovery" +#define FASTBOOT_PARTITION_SYSTEM_A "system_a" +#define FASTBOOT_PARTITION_BOOTLOADER "bootloader0" +#define FASTBOOT_PARTITION_DATA "userdata" +#define FASTBOOT_PARTITION_BOOT_B "boot_b" +#define FASTBOOT_PARTITION_SYSTEM_B "system_b" +#ifdef CONFIG_AVB_SUPPORT +#define FASTBOOT_PARTITION_VBMETA_A "vbmeta_a" +#define FASTBOOT_PARTITION_VBMETA_B "vbmeta_b" +#endif +#define FASTBOOT_PARTITION_MISC "misc" +#define FASTBOOT_PARTITION_GPT "gpt" +#define FASTBOOT_PARTITION_FBMISC "fbmisc" +#else +#define FASTBOOT_PARTITION_BOOT "boot" +#define FASTBOOT_PARTITION_RECOVERY "recovery" +#define FASTBOOT_PARTITION_SYSTEM "system" +#define FASTBOOT_PARTITION_CACHE "cache" +#define FASTBOOT_PARTITION_DEVICE "device" +#define FASTBOOT_PARTITION_BOOTLOADER "bootloader" +#define FASTBOOT_PARTITION_DATA "userdata" +#define FASTBOOT_PARTITION_GPT "gpt" +#define FASTBOOT_PARTITION_MISC "misc" +#define FASTBOOT_PARTITION_FBMISC "fbmisc" +#endif + +#ifdef CONFIG_ANDROID_THINGS_SUPPORT +#define FASTBOOT_BOOTLOADER_VBOOT_KEY "fuse at-bootloader-vboot-key" +#endif + +enum { + DEV_SATA, + DEV_MMC, + DEV_NAND, +#ifdef CONFIG_FLASH_MCUFIRMWARE_SUPPORT + /* SPI Flash */ + DEV_SF +#endif +}; + +typedef enum { +#ifdef CONFIG_ANDROID_RECOVERY + /* Revoery boot due to combo keys pressed */ + BOOTMODE_RECOVERY_KEY_PRESSED, + /* Recovery boot due to boot-recovery cmd in misc parition */ + BOOTMODE_RECOVERY_BCB_CMD, +#endif + /* Fastboot boot due to bootonce-bootloader cmd in misc parition */ + BOOTMODE_FASTBOOT_BCB_CMD, + /* Normal boot */ + BOOTMODE_NORMAL +}FbBootMode; + + +struct cmd_fastboot_interface { + /* This function is called when a buffer has been + recieved from the client app. + The buffer is a supplied by the board layer and must be unmodified. + The buffer_size is how much data is passed in. + Returns 0 on success + Returns 1 on failure + + Set by cmd_fastboot */ + int (*rx_handler)(const unsigned char *buffer, + unsigned int buffer_size); + + /* This function is called when an exception has + occurred in the device code and the state + off fastboot needs to be reset + + Set by cmd_fastboot */ + void (*reset_handler)(void); + + /* A getvar string for the product name + It can have a maximum of 60 characters + + Set by board */ + char *product_name; + + /* A getvar string for the serial number + It can have a maximum of 60 characters + + Set by board */ + char *serial_no; + + /* Nand block size + Supports the write option WRITE_NEXT_GOOD_BLOCK + + Set by board */ + unsigned int nand_block_size; + + /* Nand oob size + Set by board */ + unsigned int nand_oob_size; + + /* Transfer buffer, for handling flash updates + Should be multiple of the nand_block_size + Care should be take so it does not overrun bootloader memory + Controlled by the configure variable CFG_FASTBOOT_TRANSFER_BUFFER + + Set by board */ + unsigned char *transfer_buffer; + + /* How big is the transfer buffer + Controlled by the configure variable + CFG_FASTBOOT_TRANSFER_BUFFER_SIZE + + Set by board */ + unsigned int transfer_buffer_size; + +}; + +/* flash partitions are defined in terms of blocks +** (flash erase units) +*/ +struct fastboot_ptentry { + /* The logical name for this partition, null terminated */ + char name[16]; + /* The start wrt the nand part, must be multiple of nand block size */ + unsigned int start; + /* The length of the partition, must be multiple of nand block size */ + unsigned int length; + /* Controls the details of how operations are done on the partition + See the FASTBOOT_PTENTRY_FLAGS_*'s defined below */ + unsigned int flags; + /* partition id: 0 - normal partition; 1 - boot partition */ + unsigned int partition_id; + /* partition number in block device */ + unsigned int partition_index; + /* partition file system type in string */ + char fstype[16]; + /* filesystem UUID as string, if exists */ +#ifdef CONFIG_PARTITION_UUIDS + char uuid[37]; +#endif +}; + +struct fastboot_device_info { + unsigned char type; + unsigned char dev_id; +}; + +extern struct fastboot_device_info fastboot_devinfo; + +/* Prepare the fastboot environments, + * should be executed before "fastboot" cmd + */ +void fastboot_setup(void); + + +/* The Android-style flash handling */ + +/* tools to populate and query the partition table */ +void fastboot_flash_add_ptn(struct fastboot_ptentry *ptn); +struct fastboot_ptentry *fastboot_flash_find_ptn(const char *name); +struct fastboot_ptentry *fastboot_flash_get_ptn(unsigned n); +unsigned int fastboot_flash_get_ptn_count(void); +void fastboot_flash_dump_ptn(void); + +/* Make board into special boot mode */ +void fastboot_run_bootmode(void); + +/*Setup board-relative fastboot environment */ +void board_fastboot_setup(void); + +/*return partition index according name*/ +int fastboot_flash_find_index(const char *name); + +/*check whether bootloader is overlay with GPT table*/ +bool bootloader_gpt_overlay(void); +/* Check whether the combo keys pressed + * Return 1 if combo keys pressed for recovery boot + * Return 0 if no combo keys pressed + */ +int is_recovery_key_pressing(void); + +#ifdef CONFIG_FASTBOOT_STORAGE_NAND +/*Save parameters for NAND storage partitions */ +void save_parts_values(struct fastboot_ptentry *ptn, + unsigned int offset, unsigned int size); + +/* Checks parameters for NAND storage partitions + * Return 1 if the parameter is not set + * Return 0 if the parameter has been set + */ +int check_parts_values(struct fastboot_ptentry *ptn); +#endif /*CONFIG_FASTBOOT_STORAGE_NAND*/ + +/* Reads |num_bytes| from offset |offset| from partition with name + * |partition| (NUL-terminated UTF-8 string). If |offset| is + * negative, its absolute value should be interpreted as the number + * of bytes from the end of the partition. + * It's basically copied from fsl_read_from_partition_multi() because + * we may want to read partition when AVB is not enabled. */ +int read_from_partition_multi(const char* partition, + int64_t offset, size_t num_bytes,void* buffer, size_t* out_num_read); +#endif /* FSL_FASTBOOT_H */ diff --git a/include/image.h b/include/image.h index dbdaecbfdd3..bb54b4cc561 100644 --- a/include/image.h +++ b/include/image.h @@ -1277,6 +1277,7 @@ int android_image_get_second(const struct andr_img_hdr *hdr, ulong android_image_get_end(const struct andr_img_hdr *hdr); ulong android_image_get_kload(const struct andr_img_hdr *hdr); void android_print_contents(const struct andr_img_hdr *hdr); +bool image_arm64(void *images); #endif /* CONFIG_ANDROID_BOOT_IMAGE */ diff --git a/include/mmc.h b/include/mmc.h index b39ebdcb0f6..9ec452cd7d6 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -814,6 +814,7 @@ int board_mmc_init(bd_t *bis); int cpu_mmc_init(bd_t *bis); int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr); int mmc_get_env_dev(void); +int mmc_map_to_kernel_blk(int dev_no); /* Set block count limit because of 16 bit register limit on some hardware*/ #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT diff --git a/include/part.h b/include/part.h index c129699bad8..5678dab3f50 100644 --- a/include/part.h +++ b/include/part.h @@ -375,6 +375,14 @@ int is_valid_gpt_buf(struct blk_desc *dev_desc, void *buf); int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf); /** + * write_backup_gpt_partitions - write MBR, backup gpt table. + * @param dev_desc - block device descriptor + * @param buf - buffer which contains the MBR and Primary GPT info + * + * @return - '0' on success, otherwise error + */ +int write_backup_gpt_partitions(struct blk_desc *dev_desc, void *buf); +/** * gpt_verify_headers() - Function to read and CRC32 check of the GPT's header * and partition table entries (PTE) * diff --git a/include/recovery.h b/include/recovery.h new file mode 100644 index 00000000000..4519cffcb7a --- /dev/null +++ b/include/recovery.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __RECOVERY_H_ +#define __RECOVERY_H_ + +struct reco_envs { + char *cmd; + char *args; +}; + +void board_recovery_setup(void); + +#endif diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 7ca0c555d08..5acb18885a3 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -31,6 +31,10 @@ CONFIG_AM335X_USB1_MODE CONFIG_AM437X_USB2PHY2_HOST CONFIG_ANDES_PCU CONFIG_ANDES_PCU_BASE +CONFIG_ANDROID_AB_SUPPORT +CONFIG_ANDROID_AUTO_SUPPORT +CONFIG_ANDROID_SUPPORT +CONFIG_ANDROID_THINGS_SUPPORT CONFIG_APER_0_BASE CONFIG_APER_1_BASE CONFIG_APER_SIZE @@ -106,6 +110,10 @@ CONFIG_ATMEL_NAND_HW_PMECC CONFIG_ATMEL_SPI0 CONFIG_AT_TRANS CONFIG_AUTO_ZRELADDR +CONFIG_AVB_FUSE +CONFIG_AVB_FUSE_BANK_END +CONFIG_AVB_FUSE_BANK_SIZEW +CONFIG_AVB_FUSE_BANK_START CONFIG_BACKSIDE_L2_CACHE CONFIG_BAT_PAIR CONFIG_BAT_RW @@ -141,6 +149,8 @@ CONFIG_BOARD_TYPES CONFIG_BOOGER CONFIG_BOOTBLOCK CONFIG_BOOTFILE +CONFIG_BOOTLOADER_OFFSET_32K +CONFIG_BOOTLOADER_OFFSET_33K CONFIG_BOOTMAPSZ CONFIG_BOOTMODE CONFIG_BOOTM_LINUX @@ -493,6 +503,7 @@ CONFIG_ELBC_NAND_SPL_STATIC_PGSIZE CONFIG_EMMC_BOOT CONFIG_EMU CONFIG_ENABLE_36BIT_PHYS +CONFIG_ENABLE_LOCKSTATUS_SUPPORT CONFIG_ENABLE_MMU CONFIG_ENABLE_MUST_CHECK CONFIG_ENABLE_WARN_DEPRECATED @@ -603,6 +614,7 @@ CONFIG_EXYNOS_TMU CONFIG_FACTORYSET CONFIG_FASTBOOT_FLASH_FILLBUF_SIZE CONFIG_FASTBOOT_FLASH_NAND_TRIMFFS +CONFIG_FASTBOOT_LOCK CONFIG_FAST_FLASH_BIT CONFIG_FB_ADDR CONFIG_FB_BACKLIGHT @@ -656,6 +668,7 @@ CONFIG_FPGA_COUNT CONFIG_FPGA_DELAY CONFIG_FPGA_STRATIX_V CONFIG_FSLDMAFEC +CONFIG_FSL_CAAM_KB CONFIG_FSL_CADMUS CONFIG_FSL_CORENET CONFIG_FSL_CPLD @@ -2089,6 +2102,7 @@ CONFIG_SXNI855T CONFIG_SYSFLAGS_ADDR CONFIG_SYSFS CONFIG_SYSMGR_ISWGRP_HANDOFF +CONFIG_SYSTEM_RAMDISK_SUPPORT CONFIG_SYS_33MHZ CONFIG_SYS_64BIT CONFIG_SYS_64BIT_LBA |