summaryrefslogblamecommitdiff
path: root/user/grub/0009-linux-mixed-mode.patch
blob: d3b2135f26a878afc652193774ba92b1eb233582 (plain) (tree)














































































                                                                                          
From 1f5b180742ff2706bc3a696d115ddbc677ec75b9 Mon Sep 17 00:00:00 2001
From: Ard Biesheuvel <ardb@kernel.org>
Date: Mon, 7 Aug 2023 14:21:51 +0200
Subject: loader/efi/linux: Implement x86 mixed mode using legacy boot

Recent mixed-mode Linux kernels, i.e., v4.0 or newer, can access EFI
runtime services at OS runtime even when the OS was not entered via the
EFI stub. This is because, instead of reverting back to the firmware's
segment selectors, GDTs and IDTs, the 64-bit kernel simply calls 32-bit
runtime services using compatibility mode, i.e., the same mode used for
32-bit user space, without taking down all interrupt handling, exception
handling, etc.

This means that GRUB's legacy x86 boot mode is sufficient to make use of
this: 32-bit i686 builds of GRUB can already boot 64-bit kernels in EFI
enlightened mode, but without going via the EFI stub, and provide all
the metadata that the OS needs to map the EFI runtime regions and call
EFI runtime services successfully.

It does mean that GRUB should not attempt to invoke the firmware's
LoadImage()/StartImage() methods on kernel builds that it knows cannot
be started natively. So, add a check for this in the native EFI boot
path and fall back to legacy x86 mode in such cases.

Note that in the general case, booting non-native images of the same
native word size, e.g., x64 EFI apps on arm64 firmware, might be
supported by means of emulation. So, let's only disallow images that use
a non-native word size. This will also permit booting i686 kernels on
x86_64 builds, although without access to runtime services, as this is
not supported by Linux.

This change on top of 2.12-rc1 is sufficient to boot ordinary Linux
mixed mode builds and get full access to the EFI runtime services.

Cc: Daniel Kiper <daniel.kiper@oracle.com>
Cc: Steve McIntyre <steve@einval.com>
Cc: Julian Andres Klode <julian.klode@canonical.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 grub-core/loader/efi/linux.c | 3 +++
 include/grub/efi/pe32.h      | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index ab8fb35..bfbd95a 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -117,6 +117,9 @@ grub_arch_efi_linux_load_image_header (grub_file_t file,
         return grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read COFF image header");
     }
 
+  if (lh->pe_image_header.optional_header.magic != GRUB_PE32_NATIVE_MAGIC)
+    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "non-native image not supported");
+
   /*
    * Linux kernels built for any architecture are guaranteed to support the
    * LoadFile2 based initrd loading protocol if the image version is >= 1.
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index 101859a..4e6e9d2 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -267,6 +267,12 @@ struct grub_pe32_section_table
 
 #define GRUB_PE32_SIGNATURE_SIZE 4
 
+#if GRUB_TARGET_SIZEOF_VOID_P == 8
+#define GRUB_PE32_NATIVE_MAGIC			GRUB_PE32_PE64_MAGIC
+#else
+#define GRUB_PE32_NATIVE_MAGIC			GRUB_PE32_PE32_MAGIC
+#endif
+
 struct grub_pe_image_header
 {
   /* This is always PE\0\0.  */
-- 
cgit v1.1