This will need fixes. I already have a newer version. Real problem though
is testing it

Regards
Vladimir 'phcoder' Serbinenko

Le mar. 22 avr. 2025, 23:33, Paymon MARANDI <pay...@encs.concordia.ca> a
écrit :

> 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

Reply via email to