Fixes to allow (32 bit) arm guests to run on aarch64 hosts.
[mclu.git] / mclu_boot.ml
index 16b8ac9..c1054e5 100644 (file)
@@ -165,6 +165,27 @@ Try: `mclu on %s'\n" hostname hostname;
   let remote_template_wrapper = sprintf "/tmp/mclu%s.sh" (string_random8 ()) in
   let xml_template_wrapper = sprintf "/tmp/mclu%s.sh" (string_random8 ()) in
   let remote_image = sprintf "/var/tmp/%s.%s" name extension in
+  let remote_external_kernel_dir = sprintf "/var/tmp/%s.boot" name in
+  let remote_external_kernel = sprintf "/var/tmp/%s.boot/kernel" name in
+  let remote_external_initrd = sprintf "/var/tmp/%s.boot/initrd" name in
+  let remote_arch = node.MS.node_status.node_info.model in
+
+  (* Guest arch defaults to the node host arch, but can be overridden
+   * in the template.
+   *)
+  let guest_arch =
+    match template_info.Template.guest_arch with
+    | Some arch -> arch
+    | None -> remote_arch in
+
+  (* UEFI firmware and NVRAM on remote, if required. *)
+  let nvram =
+    match guest_arch with
+    | "aarch64" ->
+       Some ("/usr/share/edk2.git/aarch64/QEMU_EFI-pflash.raw",
+             "/usr/share/edk2.git/aarch64/vars-template-pflash.raw",
+             remote_image ^ ".nvram")
+    | _ -> None in
 
   (* Get ready to generate the guest XML. *)
   let vcpus = !vcpus in
@@ -184,16 +205,52 @@ Try: `mclu on %s'\n" hostname hostname;
   <memory unit='KiB'>%Ld</memory>
   <currentMemory unit='KiB'>%Ld</currentMemory>
   <vcpu>%d</vcpu>
+" name (memory /^ 1024L) (memory /^ 1024L) vcpus in
+
+    let xml = xml ^ "\
   <os>
-    <type>hvm</type>
     <boot dev='hd'/>
+" in
+    let xml =
+      match guest_arch with
+      | "arm" | "armv7" | "armv7l" | "armv7hl" ->
+         xml ^ "\
+    <type arch='armv7l' machine='virt'>hvm</type>
+"
+      | "aarch64" ->
+         xml ^ "\
+    <type machine='virt'>hvm</type>
+"
+      | _ ->
+         xml ^ "\
+    <type>hvm</type>
+" in
+
+    let xml =
+      match nvram with
+      | Some (loader, nvram_template, nvram) ->
+         xml ^ sprintf "\
+    <loader readonly='yes' type='pflash'>%s</loader>
+    <nvram template='%s'>%s</nvram>
+" loader nvram_template nvram
+      | None -> xml in
+
+    let xml = xml ^
+      if template_info.Template.needs_external_kernel then
+        sprintf "\
+    <kernel>%s</kernel>
+    <initrd>%s</initrd>
+" remote_external_kernel remote_external_initrd
+      else "" in
+
+    let xml = xml ^ "\
   </os>
   <features>
     <acpi/>
     <apic/>
     <pae/>
   </features>
-  <cpu mode='host-model' fallback='allow' />
+  <cpu mode='host-passthrough'/> <!-- -cpu host, also allows nested -->
   <clock offset='utc'>
     <timer name='rtc' tickpolicy='catchup'/>
     <timer name='pit' tickpolicy='delay'/>
@@ -203,7 +260,7 @@ Try: `mclu on %s'\n" hostname hostname;
   <on_reboot>restart</on_reboot>
   <on_crash>restart</on_crash>
   <devices>
-" name (memory /^ 1024L) (memory /^ 1024L) vcpus in
+" in
 
     let xml = xml ^ sprintf "\
   <disk type='file' device='disk'>
@@ -250,6 +307,12 @@ Try: `mclu on %s'\n" hostname hostname;
     <console type='pty'>
       <target type='serial' port='0'/>
     </console>
+" in
+    let xml =
+      match guest_arch with
+      | "i386" | "i486" | "i586" | "i686"
+      | "x86_64" ->
+         xml ^ "\
     <input type='tablet' bus='usb'/>
     <input type='mouse' bus='ps2'/>
     <input type='keyboard' bus='ps2'/>
@@ -257,6 +320,9 @@ Try: `mclu on %s'\n" hostname hostname;
     <video>
       <model type='cirrus' vram='9216' heads='1'/>
     </video>
+"
+      | _ -> xml in
+    let xml = xml ^ "\
   </devices>
 </domain>" in
     xml
@@ -270,6 +336,8 @@ Try: `mclu on %s'\n" hostname hostname;
       let fpf fs = fprintf chan fs in
       fpf "#!/bin/sh\n";
       fpf "export format=%s\n" (quote format);
+      fpf "export initrd=%s\n" (quote remote_external_initrd);
+      fpf "export kernel=%s\n" (quote remote_external_kernel);
       fpf "export mac_addr=%s\n" (quote mac_addr);
       fpf "export memory_kb=%Ld\n" (memory /^ 1024L);
       fpf "export name=%s\n" (quote name);
@@ -326,11 +394,13 @@ Try: `mclu on %s'\n" hostname hostname;
   let () =
     let chan = open_out remote_template_wrapper in
     let fpf fs = fprintf chan fs in
-    fpf "#!/bin/sh\n";
+    fpf "#!/bin/bash\n";
+    fpf "set -e\n";
     (* XXX Don't hard-code network_bridge here. *)
     fpf "export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=br0\n";
     fpf "export base_image=%s\n" (quote template_info.Template.base_image);
     fpf "export format=%s\n" (quote format);
+    fpf "export guest_arch=%s\n" (quote guest_arch);
     fpf "export name=%s\n" (quote name);
     fpf "export output=%s\n" (quote remote_image);
     (match size with
@@ -341,7 +411,21 @@ Try: `mclu on %s'\n" hostname hostname;
     | "" -> ()
     | tz -> fpf "export timezone=%s\n" (quote (sprintf "--timezone %s" tz))
     );
+    (match nvram with
+     | Some (_, nvram_template, nvram) ->
+        fpf "cp %s %s\n" (quote nvram_template) (quote nvram)
+     | None -> ()
+    );
     fpf "%s build\n" remote_template;
+    if template_info.Template.needs_external_kernel then (
+      fpf "rm -rf %s\n" (quote remote_external_kernel_dir);
+      fpf "mkdir %s\n" (quote remote_external_kernel_dir);
+      fpf "pushd %s\n" (quote remote_external_kernel_dir);
+      fpf "virt-builder --get-kernel %s\n" (quote remote_image);
+      fpf "ln vmlinuz-* kernel\n";
+      fpf "ln init* initrd\n";
+      fpf "popd\n";
+    );
     close_out chan;
     Unix.chmod remote_template_wrapper 0o755 in