From: Vladimir Serbinenko <[email protected]>
---
grub-core/Makefile.core.def | 1 +
grub-core/kern/efi/mm.c | 10 ++++
grub-core/kern/x86_64/efi/mm.c | 84 ++++++++++++++++++++++++++++++++++
include/grub/efi/memory.h | 5 ++
4 files changed, 100 insertions(+)
create mode 100644 grub-core/kern/x86_64/efi/mm.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 7f8cb3f7d..57e76dda5 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -219,6 +219,7 @@ kernel = {
efi = kern/efi/acpi.c;
efi = kern/efi/sb.c;
efi = kern/lockdown.c;
+ x86_64_efi = kern/x86_64/efi/mm.c;
i386_coreboot = kern/i386/pc/acpi.c;
i386_multiboot = kern/i386/pc/acpi.c;
i386_coreboot = kern/acpi.c;
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index df238b165..60ac7ed00 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -160,6 +160,16 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t
address,
}
}
+#ifdef __x86_64__
+ status = grub_efi_arch_ensure_mapping (address, pages);
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ b->free_pages (address, pages);
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return NULL;
+ }
+#endif
+
grub_efi_store_alloc (address, pages);
return (void *) ((grub_addr_t) address);
diff --git a/grub-core/kern/x86_64/efi/mm.c b/grub-core/kern/x86_64/efi/mm.c
new file mode 100644
index 000000000..01e2b9ac4
--- /dev/null
+++ b/grub-core/kern/x86_64/efi/mm.c
@@ -0,0 +1,84 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2025 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/cache.h>
+#include <grub/kernel.h>
+#include <grub/efi/efi.h>
+
+static grub_efi_status_t
+create_paging_entry(grub_uint64_t *entry)
+{
+ grub_efi_status_t status;
+ grub_efi_boot_services_t *b;
+
+ grub_uint64_t address = 0xffffffff;
+
+ b = grub_efi_system_table->boot_services;
+ /* TODO: Which type should it be? */
+ status = b->allocate_pages (GRUB_EFI_ALLOCATE_MAX_ADDRESS,
GRUB_EFI_LOADER_DATA, 1, &address);
+ if (status != GRUB_EFI_SUCCESS)
+ return status;
+ *entry = address | 7;
+ return GRUB_EFI_SUCCESS;
+}
+
+grub_efi_status_t
+grub_efi_arch_ensure_mapping (grub_efi_physical_address_t address,
+ grub_efi_uintn_t pages)
+{
+ grub_uint64_t cr3;
+ asm volatile("movq %%cr3, %0\n" : "=r"(cr3));
+ for (grub_uint64_t page = 0; page < pages; page++)
+ {
+ grub_uint64_t pageidx = (address >> 12) + page;
+ grub_uint64_t *pt4 = (grub_uint64_t *) cr3;
+ if (!(pt4[pageidx >> 27] & 1)) {
+ grub_efi_status_t status = create_paging_entry(&pt4[pageidx >> 27]);
+ if (status != GRUB_EFI_SUCCESS)
+ return status;
+ }
+ grub_uint64_t *pt3 = (grub_uint64_t *) (pt4[pageidx >> 27] & ~0xfff);
+ if (!(pt3[pageidx >> 18] & 1)) {
+ grub_efi_status_t status = create_paging_entry(&pt3[pageidx >> 18]);
+ if (status != GRUB_EFI_SUCCESS)
+ return status;
+ }
+ if (pt3[pageidx >> 18] & 0x80)
+ continue;
+ grub_uint64_t *pt2 = (grub_uint64_t *) (pt3[pageidx >> 18] & ~0xfff);
+ if (!(pt2[pageidx >> 9] & 1)) {
+ grub_efi_status_t status = create_paging_entry(&pt3[pageidx >> 9]);
+ if (status != GRUB_EFI_SUCCESS)
+ return status;
+ }
+ if (pt2[pageidx >> 9] & 0x80)
+ continue;
+
+ grub_uint64_t *pt1 = (grub_uint64_t *) (pt2[pageidx >> 9] & ~0xfff);
+ if (!(pt1[pageidx] & 1)) {
+ pt1[pageidx] = (pageidx << 12) | 7;
+ }
+ }
+
+ return GRUB_EFI_SUCCESS;
+}
diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h
index 08fe62277..2e5e4f84a 100644
--- a/include/grub/efi/memory.h
+++ b/include/grub/efi/memory.h
@@ -21,6 +21,7 @@
#include <grub/err.h>
#include <grub/types.h>
+#include <grub/efi/api.h>
/* The term "page" in UEFI refers only to a 4 KiB-aligned 4 KiB size region of
memory. It is not concerned with underlying translation management concepts,
@@ -35,4 +36,8 @@ grub_err_t grub_machine_mmap_register (grub_uint64_t start,
grub_uint64_t size,
int type, int handle);
grub_err_t grub_machine_mmap_unregister (int handle);
+grub_efi_status_t
+grub_efi_arch_ensure_mapping (grub_efi_physical_address_t address,
+ grub_efi_uintn_t pages);
+
#endif /* ! GRUB_MEMORY_MACHINE_HEADER */
--
2.49.0
_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel