Work-arounds for issues with Fedora GRUB EFI "linux" command (#572)

* Extend the header size to 4KB align the code segment in the image file.

A recent change (commit e41655885) to the Fedora implementation of the
GRUB "linux" command for EFI boot means it now loads the entire image
(including the header) at the preferred load address instead of just
loading the code section. This means the code section is no longer 4KB
aligned. In our image, the code section contains the combined .text and
.data sections, so this means the .data section is also no longer 4kB
aligned, which results in a GPF when the startup code loads the new page
directory address into CR3.

Work around this issue by extending the header size to force the code to
start on a 4KB boundary.

* Disable memory write protection after EFI setup.

A recent change (commit e41655885) to the Fedora implementation of the
GRUB "linux" command for EFI boot means it now attempts to make the
loaded code section read-only, using the EFI_MEMORY_ATTRIBUTE_PROTOCOL.
In our image the code section contains the combined .text and .data
sections. Our startup code needs to write to the .data section before
we can switch to our own page descriptor table, so globally disable
write protection as soon as we return from efisetup().

Our page descriptor table makes all pages writable (we need to be able
to write to memory to test it), so there's no need to reenable the
write protection once we've made the switch.

I have no UEFI firmware that implements the EFI_MEMORY_ATTRIBUTE_PROTOCOL,
so this fix is not yet proven.
This commit is contained in:
martinwhitaker
2026-01-19 00:51:27 +01:00
committed by GitHub
parent 1f0baf7a95
commit 213285adab
4 changed files with 10 additions and 4 deletions
+1 -1
View File
@@ -33,7 +33,7 @@
#define LOW_LOAD_ADDR 0x00010000 /* The low load address for the main program */
#define HIGH_LOAD_ADDR 0x00100000 /* The high load address for the main program */
#define SETUP_SECS 2 /* Size of the 16-bit setup code in sectors */
#define SETUP_SECS 7 /* Size of the 16-bit setup code in sectors */
#define BOOT_SEG 0x07c0 /* Segment address for the 16-bit boot code */
#define SETUP_SEG 0x07e0 /* Segment address for the 16-bit setup code */
+7 -1
View File
@@ -6,7 +6,7 @@
// It supports both the 32-bit and 64-bit Linux boot protocols and EFI boot
// for the first boot of the BSP.
//
// Copyright (C) 2020-2024 Martin Whitaker.
// Copyright (C) 2020-2025 Martin Whitaker.
//
// Derived from memtest86+ head.S:
//
@@ -134,6 +134,12 @@ efi_handover:
andq $~0xf, %rsp
call efi_setup
# Disable write protection in case the boot loader has made the
# loaded image read-only.
movq %cr0, %rcx
andw $0x7fff, %cx
movq %rcx, %cr0
# Save the boot params pointer.
movq %rax, boot_params_addr(%rip)
+1 -1
View File
@@ -59,5 +59,5 @@ SECTIONS {
_virt_img_size = _virt_sbat_start + _virt_sbat_size;
. = ASSERT(header == 0x202, "The setup header has the wrong offset!");
. = ASSERT(_file_text_start == 0x600, "The .text is at the wrong offset!");
. = ASSERT(_file_text_start == 0x1000, "The .text is at the wrong offset!");
}
+1 -1
View File
@@ -59,5 +59,5 @@ SECTIONS {
_virt_img_size = _virt_sbat_start + _virt_sbat_size;
. = ASSERT(header == 0x202, "The setup header has the wrong offset!");
. = ASSERT(_file_text_start == 0x600, "The .text is at the wrong offset!");
. = ASSERT(_file_text_start == 0x1000, "The .text is at the wrong offset!");
}