From 5ba28e31fde4b758ecdb5aea88d4aab7b9894f46 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 18 Aug 2016 12:35:16 +0100
Subject: [PATCH] Generate the lists of UEFI firmware paths.
Previously we had a list of UEFI paths in src/uefi.c, which was
accessed in virt-v2v using a private (guestfs_int_*) API and some C
binding code. This was clumsy and required the paths to be replicated
in the virt-v2v unit tests.
Instead just generate the list of paths from the generator, creating
src/uefi.c and v2v/uefi.ml with the same content.
Remove the C bindings and the virt-v2v unit tests associated with UEFI
paths.
Cherry picked from commit 04fc67775e27851ce9b6c7a082ff80f1e1793365.
For this complex cherry pick I had to take into account earlier
RHEL-only patches where we removed several sets of firmware.
---
.gitignore | 3 +
generator/Makefile.am | 3 +
generator/main.ml | 5 ++
generator/uefi.ml | 126 ++++++++++++++++++++++++++++++++++++++++
generator/uefi.mli | 21 +++++++
generator/utils.ml | 16 +++++
generator/utils.mli | 6 ++
po/POTFILES | 1 +
po/POTFILES-ml | 1 +
src/Makefile.am | 1 +
src/appliance.c | 13 ++++-
src/guestfs-internal-frontend.h | 14 ++++-
src/utils.c | 22 -------
v2v/Makefile.am | 4 ++
v2v/output_libvirt.ml | 3 +-
v2v/output_qemu.ml | 4 +-
v2v/utils-c.c | 45 --------------
v2v/utils.ml | 11 +---
v2v/utils.mli | 7 +--
19 files changed, 218 insertions(+), 88 deletions(-)
create mode 100644 generator/uefi.ml
create mode 100644 generator/uefi.mli
diff --git a/.gitignore b/.gitignore
index 85b19d4..2baf137 100644
--- a/.gitignore
+++ b/.gitignore
@@ -469,6 +469,7 @@ Makefile.in
/src/structs-free.c
/src/structs-print.c
/src/structs-print.h
+/src/uefi.c
/src/unit-tests
/stamp-h1
/sysprep/.depend
@@ -579,6 +580,8 @@ Makefile.in
/v2v/test-harness/dllv2v_test_harness.so
/v2v/test-harness/stamp-virt-v2v-test-harness.pod
/v2v/test-harness/virt-v2v-test-harness.1
+/v2v/uefi.ml
+/v2v/uefi.mli
/v2v/v2v_unit_tests
/v2v/virt-v2v
/v2v/virt-v2v.1
diff --git a/generator/Makefile.am b/generator/Makefile.am
index 393c566..3a53054 100644
--- a/generator/Makefile.am
+++ b/generator/Makefile.am
@@ -75,6 +75,8 @@ sources = \
tests_c_api.ml \
tests_c_api.mli \
types.ml \
+ uefi.ml \
+ uefi.mli \
utils.ml \
utils.mli \
xdr.ml \
@@ -112,6 +114,7 @@ objects = \
bindtests.cmo \
errnostring.cmo \
customize.cmo \
+ uefi.cmo \
main.cmo
EXTRA_DIST = $(sources) files-generated.txt
diff --git a/generator/main.ml b/generator/main.ml
index 42f6f8b..f242ed9 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -45,6 +45,7 @@ open Gobject
open Golang
open Bindtests
open Errnostring
+open Uefi
open Customize
let perror msg = function
@@ -210,6 +211,10 @@ Run it from the top source directory using the command
generate_gobject_session_header;
output_to "gobject/src/session.c" generate_gobject_session_source;
+ output_to "src/uefi.c" generate_uefi_c;
+ output_to "v2v/uefi.ml" generate_uefi_ml;
+ output_to "v2v/uefi.mli" generate_uefi_mli;
+
output_to "customize/customize_cmdline.mli" generate_customize_cmdline_mli;
output_to "customize/customize_cmdline.ml" generate_customize_cmdline_ml;
output_to "customize/customize-synopsis.pod" generate_customize_synopsis_pod;
diff --git a/generator/uefi.ml b/generator/uefi.ml
new file mode 100644
index 0000000..3b371b8
--- /dev/null
+++ b/generator/uefi.ml
@@ -0,0 +1,126 @@
+(* libguestfs
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *)
+
+(* Please read generator/README first. *)
+
+open Utils
+open Pr
+open Docstrings
+
+(* danpb is proposing that libvirt supports E<lt>loader type="efi"/E<gt>
+ * (L<https://bugzilla.redhat.com/1217444#c6>). If that happens we can
+ * simplify or even remove this code.
+ *)
+
+(* Order is significant *within architectures only*. *)
+let firmware = [
+ "x86_64",
+ "/usr/share/OVMF/OVMF_CODE.fd",
+ None,
+ "/usr/share/OVMF/OVMF_VARS.fd",
+ [];
+
+ "aarch64",
+ "/usr/share/AAVMF/AAVMF_CODE.fd",
+ None,
+ "/usr/share/AAVMF/AAVMF_VARS.fd",
+ [];
+]
+
+let arches = sort_uniq (List.map (fun (arch, _, _, _, _) -> arch) firmware)
+
+let generate_uefi_c () =
+ generate_header CStyle LGPLv2plus;
+
+ pr "#include <config.h>\n";
+ pr "\n";
+ pr "#include <stdio.h>\n";
+ pr "\n";
+ pr "#include \"guestfs.h\"\n";
+ pr "#include \"guestfs-internal-frontend.h\"\n";
+
+ List.iter (
+ fun arch ->
+ let firmware =
+ List.filter (fun (arch', _, _, _, _) -> arch = arch') firmware in
+ pr "\n";
+ pr "struct uefi_firmware\n";
+ pr "guestfs_int_uefi_%s_firmware[] = {\n" arch;
+ List.iter (
+ fun (_, code, code_debug, vars, flags) ->
+ assert (flags = []);
+ pr " { \"%s\",\n" (c_quote code);
+ (match code_debug with
+ | None -> pr " NULL,\n"
+ | Some code_debug -> pr " \"%s\",\n" (c_quote code_debug)
+ );
+ pr " \"%s\",\n" (c_quote vars);
+ pr " 0\n";
+ pr " },\n";
+ ) firmware;
+ pr "};\n";
+ ) arches
+
+let generate_uefi_ml () =
+ generate_header OCamlStyle GPLv2plus;
+
+ pr "\
+type uefi_firmware = {
+ code : string;
+ code_debug : string option;
+ vars : string;
+ flags : unit list;
+}
+";
+ List.iter (
+ fun arch ->
+ let firmware =
+ List.filter (fun (arch', _, _, _, _) -> arch = arch') firmware in
+ pr "\n";
+ pr "let uefi_%s_firmware = [\n" arch;
+ List.iter (
+ fun (_, code, code_debug, vars, flags) ->
+ assert (flags = []);
+ pr " { code = %S;\n" code;
+ (match code_debug with
+ | None -> pr " code_debug = None;\n"
+ | Some code_debug -> pr " code_debug = Some %S;\n" code_debug
+ );
+ pr " vars = %S;\n" vars;
+ pr " flags = [];\n";
+ pr " };\n";
+ ) firmware;
+ pr "]\n";
+ ) arches
+
+let generate_uefi_mli () =
+ generate_header OCamlStyle GPLv2plus;
+
+ pr "\
+(** UEFI paths. *)
+
+type uefi_firmware = {
+ code : string; (** code file *)
+ code_debug : string option; (** code debug file *)
+ vars : string; (** vars template file *)
+ flags : unit list; (** flags *)
+}
+
+";
+
+ List.iter (pr "val uefi_%s_firmware : uefi_firmware list\n") arches
diff --git a/generator/uefi.mli b/generator/uefi.mli
new file mode 100644
index 0000000..64aa1f8
--- /dev/null
+++ b/generator/uefi.mli
@@ -0,0 +1,21 @@
+(* libguestfs
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *)
+
+val generate_uefi_c : unit -> unit
+val generate_uefi_ml : unit -> unit
+val generate_uefi_mli : unit -> unit
diff --git a/generator/utils.ml b/generator/utils.ml
index 6fb04dc..fdb2b9b 100644
--- a/generator/utils.ml
+++ b/generator/utils.ml
@@ -231,6 +231,22 @@ let mapi f xs =
in
loop 0 xs
+let uniq ?(cmp = Pervasives.compare) xs =
+ let rec loop acc = function
+ | [] -> acc
+ | [x] -> x :: acc
+ | x :: (y :: _ as xs) when cmp x y = 0 ->
+ loop acc xs
+ | x :: (y :: _ as xs) ->
+ loop (x :: acc) xs
+ in
+ List.rev (loop [] xs)
+
+let sort_uniq ?(cmp = Pervasives.compare) xs =
+ let xs = List.sort cmp xs in
+ let xs = uniq ~cmp xs in
+ xs
+
let count_chars c str =
let count = ref 0 in
for i = 0 to String.length str - 1 do
diff --git a/generator/utils.mli b/generator/utils.mli
index 41dd47d..a69328f 100644
--- a/generator/utils.mli
+++ b/generator/utils.mli
@@ -84,6 +84,12 @@ val iteri : (int -> 'a -> unit) -> 'a list -> unit
val mapi : (int -> 'a -> 'b) -> 'a list -> 'b list
+val uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list
+(** Uniquify a list (the list must be sorted first). *)
+
+val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list
+(** Sort and uniquify a list. *)
+
val count_chars : char -> string -> int
(** Count number of times the character occurs in string. *)
diff --git a/po/POTFILES b/po/POTFILES
index 756fc5e..a45744b 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -357,6 +357,7 @@ src/structs-copy.c
src/structs-free.c
src/structs-print.c
src/tmpdirs.c
+src/uefi.c
src/umask.c
src/unit-tests.c
src/utils.c
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 8b1cad7..0c6cfe5 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -129,6 +129,7 @@ v2v/output_vdsm.ml
v2v/target_bus_assignment.ml
v2v/test-harness/v2v_test_harness.ml
v2v/types.ml
+v2v/uefi.ml
v2v/utils.ml
v2v/v2v.ml
v2v/v2v_unit_tests.ml
diff --git a/src/Makefile.am b/src/Makefile.am
index ab36329..e4fc5b6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -232,6 +232,7 @@ libutils_la_SOURCES = \
structs-cleanup.c \
structs-print.c \
structs-print.h \
+ uefi.c \
utils.c
libutils_la_CPPFLAGS = $(libguestfs_la_CPPFLAGS)
libutils_la_CFLAGS = $(libguestfs_la_CFLAGS)
diff --git a/src/appliance.c b/src/appliance.c
index 1687a93..6409cfb 100644
--- a/src/appliance.c
+++ b/src/appliance.c
@@ -435,9 +435,10 @@ guestfs_int_get_uefi (guestfs_h *g, char **code, char **vars)
#ifdef __aarch64__
size_t i;
- for (i = 0; guestfs_int_aavmf_firmware[i] != NULL; i += 2) {
- const char *codefile = guestfs_int_aavmf_firmware[i];
- const char *varsfile = guestfs_int_aavmf_firmware[i+1];
+ for (i = 0; guestfs_int_aavmf_firmware[i].code != NULL; ++i) {
+ const char *codefile = guestfs_int_aavmf_firmware[i].code;
+ const char *code_debug_file = guestfs_int_aavmf_firmware[i].code_debug;
+ const char *varsfile = guestfs_int_aavmf_firmware[i].vars;
if (access (codefile, R_OK) == 0 && access (varsfile, R_OK) == 0) {
CLEANUP_CMD_CLOSE struct command *copycmd = guestfs_int_new_command (g);
@@ -458,6 +459,12 @@ guestfs_int_get_uefi (guestfs_h *g, char **code, char **vars)
return -1;
}
+ /* If debugging is enabled and we can find the code file with
+ * debugging enabled, use that instead.
+ */
+ if (g->verbose && access (code_debug_file, R_OK) == 0)
+ codefile = code_debug_file;
+
/* Caller frees. */
*code = safe_strdup (g, codefile);
*vars = varst;
diff --git a/src/guestfs-internal-frontend.h b/src/guestfs-internal-frontend.h
index ed9165a..1dba172 100644
--- a/src/guestfs-internal-frontend.h
+++ b/src/guestfs-internal-frontend.h
@@ -110,9 +110,6 @@ extern int guestfs_int_random_string (char *ret, size_t len);
extern char *guestfs_int_drive_name (size_t index, char *ret);
extern ssize_t guestfs_int_drive_index (const char *);
extern int guestfs_int_is_true (const char *str);
-extern const char *guestfs_int_ovmf_i386_firmware[];
-extern const char *guestfs_int_ovmf_x86_64_firmware[];
-extern const char *guestfs_int_aavmf_firmware[];
//extern void guestfs_int_fadvise_normal (int fd);
extern void guestfs_int_fadvise_sequential (int fd);
extern void guestfs_int_fadvise_random (int fd);
@@ -121,6 +118,17 @@ extern void guestfs_int_fadvise_noreuse (int fd);
//extern void guestfs_int_fadvise_willneed (int fd);
extern char *guestfs_int_shell_unquote (const char *str);
+/* uefi.c */
+struct uefi_firmware {
+ const char *code; /* code file (NULL = end of list) */
+ const char *code_debug; /* code file with debugging msgs (may be NULL)*/
+ const char *vars; /* vars template file */
+ int flags; /* flags */
+};
+extern struct uefi_firmware guestfs_int_ovmf_i386_firmware[];
+extern struct uefi_firmware guestfs_int_ovmf_x86_64_firmware[];
+extern struct uefi_firmware guestfs_int_aavmf_firmware[];
+
/* These functions are used internally by the CLEANUP_* macros.
* Don't call them directly.
*/
diff --git a/src/utils.c b/src/utils.c
index 8ffc1ed..ab18f52 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -321,28 +321,6 @@ guestfs_int_is_true (const char *str)
return -1;
}
-/* See src/appliance.c:guestfs_int_get_uefi. */
-const char *
-guestfs_int_ovmf_i386_firmware[] = {
- NULL
-};
-
-const char *
-guestfs_int_ovmf_x86_64_firmware[] = {
- "/usr/share/OVMF/OVMF_CODE.fd",
- "/usr/share/OVMF/OVMF_VARS.fd",
-
- NULL
-};
-
-const char *
-guestfs_int_aavmf_firmware[] = {
- "/usr/share/AAVMF/AAVMF_CODE.fd",
- "/usr/share/AAVMF/AAVMF_VARS.fd",
-
- NULL
-};
-
#if 0 /* not used yet */
/**
* Hint that we will read or write the file descriptor normally.
diff --git a/v2v/Makefile.am b/v2v/Makefile.am
index 0486cfe..c1ebb17 100644
--- a/v2v/Makefile.am
+++ b/v2v/Makefile.am
@@ -72,6 +72,7 @@ SOURCES_MLI = \
OVF.mli \
target_bus_assignment.mli \
types.mli \
+ uefi.mli \
utils.mli \
vCenter.mli \
windows.mli \
@@ -81,6 +82,7 @@ SOURCES_MLI = \
SOURCES_ML = \
types.ml \
xml.ml \
+ uefi.ml \
utils.ml \
vCenter.ml \
domainxml.ml \
@@ -219,6 +221,7 @@ COPY_TO_LOCAL_BOBJECTS = \
$(top_builddir)/mllib/StatVFS.cmo \
$(top_builddir)/mllib/curl.cmo \
xml.cmo \
+ uefi.cmo \
utils.cmo \
vCenter.cmo \
domainxml.cmo \
@@ -380,6 +383,7 @@ v2v_unit_tests_BOBJECTS = \
$(top_builddir)/mllib/regedit.cmo \
types.cmo \
xml.cmo \
+ uefi.cmo \
utils.cmo \
DOM.cmo \
OVF.cmo \
diff --git a/v2v/output_libvirt.ml b/v2v/output_libvirt.ml
index 5a404ee..df0963e 100644
--- a/v2v/output_libvirt.ml
+++ b/v2v/output_libvirt.ml
@@ -118,7 +118,8 @@ let create_libvirt_xml ?pool source target_buses guestcaps
* (https://bugzilla.redhat.com/show_bug.cgi?id=1217444#c6) but
* until that day we have to use a bunch of heuristics. XXX
*)
- let code, vars_template = find_uefi_firmware guestcaps.gcaps_arch in
+ let { Uefi.code = code; vars = vars_template } =
+ find_uefi_firmware guestcaps.gcaps_arch in
[ e "loader" ["readonly", "yes"; "type", "pflash"] [ PCData code ];
e "nvram" ["template", vars_template] [] ] in
diff --git a/v2v/output_qemu.ml b/v2v/output_qemu.ml
index 94f80c2..2a944d7 100644
--- a/v2v/output_qemu.ml
+++ b/v2v/output_qemu.ml
@@ -69,7 +69,7 @@ object
(match uefi_firmware with
| None -> ()
- | Some (_, vars_template) ->
+ | Some { Uefi.vars = vars_template } ->
fpf "# Make a copy of the UEFI variables template\n";
fpf "uefi_vars=\"$(mktemp)\"\n";
fpf "cp %s \"$uefi_vars\"\n" (quote vars_template);
@@ -83,7 +83,7 @@ object
(match uefi_firmware with
| None -> ()
- | Some (code, _) ->
+ | Some { Uefi.code = code } ->
fpf "%s-drive if=pflash,format=raw,file=%s,readonly" nl (quote code);
fpf "%s-drive if=pflash,format=raw,file=\"$uefi_vars\"" nl
);
diff --git a/v2v/utils-c.c b/v2v/utils-c.c
index 77de321..af74c12 100644
--- a/v2v/utils-c.c
+++ b/v2v/utils-c.c
@@ -66,51 +66,6 @@ v2v_utils_drive_index (value strv)
CAMLreturn (Val_int (r));
}
-static value
-get_firmware (char **firmware)
-{
- CAMLparam0 ();
- CAMLlocal5 (rv, v, v1, v2, cons);
- size_t i, len;
-
- rv = Val_int (0);
-
- /* Build the list backwards so we don't have to reverse it at the end. */
- len = guestfs_int_count_strings (firmware);
-
- for (i = len; i > 0; i -= 2) {
- v1 = caml_copy_string (firmware[i-2]);
- v2 = caml_copy_string (firmware[i-1]);
- v = caml_alloc (2, 0);
- Store_field (v, 0, v1);
- Store_field (v, 1, v2);
- cons = caml_alloc (2, 0);
- Store_field (cons, 1, rv);
- rv = cons;
- Store_field (cons, 0, v);
- }
-
- CAMLreturn (rv);
-}
-
-value
-v2v_utils_ovmf_i386_firmware (value unitv)
-{
- return get_firmware ((char **) guestfs_int_ovmf_i386_firmware);
-}
-
-value
-v2v_utils_ovmf_x86_64_firmware (value unitv)
-{
- return get_firmware ((char **) guestfs_int_ovmf_x86_64_firmware);
-}
-
-value
-v2v_utils_aavmf_firmware (value unitv)
-{
- return get_firmware ((char **) guestfs_int_aavmf_firmware);
-}
-
value
v2v_utils_shell_unquote (value strv)
{
diff --git a/v2v/utils.ml b/v2v/utils.ml
index d88f8ad..e7aef79 100644
--- a/v2v/utils.ml
+++ b/v2v/utils.ml
@@ -82,25 +82,20 @@ let qemu_supports_sound_card = function
| Types.USBAudio
-> false
-external ovmf_i386_firmware : unit -> (string * string) list = "v2v_utils_ovmf_i386_firmware"
-external ovmf_x86_64_firmware : unit -> (string * string) list = "v2v_utils_ovmf_x86_64_firmware"
-external aavmf_firmware : unit -> (string * string) list = "v2v_utils_aavmf_firmware"
-
(* Find the UEFI firmware. *)
let find_uefi_firmware guest_arch =
let files =
(* The lists of firmware are actually defined in src/utils.c. *)
match guest_arch with
- | "i386" | "i486" | "i586" | "i686" -> ovmf_i386_firmware ()
- | "x86_64" -> ovmf_x86_64_firmware ()
- | "aarch64" -> aavmf_firmware ()
+ | "x86_64" -> Uefi.uefi_x86_64_firmware
+ | "aarch64" -> Uefi.uefi_aarch64_firmware
| arch ->
error (f_"don't know how to convert UEFI guests for architecture %s")
guest_arch in
let rec loop = function
| [] ->
error (f_"cannot find firmware for UEFI guests.\n\nYou probably need to install OVMF, or AAVMF (if using aarch64)")
- | ((code, vars_template) as ret) :: rest ->
+ | ({ Uefi.code = code; vars = vars_template } as ret) :: rest ->
if Sys.file_exists code && Sys.file_exists vars_template then ret
else loop rest
in
diff --git a/v2v/utils.mli b/v2v/utils.mli
index 4daf38c..bdabab4 100644
--- a/v2v/utils.mli
+++ b/v2v/utils.mli
@@ -43,10 +43,9 @@ val kvm_arch : string -> string
val qemu_supports_sound_card : Types.source_sound_model -> bool
(** Does qemu support the given sound card? *)
-val find_uefi_firmware : string -> string * string
-(** Find the UEFI firmware for the guest architecture. Returns a
- pair [(code_file, vars_file)]. This cannot return an error, it
- calls [error] and fails instead. *)
+val find_uefi_firmware : string -> Uefi.uefi_firmware
+(** Find the UEFI firmware for the guest architecture.
+ This cannot return an error, it calls [error] and fails instead. *)
val compare_app2_versions : Guestfs.application2 -> Guestfs.application2 -> int
(** Compare two app versions. *)
--
1.8.3.1