Set primary kernel in manifest and allow preloading.

The primary kernel was previously hard-coded as `vmlinuz` but the
manifest allows more flexibility. If the kernel file for any VM is not
specified, it is assumed that the image has been preloaded into memory.

The loading of the primary and secondaries are becoming increasingly
similar and will continue to do so.

Change-Id: I34f134d8a4d32e8ac92e142d3636902d52ad86ec
diff --git a/build/image/generate_initrd.py b/build/image/generate_initrd.py
index 38ce19c..4d8f281 100644
--- a/build/image/generate_initrd.py
+++ b/build/image/generate_initrd.py
@@ -29,6 +29,7 @@
 
 def Main():
     parser = argparse.ArgumentParser()
+    parser.add_argument("--primary_name", required=True)
     parser.add_argument("--primary_vm", required=True)
     parser.add_argument("--primary_vm_initrd")
     parser.add_argument(
@@ -39,17 +40,19 @@
     parser.add_argument("--staging", required=True)
     parser.add_argument("--output", required=True)
     args = parser.parse_args()
-    staged_files = ["vmlinuz", "initrd.img"]
+    staged_files = [args.primary_name, "initrd.img"]
 
     # Create staging folder if needed.
     if not os.path.isdir(args.staging):
         os.makedirs(args.staging)
 
     # Prepare the primary VM image.
-    shutil.copyfile(args.primary_vm, os.path.join(args.staging, "vmlinuz"))
+    shutil.copyfile(args.primary_vm,
+                    os.path.join(args.staging, args.primary_name))
     # Prepare the primary VM's initrd.
     if args.primary_vm_initrd:
-        shutil.copyfile(args.primary_vm_initrd, os.path.join(args.staging, "initrd.img"))
+        shutil.copyfile(args.primary_vm_initrd,
+                        os.path.join(args.staging, "initrd.img"))
     else:
         open(os.path.join(args.staging, "initrd.img"), "w").close()
     # Prepare the secondary VMs.
diff --git a/build/image/image.gni b/build/image/image.gni
index 6865f87..2c29f4a 100644
--- a/build/image/image.gni
+++ b/build/image/image.gni
@@ -173,6 +173,8 @@
 
 # Build the initial RAM disk for the hypervisor.
 template("initrd") {
+  assert(defined(invoker.primary_name),
+         "initrd() must specify a \"primary_name\" value")
   assert(defined(invoker.primary_vm),
          "initrd() must specify a \"primary_vm\" value")
 
@@ -203,6 +205,8 @@
       invoker.primary_vm,
     ]
     args = [
+      "--primary_name",
+      invoker.primary_name,
       "--primary_vm",
       rebase_path(primary_vm_image),
       "--staging",
diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md
index 1989855..4ece4ec 100644
--- a/docs/GettingStarted.md
+++ b/docs/GettingStarted.md
@@ -61,6 +61,7 @@
 	hypervisor {
 		vm1 {
 			debug_name = "Linux VM";
+			kernel_filename = "vmlinuz";
 		};
 	};
 };
diff --git a/docs/Manifest.md b/docs/Manifest.md
index 58a5600..ff1cf0e 100644
--- a/docs/Manifest.md
+++ b/docs/Manifest.md
@@ -12,6 +12,7 @@
 	hypervisor {
 		vm1 {
 			debug_name = "name";
+			kernel_filename = "vmlinuz";
 		};
 
 		vm2 {
@@ -31,10 +32,12 @@
 
 ## Example
 
-The following manifest defines two secondary VMs, the first one with 1MB of
-memory, 2 CPUs and kernel image called `kernel0` (matches filename in Hafnium's
-[ramdisk](HafniumRamDisk.md)), while the second one has 2MB of memory, 4 CPUs
-and a kernel image called `kernel1`.
+The following manifest defines a primary VM with two secondary VMs. The first
+secondary VM has 1MB of memory, 2 CPUs and kernel image called `kernel0`
+(matches filename in Hafnium's [ramdisk](HafniumRamDisk.md)). The second has 2MB
+of memory, 4 CPUs and, by omitting the `kernel_filename` property, a kernel
+preloaded into memory. The primary VM is given all remaining memory, the same
+number of CPUs as the hardware and a kernel image called `vmlinuz`.
 
 ```
 /dts-v1/;
@@ -44,6 +47,7 @@
 	hypervisor {
 		vm1 {
 			debug_name = "primary VM";
+			kernel_filename = "vmlinuz";
 		};
 
 		vm2 {
@@ -55,7 +59,6 @@
 
 		vm3 {
 			debug_name = "secondary VM 2";
-			kernel_filename = "kernel1";
 			vcpu_count = <4>;
 			mem_size = <0x200000>;
 		};
diff --git a/inc/hf/load.h b/inc/hf/load.h
index d7ccd71..b76dc1d 100644
--- a/inc/hf/load.h
+++ b/inc/hf/load.h
@@ -26,10 +26,7 @@
 #include "hf/mm.h"
 #include "hf/mpool.h"
 
-bool load_primary(struct mm_stage1_locked stage1_locked,
-		  const struct memiter *cpio, uintreg_t kernel_arg,
-		  struct memiter *initrd, struct mpool *ppool);
-bool load_secondary(struct mm_stage1_locked stage1_locked,
-		    const struct manifest *manifest, const struct memiter *cpio,
-		    const struct boot_params *params,
-		    struct boot_params_update *update, struct mpool *ppool);
+bool load_vms(struct mm_stage1_locked stage1_locked,
+	      const struct manifest *manifest, const struct memiter *cpio,
+	      const struct boot_params *params,
+	      struct boot_params_update *update, struct mpool *ppool);
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index 57657c7..cdbdd39 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -31,10 +31,10 @@
 struct manifest_vm {
 	/* Properties defined for both primary and secondary VMs. */
 	char debug_name[MANIFEST_MAX_STRING_LENGTH];
+	char kernel_filename[MANIFEST_MAX_STRING_LENGTH];
 
 	/* Properties specific to secondary VMs. */
 	struct {
-		char kernel_filename[MANIFEST_MAX_STRING_LENGTH];
 		uint64_t mem_size;
 		spci_vcpu_count_t vcpu_count;
 	} secondary;
diff --git a/src/init.c b/src/init.c
index 8a13610..4ed8c87 100644
--- a/src/init.c
+++ b/src/init.c
@@ -71,7 +71,6 @@
 	struct manifest manifest;
 	struct boot_params params;
 	struct boot_params_update update;
-	struct memiter primary_initrd;
 	struct memiter cpio;
 	void *initrd;
 	size_t i;
@@ -104,28 +103,17 @@
 	initrd = mm_identity_map(mm_stage1_locked, params.initrd_begin,
 				 params.initrd_end, MM_MODE_R, &ppool);
 	if (!initrd) {
-		panic("unable to map initrd in");
+		panic("Unable to map initrd.");
 	}
 
 	memiter_init(&cpio, initrd,
 		     pa_difference(params.initrd_begin, params.initrd_end));
 
 	/* Load all VMs. */
-	if (!load_primary(mm_stage1_locked, &cpio, params.kernel_arg,
-			  &primary_initrd, &ppool)) {
-		panic("unable to load primary VM");
-	}
-
-	/*
-	 * load_secondary will add regions assigned to the secondary VMs from
-	 * mem_ranges to reserved_ranges.
-	 */
-	update.initrd_begin = pa_from_va(va_from_ptr(primary_initrd.next));
-	update.initrd_end = pa_from_va(va_from_ptr(primary_initrd.limit));
 	update.reserved_ranges_count = 0;
-	if (!load_secondary(mm_stage1_locked, &manifest, &cpio, &params,
-			    &update, &ppool)) {
-		panic("unable to load secondary VMs");
+	if (!load_vms(mm_stage1_locked, &manifest, &cpio, &params, &update,
+		      &ppool)) {
+		panic("Unable to load VMs.");
 	}
 
 	/* Prepare to run by updating bootparams as seen by primary VM. */
diff --git a/src/load.c b/src/load.c
index db19e05..b179ba9 100644
--- a/src/load.c
+++ b/src/load.c
@@ -20,6 +20,7 @@
 
 #include "hf/api.h"
 #include "hf/boot_params.h"
+#include "hf/check.h"
 #include "hf/dlog.h"
 #include "hf/layout.h"
 #include "hf/memiter.h"
@@ -55,7 +56,7 @@
 	memcpy_s(ptr, size, from, size);
 	arch_mm_flush_dcache(ptr, size);
 
-	mm_unmap(stage1_locked, to, to_end, ppool);
+	CHECK(mm_unmap(stage1_locked, to, to_end, ppool));
 
 	return true;
 }
@@ -106,32 +107,74 @@
 	return false;
 }
 
+static bool load_kernel(struct mm_stage1_locked stage1_locked, paddr_t begin,
+			paddr_t end, const struct manifest_vm *manifest_vm,
+			const struct memiter *cpio, struct mpool *ppool)
+{
+	struct memiter kernel_filename;
+	struct memiter kernel;
+
+	memiter_init(&kernel_filename, manifest_vm->kernel_filename,
+		     strnlen_s(manifest_vm->kernel_filename,
+			       MANIFEST_MAX_STRING_LENGTH));
+
+	if (memiter_size(&kernel_filename) == 0) {
+		/* This signals the kernel has been preloaded. */
+		return true;
+	}
+
+	if (!memiter_find_file(cpio, &kernel_filename, &kernel)) {
+		dlog("Could not find kernel file \"%s\".\n",
+		     manifest_vm->kernel_filename);
+		return false;
+	}
+
+	if (pa_difference(begin, end) < memiter_size(&kernel)) {
+		dlog("Kernel is larger than available memory.\n");
+		return false;
+	}
+
+	if (!copy_to_unmapped(stage1_locked, begin, &kernel, ppool)) {
+		dlog("Unable to copy kernel.\n");
+		return false;
+	}
+
+	return true;
+}
+
 /**
  * Loads the primary VM.
  */
-bool load_primary(struct mm_stage1_locked stage1_locked,
-		  const struct memiter *cpio, uintreg_t kernel_arg,
-		  struct memiter *initrd, struct mpool *ppool)
+static bool load_primary(struct mm_stage1_locked stage1_locked,
+			 const struct manifest *manifest,
+			 const struct memiter *cpio, uintreg_t kernel_arg,
+			 struct boot_params_update *update, struct mpool *ppool)
 {
-	struct memiter it;
 	paddr_t primary_begin = layout_primary_begin();
+	const struct manifest_vm *manifest_vm =
+		&manifest->vm[HF_PRIMARY_VM_ID - HF_VM_ID_OFFSET];
+	struct memiter initrd;
 
-	if (!find_file(cpio, "vmlinuz", &it)) {
-		dlog("Unable to find vmlinuz\n");
+	/*
+	 * TODO: This bound is currently meaningless but will be addressed when
+	 * the manifest specifies the load address.
+	 */
+	paddr_t primary_end = pa_add(primary_begin, 0x8000000);
+
+	if (!load_kernel(stage1_locked, primary_begin, primary_end, manifest_vm,
+			 cpio, ppool)) {
+		dlog("Unable to load primary kernel.");
 		return false;
 	}
 
-	dlog("Copying primary to %p\n", pa_addr(primary_begin));
-	if (!copy_to_unmapped(stage1_locked, primary_begin, &it, ppool)) {
-		dlog("Unable to relocate kernel for primary vm.\n");
-		return false;
-	}
-
-	if (!find_file(cpio, "initrd.img", initrd)) {
+	if (!find_file(cpio, "initrd.img", &initrd)) {
 		dlog("Unable to find initrd.img\n");
 		return false;
 	}
 
+	update->initrd_begin = pa_from_va(va_from_ptr(initrd.next));
+	update->initrd_end = pa_from_va(va_from_ptr(initrd.limit));
+
 	{
 		struct vm *vm;
 		struct vcpu_locked vcpu_locked;
@@ -169,6 +212,47 @@
 	return true;
 }
 
+/*
+ * Loads a secondary VM.
+ */
+static bool load_secondary(struct mm_stage1_locked stage1_locked,
+			   paddr_t mem_begin, paddr_t mem_end,
+			   const struct manifest_vm *manifest_vm,
+			   const struct memiter *cpio, struct mpool *ppool)
+{
+	struct vm *vm;
+	struct vcpu *vcpu;
+	ipaddr_t secondary_entry;
+
+	if (!load_kernel(stage1_locked, mem_begin, mem_end, manifest_vm, cpio,
+			 ppool)) {
+		dlog("Unable to load kernel.\n");
+		return false;
+	}
+
+	if (!vm_init(manifest_vm->secondary.vcpu_count, ppool, &vm)) {
+		dlog("Unable to initialise VM.\n");
+		return false;
+	}
+
+	/* Grant the VM access to the memory. */
+	if (!mm_vm_identity_map(&vm->ptable, mem_begin, mem_end,
+				MM_MODE_R | MM_MODE_W | MM_MODE_X,
+				&secondary_entry, ppool)) {
+		dlog("Unable to initialise memory.\n");
+		return false;
+	}
+
+	dlog("Loaded with %u vcpus, entry at %#x.\n",
+	     manifest_vm->secondary.vcpu_count, pa_addr(mem_begin));
+
+	vcpu = vm_get_vcpu(vm, 0);
+	vcpu_secondary_reset_and_start(vcpu, secondary_entry,
+				       pa_difference(mem_begin, mem_end));
+
+	return true;
+}
+
 /**
  * Try to find a memory range of the given size within the given ranges, and
  * remove it from them. Return true on success, or false if no large enough
@@ -245,19 +329,24 @@
 	return true;
 }
 
-/**
- * Loads all secondary VMs into the memory ranges from the given params.
- * Memory reserved for the VMs is added to the `reserved_ranges` of `update`.
+/*
+ * Loads alls VMs from the manifest.
  */
-bool load_secondary(struct mm_stage1_locked stage1_locked,
-		    const struct manifest *manifest, const struct memiter *cpio,
-		    const struct boot_params *params,
-		    struct boot_params_update *update, struct mpool *ppool)
+bool load_vms(struct mm_stage1_locked stage1_locked,
+	      const struct manifest *manifest, const struct memiter *cpio,
+	      const struct boot_params *params,
+	      struct boot_params_update *update, struct mpool *ppool)
 {
 	struct vm *primary;
 	struct mem_range mem_ranges_available[MAX_MEM_RANGES];
 	size_t i;
 
+	if (!load_primary(stage1_locked, manifest, cpio, params->kernel_arg,
+			  update, ppool)) {
+		dlog("Unable to load primary VM.\n");
+		return false;
+	}
+
 	static_assert(
 		sizeof(mem_ranges_available) == sizeof(params->mem_ranges),
 		"mem_range arrays must be the same size for memcpy.");
@@ -278,14 +367,9 @@
 	for (i = 0; i < manifest->vm_count; ++i) {
 		const struct manifest_vm *manifest_vm = &manifest->vm[i];
 		spci_vm_id_t vm_id = HF_VM_ID_OFFSET + i;
-		struct vm *vm;
-		struct vcpu *vcpu;
-		struct memiter kernel;
-		struct memiter kernel_filename;
 		uint64_t mem_size;
 		paddr_t secondary_mem_begin;
 		paddr_t secondary_mem_end;
-		ipaddr_t secondary_entry;
 
 		if (vm_id == HF_PRIMARY_VM_ID) {
 			continue;
@@ -294,65 +378,28 @@
 		dlog("Loading VM%d: %s.\n", (int)vm_id,
 		     manifest_vm->debug_name);
 
-		memiter_init(&kernel_filename,
-			     manifest_vm->secondary.kernel_filename,
-			     strnlen_s(manifest_vm->secondary.kernel_filename,
-				       MANIFEST_MAX_STRING_LENGTH));
-		if (!memiter_find_file(cpio, &kernel_filename, &kernel)) {
-			dlog("Could not find kernel file \"%s\".\n",
-			     manifest_vm->secondary.kernel_filename);
-			continue;
-		}
-
 		mem_size = align_up(manifest_vm->secondary.mem_size, PAGE_SIZE);
-		if (mem_size < memiter_size(&kernel)) {
-			dlog("Kernel is larger than available memory\n");
-			continue;
-		}
-
 		if (!carve_out_mem_range(mem_ranges_available,
 					 params->mem_ranges_count, mem_size,
 					 &secondary_mem_begin,
 					 &secondary_mem_end)) {
-			dlog("Not enough memory (%u bytes)\n", mem_size);
+			dlog("Not enough memory (%u bytes).\n", mem_size);
 			continue;
 		}
 
-		if (!copy_to_unmapped(stage1_locked, secondary_mem_begin,
-				      &kernel, ppool)) {
-			dlog("Unable to copy kernel\n");
-			continue;
-		}
-
-		if (!vm_init(manifest_vm->secondary.vcpu_count, ppool, &vm)) {
-			dlog("Unable to initialise VM\n");
-			continue;
-		}
-
-		/* Grant the VM access to the memory. */
-		if (!mm_vm_identity_map(&vm->ptable, secondary_mem_begin,
-					secondary_mem_end,
-					MM_MODE_R | MM_MODE_W | MM_MODE_X,
-					&secondary_entry, ppool)) {
-			dlog("Unable to initialise memory\n");
+		if (!load_secondary(stage1_locked, secondary_mem_begin,
+				    secondary_mem_end, manifest_vm, cpio,
+				    ppool)) {
+			dlog("Unable to load VM.\n");
 			continue;
 		}
 
 		/* Deny the primary VM access to this memory. */
 		if (!mm_vm_unmap(&primary->ptable, secondary_mem_begin,
 				 secondary_mem_end, ppool)) {
-			dlog("Unable to unmap secondary VM from primary VM\n");
+			dlog("Unable to unmap secondary VM from primary VM.\n");
 			return false;
 		}
-
-		dlog("Loaded with %u vcpus, entry at %#x\n",
-		     manifest_vm->secondary.vcpu_count,
-		     pa_addr(secondary_mem_begin));
-
-		vcpu = vm_get_vcpu(vm, 0);
-		vcpu_secondary_reset_and_start(
-			vcpu, secondary_entry,
-			pa_difference(secondary_mem_begin, secondary_mem_end));
 	}
 
 	/*
diff --git a/src/manifest.c b/src/manifest.c
index dc6ed5b..80382ee 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -53,17 +53,9 @@
 	return ptr;
 }
 
-static enum manifest_return_code read_string(const struct fdt_node *node,
-					     const char *property, char *out,
-					     rsize_t out_sz)
+static enum manifest_return_code extract_string(const char *data, uint32_t size,
+						char *out, rsize_t out_sz)
 {
-	const char *data;
-	uint32_t size;
-
-	if (!fdt_read_property(node, property, &data, &size)) {
-		return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
-	}
-
 	/*
 	 * Require that the value contains exactly one NULL character and that
 	 * it is the last byte.
@@ -81,6 +73,39 @@
 	return MANIFEST_SUCCESS;
 }
 
+static enum manifest_return_code read_string(const struct fdt_node *node,
+					     const char *property, char *out,
+					     rsize_t out_sz)
+{
+	const char *data;
+	uint32_t size;
+
+	if (!fdt_read_property(node, property, &data, &size)) {
+		return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
+	}
+
+	return extract_string(data, size, out, out_sz);
+}
+
+static enum manifest_return_code read_optional_string(
+	const struct fdt_node *node, const char *property, char *out,
+	rsize_t out_sz)
+{
+	const char *data;
+	uint32_t size;
+
+	if (!fdt_read_property(node, property, &data, &size)) {
+		if (out_sz < 1) {
+			return MANIFEST_ERROR_STRING_TOO_LONG;
+		}
+
+		*out = '\0';
+		return MANIFEST_SUCCESS;
+	}
+
+	return extract_string(data, size, out, out_sz);
+}
+
 static enum manifest_return_code read_uint64(const struct fdt_node *node,
 					     const char *property,
 					     uint64_t *out)
@@ -202,10 +227,9 @@
 {
 	TRY(read_string(node, "debug_name", vm->debug_name,
 			sizeof(vm->debug_name)));
+	TRY(read_optional_string(node, "kernel_filename", vm->kernel_filename,
+				 sizeof(vm->kernel_filename)));
 	if (vm_id != HF_PRIMARY_VM_ID) {
-		TRY(read_string(node, "kernel_filename",
-				vm->secondary.kernel_filename,
-				sizeof(vm->secondary.kernel_filename)));
 		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 c87acaf..14eef49 100644
--- a/src/manifest_test.cc
+++ b/src/manifest_test.cc
@@ -410,18 +410,18 @@
 			.Compatible()
 			.StartChild("vm1")
 				.DebugName("primary_vm")
+				.KernelFilename("primary_kernel")
 			.EndChild()
 			.StartChild("vm3")
 				.DebugName("second_secondary_vm")
 				.VcpuCount(43)
 				.MemSize(0x12345)
-				.KernelFilename("second_kernel")
+				.KernelFilename("second_secondary_kernel")
 			.EndChild()
 			.StartChild("vm2")
 				.DebugName("first_secondary_vm")
 				.VcpuCount(42)
 				.MemSize(12345)
-				.KernelFilename("first_kernel")
 			.EndChild()
 		.EndChild()
 		.Build();
@@ -434,18 +434,19 @@
 
 	vm = &m.vm[0];
 	ASSERT_STREQ(vm->debug_name, "primary_vm");
+	ASSERT_STREQ(vm->kernel_filename, "primary_kernel");
 
 	vm = &m.vm[1];
 	ASSERT_STREQ(vm->debug_name, "first_secondary_vm");
+	ASSERT_STREQ(vm->kernel_filename, "");
 	ASSERT_EQ(vm->secondary.vcpu_count, 42);
 	ASSERT_EQ(vm->secondary.mem_size, 12345);
-	ASSERT_STREQ(vm->secondary.kernel_filename, "first_kernel");
 
 	vm = &m.vm[2];
 	ASSERT_STREQ(vm->debug_name, "second_secondary_vm");
+	ASSERT_STREQ(vm->kernel_filename, "second_secondary_kernel");
 	ASSERT_EQ(vm->secondary.vcpu_count, 43);
 	ASSERT_EQ(vm->secondary.mem_size, 0x12345);
-	ASSERT_STREQ(vm->secondary.kernel_filename, "second_kernel");
 }
 
 } /* namespace */
diff --git a/test/linux/BUILD.gn b/test/linux/BUILD.gn
index fcc5907..527a4c3 100644
--- a/test/linux/BUILD.gn
+++ b/test/linux/BUILD.gn
@@ -58,6 +58,7 @@
   testonly = true
 
   manifest = "manifest.dts"
+  primary_name = "vmlinuz"
   primary_vm = "//third_party:linux__prebuilt"
   primary_initrd = ":linux_test_initrd"
   secondary_vms = [ [
diff --git a/test/linux/manifest.dts b/test/linux/manifest.dts
index 1372663..71c891e 100644
--- a/test/linux/manifest.dts
+++ b/test/linux/manifest.dts
@@ -21,7 +21,8 @@
 	hypervisor {
 		compatible = "hafnium,hafnium";
 		vm1 {
-			debug_name = "primary";
+			debug_name = "linux_test";
+			kernel_filename = "vmlinuz";
 		};
 
 		vm2 {
diff --git a/test/vmapi/gicv3/BUILD.gn b/test/vmapi/gicv3/BUILD.gn
index 196f169..f3325e0 100644
--- a/test/vmapi/gicv3/BUILD.gn
+++ b/test/vmapi/gicv3/BUILD.gn
@@ -42,6 +42,7 @@
   testonly = true
 
   manifest = "manifest.dts"
+  primary_name = "gicv3_test"
   primary_vm = ":gicv3_test_vm"
   secondary_vms = [ [
         "services0",
diff --git a/test/vmapi/gicv3/manifest.dts b/test/vmapi/gicv3/manifest.dts
index 4e3a769..9f3ea87 100644
--- a/test/vmapi/gicv3/manifest.dts
+++ b/test/vmapi/gicv3/manifest.dts
@@ -21,7 +21,8 @@
 	hypervisor {
 		compatible = "hafnium,hafnium";
 		vm1 {
-			debug_name = "primary";
+			debug_name = "gicv3_test";
+			kernel_filename = "gicv3_test";
 		};
 
 		vm2 {
diff --git a/test/vmapi/primary_only/BUILD.gn b/test/vmapi/primary_only/BUILD.gn
index ecb197a..cdb35b9 100644
--- a/test/vmapi/primary_only/BUILD.gn
+++ b/test/vmapi/primary_only/BUILD.gn
@@ -31,5 +31,6 @@
 initrd("primary_only_test") {
   testonly = true
   manifest = "manifest.dts"
+  primary_name = "primary_only_test"
   primary_vm = ":primary_only_test_vm"
 }
diff --git a/test/vmapi/primary_only/manifest.dts b/test/vmapi/primary_only/manifest.dts
index 3cf090d..f83e057 100644
--- a/test/vmapi/primary_only/manifest.dts
+++ b/test/vmapi/primary_only/manifest.dts
@@ -21,7 +21,8 @@
 	hypervisor {
 		compatible = "hafnium,hafnium";
 		vm1 {
-			debug_name = "primary";
+			debug_name = "primary_only_test";
+			kernel_filename = "primary_only_test";
 		};
 	};
 };
diff --git a/test/vmapi/primary_with_secondaries/BUILD.gn b/test/vmapi/primary_with_secondaries/BUILD.gn
index 3c00989..b8bdfb2 100644
--- a/test/vmapi/primary_with_secondaries/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/BUILD.gn
@@ -50,6 +50,7 @@
 
   manifest = "manifest.dts"
 
+  primary_name = "primary_with_secondaries_test"
   primary_vm = ":primary_with_secondaries_test_vm"
   secondary_vms = [
     [
diff --git a/test/vmapi/primary_with_secondaries/manifest.dts b/test/vmapi/primary_with_secondaries/manifest.dts
index 6460a60..8cc5c00 100644
--- a/test/vmapi/primary_with_secondaries/manifest.dts
+++ b/test/vmapi/primary_with_secondaries/manifest.dts
@@ -21,7 +21,8 @@
 	hypervisor {
 		compatible = "hafnium,hafnium";
 		vm1 {
-			debug_name = "primary";
+			debug_name = "primary_with_secondaries_test";
+			kernel_filename = "primary_with_secondaries_test";
 		};
 
 		vm2 {