From: Ard Biesheuvel <ardb+git@google.com>
To: linux-kernel@vger.kernel.org
Cc: linux-efi@vger.kernel.org, x86@kernel.org,
Ard Biesheuvel <ardb@kernel.org>,
"Mike Rapoport (Microsoft)" <rppt@kernel.org>,
Benjamin Herrenschmidt <benh@kernel.crashing.org>
Subject: [PATCH v2 11/19] efi: Use nr_map not map_end to find the last valid memory map entry
Date: Thu, 19 Mar 2026 10:05:41 +0100 [thread overview]
Message-ID: <20260319090529.1091660-32-ardb+git@google.com> (raw)
In-Reply-To: <20260319090529.1091660-21-ardb+git@google.com>
From: Ard Biesheuvel <ardb@kernel.org>
Currently, the efi.memmap struct keeps track of the start and the end of
the EFI memory map in memory, as well as the number of entries.
Let's repaint the nr_map field as the number of *valid* entries, and
update all the iterators and other memory map traversal routines
accordingly.
This allows pruning of invalid or unneeded entries by moving the
remaining entries to the start of the map, without the need for
freeing/reallocating or unmapping and remapping. Now that entries are
never added, but only removed, it is possible to retain the same
allocation throughout the boot process, and free the part that is no
longer in use afterwards.
While at it, implement a version of for_each_efi_memory_desc() that
traverses the memory map in opposite order. It will be used by a
subsequent patch.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/platform/efi/efi.c | 15 +++++++-----
arch/x86/platform/efi/memmap.c | 2 +-
arch/x86/platform/efi/quirks.c | 2 +-
arch/x86/platform/efi/runtime-map.c | 4 ++--
drivers/firmware/efi/arm-runtime.c | 2 +-
drivers/firmware/efi/memattr.c | 2 +-
drivers/firmware/efi/memmap.c | 8 +++----
drivers/firmware/efi/riscv-runtime.c | 2 +-
include/linux/efi.h | 24 ++++++++++++++++----
9 files changed, 39 insertions(+), 22 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index b60f8454a1ec..183cca8fe4a6 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -222,7 +222,7 @@ int __init efi_memblock_x86_reserve_range(void)
"Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
efi.memmap.desc_version);
- memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size);
+ memblock_reserve(pmap, efi.memmap.num_valid_entries * efi.memmap.desc_size);
set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags);
return 0;
@@ -289,7 +289,7 @@ static void __init efi_clean_memmap(void)
.phys_map = efi.memmap.phys_map,
.desc_version = efi.memmap.desc_version,
.desc_size = efi.memmap.desc_size,
- .size = efi.memmap.desc_size * (efi.memmap.nr_map - n_removal),
+ .size = efi.memmap.desc_size * (efi.memmap.num_valid_entries - n_removal),
.flags = 0,
};
@@ -564,7 +564,8 @@ static inline void *efi_map_next_entry_reverse(void *entry)
{
/* Initial call */
if (!entry)
- return efi.memmap.map_end - efi.memmap.desc_size;
+ return efi_memdesc_ptr(efi.memmap.map, efi.memmap.desc_size,
+ efi.memmap.num_valid_entries - 1);
entry -= efi.memmap.desc_size;
if (entry < efi.memmap.map)
@@ -612,7 +613,9 @@ static void *efi_map_next_entry(void *entry)
return efi.memmap.map;
entry += efi.memmap.desc_size;
- if (entry >= efi.memmap.map_end)
+ if (entry >= (void *)efi_memdesc_ptr(efi.memmap.map,
+ efi.memmap.desc_size,
+ efi.memmap.num_valid_entries))
return NULL;
return entry;
@@ -743,13 +746,13 @@ static void __init kexec_enter_virtual_mode(void)
efi_memmap_unmap();
if (efi_memmap_init_late(efi.memmap.phys_map,
- efi.memmap.desc_size * efi.memmap.nr_map)) {
+ efi.memmap.desc_size * efi.memmap.num_valid_entries)) {
pr_err("Failed to remap late EFI memory map\n");
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
return;
}
- num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE);
+ num_pages = ALIGN(efi.memmap.num_valid_entries * efi.memmap.desc_size, PAGE_SIZE);
num_pages >>= PAGE_SHIFT;
if (efi_setup_page_tables(efi.memmap.phys_map, num_pages)) {
diff --git a/arch/x86/platform/efi/memmap.c b/arch/x86/platform/efi/memmap.c
index 8ef45014c7e7..fa580c4122c4 100644
--- a/arch/x86/platform/efi/memmap.c
+++ b/arch/x86/platform/efi/memmap.c
@@ -93,7 +93,7 @@ int __init efi_memmap_alloc(unsigned int num_entries,
*/
int __init efi_memmap_install(struct efi_memory_map_data *data)
{
- unsigned long size = efi.memmap.desc_size * efi.memmap.nr_map;
+ unsigned long size = efi.memmap.map_end - efi.memmap.map;
unsigned long flags = efi.memmap.flags;
u64 phys = efi.memmap.phys_map;
int ret;
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index ae4ad6389f9e..eecaa745d352 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -367,7 +367,7 @@ void __init efi_unmap_boot_services(void)
if (efi_enabled(EFI_DBG))
return;
- sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
+ sz = sizeof(*ranges_to_free) * efi.memmap.num_valid_entries + 1;
ranges_to_free = kzalloc(sz, GFP_KERNEL);
if (!ranges_to_free) {
pr_err("Failed to allocate storage for freeable EFI regions\n");
diff --git a/arch/x86/platform/efi/runtime-map.c b/arch/x86/platform/efi/runtime-map.c
index 053ff161eb9a..fc8ca1974730 100644
--- a/arch/x86/platform/efi/runtime-map.c
+++ b/arch/x86/platform/efi/runtime-map.c
@@ -138,7 +138,7 @@ add_sysfs_runtime_map_entry(struct kobject *kobj, int nr,
int efi_get_runtime_map_size(void)
{
- return efi.memmap.nr_map * efi.memmap.desc_size;
+ return efi.memmap.num_valid_entries * efi.memmap.desc_size;
}
int efi_get_runtime_map_desc_size(void)
@@ -166,7 +166,7 @@ static int __init efi_runtime_map_init(void)
if (!efi_enabled(EFI_MEMMAP) || !efi_kobj)
return 0;
- map_entries = kzalloc_objs(entry, efi.memmap.nr_map);
+ map_entries = kzalloc_objs(entry, efi.memmap.num_valid_entries);
if (!map_entries) {
ret = -ENOMEM;
goto out;
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 3167cab62014..e19997c09175 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -96,7 +96,7 @@ static int __init arm_enable_runtime_services(void)
efi_memmap_unmap();
- mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
+ mapsize = efi.memmap.desc_size * efi.memmap.num_valid_entries;
if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
pr_err("Failed to remap EFI memory map\n");
diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c
index e727cc5909cb..36f733b37df2 100644
--- a/drivers/firmware/efi/memattr.c
+++ b/drivers/firmware/efi/memattr.c
@@ -49,7 +49,7 @@ void __init efi_memattr_init(void)
* just be ignored altogether.
*/
size = tbl->num_entries * tbl->desc_size;
- if (size > 3 * efi.memmap.nr_map * efi.memmap.desc_size) {
+ if (size > 3 * efi.memmap.num_valid_entries * efi.memmap.desc_size) {
pr_warn(FW_BUG "Corrupted EFI Memory Attributes Table detected! (version == %u, desc_size == %u, num_entries == %u)\n",
tbl->version, tbl->desc_size, tbl->num_entries);
goto unmap;
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
index f1c04d7cfd71..035089791c93 100644
--- a/drivers/firmware/efi/memmap.c
+++ b/drivers/firmware/efi/memmap.c
@@ -49,7 +49,7 @@ int __init __efi_memmap_init(struct efi_memory_map_data *data)
}
map.phys_map = data->phys_map;
- map.nr_map = data->size / data->desc_size;
+ map.num_valid_entries = data->size / data->desc_size;
map.map_end = map.map + data->size;
map.desc_version = data->desc_version;
@@ -87,10 +87,8 @@ void __init efi_memmap_unmap(void)
return;
if (!(efi.memmap.flags & EFI_MEMMAP_LATE)) {
- unsigned long size;
-
- size = efi.memmap.desc_size * efi.memmap.nr_map;
- early_memunmap(efi.memmap.map, size);
+ early_memunmap(efi.memmap.map,
+ efi.memmap.map_end - efi.memmap.map);
} else {
memunmap(efi.memmap.map);
}
diff --git a/drivers/firmware/efi/riscv-runtime.c b/drivers/firmware/efi/riscv-runtime.c
index 60cdf7bf141f..087a7f8a74e6 100644
--- a/drivers/firmware/efi/riscv-runtime.c
+++ b/drivers/firmware/efi/riscv-runtime.c
@@ -66,7 +66,7 @@ static int __init riscv_enable_runtime_services(void)
efi_memmap_unmap();
- mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
+ mapsize = efi.memmap.desc_size * efi.memmap.num_valid_entries;
if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
pr_err("Failed to remap EFI memory map\n");
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 664898d09ff5..b0c3e9648126 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -568,7 +568,7 @@ struct efi_memory_map {
phys_addr_t phys_map;
void *map;
void *map_end;
- int nr_map;
+ int num_valid_entries;
unsigned long desc_version;
unsigned long desc_size;
#define EFI_MEMMAP_LATE (1UL << 0)
@@ -803,9 +803,15 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm,
/* Iterate through an efi_memory_map */
#define for_each_efi_memory_desc_in_map(m, md) \
- for ((md) = (m)->map; \
- (md) && ((void *)(md) + (m)->desc_size) <= (m)->map_end; \
- (md) = (void *)(md) + (m)->desc_size)
+ for (int __idx = 0; \
+ (md) = efi_memdesc_ptr((m)->map, (m)->desc_size, __idx), \
+ __idx < (m)->num_valid_entries; ++__idx)
+
+/* Iterate through an efi_memory_map in reverse order */
+#define for_each_efi_memory_desc_in_map_rev(m, md) \
+ for (int __idx = (m)->num_valid_entries - 1; \
+ (md) = efi_memdesc_ptr((m)->map, (m)->desc_size, __idx), \
+ __idx >= 0; --__idx)
/**
* for_each_efi_memory_desc - iterate over descriptors in efi.memmap
@@ -816,6 +822,16 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm,
#define for_each_efi_memory_desc(md) \
for_each_efi_memory_desc_in_map(&efi.memmap, md)
+/**
+ * for_each_efi_memory_desc_rev - iterate over descriptors in efi.memmap in
+ * reverse order
+ * @md: the efi_memory_desc_t * iterator
+ *
+ * Once the loop finishes @md must not be accessed.
+ */
+#define for_each_efi_memory_desc_rev(md) \
+ for_each_efi_memory_desc_in_map_rev(&efi.memmap, md)
+
/*
* Format an EFI memory descriptor's type and attributes to a user-provided
* character buffer, as per snprintf(), and return the buffer.
--
2.53.0.851.ga537e3e6e9-goog
next prev parent reply other threads:[~2026-03-19 9:06 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-19 9:05 [PATCH v2 00/19] efi/x86: Avoid the need to mangle the EFI memory map Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 01/19] memblock: Permit existing reserved regions to be marked RSRV_KERN Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 02/19] efi: Tag memblock reservations of boot services regions as RSRV_KERN Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 03/19] x86/efi: Unmap kernel-reserved boot regions from EFI page tables Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 04/19] x86/efi: Drop EFI_MEMORY_RUNTIME check from __ioremap_check_other() Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 05/19] x86/efi: Omit RSRV_KERN memblock reservations when freeing boot regions Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 06/19] x86/efi: Defer sub-1M check from unmap to free stage Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 07/19] x86/efi: Simplify real mode trampoline allocation quirk Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 08/19] x86/efi: Omit redundant kernel image overlap check Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 09/19] x86/efi: Drop redundant EFI_PARAVIRT check Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 10/19] x86/efi: Do not rely on EFI_MEMORY_RUNTIME bit and avoid entry splitting Ard Biesheuvel
2026-03-19 9:05 ` Ard Biesheuvel [this message]
2026-03-19 9:05 ` [PATCH v2 12/19] x86/efi: Only merge EFI memory map entries on 32-bit systems Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 13/19] x86/efi: Clean the memory map using iterator and filter API Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 14/19] x86/efi: Update the runtime map in place Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 15/19] x86/efi: Use iterator API when mapping EFI regions for runtime Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 16/19] x86/efi: Reuse memory map instead of reallocating it Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 17/19] x86/efi: Defer compaction of the EFI memory map Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 18/19] x86/efi: Do not abuse RUNTIME bit to mark boot regions as reserved Ard Biesheuvel
2026-03-19 9:05 ` [PATCH v2 19/19] x86/efi: Free unused tail of the EFI memory map Ard Biesheuvel
2026-03-24 9:50 ` [PATCH v2 00/19] efi/x86: Avoid the need to mangle " Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260319090529.1091660-32-ardb+git@google.com \
--to=ardb+git@google.com \
--cc=ardb@kernel.org \
--cc=benh@kernel.crashing.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rppt@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox