From: Vladimir Serbinenko <phco...@gmail.com> This is a replacement workaround for EFIs that do not map memory above 4G and allows to increase maximum available address to 128TiB --- 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 Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel