Blame SOURCES/0089-aarch64-appliance-Use-AAVMF-UEFI-if-available-for-ru.patch

ffd6ed
From eb3c98e28ad33606f70602834e455d7e0789153e Mon Sep 17 00:00:00 2001
ffd6ed
From: "Richard W.M. Jones" <rjones@redhat.com>
ffd6ed
Date: Wed, 21 Jan 2015 05:10:37 -0500
ffd6ed
Subject: [PATCH] aarch64: appliance: Use AAVMF (UEFI) if available for running
ffd6ed
 the appliance.
ffd6ed
ffd6ed
AAVMF is an open source UEFI implementation for aarch64 based on OVMF.
ffd6ed
As aarch64 is heading for requiring UEFI even inside guests, if the
ffd6ed
AAVMF firmware is installed on the host, use it as a hint that we
ffd6ed
should boot the guest using AAVMF instead of the default "empty
ffd6ed
machine".
ffd6ed
ffd6ed
Note this requires very recent AAVMF, libvirt, qemu.  However that's
ffd6ed
OK since it's only applicable to aarch64.  On non-aarch64, this patch
ffd6ed
does nothing.
ffd6ed
ffd6ed
Thanks: Laszlo Ersek for a lot of help getting this right.
ffd6ed
(cherry picked from commit 7dc837c7be84936690f4f613fea82dba4787ceec)
ffd6ed
---
ffd6ed
 src/appliance.c        | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-
ffd6ed
 src/guestfs-internal.h |  1 +
ffd6ed
 src/launch-direct.c    | 14 +++++++++++
ffd6ed
 src/launch-libvirt.c   | 25 +++++++++++++++++++
ffd6ed
 4 files changed, 105 insertions(+), 1 deletion(-)
ffd6ed
ffd6ed
diff --git a/src/appliance.c b/src/appliance.c
ffd6ed
index d7aa6b1..5fa47f2 100644
ffd6ed
--- a/src/appliance.c
ffd6ed
+++ b/src/appliance.c
ffd6ed
@@ -1,5 +1,5 @@
ffd6ed
 /* libguestfs
ffd6ed
- * Copyright (C) 2010-2012 Red Hat Inc.
ffd6ed
+ * Copyright (C) 2010-2014 Red Hat Inc.
ffd6ed
  *
ffd6ed
  * This library is free software; you can redistribute it and/or
ffd6ed
  * modify it under the terms of the GNU Lesser General Public
ffd6ed
@@ -459,3 +459,67 @@ dir_contains_files (const char *dir, ...)
ffd6ed
   va_end (args);
ffd6ed
   return 1;
ffd6ed
 }
ffd6ed
+
ffd6ed
+#ifdef __aarch64__
ffd6ed
+
ffd6ed
+#define AAVMF_DIR "/usr/share/AAVMF"
ffd6ed
+
ffd6ed
+/* Return the location of firmware needed to boot the appliance.  This
ffd6ed
+ * is aarch64 only currently, since that's the only architecture where
ffd6ed
+ * UEFI is mandatory (and that only for RHEL).
ffd6ed
+ *
ffd6ed
+ * '*code' is initialized with the path to the read-only UEFI code
ffd6ed
+ * file.  '*vars' is initialized with the path to a copy of the UEFI
ffd6ed
+ * vars file (which is cleaned up automatically on exit).
ffd6ed
+ *
ffd6ed
+ * If *code == *vars == NULL then no UEFI firmware is available.
ffd6ed
+ *
ffd6ed
+ * '*code' and '*vars' should be freed by the caller.
ffd6ed
+ *
ffd6ed
+ * If the function returns -1 then there was a real error which should
ffd6ed
+ * cause appliance building to fail (no UEFI firmware is not an
ffd6ed
+ * error).
ffd6ed
+ */
ffd6ed
+int
ffd6ed
+guestfs___get_uefi (guestfs_h *g, char **code, char **vars)
ffd6ed
+{
ffd6ed
+  if (access (AAVMF_DIR "/AAVMF_CODE.fd", R_OK) == 0 &&
ffd6ed
+      access (AAVMF_DIR "/AAVMF_VARS.fd", R_OK) == 0) {
ffd6ed
+    CLEANUP_CMD_CLOSE struct command *copycmd = guestfs___new_command (g);
ffd6ed
+    char *varst;
ffd6ed
+    int r;
ffd6ed
+
ffd6ed
+    /* Make a copy of AAVMF_VARS.fd.  You can't just map it into the
ffd6ed
+     * address space read-only as that triggers a different path
ffd6ed
+     * inside UEFI.
ffd6ed
+     */
ffd6ed
+    varst = safe_asprintf (g, "%s/AAVMF_VARS.fd.%d", g->tmpdir, ++g->unique);
ffd6ed
+    guestfs___cmd_add_arg (copycmd, "cp");
ffd6ed
+    guestfs___cmd_add_arg (copycmd, AAVMF_DIR "/AAVMF_VARS.fd");
ffd6ed
+    guestfs___cmd_add_arg (copycmd, varst);
ffd6ed
+    r = guestfs___cmd_run (copycmd);
ffd6ed
+    if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) {
ffd6ed
+      free (varst);
ffd6ed
+      return -1;
ffd6ed
+    }
ffd6ed
+
ffd6ed
+    /* Caller frees. */
ffd6ed
+    *code = safe_strdup (g, AAVMF_DIR "/AAVMF_CODE.fd");
ffd6ed
+    *vars = varst;
ffd6ed
+    return 0;
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  *code = *vars = NULL;
ffd6ed
+  return 0;
ffd6ed
+}
ffd6ed
+
ffd6ed
+#else /* !__aarch64__ */
ffd6ed
+
ffd6ed
+int
ffd6ed
+guestfs___get_uefi (guestfs_h *g, char **code, char **vars)
ffd6ed
+{
ffd6ed
+  *code = *vars = NULL;
ffd6ed
+  return 0;
ffd6ed
+}
ffd6ed
+
ffd6ed
+#endif /* !__aarch64__ */
ffd6ed
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
ffd6ed
index fd0c4a1..d5de345 100644
ffd6ed
--- a/src/guestfs-internal.h
ffd6ed
+++ b/src/guestfs-internal.h
ffd6ed
@@ -725,6 +725,7 @@ extern const char *guestfs___drive_protocol_to_string (enum drive_protocol proto
ffd6ed
 
ffd6ed
 /* appliance.c */
ffd6ed
 extern int guestfs___build_appliance (guestfs_h *g, char **kernel, char **dtb, char **initrd, char **appliance);
ffd6ed
+extern int guestfs___get_uefi (guestfs_h *g, char **code, char **vars);
ffd6ed
 
ffd6ed
 /* launch.c */
ffd6ed
 extern int64_t guestfs___timeval_diff (const struct timeval *x, const struct timeval *y);
ffd6ed
diff --git a/src/launch-direct.c b/src/launch-direct.c
ffd6ed
index 5301176..2834967 100644
ffd6ed
--- a/src/launch-direct.c
ffd6ed
+++ b/src/launch-direct.c
ffd6ed
@@ -267,6 +267,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
ffd6ed
   int sv[2];
ffd6ed
   char guestfsd_sock[256];
ffd6ed
   struct sockaddr_un addr;
ffd6ed
+  CLEANUP_FREE char *uefi_code = NULL, *uefi_vars = NULL;
ffd6ed
   CLEANUP_FREE char *kernel = NULL, *dtb = NULL,
ffd6ed
     *initrd = NULL, *appliance = NULL;
ffd6ed
   int has_appliance_drive;
ffd6ed
@@ -474,6 +475,19 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
ffd6ed
     ADD_CMDLINE ("kvm-pit.lost_tick_policy=discard");
ffd6ed
   }
ffd6ed
 
ffd6ed
+  /* UEFI (firmware) if required. */
ffd6ed
+  if (guestfs___get_uefi (g, &uefi_code, &uefi_vars) == -1)
ffd6ed
+    goto cleanup0;
ffd6ed
+  if (uefi_code) {
ffd6ed
+    ADD_CMDLINE ("-drive");
ffd6ed
+    ADD_CMDLINE_PRINTF ("if=pflash,format=raw,file=%s,readonly", uefi_code);
ffd6ed
+    if (uefi_vars) {
ffd6ed
+      ADD_CMDLINE ("-drive");
ffd6ed
+      ADD_CMDLINE_PRINTF ("if=pflash,format=raw,file=%s", uefi_vars);
ffd6ed
+    }
ffd6ed
+  }
ffd6ed
+
ffd6ed
+  /* Kernel, DTB and initrd. */
ffd6ed
   ADD_CMDLINE ("-kernel");
ffd6ed
   ADD_CMDLINE (kernel);
ffd6ed
   if (dtb) {
ffd6ed
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
ffd6ed
index f8f818a..e6899ac 100644
ffd6ed
--- a/src/launch-libvirt.c
ffd6ed
+++ b/src/launch-libvirt.c
ffd6ed
@@ -109,6 +109,8 @@ struct backend_libvirt_data {
ffd6ed
   char name[DOMAIN_NAME_LEN];   /* random name */
ffd6ed
   bool is_kvm;                  /* false = qemu, true = kvm (from capabilities)*/
ffd6ed
   unsigned long qemu_version;   /* qemu version (from libvirt) */
ffd6ed
+  char *uefi_code;		/* UEFI (firmware) code and variables. */
ffd6ed
+  char *uefi_vars;
ffd6ed
 };
ffd6ed
 
ffd6ed
 /* Parameters passed to construct_libvirt_xml and subfunctions.  We
ffd6ed
@@ -318,6 +320,10 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri)
ffd6ed
   if (parse_capabilities (g, capabilities_xml, data) == -1)
ffd6ed
     goto cleanup;
ffd6ed
 
ffd6ed
+  /* UEFI code and variables, on architectures where that is required. */
ffd6ed
+  if (guestfs___get_uefi (g, &data->uefi_code, &data->uefi_vars) == -1)
ffd6ed
+    goto cleanup;
ffd6ed
+
ffd6ed
   /* Misc backend settings. */
ffd6ed
   guestfs_push_error_handler (g, NULL, NULL);
ffd6ed
   data->selinux_label =
ffd6ed
@@ -1095,6 +1101,20 @@ construct_libvirt_xml_boot (guestfs_h *g,
ffd6ed
       string ("hvm");
ffd6ed
     } end_element ();
ffd6ed
 
ffd6ed
+    if (params->data->uefi_code) {
ffd6ed
+      start_element ("loader") {
ffd6ed
+	attribute ("readonly", "yes");
ffd6ed
+	attribute ("type", "pflash");
ffd6ed
+	string (params->data->uefi_code);
ffd6ed
+      } end_element ();
ffd6ed
+
ffd6ed
+      if (params->data->uefi_vars) {
ffd6ed
+	start_element ("nvram") {
ffd6ed
+	  string (params->data->uefi_vars);
ffd6ed
+	} end_element ();
ffd6ed
+      }
ffd6ed
+    }
ffd6ed
+
ffd6ed
     start_element ("kernel") {
ffd6ed
       string (params->kernel);
ffd6ed
     } end_element ();
ffd6ed
@@ -1709,6 +1729,11 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors)
ffd6ed
   free (data->network_bridge);
ffd6ed
   data->network_bridge = NULL;
ffd6ed
 
ffd6ed
+  free (data->uefi_code);
ffd6ed
+  data->uefi_code = NULL;
ffd6ed
+  free (data->uefi_vars);
ffd6ed
+  data->uefi_vars = NULL;
ffd6ed
+
ffd6ed
   return ret;
ffd6ed
 }
ffd6ed
 
ffd6ed
-- 
ffd6ed
1.8.3.1
ffd6ed