Merge tag 'efi-fixes-for-v7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi

Pull EFI fix from Ard Biesheuvel:
 "Fix for the x86 EFI workaround keeping boot services code and data
  regions reserved until after SetVirtualAddressMap() completes:
  deferred struct page initialization may result in some of this memory
  being lost permanently"

* tag 'efi-fixes-for-v7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
  x86/efi: defer freeing of boot services memory
This commit is contained in:
Linus Torvalds
2026-03-08 12:13:09 -07:00
4 changed files with 55 additions and 6 deletions

View File

@@ -138,7 +138,7 @@ extern void __init efi_apply_memmap_quirks(void);
extern int __init efi_reuse_config(u64 tables, int nr_tables);
extern void efi_delete_dummy_variable(void);
extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
extern void efi_free_boot_services(void);
extern void efi_unmap_boot_services(void);
void arch_efi_call_virt_setup(void);
void arch_efi_call_virt_teardown(void);

View File

@@ -836,7 +836,7 @@ static void __init __efi_enter_virtual_mode(void)
}
efi_check_for_embedded_firmwares();
efi_free_boot_services();
efi_unmap_boot_services();
if (!efi_is_mixed())
efi_native_runtime_setup();

View File

@@ -341,7 +341,7 @@ void __init efi_reserve_boot_services(void)
/*
* Because the following memblock_reserve() is paired
* with memblock_free_late() for this region in
* with free_reserved_area() for this region in
* efi_free_boot_services(), we must be extremely
* careful not to reserve, and subsequently free,
* critical regions of memory (like the kernel image) or
@@ -404,17 +404,33 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)
pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
}
void __init efi_free_boot_services(void)
struct efi_freeable_range {
u64 start;
u64 end;
};
static struct efi_freeable_range *ranges_to_free;
void __init efi_unmap_boot_services(void)
{
struct efi_memory_map_data data = { 0 };
efi_memory_desc_t *md;
int num_entries = 0;
int idx = 0;
size_t sz;
void *new, *new_md;
/* Keep all regions for /sys/kernel/debug/efi */
if (efi_enabled(EFI_DBG))
return;
sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
ranges_to_free = kzalloc(sz, GFP_KERNEL);
if (!ranges_to_free) {
pr_err("Failed to allocate storage for freeable EFI regions\n");
return;
}
for_each_efi_memory_desc(md) {
unsigned long long start = md->phys_addr;
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -471,7 +487,15 @@ void __init efi_free_boot_services(void)
start = SZ_1M;
}
memblock_free_late(start, size);
/*
* With CONFIG_DEFERRED_STRUCT_PAGE_INIT parts of the memory
* map are still not initialized and we can't reliably free
* memory here.
* Queue the ranges to free at a later point.
*/
ranges_to_free[idx].start = start;
ranges_to_free[idx].end = start + size;
idx++;
}
if (!num_entries)
@@ -512,6 +536,31 @@ void __init efi_free_boot_services(void)
}
}
static int __init efi_free_boot_services(void)
{
struct efi_freeable_range *range = ranges_to_free;
unsigned long freed = 0;
if (!ranges_to_free)
return 0;
while (range->start) {
void *start = phys_to_virt(range->start);
void *end = phys_to_virt(range->end);
free_reserved_area(start, end, -1, NULL);
freed += (end - start);
range++;
}
kfree(ranges_to_free);
if (freed)
pr_info("Freeing EFI boot services memory: %ldK\n", freed / SZ_1K);
return 0;
}
arch_initcall(efi_free_boot_services);
/*
* A number of config table entries get remapped to virtual addresses
* after entering EFI virtual mode. However, the kexec kernel requires

View File

@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
* as an alternative to ordinary EFI variables, due to platform-dependent
* limitations. The memory occupied by this table is marked as reserved.
*
* This routine must be called before efi_free_boot_services() in order
* This routine must be called before efi_unmap_boot_services() in order
* to guarantee that it can mark the table as reserved.
*
* Implicit inputs: