mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
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:
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user