[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] loader/i386/linux: Prefer entry in long mode when booting vi
From: |
Ard Biesheuvel |
Subject: |
Re: [PATCH] loader/i386/linux: Prefer entry in long mode when booting via EFI |
Date: |
Sun, 17 Sep 2023 18:28:29 +0200 |
On Thu, 3 Aug 2023 at 15:24, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> The x86_64 Linux kernel can be booted in 32-bit mode, in which case the
> startup code creates a set of preliminary page tables that map the first
> 1GiB of physical memory 1:1, and enables paging. This is a prerequisite
this should be '4 GiB'
> for 64-bit execution, and can therefore only be implemented in 32-bit
> code.
>
> The x86_64 Linux kernel can also be booted in 64-bit mode directly: this
> implies that paging is already enabled, and it is the responsibility of
> the bootloader to ensure that the the active page tables cover the
> entire loaded image, including its BSS space, the size of which is
> described in the image's setup header.
>
> Given that the EFI spec mandates execution in long mode for x86_64, and
> stipulates that all system memory is mapped 1:1, the Linux/x86
> requirements for 64-bit entry can be met trivially when booting on
> x86_64 via EFI. So enter via the 64-bit entrypoint in this case.
>
> This involves inspecting the xloadflags field in the setup header to
> check whether the 64-bit entrypoint is supported. This field was
> introduced in Linux version v3.8 (early 2013)
>
> This change ensures that all EFI firmware tables and other assets passed
> by the firmware or bootloader in memory remain mapped and accessible
> throughout the early startup code.
The part between the () should just be dropped entirely: I
misunderstood the code when I was reading it/
The early code just maps the first 4 GiB 1:1
> (Note that Linux's 32-bit startup
> code creates multiple shadow mappings of the first 1GiB of physical
> memory up to the 4 GiB mark so anything that resides there becomes
> inaccessible until the 64-bit startup code replaces the preliminary
> mappings with more accurate ones)
>
> Avoiding the drop out of long mode will also be needed to support
> upcoming CPU designs that no longer implement 32-bit mode at all (as
> recently announced by Intel [0])
>
> [0]
> https://www.intel.com/content/www/us/en/developer/articles/technical/envisioning-future-simplified-architecture.html
>
> Cc: Daniel Kiper <daniel.kiper@oracle.com>
> Cc: Julian Andres Klode <julian.klode@canonical.com>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> grub-core/loader/i386/linux.c | 12 ++++++++++++
> include/grub/i386/linux.h | 15 +++++++++++++--
> 2 files changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
> index 997647a33326eeb8..a83cc52a656d587b 100644
> --- a/grub-core/loader/i386/linux.c
> +++ b/grub-core/loader/i386/linux.c
> @@ -624,6 +624,18 @@ grub_linux_boot (void)
> }
> #endif
>
> +#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
> + if (grub_le_to_cpu16 (ctx.params->version) >= 0x020c &&
> + (linux_params.xloadflags & LINUX_X86_XLF_KERNEL_64) != 0)
> + {
> + struct grub_relocator64_efi_state state64;
> +
> + state64.rsi = ctx.real_mode_target;
> + state64.rip = ctx.params->code32_start + LINUX_X86_STARTUP64_OFFSET;
> + return grub_relocator64_efi_boot (relocator, state64);
> + }
> +#endif
> +
> /* FIXME. */
> /* asm volatile ("lidt %0" : : "m" (idt_desc)); */
> state.ebp = state.edi = state.ebx = 0;
> diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
> index 0fd6e1212fd2fa86..d4b550869534e255 100644
> --- a/include/grub/i386/linux.h
> +++ b/include/grub/i386/linux.h
> @@ -69,6 +69,16 @@
> #define GRUB_LINUX_OFW_SIGNATURE \
> (' ' << 24 | 'W' << 16 | 'F' << 8 | 'O')
>
> +#define LINUX_X86_XLF_KERNEL_64 (1<<0)
> +#define LINUX_X86_XLF_CAN_BE_LOADED_ABOVE_4G (1<<1)
> +#define LINUX_X86_XLF_EFI_HANDOVER_32 (1<<2)
> +#define LINUX_X86_XLF_EFI_HANDOVER_64 (1<<3)
> +#define LINUX_X86_XLF_EFI_KEXEC (1<<4)
> +#define LINUX_X86_XLF_5LEVEL (1<<5)
> +#define LINUX_X86_XLF_5LEVEL_ENABLED (1<<6)
> +
> +#define LINUX_X86_STARTUP64_OFFSET 0x200
> +
> #ifndef ASM_FILE
>
> #define GRUB_E820_RAM 1
> @@ -138,7 +148,7 @@ struct linux_i386_kernel_header
> grub_uint32_t kernel_alignment;
> grub_uint8_t relocatable;
> grub_uint8_t min_alignment;
> - grub_uint8_t pad[2];
> + grub_uint16_t xloadflags;
> grub_uint32_t cmdline_size;
> grub_uint32_t hardware_subarch;
> grub_uint64_t hardware_subarch_data;
> @@ -315,7 +325,8 @@ struct linux_kernel_params
> grub_uint32_t initrd_addr_max; /* Maximum initrd address */
> grub_uint32_t kernel_alignment; /* Alignment of the kernel */
> grub_uint8_t relocatable_kernel; /* Is the kernel relocatable */
> - grub_uint8_t pad1[3];
> + grub_uint8_t min_alignment;
> + grub_uint16_t xloadflags;
> grub_uint32_t cmdline_size; /* Size of the kernel command line */
> grub_uint32_t hardware_subarch;
> grub_uint64_t hardware_subarch_data;
> --
> 2.39.2
>