|
|
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 |
|