vmbase_example: Clarify that the payload is a BIOS

Rename all Soong targets to include "_bios" and refactor the linker
script and idmap.S to be preprocessed and receive a CPP macro
representing the "mode". Rename image.ld to reflect this.

Modify the test to use the new "_bios" binary name and refactor it to
make the core logic re-usable for future vmbase_example modes.

No functional change intended.

Test: atest vmbase_example.integration_test
Change-Id: I06679d154494d85916ff534298a066519b1b0778
diff --git a/guest/vmbase_example/Android.bp b/guest/vmbase_example/Android.bp
index 630cee6..86a63b7 100644
--- a/guest/vmbase_example/Android.bp
+++ b/guest/vmbase_example/Android.bp
@@ -19,8 +19,41 @@
     ],
 }
 
-cc_binary {
-    name: "vmbase_example",
+genrule {
+    name: "vmbase_image.ld.S.mm",
+    // Soong won't let us use cc_object to preprocess *.ld.S files because it
+    // can't resist feeding any and all *.S files to the assembler, which fails
+    // because linker scripts typically aren't valid assembly. Also, cc_object
+    // rejects inputs that don't end in one of .{s,S,c,cpp,cc,cxx,mm}. So keep
+    // the proper extension (.ld.S) for the file in VCS and use this convoluted
+    // extra step to please Soong by pretending that our linker script is in
+    // fact some Object C++ code, which fortunately it doesn't try to compile.
+    srcs: ["image.ld.S"],
+    out: ["image.ld.S.mm"],
+    cmd: "cp $(in) $(out)",
+    visibility: ["//visibility:private"],
+}
+
+cc_defaults {
+    name: "vmbase_example_ld_defaults",
+    defaults: ["vmbase_cc_defaults"],
+    cflags: [
+        "-E",
+        "-P",
+        "-xassembler-with-cpp", // allow C preprocessor directives
+    ],
+    srcs: [":vmbase_image.ld.S.mm"],
+    visibility: ["//visibility:private"],
+}
+
+cc_object {
+    name: "vmbase_example_bios.ld",
+    defaults: ["vmbase_example_ld_defaults"],
+    cflags: ["-DVMBASE_EXAMPLE_IS_BIOS"],
+}
+
+cc_defaults {
+    name: "vmbase_example_elf_defaults",
     defaults: ["vmbase_elf_defaults"],
     srcs: [
         "idmap.S",
@@ -28,16 +61,22 @@
     static_libs: [
         "libvmbase_example",
     ],
+}
+
+cc_binary {
+    name: "vmbase_example_bios",
+    defaults: ["vmbase_example_elf_defaults"],
+    asflags: ["-DVMBASE_EXAMPLE_IS_BIOS"],
     linker_scripts: [
-        "image.ld",
+        ":vmbase_example_bios.ld",
         ":vmbase_sections",
     ],
 }
 
 raw_binary {
-    name: "vmbase_example_bin",
-    stem: "vmbase_example.bin",
-    src: ":vmbase_example",
+    name: "vmbase_example_bios_bin",
+    stem: "vmbase_example_bios.bin",
+    src: ":vmbase_example_bios",
     enabled: false,
     target: {
         android_arm64: {
diff --git a/guest/vmbase_example/idmap.S b/guest/vmbase_example/idmap.S
index 71a6ade..268de5f 100644
--- a/guest/vmbase_example/idmap.S
+++ b/guest/vmbase_example/idmap.S
@@ -43,8 +43,12 @@
 	.quad		.L_TT_TYPE_TABLE + 0f		// up to 1 GiB of DRAM
 	.fill		509, 8, 0x0			// 509 GiB of remaining VA space
 
-	/* level 2 */
-0:	.quad		.L_BLOCK_MEM | 0x80000000	// DT provided by VMM
+0:	/* level 2 */
+#if defined(VMBASE_EXAMPLE_IS_BIOS)
+	.quad		.L_BLOCK_MEM | 0x80000000	// DT provided by VMM
 	.quad		.L_BLOCK_MEM_XIP | 0x80200000	// 2 MiB of DRAM containing image
 	.quad		.L_BLOCK_MEM | 0x80400000	// 2 MiB of writable DRAM
 	.fill		509, 8, 0x0
+#else
+#error "Unexpected vmbase_example mode: failed to generate idmap"
+#endif
diff --git a/guest/vmbase_example/image.ld b/guest/vmbase_example/image.ld.S
similarity index 85%
rename from guest/vmbase_example/image.ld
rename to guest/vmbase_example/image.ld.S
index 95ffdf8..3bfab9c 100644
--- a/guest/vmbase_example/image.ld
+++ b/guest/vmbase_example/image.ld.S
@@ -16,6 +16,10 @@
 
 MEMORY
 {
+#if defined(VMBASE_EXAMPLE_IS_BIOS)
 	image		: ORIGIN = 0x80200000, LENGTH = 2M
 	writable_data	: ORIGIN = 0x80400000, LENGTH = 2M
+#else
+#error "Unexpected vmbase_example mode: failed to generate image layout"
+#endif
 }
diff --git a/tests/vmbase_example/Android.bp b/tests/vmbase_example/Android.bp
index 6e902b1..d652196 100644
--- a/tests/vmbase_example/Android.bp
+++ b/tests/vmbase_example/Android.bp
@@ -18,7 +18,7 @@
         "libvmclient",
     ],
     data: [
-        ":vmbase_example_bin",
+        ":vmbase_example_bios_bin",
     ],
     test_suites: ["general-tests"],
     enabled: false,
diff --git a/tests/vmbase_example/src/main.rs b/tests/vmbase_example/src/main.rs
index 8f9fafc..de704fa 100644
--- a/tests/vmbase_example/src/main.rs
+++ b/tests/vmbase_example/src/main.rs
@@ -31,13 +31,17 @@
 };
 use vmclient::{DeathReason, VmInstance};
 
-const VMBASE_EXAMPLE_PATH: &str = "vmbase_example.bin";
+const VMBASE_EXAMPLE_BIOS_PATH: &str = "vmbase_example_bios.bin";
 const TEST_DISK_IMAGE_PATH: &str = "test_disk.img";
 const EMPTY_DISK_IMAGE_PATH: &str = "empty_disk.img";
 
-/// Runs the vmbase_example VM as an unprotected VM via VirtualizationService.
+/// Runs the vmbase_example VM as an unprotected VM BIOS via VirtualizationService.
 #[test]
-fn test_run_example_vm() -> Result<(), Error> {
+fn test_run_example_bios_vm() -> Result<(), Error> {
+    run_test(Some(open_payload(VMBASE_EXAMPLE_BIOS_PATH)?))
+}
+
+fn run_test(bootloader: Option<ParcelFileDescriptor>) -> Result<(), Error> {
     android_logger::init_once(
         android_logger::Config::default()
             .with_tag("vmbase")
@@ -56,12 +60,6 @@
         vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
     let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
 
-    // Start example VM.
-    let bootloader = ParcelFileDescriptor::new(
-        File::open(VMBASE_EXAMPLE_PATH)
-            .with_context(|| format!("Failed to open VM image {}", VMBASE_EXAMPLE_PATH))?,
-    );
-
     // Make file for test disk image.
     let mut test_image = File::options()
         .create(true)
@@ -94,7 +92,7 @@
         kernel: None,
         initrd: None,
         params: None,
-        bootloader: Some(bootloader),
+        bootloader,
         disks: vec![disk_image, empty_disk_image],
         protectedVm: false,
         memoryMib: 300,
@@ -142,6 +140,11 @@
     Ok((reader_fd.into(), writer_fd.into()))
 }
 
+fn open_payload(path: &str) -> Result<ParcelFileDescriptor, Error> {
+    let file = File::open(path).with_context(|| format!("Failed to open VM image {path}"))?;
+    Ok(ParcelFileDescriptor::new(file))
+}
+
 struct VmLogProcessor {
     reader: Option<File>,
     expected: VecDeque<String>,