ANDROID: Handle a new init_boot partition that contains ramdisk

This new init_boot partition contains the ramdisk the used to live in
the boot partition. The boot partition will no longer contain that
ramdisk.

The bootloader remain flexible to be able to use the ramdisk from
boot or init_boot partititon.

Test: Boot cuttlefish
Bug: 203698939

Change-Id: I687ec1264494e9fe85321414b64eeebbc0e4e156
diff --git a/common/android_bootloader.c b/common/android_bootloader.c
index b82bf98..f321337 100644
--- a/common/android_bootloader.c
+++ b/common/android_bootloader.c
@@ -26,6 +26,7 @@
 #define ANDROID_PARTITION_RECOVERY "recovery"
 #define ANDROID_PARTITION_SYSTEM "system"
 #define ANDROID_PARTITION_BOOTCONFIG "bootconfig"
+#define ANDROID_PARTITION_INIT_BOOT "init_boot"
 
 #define ANDROID_ARG_SLOT_SUFFIX "androidboot.slot_suffix="
 #define ANDROID_ARG_ROOT "root="
@@ -404,7 +405,8 @@
 	enum android_boot_mode mode;
 	struct disk_partition boot_part_info;
 	struct disk_partition vendor_boot_part_info;
-	int boot_part_num, vendor_boot_part_num;
+	struct disk_partition init_boot_part_info;
+	int boot_part_num, vendor_boot_part_num, init_boot_part_num;
 	char *command_line;
 	char slot_suffix[3];
 	const char *mode_cmdline = NULL;
@@ -412,6 +414,7 @@
 	char *avb_bootconfig = NULL;
 	const char *boot_partition = ANDROID_PARTITION_BOOT;
 	const char *vendor_boot_partition = ANDROID_PARTITION_VENDOR_BOOT;
+	const char *init_boot_partition = ANDROID_PARTITION_INIT_BOOT;
 #ifdef CONFIG_ANDROID_SYSTEM_AS_ROOT
 	int system_part_num
 	struct disk_partition system_part_info;
@@ -486,6 +489,7 @@
 	 * disk again.*/
 	AvbSlotVerifyData *avb_out_data = NULL;
 	AvbPartitionData *verified_boot_img = NULL;
+	AvbPartitionData *verified_init_boot_img = NULL;
 	AvbPartitionData *verified_vendor_boot_img = NULL;
 	AvbSlotVerifyData *avb_out_bootconfig_data = NULL;
 	AvbPartitionData *verified_bootconfig_img = NULL;
@@ -498,14 +502,18 @@
 		for (int i = 0; i < avb_out_data->num_loaded_partitions; i++) {
 			AvbPartitionData *p =
 			    &avb_out_data->loaded_partitions[i];
-			if (strcmp("boot", p->partition_name) == 0) {
+			if (strcmp(ANDROID_PARTITION_BOOT, p->partition_name) == 0) {
 				verified_boot_img = p;
 			}
-			if (strcmp("vendor_boot", p->partition_name) == 0) {
+			if (strcmp(ANDROID_PARTITION_INIT_BOOT, p->partition_name) == 0) {
+				verified_init_boot_img = p;
+			}
+			if (strcmp(ANDROID_PARTITION_VENDOR_BOOT, p->partition_name) == 0) {
 				verified_vendor_boot_img = p;
 			}
 		}
-		if (verified_boot_img == NULL || verified_vendor_boot_img == NULL) {
+		if (verified_boot_img == NULL || verified_vendor_boot_img == NULL ||
+				verified_init_boot_img == NULL) {
 			debug("verified partition not found");
 			goto bail;
 		}
@@ -574,15 +582,24 @@
 	boot_part_num =
 	    android_part_get_info_by_name_suffix(dev_desc, boot_partition,
 						 slot_suffix, &boot_part_info);
+	init_boot_part_num =
+	    android_part_get_info_by_name_suffix(dev_desc, init_boot_partition,
+						 slot_suffix, &init_boot_part_info);
 	/* Load the vendor boot partition if there is one. */
 	vendor_boot_part_num =
 	    android_part_get_info_by_name_suffix(dev_desc, vendor_boot_partition,
 						 slot_suffix,
 						 &vendor_boot_part_info);
+	if (init_boot_part_num < 0) {
+		log_err("Failed to find init_boot partition");
+		goto bail;
+	}
+	debug("ANDROID: Loading ramdisk from \"%s\", partition %d.\n",
+		init_boot_part_info.name, init_boot_part_num);
 	if (boot_part_num < 0)
 		goto bail;
 	debug("ANDROID: Loading kernel from \"%s\", partition %d.\n",
-	      boot_part_info.name, boot_part_num);
+		boot_part_info.name, boot_part_num);
 
 #ifdef CONFIG_ANDROID_SYSTEM_AS_ROOT
 	system_part_num =
@@ -621,11 +638,12 @@
 	}
 
 	struct andr_boot_info* boot_info = android_image_load(dev_desc, &boot_part_info,
-				 vendor_boot_part_info_ptr,
-				 kernel_address, slot_suffix, normal_boot, avb_bootconfig,
-				 persistant_dev_desc, bootconfig_part_info_ptr,
-				 verified_boot_img, verified_vendor_boot_img,
-				 verified_bootconfig_img);
+				vendor_boot_part_info_ptr,
+				&init_boot_part_info,
+				kernel_address, slot_suffix, normal_boot, avb_bootconfig,
+				persistant_dev_desc, bootconfig_part_info_ptr,
+				verified_boot_img, verified_vendor_boot_img,
+				verified_bootconfig_img, verified_init_boot_img);
 
 	if (!boot_info)
 		goto bail;
diff --git a/common/avb_verify.c b/common/avb_verify.c
index 2940d55..9050f51 100644
--- a/common/avb_verify.c
+++ b/common/avb_verify.c
@@ -956,7 +956,7 @@
 	       AvbSlotVerifyData **out_data,
 	       char **out_cmdline)
 {
-	const char * const requested_partitions[] = {"boot", "vendor_boot", NULL};
+	const char * const requested_partitions[] = {"boot", "vendor_boot", "init_boot", NULL};
 	return avb_verify_partitions(ops, slot_suffix, requested_partitions, out_data, out_cmdline);
 }
 
diff --git a/common/image-android.c b/common/image-android.c
index a1be09f..370763c 100644
--- a/common/image-android.c
+++ b/common/image-android.c
@@ -88,7 +88,9 @@
 static bool android_read_from_avb_partition(const AvbPartitionData *part,
 				    size_t offset, void *dest, size_t size) {
 	if (offset + size > part->data_size) {
-		debug("attempted to read past the partition boundary");
+		debug("Attempted to read past the %s partition boundary. "
+			"Offset: %d, read size: %d, partition size: %d\n",
+			part->partition_name, offset, size, part->data_size);
 		return false;
 	}
 	memcpy(dest, part->data + offset, size);
@@ -223,10 +225,11 @@
 
 static void _populate_boot_info(const struct boot_img_hdr_v4* boot_hdr,
 		const struct vendor_boot_img_hdr_v4* vboot_hdr,
+		const struct boot_img_hdr_v4* init_boot_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_ramdisk_size = init_boot_hdr->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;
@@ -442,15 +445,16 @@
 	return true;
 }
 
-static bool _read_in_boot_ramdisk(struct blk_desc *dev_desc,
+static bool _read_in_ramdisk(struct blk_desc *dev_desc,
 		const struct disk_partition *boot_img,
 		const struct andr_boot_info *boot_info,
-		const AvbPartitionData *verified_boot_img) {
+		const AvbPartitionData *verified_boot_img,
+		size_t aligned_kernel_offset) {
 
 	// Ramdisk is after the kernel
 	size_t offset =
 		ALIGN(ANDR_BOOT_IMG_HDR_SIZE, ANDR_BOOT_IMG_HDR_SIZE) +
-		ALIGN(boot_info->kernel_size, ANDR_BOOT_IMG_HDR_SIZE);
+		aligned_kernel_offset;
 	size_t size = ALIGN(boot_info->boot_ramdisk_size, ANDR_BOOT_IMG_PAGE_SIZE);
 	void *laddr = (void*)boot_info->boot_ramdisk_addr;
 	if (!android_read_data("ramdisk", dev_desc, boot_img, verified_boot_img,
@@ -461,9 +465,31 @@
 	return true;
 }
 
+static bool _read_in_boot_ramdisk(struct blk_desc *dev_desc,
+		const struct disk_partition *boot_img,
+		const struct andr_boot_info *boot_info,
+		const AvbPartitionData *verified_boot_img) {
+
+	// Ramdisk is after the kernel
+	size_t aligned_kernel_offset =
+		ALIGN(boot_info->kernel_size, ANDR_BOOT_IMG_HDR_SIZE);
+	return _read_in_ramdisk(dev_desc, boot_img, boot_info, verified_boot_img,
+							aligned_kernel_offset);
+}
+
+static bool _read_in_init_boot_ramdisk(struct blk_desc *dev_desc,
+		const struct disk_partition *boot_img,
+		const struct andr_boot_info *boot_info,
+		const AvbPartitionData *verified_boot_img) {
+	// init_boot does not contain a kernel
+	return _read_in_ramdisk(dev_desc, boot_img, boot_info, verified_boot_img,
+							/* aligned_kernel_offset */ 0);
+}
+
 struct andr_boot_info* android_image_load(struct blk_desc *dev_desc,
 			const struct disk_partition *boot_img,
 			const struct disk_partition *vendor_boot_img,
+			const struct disk_partition *init_boot_img,
 			unsigned long load_address, const char *slot_suffix,
 			const bool normal_boot,
 			const char *avb_bootconfig,
@@ -471,8 +497,10 @@
 			const struct disk_partition *device_specific_bootconfig_img,
 			const AvbPartitionData *verified_boot_img,
 			const AvbPartitionData *verified_vendor_boot_img,
-			const AvbPartitionData *verified_bootconfig_img) {
+			const AvbPartitionData *verified_bootconfig_img,
+			const AvbPartitionData *verified_init_boot_img) {
 	struct boot_img_hdr_v4 *boot_hdr = NULL;
+	struct boot_img_hdr_v4 *init_boot_hdr = NULL;
 	struct vendor_boot_img_hdr_v4 *vboot_hdr = NULL;
 	struct andr_boot_info *boot_info = NULL;
 	void *kernel_rd_addr = NULL;
@@ -481,14 +509,22 @@
 		debug("Android Image load inputs are invalid.\n");
 		goto image_load_exit;
 	}
+	if(!init_boot_img) {
+		debug("Failed to find init_boot partition.\n");
+	}
 
 	boot_hdr = _extract_boot_image_header(dev_desc, boot_img,
 					      verified_boot_img);
+	init_boot_hdr = _extract_boot_image_header(dev_desc, init_boot_img,
+					      verified_init_boot_img);
 	vboot_hdr = _extract_vendor_boot_image_header(dev_desc, vendor_boot_img,
 						      verified_vendor_boot_img);
 	if(!boot_hdr || !vboot_hdr) {
 		goto image_load_exit;
 	}
+	if(!init_boot_hdr) {
+		debug("Failed to extract init_boot boot header.\n");
+	}
 
 	boot_info = (struct andr_boot_info*)malloc(sizeof(struct andr_boot_info));
 	if(!boot_info) {
@@ -505,12 +541,14 @@
 		goto image_load_exit;
 	}
 
-	_populate_boot_info(boot_hdr, vboot_hdr, kernel_rd_addr, boot_info);
+	_populate_boot_info(boot_hdr, vboot_hdr, init_boot_hdr, kernel_rd_addr, boot_info);
 	if(!_read_in_kernel(dev_desc, boot_img, boot_info, verified_boot_img)
 		|| !_read_in_vendor_ramdisk(dev_desc, vendor_boot_img,
 					    boot_info, verified_vendor_boot_img)
-		|| !_read_in_boot_ramdisk(dev_desc, boot_img, boot_info,
-					  verified_boot_img)
+		|| !(_read_in_init_boot_ramdisk(dev_desc, init_boot_img, boot_info,
+					  verified_init_boot_img) ||
+			 _read_in_boot_ramdisk(dev_desc, boot_img, boot_info,
+					  verified_boot_img))
 		|| !_read_in_bootconfig(dev_desc, vendor_boot_img, boot_info,
 					slot_suffix, normal_boot, avb_bootconfig,
 					persistent_dev_desc,
diff --git a/include/image.h b/include/image.h
index 5844dee..18596ec 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1517,8 +1517,10 @@
  * Android Image as described in the header size. In case of error reading the
  * image, NULL is returned.
  * @dev_desc:		The device where to read the image from
- * @boot_img_info:	The partition in |dev_desc| to read the kernel and init
- * @device_info:	The partition in |dev_desc| to read device specific
+ * @boot_img_info:	The partition in |dev_desc| to read the kernel and
+ * optionally init
+ * @vendor_boot_info:	The partition in |dev_desc| to read vendor specific
+ * @init_boot_info: The partition in |dev_desc| to read init
  * 			content from. This partition is not expected on devices
  * 			with android boot images version 1 and 2.
  * @load_address:	The address where the image will be loaded
@@ -1533,11 +1535,14 @@
  * is not NULL, data should be read from here instead of dev_desc
  * @verified_bootconfig_image: bootconfig partition that is verified. If this is
  * not NULL, data should be read from here instead of dev_desc
+ * @verified_init_boot_image: init_boot partition that is verified. If this is not NULL,
+ * data should be read from here instead of dev_desc.
  * @return: android boot info struct pointer
  */
 struct andr_boot_info* android_image_load(struct blk_desc *dev_desc,
 			const struct disk_partition *boot_img_info,
-			const struct disk_partition *device_info,
+			const struct disk_partition *vendor_boot_info,
+			const struct disk_partition *init_boot_img_info,
 			unsigned long load_address, const char *slot_suffix,
 			const bool normal_boot,
 			const char *avb_bootconfig,
@@ -1545,7 +1550,8 @@
 			const struct disk_partition *device_specific_bootconfig_img,
 			const AvbPartitionData *verified_boot_img,
 			const AvbPartitionData *verified_vendor_boot_img,
-			const AvbPartitionData *verified_bootconfig_img);
+			const AvbPartitionData *verified_bootconfig_img,
+			const AvbPartitionData *verified_init_boot_img);
 
 #endif /* CONFIG_ANDROID_BOOT_IMAGE */
 #endif /* !USE_HOSTCC */