cuttlefish: Add support for vendor boot header v4

No acutal change in behavior outside of gathering more info from the
boot header.
Vendor boot header v4 comes with ramdisk fragment changes and bootconfig
changes.
Boot header v4 has no changes.
Vendor ramdisk fragments aren't being handled in any special way, and
the vendor ramdisk can continue to be placed into memory as is.
Bootconfig support comes in a follow-on commit.

Test: boot cuttlefish using a boot image with v4 header
Bug: 173815685
Change-Id: If9213f51ea4cb75c8274d4a6986c3422d11a379b
diff --git a/common/image-android.c b/common/image-android.c
index 161f933..47d7925 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -69,16 +69,17 @@
 	return 0;
 }
 
-static struct boot_img_hdr_v3* _extract_boot_image_header(
+static struct boot_img_hdr_v4* _extract_boot_image_header(
 		struct blk_desc *dev_desc,
 		const struct disk_partition *boot_img) {
 	long blk_cnt, blks_read;
-	blk_cnt = BLK_CNT(sizeof(struct boot_img_hdr_v3), boot_img->blksz);
+	blk_cnt = BLK_CNT(sizeof(struct boot_img_hdr_v4), boot_img->blksz);
 
-	struct boot_img_hdr_v3 *boot_hdr = (struct boot_img_hdr_v3*)
+	struct boot_img_hdr_v4 *boot_hdr = (struct boot_img_hdr_v4*)
 		(malloc(blk_cnt * boot_img->blksz));
 
 	if(!blk_cnt || !boot_hdr) {
+		free(boot_hdr);
 		return NULL;
 	}
 
@@ -86,17 +87,20 @@
 	if(blks_read != blk_cnt) {
 		debug("boot img header blk cnt is %ld and blks read is %ld\n",
 			blk_cnt, blks_read);
+		free(boot_hdr);
 		return NULL;
 	}
 
 	if(strncmp(ANDR_BOOT_MAGIC, (const char *)boot_hdr->magic,
 		   ANDR_BOOT_MAGIC_SIZE)) {
 		debug("boot header magic is invalid.\n");
+		free(boot_hdr);
 		return NULL;
 	}
 
-	if(boot_hdr->header_version != 3) {
-		debug("boot header is not v3.\n");
+	if(boot_hdr->header_version < 3) {
+		debug("boot header is less than v3.\n");
+                free(boot_hdr);
 		return NULL;
 	}
 
@@ -104,18 +108,19 @@
 	return boot_hdr;
 }
 
-static struct vendor_boot_img_hdr_v3* _extract_vendor_boot_image_header(
+static struct vendor_boot_img_hdr_v4* _extract_vendor_boot_image_header(
 		struct blk_desc *dev_desc,
 		const struct disk_partition *vendor_boot_img) {
 	long blk_cnt, blks_read;
-	blk_cnt = BLK_CNT(sizeof(struct vendor_boot_img_hdr_v3),
+	blk_cnt = BLK_CNT(sizeof(struct vendor_boot_img_hdr_v4),
 			vendor_boot_img->blksz);
 
-	struct vendor_boot_img_hdr_v3 *vboot_hdr =
-		(struct vendor_boot_img_hdr_v3*)
+	struct vendor_boot_img_hdr_v4 *vboot_hdr =
+		(struct vendor_boot_img_hdr_v4*)
 		(malloc(blk_cnt * vendor_boot_img->blksz));
 
 	if(!blk_cnt || !vboot_hdr) {
+		free(vboot_hdr);
 		return NULL;
 	}
 
@@ -123,35 +128,51 @@
 	if(blks_read != blk_cnt) {
 		debug("vboot img header blk cnt is %ld and blks read is %ld\n",
 			blk_cnt, blks_read);
+		free(vboot_hdr);
 		return NULL;
 	}
 
 	if(strncmp(VENDOR_BOOT_MAGIC, (const char *)vboot_hdr->magic,
 		   VENDOR_BOOT_MAGIC_SIZE)) {
 		debug("vendor boot header magic is invalid.\n");
+		free(vboot_hdr);
 		return NULL;
 	}
 
-	if(vboot_hdr->header_version != 3) {
-		debug("vendor boot header is not v3.\n");
+	if(vboot_hdr->header_version < 3) {
+		debug("vendor boot header is less than v3.\n");
+		free(vboot_hdr);
 		return NULL;
 	}
 
 	return vboot_hdr;
 }
 
-static void _populate_boot_info(const struct boot_img_hdr_v3* boot_hdr,
-		const struct vendor_boot_img_hdr_v3* vboot_hdr,
+static void _populate_boot_info(const struct boot_img_hdr_v4* boot_hdr,
+		const struct vendor_boot_img_hdr_v4* vboot_hdr,
 		const void* load_addr,
 		struct andr_boot_info *boot_info) {
 	boot_info->kernel_size = boot_hdr->kernel_size;
 	boot_info->boot_ramdisk_size = boot_hdr->ramdisk_size;
+	boot_info->boot_header_version = boot_hdr->header_version;
 	boot_info->vendor_ramdisk_size = vboot_hdr->vendor_ramdisk_size;
 	boot_info->tags_addr = vboot_hdr->tags_addr;
 	boot_info->os_version = boot_hdr->os_version;
 	boot_info->page_size = vboot_hdr->page_size;
 	boot_info->dtb_size = vboot_hdr->dtb_size;
 	boot_info->dtb_addr = vboot_hdr->dtb_addr;
+	boot_info->vendor_header_version = vboot_hdr->header_version;
+	if (vboot_hdr->header_version > 3) {
+		boot_info->vendor_ramdisk_table_size = vboot_hdr->vendor_ramdisk_table_size;
+		boot_info->vendor_ramdisk_table_entry_num = vboot_hdr->vendor_ramdisk_table_entry_num;
+		boot_info->vendor_ramdisk_table_entry_size = vboot_hdr->vendor_ramdisk_table_entry_size;
+		boot_info->vendor_bootconfig_size = vboot_hdr->vendor_bootconfig_size;
+	} else {
+		boot_info->vendor_ramdisk_table_size = 0;
+		boot_info->vendor_ramdisk_table_entry_num = 0;
+		boot_info->vendor_ramdisk_table_entry_size = 0;
+		boot_info->vendor_bootconfig_size = 0;
+	}
 
 	memset(boot_info->name, 0, ANDR_BOOT_NAME_SIZE);
 	strncpy(boot_info->name, (const char *)vboot_hdr->name,
@@ -198,10 +219,10 @@
 static bool _read_in_vendor_ramdisk(struct blk_desc *dev_desc,
 		const struct disk_partition *vendor_boot_img,
 		const struct andr_boot_info *boot_info) {
-	u32 vendor_hdr_size_page_aligned = 
-		ALIGN(sizeof(struct vendor_boot_img_hdr_v3),
+	u32 vendor_hdr_size_page_aligned =
+		ALIGN(sizeof(struct vendor_boot_img_hdr_v4),
 			boot_info->page_size);
-	u32 vendor_ramdisk_size_page_aligned = 
+	u32 vendor_ramdisk_size_page_aligned =
 		ALIGN(boot_info->vendor_ramdisk_size, boot_info->page_size);
 	lbaint_t ramdisk_lba = vendor_boot_img->start
 		+ BLK_CNT(vendor_hdr_size_page_aligned, vendor_boot_img->blksz);
@@ -252,8 +273,8 @@
 			const struct disk_partition *boot_img,
 			const struct disk_partition *vendor_boot_img,
 			unsigned long load_address) {
-	struct boot_img_hdr_v3 *boot_hdr = NULL;
-	struct vendor_boot_img_hdr_v3 *vboot_hdr = NULL;
+	struct boot_img_hdr_v4 *boot_hdr = NULL;
+	struct vendor_boot_img_hdr_v4 *vboot_hdr = NULL;
 	struct andr_boot_info *boot_info = NULL;
 	void *kernel_rd_addr = NULL;
 
diff --git a/include/android_image.h b/include/android_image.h
index 3f50a18..3d3e096 100644
--- a/include/android_image.h
+++ b/include/android_image.h
@@ -27,6 +27,12 @@
 #define ANDR_BOOT_IMG_HDR_SIZE (ANDR_BOOT_IMG_PAGE_SIZE)
 #define TOTAL_BOOT_ARGS_SIZE (ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE + \
                               VENDOR_BOOT_ARGS_SIZE + 1)
+#define VENDOR_RAMDISK_TYPE_NONE 0
+#define VENDOR_RAMDISK_TYPE_PLATFORM 1
+#define VENDOR_RAMDISK_TYPE_RECOVERY 2
+#define VENDOR_RAMDISK_TYPE_DLKM 3
+#define VENDOR_RAMDISK_NAME_SIZE 32
+#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16
 
 /* The bootloader expects this struct at the front of the kernel and ramdisk */
 struct andr_boot_info {
@@ -49,9 +55,17 @@
 
     u32 dtb_size; /* size in bytes for DTB image */
     u64 dtb_addr; /* physical load address for DTB image */
+
+    u32 boot_header_version;
+    u32 vendor_header_version;
+
+    u32 vendor_ramdisk_table_size;
+    u32 vendor_ramdisk_table_entry_num;
+    u32 vendor_ramdisk_table_entry_size;
+    u32 vendor_bootconfig_size; /* size in bytes for bootconfig image */
 } __attribute__((packed));
 
-struct boot_img_hdr_v3 {
+struct boot_img_hdr_v4 {
     // Must be ANDR_BOOT_MAGIC.
     uint8_t magic[ANDR_BOOT_MAGIC_SIZE];
 
@@ -73,7 +87,7 @@
     uint8_t cmdline[ANDR_BOOT_ARGS_SIZE + ANDR_BOOT_EXTRA_ARGS_SIZE];
 } __attribute__((packed));
 
-struct vendor_boot_img_hdr_v3 {
+struct vendor_boot_img_hdr_v4 {
     // Must be VENDOR_BOOT_MAGIC.
     uint8_t magic[VENDOR_BOOT_MAGIC_SIZE];
 
@@ -96,8 +110,108 @@
 
     uint32_t dtb_size; /* size in bytes for DTB image */
     uint64_t dtb_addr; /* physical load address for DTB image */
+    /* new for v4 */
+    uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */
+    uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */
+    uint32_t vendor_ramdisk_table_entry_size;
+    uint32_t vendor_bootconfig_size; /* size in bytes for bootconfig image */
 } __attribute__((packed));
 
+struct vendor_ramdisk_table_entry_v4 {
+    uint32_t ramdisk_size; /* size in bytes for the ramdisk image */
+    uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */
+    uint32_t ramdisk_type; /* type of the ramdisk */
+    uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */
+
+    // Hardware identifiers describing the board, soc or platform which this
+    // ramdisk is intended to be loaded on.
+    uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE];
+} __attribute__((packed));
+
+/* When the boot image header has a version of 4, the structure of the boot
+ * image is the same as version 3:
+ *
+ * +---------------------+
+ * | 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 4 of the boot image header, page size is fixed at 4096
+ * bytes.
+ *
+ * The structure of the vendor boot image version 4, which is required to be
+ * present when a version 4 boot image is used, is as follows:
+ *
+ * +------------------------+
+ * | vendor boot header     | o pages
+ * +------------------------+
+ * | vendor ramdisk section | p pages
+ * +------------------------+
+ * | dtb                    | q pages
+ * +------------------------+
+ * | vendor ramdisk table   | r pages
+ * +------------------------+
+ * | bootconfig             | s pages
+ * +------------------------+
+ *
+ * o = (2124 + page_size - 1) / page_size
+ * p = (vendor_ramdisk_size + page_size - 1) / page_size
+ * q = (dtb_size + page_size - 1) / page_size
+ * r = (vendor_ramdisk_table_size + page_size - 1) / page_size
+ * s = (vendor_bootconfig_size + page_size - 1) / page_size
+ *
+ * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can
+ * be included in the vendor boot image. The bootloader can select a subset of
+ * ramdisks to load at runtime. To help the bootloader select the ramdisks, each
+ * ramdisk is tagged with a type tag and a set of hardware identifiers
+ * describing the board, soc or platform that this ramdisk is intended for.
+ *
+ * The vendor ramdisk section is consist of multiple ramdisk images concatenated
+ * one after another, and vendor_ramdisk_size is the size of the section, which
+ * is the total size of all the ramdisks included in the vendor boot image.
+ *
+ * The vendor ramdisk table holds the size, offset, type, name and hardware
+ * identifiers of each ramdisk. The type field denotes the type of its content.
+ * The hardware identifiers are specified in the board_id field in each table
+ * entry. The board_id field is consist of a vector of unsigned integer words,
+ * and the encoding scheme is defined by the hardware vendor.
+ *
+ * For the different type of ramdisks, there are:
+ *    - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified.
+ *    - VENDOR_RAMDISK_TYPE_PLATFORM ramdisk contains platform specific bits.
+ *    - VENDOR_RAMDISK_TYPE_RECOVERY ramdisk contains recovery resources.
+ *    - VENDOR_RAMDISK_TYPE_DLKM ramdisk contains dynamic loadable kernel
+ *      modules.
+ *
+ * Version 4 of the vendor boot image also adds a bootconfig section to the end
+ * of the image. This section contains Boot Configuration parameters known at
+ * build time. The bootloader is responsible for placing this section directly
+ * after the boot image ramdisk, followed by the bootconfig trailer, before
+ * entering the kernel.
+ *
+ * 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, 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 ramdisks at ramdisk_addr
+ * 4. load the generic ramdisk immediately following the vendor ramdisk in
+ *    memory
+ * 5. load the vendor bootconfig immediately following the generic ramdisk. Add
+ *    additional bootconfig parameters followed by the bootconfig trailer.
+ * 6. set up registers for kernel entry as required by your architecture
+ * 7. 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
+ */
+
 /* When the boot image header has a version of 3, the structure of the boot
  * image is as follows:
  *