diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
commit | 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch) | |
tree | 32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/mmap/efi | |
parent | Initial commit. (diff) | |
download | grub2-6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e.tar.xz grub2-6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e.zip |
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'grub-core/mmap/efi')
-rw-r--r-- | grub-core/mmap/efi/mmap.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/grub-core/mmap/efi/mmap.c b/grub-core/mmap/efi/mmap.c new file mode 100644 index 0000000..bd495a1 --- /dev/null +++ b/grub-core/mmap/efi/mmap.c @@ -0,0 +1,318 @@ +/* Mmap management. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/machine/memory.h> +#include <grub/memory.h> +#include <grub/err.h> +#include <grub/efi/api.h> +#include <grub/efi/efi.h> +#include <grub/mm.h> +#include <grub/misc.h> + +#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +grub_err_t +grub_efi_mmap_iterate (grub_memory_hook_t hook, void *hook_data, + int avoid_efi_boot_services) +{ + grub_efi_uintn_t mmap_size = 0; + grub_efi_memory_descriptor_t *map_buf = 0; + grub_efi_uintn_t map_key = 0; + grub_efi_uintn_t desc_size = 0; + grub_efi_uint32_t desc_version = 0; + grub_efi_memory_descriptor_t *desc; + + if (grub_efi_get_memory_map (&mmap_size, map_buf, + &map_key, &desc_size, + &desc_version) < 0) + return grub_errno; + + map_buf = grub_malloc (mmap_size); + if (! map_buf) + return grub_errno; + + if (grub_efi_get_memory_map (&mmap_size, map_buf, + &map_key, &desc_size, + &desc_version) <= 0) + { + grub_free (map_buf); + return grub_errno; + } + + for (desc = map_buf; + desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n", + (unsigned long long) desc->physical_start, + (unsigned long long) desc->physical_start + + desc->num_pages * 4096, desc->type); + switch (desc->type) + { + case GRUB_EFI_BOOT_SERVICES_CODE: + if (!avoid_efi_boot_services) + { + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_AVAILABLE, hook_data); + break; + } + /* FALLTHROUGH */ + case GRUB_EFI_RUNTIME_SERVICES_CODE: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_CODE, hook_data); + break; + + case GRUB_EFI_UNUSABLE_MEMORY: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_BADRAM, hook_data); + break; + + case GRUB_EFI_BOOT_SERVICES_DATA: + if (!avoid_efi_boot_services) + { + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_AVAILABLE, hook_data); + break; + } + /* FALLTHROUGH */ + case GRUB_EFI_RESERVED_MEMORY_TYPE: + case GRUB_EFI_RUNTIME_SERVICES_DATA: + case GRUB_EFI_MEMORY_MAPPED_IO: + case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: + case GRUB_EFI_PAL_CODE: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_RESERVED, hook_data); + break; + + case GRUB_EFI_LOADER_CODE: + case GRUB_EFI_LOADER_DATA: + case GRUB_EFI_CONVENTIONAL_MEMORY: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_AVAILABLE, hook_data); + break; + + case GRUB_EFI_ACPI_RECLAIM_MEMORY: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_ACPI, hook_data); + break; + + case GRUB_EFI_ACPI_MEMORY_NVS: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_NVS, hook_data); + break; + + case GRUB_EFI_PERSISTENT_MEMORY: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_PERSISTENT, hook_data); + break; + + default: + grub_printf ("Unknown memory type %d, considering reserved\n", + desc->type); + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_RESERVED, hook_data); + break; + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data) +{ + return grub_efi_mmap_iterate (hook, hook_data, 0); +} + +static inline grub_efi_memory_type_t +make_efi_memtype (int type) +{ + switch (type) + { + case GRUB_MEMORY_CODE: + return GRUB_EFI_RUNTIME_SERVICES_CODE; + + /* No way to remove a chunk of memory from EFI mmap. + So mark it as unusable. */ + case GRUB_MEMORY_HOLE: + /* + * AllocatePages() does not support GRUB_EFI_PERSISTENT_MEMORY, + * so no translation for GRUB_MEMORY_PERSISTENT or + * GRUB_MEMORY_PERSISTENT_LEGACY. + */ + case GRUB_MEMORY_PERSISTENT: + case GRUB_MEMORY_PERSISTENT_LEGACY: + case GRUB_MEMORY_RESERVED: + return GRUB_EFI_UNUSABLE_MEMORY; + + case GRUB_MEMORY_AVAILABLE: + return GRUB_EFI_CONVENTIONAL_MEMORY; + + case GRUB_MEMORY_ACPI: + return GRUB_EFI_ACPI_RECLAIM_MEMORY; + + case GRUB_MEMORY_NVS: + return GRUB_EFI_ACPI_MEMORY_NVS; + } + + return GRUB_EFI_UNUSABLE_MEMORY; +} + +struct overlay +{ + struct overlay *next; + grub_efi_physical_address_t address; + grub_efi_uintn_t pages; + int handle; +}; + +static struct overlay *overlays = 0; +static int curhandle = 1; + +int +grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type) +{ + grub_uint64_t end = start + size; + grub_efi_physical_address_t address; + grub_efi_boot_services_t *b; + grub_efi_uintn_t pages; + grub_efi_status_t status; + struct overlay *curover; + + curover = (struct overlay *) grub_malloc (sizeof (struct overlay)); + if (! curover) + return 0; + + b = grub_efi_system_table->boot_services; + address = start & (~0xfffULL); + pages = (end - address + 0xfff) >> 12; + status = efi_call_2 (b->free_pages, address, pages); + if (status != GRUB_EFI_SUCCESS && status != GRUB_EFI_NOT_FOUND) + { + grub_free (curover); + return 0; + } + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS, + make_efi_memtype (type), pages, &address); + if (status != GRUB_EFI_SUCCESS) + { + grub_free (curover); + return 0; + } + curover->next = overlays; + curover->handle = curhandle++; + curover->address = address; + curover->pages = pages; + overlays = curover; + + return curover->handle; +} + +grub_err_t +grub_mmap_unregister (int handle) +{ + struct overlay *curover, *prevover; + grub_efi_boot_services_t *b; + + b = grub_efi_system_table->boot_services; + + + for (curover = overlays, prevover = 0; curover; + prevover = curover, curover = curover->next) + { + if (curover->handle == handle) + { + efi_call_2 (b->free_pages, curover->address, curover->pages); + if (prevover != 0) + prevover->next = curover->next; + else + overlays = curover->next; + grub_free (curover); + return GRUB_ERR_NONE; + } + } + return grub_error (GRUB_ERR_BUG, "handle %d not found", handle); +} + +/* Result is always page-aligned. */ +void * +grub_mmap_malign_and_register (grub_uint64_t align __attribute__ ((unused)), + grub_uint64_t size, + int *handle, int type, + int flags __attribute__ ((unused))) +{ + grub_efi_physical_address_t address; + grub_efi_boot_services_t *b; + grub_efi_uintn_t pages; + grub_efi_status_t status; + struct overlay *curover; + grub_efi_allocate_type_t atype; + + curover = (struct overlay *) grub_malloc (sizeof (struct overlay)); + if (! curover) + return 0; + + b = grub_efi_system_table->boot_services; + + address = 0xffffffff; + +#if GRUB_TARGET_SIZEOF_VOID_P < 8 + /* Limit the memory access to less than 4GB for 32-bit platforms. */ + atype = GRUB_EFI_ALLOCATE_MAX_ADDRESS; +#else + atype = GRUB_EFI_ALLOCATE_ANY_PAGES; +#endif + + pages = (size + 0xfff) >> 12; + status = efi_call_4 (b->allocate_pages, atype, + make_efi_memtype (type), pages, &address); + if (status != GRUB_EFI_SUCCESS) + { + grub_free (curover); + return 0; + } + + if (address == 0) + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ + address = 0xffffffff; + status = efi_call_4 (b->allocate_pages, atype, + make_efi_memtype (type), pages, &address); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) + return 0; + } + + curover->next = overlays; + curover->handle = curhandle++; + curover->address = address; + curover->pages = pages; + overlays = curover; + *handle = curover->handle; + + return (void *) (grub_addr_t) curover->address; +} + +void +grub_mmap_free_and_unregister (int handle) +{ + grub_mmap_unregister (handle); +} |