Build: generate initrd images for the hypervisor.
This packages the VMs to create the initial RAM disk.
Change-Id: I31f1a0650583eb4122233beb0abaa933909cb389
diff --git a/BUILD.gn b/BUILD.gn
index 6d5dae0..4b21696 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -5,7 +5,7 @@
deps = [
":hypervisor",
- "//test/vm:test_vm($arch_toolchain)",
+ "//test/vm:test_vm_initrd($arch_toolchain)",
]
}
diff --git a/build/BUILD.gn b/build/BUILD.gn
index 73c58b4..b8ec9fc 100644
--- a/build/BUILD.gn
+++ b/build/BUILD.gn
@@ -13,6 +13,7 @@
cflags_c = [
"-std=c11",
+ "-Wdeclaration-after-statement",
]
cflags_cc = [
@@ -43,10 +44,16 @@
"-fno-builtin",
"-ffreestanding",
"-fpic",
- "-Wno-extended-offsetof", # have clang give us some slack
]
+ if (!use_gcc) {
+ cflags += [
+ "-Wno-extended-offsetof", # have clang give us some slack
+ ]
+ }
+
defines += [
+ # TODO: move these build args for the platforms
"MAX_CPUS=8",
"MAX_VMS=16",
"STACK_SIZE=4096",
diff --git a/build/image/convert_to_binary.py b/build/image/convert_to_binary.py
index 7900cf2..bf50a8e 100644
--- a/build/image/convert_to_binary.py
+++ b/build/image/convert_to_binary.py
@@ -6,7 +6,6 @@
"""
import argparse
-import os
import subprocess
import sys
@@ -16,7 +15,7 @@
parser.add_argument("--input", required=True)
parser.add_argument("--output", required=True)
args = parser.parse_args()
- raw = subprocess.check_output([
+ subprocess.check_call([
"{}objcopy".format(args.tool_prefix),
"-O",
"binary",
diff --git a/build/image/extract_offsets.py b/build/image/extract_offsets.py
index cf4f5c7..23e711a 100644
--- a/build/image/extract_offsets.py
+++ b/build/image/extract_offsets.py
@@ -8,7 +8,6 @@
"""
import argparse
-import os
import re
import subprocess
import sys
diff --git a/build/image/generate_initrd.py b/build/image/generate_initrd.py
new file mode 100644
index 0000000..488745f
--- /dev/null
+++ b/build/image/generate_initrd.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+"""Generate an initial RAM disk for the hypervisor.
+
+Packages the VMs, initrds for the VMs and the list of secondary VMs (vms.txt)
+into an initial RAM disk image.
+"""
+
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+
+def Main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--primary_vm", required=True)
+ parser.add_argument("--primary_vm_initrd")
+ parser.add_argument("--secondary_vm", action="append", nargs=4, metavar=("MEMORY", "CORES", "NAME", "IMAGE"))
+ parser.add_argument("--staging", required=True)
+ parser.add_argument("--output", required=True)
+ args = parser.parse_args()
+ # Prepare the primary VM image.
+ staged_files = ["vmlinuz"]
+ shutil.copyfile(args.primary_vm, os.path.join(args.staging, "vmlinuz"))
+ # Prepare the primary VM's initrd. Currently, it just makes an empty one.
+ if args.primary_vm_initrd:
+ raise NotImplementedError("This doesn't copy the primary VM's initrd yet")
+ with open(os.path.join(args.staging, "initrd.img"), "w") as vms_txt:
+ staged_files.append("initrd.img")
+ # Prepare the secondary VMs.
+ with open(os.path.join(args.staging, "vms.txt"), "w") as vms_txt:
+ staged_files.append("vms.txt")
+ if args.secondary_vm:
+ for vm in args.secondary_vm:
+ (vm_memory, vm_cores, vm_name, vm_image) = vm
+ staged_files.append(vm_name)
+ shutil.copy(vm_image, os.path.join(args.staging, vm_name))
+ vms_txt.write("{} {} {}\n".format(vm_memory, vm_cores, vm_name))
+ # Package files into an initial RAM disk.
+ with open(args.output, "w") as initrd:
+ # Move into the staging directory so the file names taken by cpio don't
+ # include the path.
+ os.chdir(args.staging)
+ cpio = subprocess.Popen([
+ "cpio",
+ "--create"],
+ stdin=subprocess.PIPE,
+ stdout=initrd,
+ stderr=subprocess.PIPE)
+ cpio.communicate(input="\n".join(staged_files).encode("utf-8"))
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(Main())
diff --git a/build/image/image.gni b/build/image/image.gni
index afc4e79..a24b81c 100644
--- a/build/image/image.gni
+++ b/build/image/image.gni
@@ -1,10 +1,11 @@
import("//build/arch/common.gni")
+# Build image, link to an ELF file then convert to plain binary.
template("image_binary") {
assert(defined(invoker.image_name),
- "image_binary() must specify a \"image_name\" value")
+ "image_binary() must specify an \"image_name\" value")
assert(defined(invoker.origin_address),
- "image_binary() must specify a \"origin_address\" value")
+ "image_binary() must specify an \"origin_address\" value")
output_root = ""
if (defined(invoker.output_path)) {
@@ -98,3 +99,66 @@
origin_address = "0x1000"
}
}
+
+# Build the initial RAM disk for the hypervisor.
+template("initrd") {
+ assert(defined(invoker.primary_vm),
+ "initrd() must specify a \"primary_vm\" value")
+
+ action(target_name) {
+ forward_variables_from(invoker, [ "testonly" ])
+ script = "//build/image/generate_initrd.py"
+
+ initrd_base = "${root_out_dir}/initrd/${target_name}"
+ initrd_file = "${initrd_base}.img"
+ initrd_staging = "${initrd_base}"
+ vm_dir = rebase_path("${root_out_dir}/vm/")
+
+ deps = [
+ invoker.primary_vm,
+ ]
+
+ args = [
+ "--primary_vm",
+ vm_dir + get_label_info(invoker.primary_vm, "name") + ".bin",
+ "--staging",
+ rebase_path(initrd_staging),
+ "--output",
+ rebase_path(initrd_file),
+ ]
+
+ # Add the info about the secondary VMs. The information about the VMs is
+ # encoded in lists with the following elements:
+ #
+ # 1. Memory in bytes.
+ # 2. Number of cores.
+ # 3. File name for the VM image.
+ # 4. Build target for the VM.
+ #
+ # TODO: is there a less hacky way to do this?
+ if (defined(invoker.secondary_vms)) {
+ foreach(vm, invoker.secondary_vms) {
+ args += ["--secondary_vm"]
+
+ # This is a hack to find the field which names the build target for the
+ # VM so it can be added to the dependencies and the image path be
+ # passed to the script. The target will be a path or have a semicolon
+ # so getting the label name will yield a diferent value. The other
+ # fields are simple text so won't change.
+ foreach (field, vm) {
+ if (get_label_info(field, "name") != field) {
+ deps += [field]
+ args += [vm_dir + get_label_info(field, "name") + ".bin"]
+ } else {
+ args += [field]
+ }
+ }
+ }
+ }
+
+ outputs = [
+ initrd_file,
+ "${initrd_staging}/vms.txt",
+ ]
+ }
+}
diff --git a/test/vm/BUILD.gn b/test/vm/BUILD.gn
index 7216b67..82f6f64 100644
--- a/test/vm/BUILD.gn
+++ b/test/vm/BUILD.gn
@@ -14,3 +14,8 @@
"//src/arch/${arch}:entry",
]
}
+
+initrd("test_vm_initrd") {
+ testonly = true
+ primary_vm = ":test_vm"
+}