[PATCH v3 10/17] x86/efi: Do not rely on EFI_MEMORY_RUNTIME bit and avoid entry splitting
Ard Biesheuvel <[email protected]>
| Newsgroups | org.kernel.vger.linux-efi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Ard Biesheuvel <[email protected]> Now that efi_mem_reserve() has been updated to rely on RSRV_KERN memblock reservations, it is no longer needed to mark memblock reserved boot services regions as EFI_MEMORY_RUNTIME. This means that it is no longer needed to split existing entries in the EFI memory map, removing the need to re-allocate/copy/remap the entire EFI memory map on every call to efi_mem_reserve(). So drop this functionality - it is no longer needed. Signed-off-by: Ard Biesheuvel <[email protected]> --- arch/x86/include/asm/efi.h | 4 - arch/x86/platform/efi/memmap.c | 138 -------------------- arch/x86/platform/efi/quirks.c | 77 +++-------- 3 files changed, 17 insertions(+), 202 deletions(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index f291845b403a..7d8f627805df 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -402,10 +402,6 @@ extern int __init efi_memmap_alloc(unsigned int num_entries, struct efi_memory_map_data *data); extern int __init efi_memmap_install(struct efi_memory_map_data *data); -extern int __init efi_memmap_split_count(efi_memory_desc_t *md, - struct range *range); -extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap, - void *buf, struct efi_mem_range *mem); enum efi_secureboot_mode __x86_efi_boot_mode(void); diff --git a/arch/x86/platform/efi/memmap.c b/arch/x86/platform/efi/memmap.c index 697a9a26a005..da7483a33d68 100644 --- a/arch/x86/platform/efi/memmap.c +++ b/arch/x86/platform/efi/memmap.c @@ -107,141 +107,3 @@ int __init efi_memmap_install(struct efi_memory_map_data *data) __efi_memmap_free(phys, size, flags); return 0; } - -/** - * efi_memmap_split_count - Count number of additional EFI memmap entries - * @md: EFI memory descriptor to split - * @range: Address range (start, end) to split around - * - * Returns the number of additional EFI memmap entries required to - * accommodate @range. - */ -int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range) -{ - u64 m_start, m_end; - u64 start, end; - int count = 0; - - start = md->phys_addr; - end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1; - - /* modifying range */ - m_start = range->start; - m_end = range->end; - - if (m_start <= start) { - /* split into 2 parts */ - if (start < m_end && m_end < end) - count++; - } - - if (start < m_start && m_start < end) { - /* split into 3 parts */ - if (m_end < end) - count += 2; - /* split into 2 parts */ - if (end <= m_end) - count++; - } - - return count; -} - -/** - * efi_memmap_insert - Insert a memory region in an EFI memmap - * @old_memmap: The existing EFI memory map structure - * @buf: Address of buffer to store new map - * @mem: Memory map entry to insert - * - * It is suggested that you call efi_memmap_split_count() first - * to see how large @buf needs to be. - */ -void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf, - struct efi_mem_range *mem) -{ - u64 m_start, m_end, m_attr; - efi_memory_desc_t *md; - u64 start, end; - void *old, *new; - - /* modifying range */ - m_start = mem->range.start; - m_end = mem->range.end; - m_attr = mem->attribute; - - /* - * The EFI memory map deals with regions in EFI_PAGE_SIZE - * units. Ensure that the region described by 'mem' is aligned - * correctly. - */ - if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) || - !IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) { - WARN_ON(1); - return; - } - - for (old = old_memmap->map, new = buf; - old < old_memmap->map_end; - old += old_memmap->desc_size, new += old_memmap->desc_size) { - - /* copy original EFI memory descriptor */ - memcpy(new, old, old_memmap->desc_size); - md = new; - start = md->phys_addr; - end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; - - if (m_start <= start && end <= m_end) - md->attribute |= m_attr; - - if (m_start <= start && - (start < m_end && m_end < end)) { - /* first part */ - md->attribute |= m_attr; - md->num_pages = (m_end - md->phys_addr + 1) >> - EFI_PAGE_SHIFT; - /* latter part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->phys_addr = m_end + 1; - md->num_pages = (end - md->phys_addr + 1) >> - EFI_PAGE_SHIFT; - } - - if ((start < m_start && m_start < end) && m_end < end) { - /* first part */ - md->num_pages = (m_start - md->phys_addr) >> - EFI_PAGE_SHIFT; - /* middle part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->attribute |= m_attr; - md->phys_addr = m_start; - md->num_pages = (m_end - m_start + 1) >> - EFI_PAGE_SHIFT; - /* last part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->phys_addr = m_end + 1; - md->num_pages = (end - m_end) >> - EFI_PAGE_SHIFT; - } - - if ((start < m_start && m_start < end) && - (end <= m_end)) { - /* first part */ - md->num_pages = (m_start - md->phys_addr) >> - EFI_PAGE_SHIFT; - /* latter part */ - new += old_memmap->desc_size; - memcpy(new, old, old_memmap->desc_size); - md = new; - md->phys_addr = m_start; - md->num_pages = (end - md->phys_addr + 1) >> - EFI_PAGE_SHIFT; - md->attribute |= m_attr; - } - } -} diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index ce06a388fc11..efb828b7e2ab 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -239,63 +239,9 @@ EXPORT_SYMBOL_GPL(efi_query_variable_store); * buggy implementations we reserve boot services region during EFI * init and make sure it stays executable. Then, after * SetVirtualAddressMap(), it is discarded. - * - * However, some boot services regions contain data that is required - * by drivers, so we need to track which memory ranges can never be - * freed. This is done by tagging those regions with the - * EFI_MEMORY_RUNTIME attribute. - * - * Any driver that wants to mark a region as reserved must use - * efi_mem_reserve() which will insert a new EFI memory descriptor - * into efi.memmap (splitting existing regions if necessary) and tag - * it with EFI_MEMORY_RUNTIME. */ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) { - struct efi_memory_map_data data = { 0 }; - struct efi_mem_range mr; - efi_memory_desc_t md; - int num_entries; - void *new; - - if (efi_mem_desc_lookup(addr, &md) || - md.type != EFI_BOOT_SERVICES_DATA) { - pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr); - return; - } - - if (addr + size > md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT)) { - pr_err("Region spans EFI memory descriptors, %pa\n", &addr); - return; - } - - size += addr % EFI_PAGE_SIZE; - size = round_up(size, EFI_PAGE_SIZE); - addr = round_down(addr, EFI_PAGE_SIZE); - - mr.range.start = addr; - mr.range.end = addr + size - 1; - mr.attribute = md.attribute | EFI_MEMORY_RUNTIME; - - num_entries = efi_memmap_split_count(&md, &mr.range); - num_entries += efi.memmap.nr_map; - - if (efi_memmap_alloc(num_entries, &data) != 0) { - pr_err("Could not allocate boot services memmap\n"); - return; - } - - new = early_memremap_prot(data.phys_map, data.size, - pgprot_val(pgprot_encrypted(FIXMAP_PAGE_NORMAL))); - if (!new) { - pr_err("Failed to map new boot services memmap\n"); - return; - } - - efi_memmap_insert(&efi.memmap, new, &mr); - early_memunmap(new, data.size); - - efi_memmap_install(&data); e820__range_update(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED); e820__update_table(e820_table); } @@ -404,7 +350,8 @@ struct efi_freeable_range { static struct efi_freeable_range *ranges_to_free __initdata; static int num_to_free __initdata; -static int __init efi_add_range_to_free(u64 range_start, u64 range_end) +static int __init efi_add_range_to_free(u64 range_start, u64 range_end, + bool *has_reservations) { struct memblock_region *region; static int idx __initdata; @@ -420,15 +367,18 @@ static int __init efi_add_range_to_free(u64 range_start, u64 range_end) if (region_end < range_start) continue; - if (region->flags & MEMBLOCK_RSRV_KERN) - continue; - start = PAGE_ALIGN(max(range_start, region->base)); end = PAGE_ALIGN_DOWN(min(range_end, region_end)); if (start >= end) continue; + if ((region->flags & MEMBLOCK_RSRV_KERN) || + !can_free_region(start, end - start)) { + *has_reservations = true; + continue; + } + ranges_to_free[idx].start = start; ranges_to_free[idx].end = end; @@ -471,6 +421,7 @@ void __init efi_unmap_boot_services(void) for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; + bool has_reservations = false; if (md->type != EFI_BOOT_SERVICES_CODE && md->type != EFI_BOOT_SERVICES_DATA) { @@ -497,10 +448,13 @@ void __init efi_unmap_boot_services(void) * memory here. * Queue the ranges to free at a later point. */ - if (efi_add_range_to_free(start, start + size)) { + if (efi_add_range_to_free(start, start + size, &has_reservations)) { pr_err("Failed to reallocate storage for freeable EFI regions\n"); return; } + + if (has_reservations) + num_entries++; } if (!num_entries) @@ -526,8 +480,11 @@ void __init efi_unmap_boot_services(void) for_each_efi_memory_desc(md) { if (!(md->attribute & EFI_MEMORY_RUNTIME) && (md->type == EFI_BOOT_SERVICES_CODE || - md->type == EFI_BOOT_SERVICES_DATA)) + md->type == EFI_BOOT_SERVICES_DATA) && + can_free_region(md->phys_addr, + md->num_pages << EFI_PAGE_SHIFT)) { continue; + } memcpy(new_md, md, efi.memmap.desc_size); new_md += efi.memmap.desc_size; -- 2.54.0.rc2.544.gc7ae2d5bb8-goog