Ramdisk in the manifest, simplify initrd generation

We currently support loading a ramdisk for the primary. In fact, all
primaries are required to have one called 'initrd.img'. This makes
the ramdisk optional and specifies its filename in the manifest.

With that, generate_initrd.py loses the last remaining hardcoded
assumption about the structure of the Hafnium ramdisk. Refactor the
script and the build so that generate_initrd.py simply accepts a list of
(name in ramdisk, path on host) pairs.

Bug: 117551352
Change-Id: Iff2d70205940a1740c473d1cac34d5a05d6d6791
diff --git a/src/boot_flow/android.c b/src/boot_flow/android.c
index cf7246e..0221674 100644
--- a/src/boot_flow/android.c
+++ b/src/boot_flow/android.c
@@ -51,10 +51,12 @@
  * Android boot flow does not change based on the updates.
  */
 bool plat_boot_flow_update(struct mm_stage1_locked stage1_locked,
+			   const struct manifest *manifest,
 			   struct boot_params_update *p, struct memiter *cpio,
 			   struct mpool *ppool)
 {
 	(void)stage1_locked;
+	(void)manifest;
 	(void)p;
 	(void)cpio;
 	(void)ppool;
diff --git a/src/boot_flow/common.c b/src/boot_flow/common.c
index 586d3d2..b295824 100644
--- a/src/boot_flow/common.c
+++ b/src/boot_flow/common.c
@@ -87,8 +87,9 @@
  * Takes action on any updates that were generated.
  */
 bool boot_flow_update(struct mm_stage1_locked stage1_locked,
+		      const struct manifest *manifest,
 		      struct boot_params_update *p, struct memiter *cpio,
 		      struct mpool *ppool)
 {
-	return plat_boot_flow_update(stage1_locked, p, cpio, ppool);
+	return plat_boot_flow_update(stage1_locked, manifest, p, cpio, ppool);
 }
diff --git a/src/boot_flow/linux.c b/src/boot_flow/linux.c
index 9d4d886..e1e257c 100644
--- a/src/boot_flow/linux.c
+++ b/src/boot_flow/linux.c
@@ -52,14 +52,19 @@
 }
 
 bool plat_boot_flow_update(struct mm_stage1_locked stage1_locked,
+			   const struct manifest *manifest,
 			   struct boot_params_update *update,
 			   struct memiter *cpio, struct mpool *ppool)
 {
-	static struct string filename = STRING_INIT("initrd.img");
 	struct memiter primary_initrd;
+	const struct string *filename =
+		&manifest->vm[HF_PRIMARY_VM_INDEX].primary.ramdisk_filename;
 
-	if (!cpio_get_file(cpio, &filename, &primary_initrd)) {
-		dlog("Unable to find initrd.img\n");
+	if (string_is_empty(filename)) {
+		memiter_init(&primary_initrd, NULL, 0);
+	} else if (!cpio_get_file(cpio, filename, &primary_initrd)) {
+		dlog("Unable to find primary initrd \"%s\".\n",
+		     string_data(filename));
 		return false;
 	}
 
diff --git a/src/init.c b/src/init.c
index 4948697..6d9e8ad 100644
--- a/src/init.c
+++ b/src/init.c
@@ -116,7 +116,8 @@
 		panic("Unable to load VMs.");
 	}
 
-	if (!boot_flow_update(mm_stage1_locked, &update, &cpio, &ppool)) {
+	if (!boot_flow_update(mm_stage1_locked, &manifest, &update, &cpio,
+			      &ppool)) {
 		panic("Unable to update boot flow.");
 	}
 
diff --git a/src/load.c b/src/load.c
index 7138824..01640f8 100644
--- a/src/load.c
+++ b/src/load.c
@@ -100,8 +100,8 @@
 			 struct mpool *ppool)
 {
 	paddr_t primary_begin = layout_primary_begin();
-	const struct manifest_vm *manifest_vm =
-		&manifest->vm[HF_PRIMARY_VM_ID - HF_VM_ID_OFFSET];
+	struct vm *vm;
+	struct vcpu_locked vcpu_locked;
 
 	/*
 	 * TODO: This bound is currently meaningless but will be addressed when
@@ -109,46 +109,41 @@
 	 */
 	paddr_t primary_end = pa_add(primary_begin, 0x8000000);
 
-	if (!load_kernel(stage1_locked, primary_begin, primary_end, manifest_vm,
-			 cpio, ppool)) {
+	if (!load_kernel(stage1_locked, primary_begin, primary_end,
+			 &manifest->vm[HF_PRIMARY_VM_INDEX], cpio, ppool)) {
 		dlog("Unable to load primary kernel.");
 		return false;
 	}
 
-	{
-		struct vm *vm;
-		struct vcpu_locked vcpu_locked;
-
-		if (!vm_init(MAX_CPUS, ppool, &vm)) {
-			dlog("Unable to initialise primary vm\n");
-			return false;
-		}
-
-		if (vm->id != HF_PRIMARY_VM_ID) {
-			dlog("Primary vm was not given correct id\n");
-			return false;
-		}
-
-		/* Map the 1TB of memory. */
-		/* TODO: We should do a whitelist rather than a blacklist. */
-		if (!mm_vm_identity_map(
-			    &vm->ptable, pa_init(0),
-			    pa_init(UINT64_C(1024) * 1024 * 1024 * 1024),
-			    MM_MODE_R | MM_MODE_W | MM_MODE_X, NULL, ppool)) {
-			dlog("Unable to initialise memory for primary vm\n");
-			return false;
-		}
-
-		if (!mm_vm_unmap_hypervisor(&vm->ptable, ppool)) {
-			dlog("Unable to unmap hypervisor from primary vm\n");
-			return false;
-		}
-
-		vcpu_locked = vcpu_lock(vm_get_vcpu(vm, 0));
-		vcpu_on(vcpu_locked, ipa_from_pa(primary_begin), kernel_arg);
-		vcpu_unlock(&vcpu_locked);
+	if (!vm_init(MAX_CPUS, ppool, &vm)) {
+		dlog("Unable to initialise primary vm\n");
+		return false;
 	}
 
+	if (vm->id != HF_PRIMARY_VM_ID) {
+		dlog("Primary vm was not given correct id\n");
+		return false;
+	}
+
+	/* Map the 1TB of memory. */
+	/* TODO: We should do a whitelist rather than a blacklist. */
+	if (!mm_vm_identity_map(&vm->ptable, pa_init(0),
+				pa_init(UINT64_C(1024) * 1024 * 1024 * 1024),
+				MM_MODE_R | MM_MODE_W | MM_MODE_X, NULL,
+				ppool)) {
+		dlog("Unable to initialise memory for primary vm\n");
+		return false;
+	}
+
+	if (!mm_vm_unmap_hypervisor(&vm->ptable, ppool)) {
+		dlog("Unable to unmap hypervisor from primary vm\n");
+		return false;
+	}
+
+	vcpu_locked = vcpu_lock(vm_get_vcpu(vm, 0));
+	vcpu_on(vcpu_locked, ipa_from_pa(primary_begin), kernel_arg);
+	vcpu_unlock(&vcpu_locked);
+
 	return true;
 }
 
diff --git a/src/manifest.c b/src/manifest.c
index 6d8b4ba..222716f 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -209,7 +209,10 @@
 	TRY(read_string(node, "debug_name", &vm->debug_name));
 	TRY(read_optional_string(node, "kernel_filename",
 				 &vm->kernel_filename));
-	if (vm_id != HF_PRIMARY_VM_ID) {
+	if (vm_id == HF_PRIMARY_VM_ID) {
+		TRY(read_optional_string(node, "ramdisk_filename",
+					 &vm->primary.ramdisk_filename));
+	} else {
 		TRY(read_uint64(node, "mem_size", &vm->secondary.mem_size));
 		TRY(read_uint16(node, "vcpu_count", &vm->secondary.vcpu_count));
 	}
diff --git a/src/manifest_test.cc b/src/manifest_test.cc
index d7690b4..902cf21 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -161,6 +161,11 @@
 		return StringProperty("kernel_filename", value);
 	}
 
+	ManifestDtBuilder &RamdiskFilename(const std::string_view &value)
+	{
+		return StringProperty("ramdisk_filename", value);
+	}
+
 	ManifestDtBuilder &VcpuCount(uint64_t value)
 	{
 		return IntegerProperty("vcpu_count", value);
@@ -398,6 +403,29 @@
 		  MANIFEST_ERROR_INTEGER_OVERFLOW);
 }
 
+TEST(manifest, no_ramdisk_primary)
+{
+	struct manifest m;
+	struct fdt_node fdt_root;
+
+	/* clang-format off */
+	std::vector<char> dtb = ManifestDtBuilder()
+		.StartChild("hypervisor")
+			.Compatible()
+			.StartChild("vm1")
+				.DebugName("primary_vm")
+			.EndChild()
+		.EndChild()
+		.Build();
+	/* clang-format on */
+
+	ASSERT_TRUE(get_fdt_root(dtb, &fdt_root));
+	ASSERT_EQ(manifest_init(&m, &fdt_root), MANIFEST_SUCCESS);
+	ASSERT_EQ(m.vm_count, 1);
+	ASSERT_STREQ(string_data(&m.vm[0].debug_name), "primary_vm");
+	ASSERT_STREQ(string_data(&m.vm[0].primary.ramdisk_filename), "");
+}
+
 TEST(manifest, valid)
 {
 	struct manifest m;
@@ -411,6 +439,7 @@
 			.StartChild("vm1")
 				.DebugName("primary_vm")
 				.KernelFilename("primary_kernel")
+				.RamdiskFilename("primary_ramdisk")
 			.EndChild()
 			.StartChild("vm3")
 				.DebugName("second_secondary_vm")
@@ -435,6 +464,8 @@
 	vm = &m.vm[0];
 	ASSERT_STREQ(string_data(&vm->debug_name), "primary_vm");
 	ASSERT_STREQ(string_data(&vm->kernel_filename), "primary_kernel");
+	ASSERT_STREQ(string_data(&vm->primary.ramdisk_filename),
+		     "primary_ramdisk");
 
 	vm = &m.vm[1];
 	ASSERT_STREQ(string_data(&vm->debug_name), "first_secondary_vm");