MA-17260 Add vendor boot and boot header v3 support
authorJi Luo <ji.luo@nxp.com>
Thu, 28 May 2020 03:06:37 +0000 (11:06 +0800)
committerJi Luo <ji.luo@nxp.com>
Thu, 13 May 2021 01:49:18 +0000 (09:49 +0800)
GKI(Generic Kernel Image) would require the boot header v3 and vendor
boot support, all device specific info are moved to vendor_boot partition
,the boot header v3 will not be compatible with earlier version(0/1/2).

This commit adds support for boot header v3 and vendor boot, it would
concatenate the generic ramdisk and vendor ramdisk to generate the
final ramdisk passed to kernel.

Test: boots with or without boot header v3 and vendor boot support.

Signed-off-by: Ji Luo <ji.luo@nxp.com>
Change-Id: Ib3298ae46bfc728aa4a34909d372eff6cc86ca70
(cherry picked from commit c3854f270a19e7d57b996e6074d692ab9bc88c32)

common/image-android.c
drivers/fastboot/fb_fsl/fb_fsl_boot.c
include/android_image.h
include/image.h
lib/Kconfig

index d7e3c93..892801d 100644 (file)
@@ -26,6 +26,7 @@
 #include <mmc.h>
 
 #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR      0x10008000
+#define COMMANDLINE_LENGTH                     2048
 
 static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1];
 
@@ -55,80 +56,17 @@ static ulong android_image_get_kernel_addr(const struct andr_img_hdr *hdr)
        return hdr->kernel_addr;
 }
 
-/**
- * android_image_get_kernel() - processes kernel part of Android boot images
- * @hdr:       Pointer to image header, which is at the start
- *                     of the image.
- * @verify:    Checksum verification flag. Currently unimplemented.
- * @os_data:   Pointer to a ulong variable, will hold os data start
- *                     address.
- * @os_len:    Pointer to a ulong variable, will hold os data length.
- *
- * This function returns the os image's start address and length. Also,
- * it appends the kernel command line to the bootargs env variable.
- *
- * Return: Zero, os start address and length on success,
- *             otherwise on failure.
- */
-int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
-                            ulong *os_data, ulong *os_len)
+static void append_kernel_cmdline(char *commandline)
 {
-       extern boot_metric metrics;
-       u32 kernel_addr = android_image_get_kernel_addr(hdr);
-       const struct image_header *ihdr = (const struct image_header *)
-               ((uintptr_t)hdr + hdr->page_size);
-
-       /*
-        * Not all Android tools use the id field for signing the image with
-        * sha1 (or anything) so we don't check it. It is not obvious that the
-        * string is null terminated so we take care of this.
-        */
-       strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
-       andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
-       if (strlen(andr_tmp_str))
-               printf("Android's image name: %s\n", andr_tmp_str);
-
-       printf("Kernel load addr 0x%08x size %u KiB\n",
-              kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
-
        char newbootargs[512] = {0};
-       char commandline[2048] = {0};
-       int offset;
-       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 {
-               offset = fdt_path_offset(gd->fdt_blob, "/chosen");
-               if (offset > 0) {
-                       bootargs = (char *)fdt_getprop(gd->fdt_blob, offset,
-                                                       "bootargs", NULL);
-                       if (bootargs)
-                               sprintf(commandline, "%s ", bootargs);
-               }
-
-               if (*hdr->cmdline) {
-                       if (strlen(hdr->cmdline) + 1 >
-                               sizeof(commandline) - strlen(commandline)) {
-                               printf("cmdline in bootimg is too long!\n");
-                               return -1;
-                       }
-                       else
-                               strncat(commandline, hdr->cmdline, sizeof(commandline) - strlen(commandline));
-               }
-       }
+       extern boot_metric metrics;
 
        /* Add 'bootargs_ram_capacity' to hold the parameters based on different ram capacity */
        char *bootargs_ram_capacity = env_get("bootargs_ram_capacity");
        if (bootargs_ram_capacity) {
-               strncat(commandline, " ", sizeof(commandline) - strlen(commandline));
+               strncat(commandline, " ", COMMANDLINE_LENGTH - strlen(commandline));
                strncat(commandline, bootargs_ram_capacity,
-                       sizeof(commandline) - strlen(commandline));
+                       COMMANDLINE_LENGTH - strlen(commandline));
        }
 
 #ifdef CONFIG_SERIAL_TAG
@@ -139,7 +77,7 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
                                        " androidboot.serialno=%08x%08x",
                                        serialnr.high,
                                        serialnr.low);
-       strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline));
+       strncat(commandline, newbootargs, COMMANDLINE_LENGTH - strlen(commandline));
 
        if (serialnr.high + serialnr.low != 0) {
                char bd_addr[16]={0};
@@ -151,7 +89,7 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
                        " androidboot.btmacaddr=%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
                        bd_addr[0],bd_addr[1],bd_addr[2],bd_addr[3],bd_addr[4],bd_addr[5],
                        bd_addr[6],bd_addr[7],bd_addr[8],bd_addr[9],bd_addr[10],bd_addr[11]);
-               strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline));
+               strncat(commandline, newbootargs, COMMANDLINE_LENGTH - strlen(commandline));
        }
 #endif
 
@@ -161,12 +99,12 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
                sprintf(newbootargs,
                        " androidboot.soc_type=%s",
                        soc_type);
-               strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline));
+               strncat(commandline, newbootargs, COMMANDLINE_LENGTH - strlen(commandline));
        }
 
        sprintf(newbootargs,
                        " androidboot.boot_device_root=mmcblk%d", mmc_map_to_kernel_blk(mmc_get_env_dev()));
-       strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline));
+       strncat(commandline, newbootargs, COMMANDLINE_LENGTH - strlen(commandline));
 
        /* boot metric variables */
        metrics.ble_1 = get_timer(0);
@@ -174,7 +112,7 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
                " 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));
+       strncat(commandline, newbootargs, COMMANDLINE_LENGTH - strlen(commandline));
 
 #if defined(CONFIG_ARCH_MX6) || defined(CONFIG_ARCH_MX7) || \
        defined(CONFIG_ARCH_MX7ULP) || defined(CONFIG_ARCH_IMX8M)
@@ -191,14 +129,14 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
 #else
        sprintf(newbootargs," androidboot.bootreason=reboot");
 #endif
-       strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline));
+       strncat(commandline, newbootargs, COMMANDLINE_LENGTH - 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));
+               strncat(commandline, " ", COMMANDLINE_LENGTH - strlen(commandline));
+               strncat(commandline, bootargs_sec, COMMANDLINE_LENGTH - strlen(commandline));
        }
 #endif
 #ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT
@@ -209,8 +147,8 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
         */
        char *bootargs_3rd = env_get("bootargs_3rd");
        if (bootargs_3rd) {
-               strncat(commandline, " ", sizeof(commandline) - strlen(commandline));
-               strncat(commandline, bootargs_3rd, sizeof(commandline) - strlen(commandline));
+               strncat(commandline, " ", COMMANDLINE_LENGTH - strlen(commandline));
+               strncat(commandline, bootargs_3rd, COMMANDLINE_LENGTH - strlen(commandline));
        }
 #endif
 
@@ -220,18 +158,18 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
         */
 #if defined(CONFIG_ANDROID_SUPPORT) || defined(CONFIG_ANDROID_AUTO_SUPPORT)
        sprintf(newbootargs," androidboot.dtbo_idx=0");
-       strncat(commandline, newbootargs, sizeof(commandline) - strlen(commandline));
+       strncat(commandline, newbootargs, COMMANDLINE_LENGTH - strlen(commandline));
 #endif
 
        char *keystore = env_get("keystore");
        if ((keystore == NULL) || strncmp(keystore, "trusty", sizeof("trusty"))) {
                char *bootargs_trusty = "androidboot.keystore=software";
-               strncat(commandline, " ", sizeof(commandline) - strlen(commandline));
-               strncat(commandline, bootargs_trusty, sizeof(commandline) - strlen(commandline));
+               strncat(commandline, " ", COMMANDLINE_LENGTH - strlen(commandline));
+               strncat(commandline, bootargs_trusty, COMMANDLINE_LENGTH - strlen(commandline));
        } else {
                char *bootargs_trusty = "androidboot.keystore=trusty";
-               strncat(commandline, " ", sizeof(commandline) - strlen(commandline));
-               strncat(commandline, bootargs_trusty, sizeof(commandline) - strlen(commandline));
+               strncat(commandline, " ", COMMANDLINE_LENGTH - strlen(commandline));
+               strncat(commandline, bootargs_trusty, COMMANDLINE_LENGTH - strlen(commandline));
        }
 
 #ifdef CONFIG_APPEND_BOOTARGS
@@ -240,14 +178,83 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
        char *append_bootargs = env_get("append_bootargs");
        if (append_bootargs) {
                if (strlen(append_bootargs) + 2 >
-                               (sizeof(commandline) - strlen(commandline))) {
+                               (COMMANDLINE_LENGTH - 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));
+                       strncat(commandline, " ", COMMANDLINE_LENGTH - strlen(commandline));
+                       strncat(commandline, append_bootargs, COMMANDLINE_LENGTH - strlen(commandline));
                }
        }
 #endif
+}
+
+/**
+ * android_image_get_kernel() - processes kernel part of Android boot images
+ * @hdr:       Pointer to image header, which is at the start
+ *                     of the image.
+ * @verify:    Checksum verification flag. Currently unimplemented.
+ * @os_data:   Pointer to a ulong variable, will hold os data start
+ *                     address.
+ * @os_len:    Pointer to a ulong variable, will hold os data length.
+ *
+ * This function returns the os image's start address and length. Also,
+ * it appends the kernel command line to the bootargs env variable.
+ *
+ * Return: Zero, os start address and length on success,
+ *             otherwise on failure.
+ */
+int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
+                            ulong *os_data, ulong *os_len)
+{
+       u32 kernel_addr = android_image_get_kernel_addr(hdr);
+       const struct image_header *ihdr = (const struct image_header *)
+               ((uintptr_t)hdr + hdr->page_size);
+
+       /*
+        * Not all Android tools use the id field for signing the image with
+        * sha1 (or anything) so we don't check it. It is not obvious that the
+        * string is null terminated so we take care of this.
+        */
+       strncpy(andr_tmp_str, hdr->name, ANDR_BOOT_NAME_SIZE);
+       andr_tmp_str[ANDR_BOOT_NAME_SIZE] = '\0';
+       if (strlen(andr_tmp_str))
+               printf("Android's image name: %s\n", andr_tmp_str);
+
+       printf("Kernel load addr 0x%08x size %u KiB\n",
+              kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+
+       char commandline[COMMANDLINE_LENGTH] = {0};
+       int offset;
+       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 {
+               offset = fdt_path_offset(gd->fdt_blob, "/chosen");
+               if (offset > 0) {
+                       bootargs = (char *)fdt_getprop(gd->fdt_blob, offset,
+                                                       "bootargs", NULL);
+                       if (bootargs)
+                               sprintf(commandline, "%s ", bootargs);
+               }
+
+               if (*hdr->cmdline) {
+                       if (strlen(hdr->cmdline) + 1 >
+                               COMMANDLINE_LENGTH - strlen(commandline)) {
+                               printf("cmdline in bootimg is too long!\n");
+                               return -1;
+                       }
+                       else
+                               strncat(commandline, hdr->cmdline, COMMANDLINE_LENGTH - strlen(commandline));
+               }
+       }
+
+       append_kernel_cmdline(commandline);
 
        debug("Kernel command line: %s\n", commandline);
        env_set("bootargs", commandline);
@@ -266,6 +273,84 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
                else
                        *os_len = hdr->kernel_size;
        }
+
+       return 0;
+}
+
+/**
+ * android_image_get_kernel() - processes kernel part of Android boot images
+ * @hdr:       Pointer to boot image header, which is at the start
+ *                     of the image.
+ * @vendor_hdr:        Pointer to vendor_boot image header, which is at the start
+ *                     of the image.
+ * This function appends the kernel command line to the bootargs env variable.
+ *
+ * Return: Zero on success, otherwise on failure.
+ */
+int android_image_get_kernel_v3(const struct boot_img_hdr_v3 *hdr,
+                               const struct vendor_boot_img_hdr_v3 *vendor_hdr)
+{
+       u32 kernel_addr = vendor_hdr->kernel_addr;
+
+       /*
+        * Not all Android tools use the id field for signing the image with
+        * sha1 (or anything) so we don't check it. It is not obvious that the
+        * string is null terminated so we take care of this.
+        */
+       strncpy(andr_tmp_str, (char *)(vendor_hdr->name), ANDR_VENDOR_BOOT_NAME_SIZE);
+       andr_tmp_str[ANDR_VENDOR_BOOT_NAME_SIZE] = '\0';
+       if (strlen(andr_tmp_str))
+               printf("Android's image name: %s\n", andr_tmp_str);
+
+       printf("Kernel load addr 0x%08x size %u KiB\n",
+              kernel_addr, DIV_ROUND_UP(hdr->kernel_size, 1024));
+
+       char commandline[COMMANDLINE_LENGTH] = {0};
+       int offset;
+       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 {
+               offset = fdt_path_offset(gd->fdt_blob, "/chosen");
+               if (offset > 0) {
+                       bootargs = (char *)fdt_getprop(gd->fdt_blob, offset,
+                                                       "bootargs", NULL);
+                       if (bootargs)
+                               sprintf(commandline, "%s ", bootargs);
+               }
+
+               if (*vendor_hdr->cmdline) {
+                       if (strlen((char *)vendor_hdr->cmdline) + 1 >
+                               COMMANDLINE_LENGTH - strlen(commandline)) {
+                               printf("cmdline in bootimg is too long!\n");
+                               return -1;
+                       }
+                       else
+                               strncat(commandline, (char *)(vendor_hdr->cmdline), COMMANDLINE_LENGTH - strlen(commandline));
+               }
+
+               if (*hdr->cmdline) {
+                       if (strlen((char *)hdr->cmdline) + 1 >
+                               COMMANDLINE_LENGTH - strlen(commandline)) {
+                               printf("cmdline in bootimg is too long!\n");
+                               return -1;
+                       }
+                       else
+                               strncat(commandline, (char *)hdr->cmdline, COMMANDLINE_LENGTH - strlen(commandline));
+               }
+       }
+
+       append_kernel_cmdline(commandline);
+
+       debug("Kernel command line: %s\n", commandline);
+       env_set("bootargs", commandline);
+
        return 0;
 }
 
@@ -274,6 +359,13 @@ int android_image_check_header(const struct andr_img_hdr *hdr)
        return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE);
 }
 
+int android_image_check_header_v3(const struct boot_img_hdr_v3 *hdr,
+                                 const struct vendor_boot_img_hdr_v3 *vendor_hdr)
+{
+       return memcmp(ANDR_BOOT_MAGIC, hdr->magic, ANDR_BOOT_MAGIC_SIZE) ||
+               memcmp(ANDR_VENDOR_BOOT_MAGIC, vendor_hdr->magic, ANDR_VENDOR_BOOT_MAGIC_SIZE);
+}
+
 ulong android_image_get_end(const struct andr_img_hdr *hdr)
 {
        ulong end;
index 8e7acd5..ca2c421 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/arch/sys_proto.h>
 #include <asm/setup.h>
 #include <env.h>
+#include <lz4.h>
 #include "../lib/avb/fsl/utils.h"
 
 #ifdef CONFIG_AVB_SUPPORT
@@ -498,7 +499,11 @@ fail:
 
 #if defined(CONFIG_AVB_SUPPORT) && defined(CONFIG_MMC)
 /* we can use avb to verify Trusty if we want */
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+const char *requested_partitions_boot[] = {"boot", "vendor_boot", FDT_PART_NAME, NULL};
+#else
 const char *requested_partitions_boot[] = {"boot", FDT_PART_NAME, NULL};
+#endif
 const char *requested_partitions_recovery[] = {"recovery", FDT_PART_NAME, NULL};
 
 static bool is_load_fdt_from_part(void)
@@ -547,8 +552,13 @@ static int find_partition_data_by_name(char* part_name,
 int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
 
        ulong addr = 0;
+       /* 'hdr' should point to boot.img */
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       struct boot_img_hdr_v3 *hdr = NULL;
+       struct vendor_boot_img_hdr_v3 *vendor_hdr = NULL;
+#else
        struct andr_img_hdr *hdr = NULL;
-       ulong image_size;
+#endif
        u32 avb_metric;
        bool check_image_arm64 =  false;
        bool is_recovery_mode = false;
@@ -556,6 +566,9 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
        AvbABFlowResult avb_result;
        AvbSlotVerifyData *avb_out_data = NULL;
        AvbPartitionData *avb_loadpart = NULL;
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       AvbPartitionData *avb_vendorboot = NULL;
+#endif
 
        /* get bootmode, default to boot "boot" */
        if (argc > 1) {
@@ -581,7 +594,11 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
        avb_metric = get_timer(0);
        /* we don't need to verify fdt partition if we don't have it. */
        if (!is_load_fdt_from_part()) {
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+               requested_partitions_boot[2] = NULL;
+#else
                requested_partitions_boot[1] = NULL;
+#endif
                requested_partitions_recovery[1] = NULL;
        }
 #ifndef CONFIG_SYSTEM_RAMDISK_SUPPORT
@@ -590,7 +607,7 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
        }
 #endif
 
-       /* if in lock state, do avb verify */
+       /* do avb verify */
 #ifndef CONFIG_DUAL_BOOTLOADER
        /* 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
@@ -637,6 +654,10 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
 #ifdef CONFIG_SYSTEM_RAMDISK_SUPPORT
                if (find_partition_data_by_name("boot", avb_out_data, &avb_loadpart))
                        goto fail;
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+               if (find_partition_data_by_name("vendor_boot", avb_out_data, &avb_vendorboot))
+                       goto fail;
+#endif
 #else
                if (!is_recovery_mode) {
                        if (find_partition_data_by_name("boot", avb_out_data, &avb_loadpart))
@@ -647,10 +668,19 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
                }
 #endif
                assert(avb_loadpart != NULL);
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+               assert(avb_vendorboot != NULL);
+#endif
                /* we should use avb_part_data->data as boot image */
                /* boot image is already read by avb */
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+               hdr = (struct boot_img_hdr_v3 *)avb_loadpart->data;
+               vendor_hdr = (struct vendor_boot_img_hdr_v3 *)avb_vendorboot->data;
+               if (android_image_check_header_v3(hdr, vendor_hdr)) {
+#else
                hdr = (struct andr_img_hdr *)avb_loadpart->data;
                if (android_image_check_header(hdr)) {
+#endif
                        printf("boota: bad boot image magic\n");
                        goto fail;
                }
@@ -689,32 +719,47 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
                                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,
+                * physical dram address. If we are using compressed lz4 kernel image,
                 * we need to decompress the kernel image first. */
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+               if (image_arm64((void *)((ulong)hdr + 4096))) {
+                       memcpy((void *)(long)vendor_hdr->kernel_addr,
+                                       (void *)((ulong)hdr + 4096), hdr->kernel_size);
+               } else if (IS_ENABLED(CONFIG_LZ4)) {
+                       size_t lz4_len = MAX_KERNEL_LEN;
+                       if (ulz4fn((void *)((ulong)hdr + 4096),
+                                               hdr->kernel_size, (void *)(ulong)vendor_hdr->kernel_addr, &lz4_len) != 0) {
+                               printf("Decompress kernel fail!\n");
+                               goto fail;
+                       }
+               } else {
+                       printf("Wrong kernel image! Please check if you need to enable 'CONFIG_LZ4'\n");
+                       goto fail;
+               }
+#else /* CONFIG_VENDOR_BOOT_SUPPORT */
+#if defined (CONFIG_ARCH_IMX8) || defined (CONFIG_ARCH_IMX8M)
                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
+               } else if (IS_ENABLED(CONFIG_LZ4)) {
                        size_t lz4_len = MAX_KERNEL_LEN;
                        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");
+               } else {
+                       printf("Wrong kernel image! Please check if you need to enable 'CONFIG_LZ4'\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 */
+#endif /* CONFIG_VENDOR_BOOT_SUPPORT */
        } else {
                /* Fall into fastboot mode if get unacceptable error from avb
                 * or verify fail in lock state.
@@ -725,8 +770,22 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
                goto fail;
        }
 
-       flush_cache((ulong)image_load_addr, image_size);
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       check_image_arm64  = image_arm64((void *)(ulong)vendor_hdr->kernel_addr);
+#else
        check_image_arm64  = image_arm64((void *)(ulong)hdr->kernel_addr);
+#endif
+
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       /* Need to concatenate vendor_boot ramdisk and boot ramdisk, check
+        * "include/android_image.h" for boot/vendor_boot image overlay.
+        */
+       memcpy((void *)(ulong)vendor_hdr->ramdisk_addr,
+                       (void *)(ulong)vendor_hdr + ALIGN(sizeof(struct vendor_boot_img_hdr_v3), vendor_hdr->page_size),
+                        vendor_hdr->vendor_ramdisk_size);
+       memcpy((void *)(ulong)vendor_hdr->ramdisk_addr + vendor_hdr->vendor_ramdisk_size,
+                       (void *)(ulong)hdr + 4096 + ALIGN(hdr->kernel_size, 4096), hdr->ramdisk_size);
+#else /* CONFIG_VENDOR_BOOT_SUPPORT */
 #if !defined(CONFIG_SYSTEM_RAMDISK_SUPPORT) || !defined(CONFIG_ANDROID_AUTO_SUPPORT)
        memcpy((void *)(ulong)hdr->ramdisk_addr, (void *)(ulong)hdr + hdr->page_size
                        + ALIGN(hdr->kernel_size, hdr->page_size), hdr->ramdisk_size);
@@ -735,82 +794,87 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
                memcpy((void *)(ulong)hdr->ramdisk_addr, (void *)(ulong)hdr + hdr->page_size
                                + ALIGN(hdr->kernel_size, hdr->page_size), hdr->ramdisk_size);
 #endif
+#endif /* CONFIG_VENDOR_BOOT_SUPPORT */
 
-#ifdef CONFIG_OF_LIBFDT
        /* load the dtb file */
+#ifdef CONFIG_OF_LIBFDT
        u32 fdt_addr = 0;
        u32 fdt_size = 0;
        struct dt_table_header *dt_img = NULL;
 
-       if (is_load_fdt_from_part()) {
-               fdt_addr = (ulong)((ulong)(hdr->kernel_addr) + MAX_KERNEL_LEN);
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       fdt_addr = (ulong)((ulong)(vendor_hdr->kernel_addr) + MAX_KERNEL_LEN);
+#else
+       fdt_addr = (ulong)((ulong)(hdr->kernel_addr) + MAX_KERNEL_LEN);
+#endif
 #ifdef CONFIG_ANDROID_THINGS_SUPPORT
-               if (find_partition_data_by_name("oem_bootloader",
-                                       avb_out_data, &avb_loadpart)) {
-                       goto fail;
-               } else
-                       dt_img = (struct dt_table_header *)avb_loadpart->data;
+       if (find_partition_data_by_name("oem_bootloader",
+                               avb_out_data, &avb_loadpart)) {
+               goto fail;
+       } else
+               dt_img = (struct dt_table_header *)avb_loadpart->data;
 #elif defined(CONFIG_SYSTEM_RAMDISK_SUPPORT) /* It means boot.img(recovery) do not include dtb, it need load dtb from partition */
-               if (find_partition_data_by_name("dtbo",
-                                       avb_out_data, &avb_loadpart)) {
-                       goto fail;
-               } else
-                       dt_img = (struct dt_table_header *)avb_loadpart->data;
+       if (find_partition_data_by_name("dtbo",
+                               avb_out_data, &avb_loadpart)) {
+               goto fail;
+       } else
+               dt_img = (struct dt_table_header *)avb_loadpart->data;
 #else /* recovery.img include dts while boot.img use dtbo */
-               if (is_recovery_mode) {
-                       if (hdr->header_version != 1) {
-                               printf("boota: boot image header version error!\n");
-                               goto fail;
-                       }
-
-                       dt_img = (struct dt_table_header *)((void *)(ulong)hdr +
-                                               hdr->page_size +
-                                               ALIGN(hdr->kernel_size, hdr->page_size) +
-                                               ALIGN(hdr->ramdisk_size, hdr->page_size) +
-                                               ALIGN(hdr->second_size, hdr->page_size));
-               } else if (find_partition_data_by_name("dtbo",
-                                               avb_out_data, &avb_loadpart)) {
-                       goto fail;
-               } else
-                       dt_img = (struct dt_table_header *)avb_loadpart->data;
-#endif
-
-               if (be32_to_cpu(dt_img->magic) != DT_TABLE_MAGIC) {
-                       printf("boota: bad dt table magic %08x\n",
-                                       be32_to_cpu(dt_img->magic));
-                       goto fail;
-               } else if (!be32_to_cpu(dt_img->dt_entry_count)) {
-                       printf("boota: no dt entries\n");
+       if (is_recovery_mode) {
+               if (hdr->header_version != 1) {
+                       printf("boota: boot image header version error!\n");
                        goto fail;
                }
 
-               struct dt_table_entry *dt_entry;
-               dt_entry = (struct dt_table_entry *)((ulong)dt_img +
-                               be32_to_cpu(dt_img->dt_entries_offset));
-               fdt_size = be32_to_cpu(dt_entry->dt_size);
-               memcpy((void *)fdt_addr, (void *)((ulong)dt_img +
-                               be32_to_cpu(dt_entry->dt_offset)), fdt_size);
-       } else {
-               fdt_addr = (ulong)(hdr->second_addr);
-               fdt_size = (ulong)(hdr->second_size);
-               if (fdt_size && fdt_addr) {
-                       memcpy((void *)(ulong)fdt_addr,
-                               (void *)(ulong)hdr + hdr->page_size
-                               + ALIGN(hdr->kernel_size, hdr->page_size)
-                               + ALIGN(hdr->ramdisk_size, hdr->page_size),
-                               fdt_size);
-               }
+               dt_img = (struct dt_table_header *)((void *)(ulong)hdr +
+                                       hdr->page_size +
+                                       ALIGN(hdr->kernel_size, hdr->page_size) +
+                                       ALIGN(hdr->ramdisk_size, hdr->page_size) +
+                                       ALIGN(hdr->second_size, hdr->page_size));
+       } else if (find_partition_data_by_name("dtbo",
+                                       avb_out_data, &avb_loadpart)) {
+               goto fail;
+       } else
+               dt_img = (struct dt_table_header *)avb_loadpart->data;
+#endif
+
+       if (be32_to_cpu(dt_img->magic) != DT_TABLE_MAGIC) {
+               printf("boota: bad dt table magic %08x\n",
+                               be32_to_cpu(dt_img->magic));
+               goto fail;
+       } else if (!be32_to_cpu(dt_img->dt_entry_count)) {
+               printf("boota: no dt entries\n");
+               goto fail;
        }
+
+       struct dt_table_entry *dt_entry;
+       dt_entry = (struct dt_table_entry *)((ulong)dt_img +
+                       be32_to_cpu(dt_img->dt_entries_offset));
+       fdt_size = be32_to_cpu(dt_entry->dt_size);
+       memcpy((void *)fdt_addr, (void *)((ulong)dt_img +
+                       be32_to_cpu(dt_entry->dt_offset)), fdt_size);
 #endif /*CONFIG_OF_LIBFDT*/
 
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       android_image_get_kernel_v3(hdr, vendor_hdr);
+       addr = vendor_hdr->kernel_addr;
+#else
        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);
        }
+#endif
+
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       printf("kernel   @ %08x (%d)\n", vendor_hdr->kernel_addr, hdr->kernel_size);
+       printf("ramdisk  @ %08x (%d)\n", vendor_hdr->ramdisk_addr,
+                                       vendor_hdr->vendor_ramdisk_size + hdr->ramdisk_size);
+#else
        printf("kernel   @ %08x (%d)\n", hdr->kernel_addr, hdr->kernel_size);
        printf("ramdisk  @ %08x (%d)\n", hdr->ramdisk_addr, hdr->ramdisk_size);
+#endif
 #ifdef CONFIG_OF_LIBFDT
        if (fdt_size)
                printf("fdt      @ %08x (%d)\n", fdt_addr, fdt_size);
@@ -827,7 +891,12 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
                boot_args[0] = "bootm";
 
        sprintf(boot_addr_start, "0x%lx", addr);
+#ifdef CONFIG_VENDOR_BOOT_SUPPORT
+       sprintf(ramdisk_addr, "0x%x:0x%x", vendor_hdr->ramdisk_addr,
+                                          vendor_hdr->vendor_ramdisk_size + hdr->ramdisk_size);
+#else
        sprintf(ramdisk_addr, "0x%x:0x%x", hdr->ramdisk_addr, hdr->ramdisk_size);
+#endif
        sprintf(fdt_addr_start, "0x%x", fdt_addr);
 
 /* when CONFIG_SYSTEM_RAMDISK_SUPPORT is enabled and it's for Android Auto, if it's not recovery mode
index ef6ecc2..fb43503 100644 (file)
 #define ANDR_BOOT_ARGS_SIZE 512
 #define ANDR_BOOT_EXTRA_ARGS_SIZE 1024
 
+#define ANDR_VENDOR_BOOT_MAGIC "VNDRBOOT"
+#define ANDR_VENDOR_BOOT_MAGIC_SIZE 8
+#define ANDR_VENDOR_BOOT_ARGS_SIZE 2048
+#define ANDR_VENDOR_BOOT_NAME_SIZE 16
+
 /* The bootloader expects the structure of andr_img_hdr with header
  * version 0 to be as follows: */
 /* Boot metric variables (in millisecond) */
@@ -80,6 +85,66 @@ struct andr_img_hdr {
     u64 dtb_addr; /* physical load address for DTB image */
 } __attribute__((packed));
 
+struct boot_img_hdr_v3 {
+    // Must be BOOT_MAGIC.
+    uint8_t magic[ANDR_BOOT_MAGIC_SIZE];
+
+    uint32_t kernel_size; /* size in bytes */
+    uint32_t ramdisk_size; /* size in bytes */
+
+    // Operating system version and security patch level.
+    // For version "A.B.C" and patch level "Y-M-D":
+    //   (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
+    //   os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
+    uint32_t os_version;
+
+#if __cplusplus
+    void SetOsVersion(unsigned major, unsigned minor, unsigned patch) {
+        os_version &= ((1 << 11) - 1);
+        os_version |= (((major & 0x7f) << 25) | ((minor & 0x7f) << 18) | ((patch & 0x7f) << 11));
+    }
+
+    void SetOsPatchLevel(unsigned year, unsigned month) {
+        os_version &= ~((1 << 11) - 1);
+        os_version |= (((year - 2000) & 0x7f) << 4) | ((month & 0xf) << 0);
+    }
+#endif
+
+    uint32_t header_size;
+
+    uint32_t reserved[4];
+
+    // Version of the boot image header.
+    uint32_t header_version;
+
+    uint8_t cmdline[ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE];
+} __attribute__((packed));
+
+struct vendor_boot_img_hdr_v3 {
+    // Must be ANDR_VENDOR_BOOT_MAGIC.
+    uint8_t magic[ANDR_VENDOR_BOOT_MAGIC_SIZE];
+
+    // Version of the vendor boot image header.
+    uint32_t header_version;
+
+    uint32_t page_size; /* flash page size we assume */
+
+    uint32_t kernel_addr; /* physical load addr */
+    uint32_t ramdisk_addr; /* physical load addr */
+
+    uint32_t vendor_ramdisk_size; /* size in bytes */
+
+    uint8_t cmdline[ANDR_VENDOR_BOOT_ARGS_SIZE];
+
+    uint32_t tags_addr; /* physical addr for kernel tags (if required) */
+    uint8_t name[ANDR_VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */
+
+    uint32_t header_size;
+
+    uint32_t dtb_size; /* size in bytes for DTB image */
+    uint64_t dtb_addr; /* physical load address for DTB image */
+} __attribute__((packed));
+
 /* When a boot header is of version 0, the structure of boot image is as
  * follows:
  *
@@ -152,6 +217,51 @@ struct andr_img_hdr {
  *    else: jump to kernel_addr
  */
 
+/* When the boot image header has a version of 3, the structure of the boot
+ * image is as follows:
+ *
+ * +---------------------+
+ * | boot header         | 4096 bytes
+ * +---------------------+
+ * | kernel              | m pages
+ * +---------------------+
+ * | ramdisk             | n pages
+ * +---------------------+
+ *
+ * m = (kernel_size + 4096 - 1) / 4096
+ * n = (ramdisk_size + 4096 - 1) / 4096
+ *
+ * Note that in version 3 of the boot image header, page size is fixed at 4096 bytes.
+ *
+ * The structure of the vendor boot image (introduced with version 3 and
+ * required to be present when a v3 boot image is used) is as follows:
+ *
+ * +---------------------+
+ * | vendor boot header  | o pages
+ * +---------------------+
+ * | vendor ramdisk      | p pages
+ * +---------------------+
+ * | dtb                 | q pages
+ * +---------------------+
+
+ * o = (2112 + page_size - 1) / page_size
+ * p = (vendor_ramdisk_size + page_size - 1) / page_size
+ * q = (dtb_size + page_size - 1) / page_size
+ *
+ * 0. all entities in the boot image are 4096-byte aligned in flash, all
+ *    entities in the vendor boot image are page_size (determined by the vendor
+ *    and specified in the vendor boot image header) aligned in flash
+ * 1. kernel, ramdisk, vendor ramdisk, and DTB are required (size != 0)
+ * 2. load the kernel and DTB at the specified physical address (kernel_addr,
+ *    dtb_addr)
+ * 3. load the vendor ramdisk at ramdisk_addr
+ * 4. load the generic ramdisk immediately following the vendor ramdisk in
+ *    memory
+ * 5. set up registers for kernel entry as required by your architecture
+ * 6. if the platform has a second stage bootloader jump to it (must be
+ *    contained outside boot and vendor boot partitions), otherwise
+ *    jump to kernel_addr
+ */
 struct header_image {
        uint32_t        code0;          /* Executable code */
        uint32_t        code1;          /* Executable code */
index 05266b4..3b0d896 100644 (file)
@@ -1522,9 +1522,13 @@ struct cipher_algo *image_get_cipher_algo(const char *full_name);
 #if !defined(USE_HOSTCC)
 #if defined(CONFIG_ANDROID_BOOT_IMAGE)
 struct andr_img_hdr;
+struct boot_img_hdr_v3;
+struct vendor_boot_img_hdr_v3;
 int android_image_check_header(const struct andr_img_hdr *hdr);
+int android_image_check_header_v3(const struct boot_img_hdr_v3 *hdr, const struct vendor_boot_img_hdr_v3 *vendor_hdr);
 int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
                             ulong *os_data, ulong *os_len);
+int android_image_get_kernel_v3(const struct boot_img_hdr_v3 *hdr, const struct vendor_boot_img_hdr_v3 *vendor_hdr);
 int android_image_get_ramdisk(const struct andr_img_hdr *hdr,
                              ulong *rd_data, ulong *rd_len);
 int android_image_get_second(const struct andr_img_hdr *hdr,
index e16db5e..c34fa5c 100644 (file)
@@ -371,6 +371,9 @@ config TRUSTY_UNLOCK_PERMISSION
        bool "Support unlock permission protection in trusty"
        depends on IMX_TRUSTY_OS
 
+config VENDOR_BOOT_SUPPORT
+       bool "Support vendor boot load"
+
 endmenu
 
 menu "Hashing Support"