Commit 6898fcf74d13 ("relocator: Switch to own page table while moving
chunks") makes the relocator switch CR3 to a GRUB-owned page table to
prevent chunk movers clobbering firmware-owned page table, with
identical mapping in [0, max_ram_size) range.

However, for loaded images that use EFI boot services or MMIO mapped
above max_ram_size, those addresses are absent from the preamble page
table, causing #PF on access. Fix by copying the firmware's PML4 and
only overwriting entries for [0, max_ram_size).

Assisted-by: github-copilot:claude-opus-4.7
Signed-off-by: Jiaqing Zhao <[email protected]>
---
 grub-core/lib/i386/relocator_common_c.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/grub-core/lib/i386/relocator_common_c.c 
b/grub-core/lib/i386/relocator_common_c.c
index c9c5efa72..be4da1fa8 100644
--- a/grub-core/lib/i386/relocator_common_c.c
+++ b/grub-core/lib/i386/relocator_common_c.c
@@ -109,6 +109,7 @@ grub_cpu_relocator_preamble (void *rels)
   grub_uint64_t *pt2 = pt3 + (npt3pages << PAGE_IDX_SIZE);
   grub_uint64_t *endpreamble = pt2 + (npt2pages << PAGE_IDX_SIZE);
   grub_uint64_t i;
+  grub_uint64_t firmware_cr3;
 
   /* movabs $pt4, %rax.  */
   *p++ = 0x48;
@@ -125,6 +126,13 @@ grub_cpu_relocator_preamble (void *rels)
   *p++ = 0xe9;
   *(grub_uint32_t *) p = (grub_uint8_t *) endpreamble - p - 4;
 
+  /*
+   * Inherit the firmware's PML4 so that high mappings (EFI runtime, MMIO, 
etc.)
+   * remain reachable while after switching to own page table.
+   */
+  asm volatile ("mov %%cr3, %0" : "=r" (firmware_cr3));
+  grub_memcpy (pt4, (void *) (firmware_cr3 & ~0xfffULL), GRUB_PAGE_SIZE);
+
   for (i = 0; i < npt3pages; i++)
     pt4[i] = ((grub_uint64_t) pt3 + (i << GRUB_PAGE_SHIFT)) | PAGE_PRESENT | 
PAGE_WRITABLE | PAGE_USER;
 
-- 
2.53.0


_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to