virt-v2v/0041-convert_windows-fix-up...

88 lines
3.7 KiB
Diff

From 796573e6f530d4736bcd9d81a6dc113f928a4d27 Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
Date: Fri, 2 Dec 2022 13:44:09 +0100
Subject: [PATCH] convert_windows: fix up the UEFI fallback boot loader if
broken
The "fallback" (or "default") boot behavior is described at great length
here:
https://blog.uncooperative.org/uefi/linux/shim/efi%20system%20partition/2014/02/06/the-efi-system-partition.html
The gist of it applies to all UEFI OSes, including Windows. For the
fallback boot behavior to work, the \EFI\BOOT\BOOTX64.efi boot loader on
the EFI system partition must match the installed operating system. We've
encountered a physical machine, during a virt-p2v conversion, where (a)
\EFI\BOOT\BOOTX64.efi belongs to a previously installed, but now wiped,
RHEL (hence shim+grub) deployment, and (b) the currently installed
operating system is Windows.
Virt-v2v never transfers the UEFI variables (including the UEFI boot
options) of the source, therefore the converted VM always relies on the
default boot behavior when it is first started up. In the above scenario,
where \EFI\BOOT\BOOTX64.efi is actually "shim", the mismatch is triggered
at first boot after conversion, and a broken grub shell is reached instead
of the Windows boot loader.
Detect this situation by investigating \EFI\BOOT\BOOTX64.efi on the EFI
system partition of a Windows disk image. If the file is missing, or is
not -- as expected -- a duplicate of \EFI\Microsoft\Boot\bootmgfw.efi,
then copy the latter to the former.
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2149629
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20221202124409.11741-3-lersek@redhat.com>
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
(cherry picked from commit 9d4b58dcecc40da5c97a0e716f44757c422160f0)
---
convert/convert_windows.ml | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/convert/convert_windows.ml b/convert/convert_windows.ml
index 34a5044d..57a7ff03 100644
--- a/convert/convert_windows.ml
+++ b/convert/convert_windows.ml
@@ -836,17 +836,42 @@ let convert (g : G.guestfs) _ inspect _ static_ips =
);
with
Not_found -> ()
+
+ and fix_win_uefi_fallback esp_path uefi_arch =
+ (* [esp_path] is on NTFS, and therefore it is considered case-sensitive;
+ * refer to
+ * <https://libguestfs.org/guestfs.3.html#guestfs_case_sensitive_path>.
+ * However, the EFI system partition mounted under [esp_path] is FAT32 per
+ * UEFI spec, and the Linux vfat driver in the libguestfs appliance treats
+ * pathnames case-insensitively. Therefore, we're free to use any case in
+ * the ESP-relative pathnames below.
+ *)
+ let bootmgfw = sprintf "%s/efi/microsoft/boot/bootmgfw.efi" esp_path in
+ if g#is_file bootmgfw then
+ let bootdir = sprintf "%s/efi/boot" esp_path in
+ let fallback = sprintf "%s/boot%s.efi" bootdir uefi_arch in
+ if not (g#is_file fallback) || not (g#equal fallback bootmgfw) then (
+ info (f_"Fixing UEFI bootloader.");
+ g#rm_rf bootdir;
+ g#mkdir_p bootdir;
+ g#cp_a bootmgfw fallback
+ )
in
match inspect.i_firmware with
| I_BIOS -> ()
| I_UEFI esp_list ->
let esp_temp_path = g#mkdtemp "/Windows/Temp/ESP_XXXXXX" in
+ let uefi_arch = get_uefi_arch_suffix inspect.i_arch in
List.iter (
fun dev_path ->
g#mount dev_path esp_temp_path;
fix_win_uefi_bcd esp_temp_path;
+ (match uefi_arch with
+ | Some uefi_arch -> fix_win_uefi_fallback esp_temp_path uefi_arch
+ | None -> ()
+ );
g#umount esp_temp_path;
) esp_list;