162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common EFI (Extensible Firmware Interface) support functions 462306a36Sopenharmony_ci * Based on Extensible Firmware Interface Specification version 1.0 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1999 VA Linux Systems 762306a36Sopenharmony_ci * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 862306a36Sopenharmony_ci * Copyright (C) 1999-2002 Hewlett-Packard Co. 962306a36Sopenharmony_ci * David Mosberger-Tang <davidm@hpl.hp.com> 1062306a36Sopenharmony_ci * Stephane Eranian <eranian@hpl.hp.com> 1162306a36Sopenharmony_ci * Copyright (C) 2005-2008 Intel Co. 1262306a36Sopenharmony_ci * Fenghua Yu <fenghua.yu@intel.com> 1362306a36Sopenharmony_ci * Bibo Mao <bibo.mao@intel.com> 1462306a36Sopenharmony_ci * Chandramouli Narayanan <mouli@linux.intel.com> 1562306a36Sopenharmony_ci * Huang Ying <ying.huang@intel.com> 1662306a36Sopenharmony_ci * Copyright (C) 2013 SuSE Labs 1762306a36Sopenharmony_ci * Borislav Petkov <bp@suse.de> - runtime services VA mapping 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Copied from efi_32.c to eliminate the duplicated code between EFI 2062306a36Sopenharmony_ci * 32/64 support code. --ying 2007-10-26 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * All EFI Runtime Services are not implemented yet as EFI only 2362306a36Sopenharmony_ci * supports physical mode addressing on SoftSDV. This is to be fixed 2462306a36Sopenharmony_ci * in a future version. --drummond 1999-07-20 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Implemented EFI runtime services and virtual mode calls. --davidm 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Goutham Rao: <goutham.rao@intel.com> 2962306a36Sopenharmony_ci * Skip non-WB memory and ignore empty memory ranges. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/kernel.h> 3562306a36Sopenharmony_ci#include <linux/init.h> 3662306a36Sopenharmony_ci#include <linux/efi.h> 3762306a36Sopenharmony_ci#include <linux/efi-bgrt.h> 3862306a36Sopenharmony_ci#include <linux/export.h> 3962306a36Sopenharmony_ci#include <linux/memblock.h> 4062306a36Sopenharmony_ci#include <linux/slab.h> 4162306a36Sopenharmony_ci#include <linux/spinlock.h> 4262306a36Sopenharmony_ci#include <linux/uaccess.h> 4362306a36Sopenharmony_ci#include <linux/time.h> 4462306a36Sopenharmony_ci#include <linux/io.h> 4562306a36Sopenharmony_ci#include <linux/reboot.h> 4662306a36Sopenharmony_ci#include <linux/bcd.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include <asm/setup.h> 4962306a36Sopenharmony_ci#include <asm/efi.h> 5062306a36Sopenharmony_ci#include <asm/e820/api.h> 5162306a36Sopenharmony_ci#include <asm/time.h> 5262306a36Sopenharmony_ci#include <asm/tlbflush.h> 5362306a36Sopenharmony_ci#include <asm/x86_init.h> 5462306a36Sopenharmony_ci#include <asm/uv/uv.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic unsigned long efi_systab_phys __initdata; 5762306a36Sopenharmony_cistatic unsigned long prop_phys = EFI_INVALID_TABLE_ADDR; 5862306a36Sopenharmony_cistatic unsigned long uga_phys = EFI_INVALID_TABLE_ADDR; 5962306a36Sopenharmony_cistatic unsigned long efi_runtime, efi_nr_tables; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciunsigned long efi_fw_vendor, efi_config_table; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const efi_config_table_type_t arch_tables[] __initconst = { 6462306a36Sopenharmony_ci {EFI_PROPERTIES_TABLE_GUID, &prop_phys, "PROP" }, 6562306a36Sopenharmony_ci {UGA_IO_PROTOCOL_GUID, &uga_phys, "UGA" }, 6662306a36Sopenharmony_ci#ifdef CONFIG_X86_UV 6762306a36Sopenharmony_ci {UV_SYSTEM_TABLE_GUID, &uv_systab_phys, "UVsystab" }, 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci {}, 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic const unsigned long * const efi_tables[] = { 7362306a36Sopenharmony_ci &efi.acpi, 7462306a36Sopenharmony_ci &efi.acpi20, 7562306a36Sopenharmony_ci &efi.smbios, 7662306a36Sopenharmony_ci &efi.smbios3, 7762306a36Sopenharmony_ci &uga_phys, 7862306a36Sopenharmony_ci#ifdef CONFIG_X86_UV 7962306a36Sopenharmony_ci &uv_systab_phys, 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci &efi_fw_vendor, 8262306a36Sopenharmony_ci &efi_runtime, 8362306a36Sopenharmony_ci &efi_config_table, 8462306a36Sopenharmony_ci &efi.esrt, 8562306a36Sopenharmony_ci &prop_phys, 8662306a36Sopenharmony_ci &efi_mem_attr_table, 8762306a36Sopenharmony_ci#ifdef CONFIG_EFI_RCI2_TABLE 8862306a36Sopenharmony_ci &rci2_table_phys, 8962306a36Sopenharmony_ci#endif 9062306a36Sopenharmony_ci &efi.tpm_log, 9162306a36Sopenharmony_ci &efi.tpm_final_log, 9262306a36Sopenharmony_ci &efi_rng_seed, 9362306a36Sopenharmony_ci#ifdef CONFIG_LOAD_UEFI_KEYS 9462306a36Sopenharmony_ci &efi.mokvar_table, 9562306a36Sopenharmony_ci#endif 9662306a36Sopenharmony_ci#ifdef CONFIG_EFI_COCO_SECRET 9762306a36Sopenharmony_ci &efi.coco_secret, 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci#ifdef CONFIG_UNACCEPTED_MEMORY 10062306a36Sopenharmony_ci &efi.unaccepted, 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciu64 efi_setup; /* efi setup_data physical address */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int add_efi_memmap __initdata; 10762306a36Sopenharmony_cistatic int __init setup_add_efi_memmap(char *arg) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci add_efi_memmap = 1; 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ciearly_param("add_efi_memmap", setup_add_efi_memmap); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * Tell the kernel about the EFI memory map. This might include 11662306a36Sopenharmony_ci * more than the max 128 entries that can fit in the passed in e820 11762306a36Sopenharmony_ci * legacy (zeropage) memory map, but the kernel's e820 table can hold 11862306a36Sopenharmony_ci * E820_MAX_ENTRIES. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void __init do_add_efi_memmap(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci efi_memory_desc_t *md; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!efi_enabled(EFI_MEMMAP)) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for_each_efi_memory_desc(md) { 12962306a36Sopenharmony_ci unsigned long long start = md->phys_addr; 13062306a36Sopenharmony_ci unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; 13162306a36Sopenharmony_ci int e820_type; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci switch (md->type) { 13462306a36Sopenharmony_ci case EFI_LOADER_CODE: 13562306a36Sopenharmony_ci case EFI_LOADER_DATA: 13662306a36Sopenharmony_ci case EFI_BOOT_SERVICES_CODE: 13762306a36Sopenharmony_ci case EFI_BOOT_SERVICES_DATA: 13862306a36Sopenharmony_ci case EFI_CONVENTIONAL_MEMORY: 13962306a36Sopenharmony_ci if (efi_soft_reserve_enabled() 14062306a36Sopenharmony_ci && (md->attribute & EFI_MEMORY_SP)) 14162306a36Sopenharmony_ci e820_type = E820_TYPE_SOFT_RESERVED; 14262306a36Sopenharmony_ci else if (md->attribute & EFI_MEMORY_WB) 14362306a36Sopenharmony_ci e820_type = E820_TYPE_RAM; 14462306a36Sopenharmony_ci else 14562306a36Sopenharmony_ci e820_type = E820_TYPE_RESERVED; 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case EFI_ACPI_RECLAIM_MEMORY: 14862306a36Sopenharmony_ci e820_type = E820_TYPE_ACPI; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case EFI_ACPI_MEMORY_NVS: 15162306a36Sopenharmony_ci e820_type = E820_TYPE_NVS; 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case EFI_UNUSABLE_MEMORY: 15462306a36Sopenharmony_ci e820_type = E820_TYPE_UNUSABLE; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci case EFI_PERSISTENT_MEMORY: 15762306a36Sopenharmony_ci e820_type = E820_TYPE_PMEM; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci default: 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE 16262306a36Sopenharmony_ci * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO 16362306a36Sopenharmony_ci * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci e820_type = E820_TYPE_RESERVED; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci e820__range_add(start, size, e820_type); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci e820__update_table(e820_table); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* 17562306a36Sopenharmony_ci * Given add_efi_memmap defaults to 0 and there is no alternative 17662306a36Sopenharmony_ci * e820 mechanism for soft-reserved memory, import the full EFI memory 17762306a36Sopenharmony_ci * map if soft reservations are present and enabled. Otherwise, the 17862306a36Sopenharmony_ci * mechanism to disable the kernel's consideration of EFI_MEMORY_SP is 17962306a36Sopenharmony_ci * the efi=nosoftreserve option. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic bool do_efi_soft_reserve(void) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci efi_memory_desc_t *md; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (!efi_enabled(EFI_MEMMAP)) 18662306a36Sopenharmony_ci return false; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (!efi_soft_reserve_enabled()) 18962306a36Sopenharmony_ci return false; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for_each_efi_memory_desc(md) 19262306a36Sopenharmony_ci if (md->type == EFI_CONVENTIONAL_MEMORY && 19362306a36Sopenharmony_ci (md->attribute & EFI_MEMORY_SP)) 19462306a36Sopenharmony_ci return true; 19562306a36Sopenharmony_ci return false; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciint __init efi_memblock_x86_reserve_range(void) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct efi_info *e = &boot_params.efi_info; 20162306a36Sopenharmony_ci struct efi_memory_map_data data; 20262306a36Sopenharmony_ci phys_addr_t pmap; 20362306a36Sopenharmony_ci int rv; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (efi_enabled(EFI_PARAVIRT)) 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Can't handle firmware tables above 4GB on i386 */ 20962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_32) && e->efi_memmap_hi > 0) { 21062306a36Sopenharmony_ci pr_err("Memory map is above 4GB, disabling EFI.\n"); 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci pmap = (phys_addr_t)(e->efi_memmap | ((u64)e->efi_memmap_hi << 32)); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci data.phys_map = pmap; 21662306a36Sopenharmony_ci data.size = e->efi_memmap_size; 21762306a36Sopenharmony_ci data.desc_size = e->efi_memdesc_size; 21862306a36Sopenharmony_ci data.desc_version = e->efi_memdesc_version; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (!efi_enabled(EFI_PARAVIRT)) { 22162306a36Sopenharmony_ci rv = efi_memmap_init_early(&data); 22262306a36Sopenharmony_ci if (rv) 22362306a36Sopenharmony_ci return rv; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (add_efi_memmap || do_efi_soft_reserve()) 22762306a36Sopenharmony_ci do_add_efi_memmap(); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci efi_fake_memmap_early(); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci WARN(efi.memmap.desc_version != 1, 23262306a36Sopenharmony_ci "Unexpected EFI_MEMORY_DESCRIPTOR version %ld", 23362306a36Sopenharmony_ci efi.memmap.desc_version); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); 23662306a36Sopenharmony_ci set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci#define OVERFLOW_ADDR_SHIFT (64 - EFI_PAGE_SHIFT) 24262306a36Sopenharmony_ci#define OVERFLOW_ADDR_MASK (U64_MAX << OVERFLOW_ADDR_SHIFT) 24362306a36Sopenharmony_ci#define U64_HIGH_BIT (~(U64_MAX >> 1)) 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic bool __init efi_memmap_entry_valid(const efi_memory_desc_t *md, int i) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci u64 end = (md->num_pages << EFI_PAGE_SHIFT) + md->phys_addr - 1; 24862306a36Sopenharmony_ci u64 end_hi = 0; 24962306a36Sopenharmony_ci char buf[64]; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (md->num_pages == 0) { 25262306a36Sopenharmony_ci end = 0; 25362306a36Sopenharmony_ci } else if (md->num_pages > EFI_PAGES_MAX || 25462306a36Sopenharmony_ci EFI_PAGES_MAX - md->num_pages < 25562306a36Sopenharmony_ci (md->phys_addr >> EFI_PAGE_SHIFT)) { 25662306a36Sopenharmony_ci end_hi = (md->num_pages & OVERFLOW_ADDR_MASK) 25762306a36Sopenharmony_ci >> OVERFLOW_ADDR_SHIFT; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if ((md->phys_addr & U64_HIGH_BIT) && !(end & U64_HIGH_BIT)) 26062306a36Sopenharmony_ci end_hi += 1; 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci return true; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci pr_warn_once(FW_BUG "Invalid EFI memory map entries:\n"); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (end_hi) { 26862306a36Sopenharmony_ci pr_warn("mem%02u: %s range=[0x%016llx-0x%llx%016llx] (invalid)\n", 26962306a36Sopenharmony_ci i, efi_md_typeattr_format(buf, sizeof(buf), md), 27062306a36Sopenharmony_ci md->phys_addr, end_hi, end); 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci pr_warn("mem%02u: %s range=[0x%016llx-0x%016llx] (invalid)\n", 27362306a36Sopenharmony_ci i, efi_md_typeattr_format(buf, sizeof(buf), md), 27462306a36Sopenharmony_ci md->phys_addr, end); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci return false; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void __init efi_clean_memmap(void) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci efi_memory_desc_t *out = efi.memmap.map; 28262306a36Sopenharmony_ci const efi_memory_desc_t *in = out; 28362306a36Sopenharmony_ci const efi_memory_desc_t *end = efi.memmap.map_end; 28462306a36Sopenharmony_ci int i, n_removal; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci for (i = n_removal = 0; in < end; i++) { 28762306a36Sopenharmony_ci if (efi_memmap_entry_valid(in, i)) { 28862306a36Sopenharmony_ci if (out != in) 28962306a36Sopenharmony_ci memcpy(out, in, efi.memmap.desc_size); 29062306a36Sopenharmony_ci out = (void *)out + efi.memmap.desc_size; 29162306a36Sopenharmony_ci } else { 29262306a36Sopenharmony_ci n_removal++; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci in = (void *)in + efi.memmap.desc_size; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (n_removal > 0) { 29862306a36Sopenharmony_ci struct efi_memory_map_data data = { 29962306a36Sopenharmony_ci .phys_map = efi.memmap.phys_map, 30062306a36Sopenharmony_ci .desc_version = efi.memmap.desc_version, 30162306a36Sopenharmony_ci .desc_size = efi.memmap.desc_size, 30262306a36Sopenharmony_ci .size = efi.memmap.desc_size * (efi.memmap.nr_map - n_removal), 30362306a36Sopenharmony_ci .flags = 0, 30462306a36Sopenharmony_ci }; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci pr_warn("Removing %d invalid memory map entries.\n", n_removal); 30762306a36Sopenharmony_ci efi_memmap_install(&data); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* 31262306a36Sopenharmony_ci * Firmware can use EfiMemoryMappedIO to request that MMIO regions be 31362306a36Sopenharmony_ci * mapped by the OS so they can be accessed by EFI runtime services, but 31462306a36Sopenharmony_ci * should have no other significance to the OS (UEFI r2.10, sec 7.2). 31562306a36Sopenharmony_ci * However, most bootloaders and EFI stubs convert EfiMemoryMappedIO 31662306a36Sopenharmony_ci * regions to E820_TYPE_RESERVED entries, which prevent Linux from 31762306a36Sopenharmony_ci * allocating space from them (see remove_e820_regions()). 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * Some platforms use EfiMemoryMappedIO entries for PCI MMCONFIG space and 32062306a36Sopenharmony_ci * PCI host bridge windows, which means Linux can't allocate BAR space for 32162306a36Sopenharmony_ci * hot-added devices. 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Remove large EfiMemoryMappedIO regions from the E820 map to avoid this 32462306a36Sopenharmony_ci * problem. 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * Retain small EfiMemoryMappedIO regions because on some platforms, these 32762306a36Sopenharmony_ci * describe non-window space that's included in host bridge _CRS. If we 32862306a36Sopenharmony_ci * assign that space to PCI devices, they don't work. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistatic void __init efi_remove_e820_mmio(void) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci efi_memory_desc_t *md; 33362306a36Sopenharmony_ci u64 size, start, end; 33462306a36Sopenharmony_ci int i = 0; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci for_each_efi_memory_desc(md) { 33762306a36Sopenharmony_ci if (md->type == EFI_MEMORY_MAPPED_IO) { 33862306a36Sopenharmony_ci size = md->num_pages << EFI_PAGE_SHIFT; 33962306a36Sopenharmony_ci start = md->phys_addr; 34062306a36Sopenharmony_ci end = start + size - 1; 34162306a36Sopenharmony_ci if (size >= 256*1024) { 34262306a36Sopenharmony_ci pr_info("Remove mem%02u: MMIO range=[0x%08llx-0x%08llx] (%lluMB) from e820 map\n", 34362306a36Sopenharmony_ci i, start, end, size >> 20); 34462306a36Sopenharmony_ci e820__range_remove(start, size, 34562306a36Sopenharmony_ci E820_TYPE_RESERVED, 1); 34662306a36Sopenharmony_ci } else { 34762306a36Sopenharmony_ci pr_info("Not removing mem%02u: MMIO range=[0x%08llx-0x%08llx] (%lluKB) from e820 map\n", 34862306a36Sopenharmony_ci i, start, end, size >> 10); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci i++; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_civoid __init efi_print_memmap(void) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci efi_memory_desc_t *md; 35862306a36Sopenharmony_ci int i = 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci for_each_efi_memory_desc(md) { 36162306a36Sopenharmony_ci char buf[64]; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci pr_info("mem%02u: %s range=[0x%016llx-0x%016llx] (%lluMB)\n", 36462306a36Sopenharmony_ci i++, efi_md_typeattr_format(buf, sizeof(buf), md), 36562306a36Sopenharmony_ci md->phys_addr, 36662306a36Sopenharmony_ci md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1, 36762306a36Sopenharmony_ci (md->num_pages >> (20 - EFI_PAGE_SHIFT))); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int __init efi_systab_init(unsigned long phys) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t) 37462306a36Sopenharmony_ci : sizeof(efi_system_table_32_t); 37562306a36Sopenharmony_ci const efi_table_hdr_t *hdr; 37662306a36Sopenharmony_ci bool over4g = false; 37762306a36Sopenharmony_ci void *p; 37862306a36Sopenharmony_ci int ret; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci hdr = p = early_memremap_ro(phys, size); 38162306a36Sopenharmony_ci if (p == NULL) { 38262306a36Sopenharmony_ci pr_err("Couldn't map the system table!\n"); 38362306a36Sopenharmony_ci return -ENOMEM; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ret = efi_systab_check_header(hdr); 38762306a36Sopenharmony_ci if (ret) { 38862306a36Sopenharmony_ci early_memunmap(p, size); 38962306a36Sopenharmony_ci return ret; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (efi_enabled(EFI_64BIT)) { 39362306a36Sopenharmony_ci const efi_system_table_64_t *systab64 = p; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci efi_runtime = systab64->runtime; 39662306a36Sopenharmony_ci over4g = systab64->runtime > U32_MAX; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (efi_setup) { 39962306a36Sopenharmony_ci struct efi_setup_data *data; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci data = early_memremap_ro(efi_setup, sizeof(*data)); 40262306a36Sopenharmony_ci if (!data) { 40362306a36Sopenharmony_ci early_memunmap(p, size); 40462306a36Sopenharmony_ci return -ENOMEM; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci efi_fw_vendor = (unsigned long)data->fw_vendor; 40862306a36Sopenharmony_ci efi_config_table = (unsigned long)data->tables; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci over4g |= data->fw_vendor > U32_MAX || 41162306a36Sopenharmony_ci data->tables > U32_MAX; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci early_memunmap(data, sizeof(*data)); 41462306a36Sopenharmony_ci } else { 41562306a36Sopenharmony_ci efi_fw_vendor = systab64->fw_vendor; 41662306a36Sopenharmony_ci efi_config_table = systab64->tables; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci over4g |= systab64->fw_vendor > U32_MAX || 41962306a36Sopenharmony_ci systab64->tables > U32_MAX; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci efi_nr_tables = systab64->nr_tables; 42262306a36Sopenharmony_ci } else { 42362306a36Sopenharmony_ci const efi_system_table_32_t *systab32 = p; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci efi_fw_vendor = systab32->fw_vendor; 42662306a36Sopenharmony_ci efi_runtime = systab32->runtime; 42762306a36Sopenharmony_ci efi_config_table = systab32->tables; 42862306a36Sopenharmony_ci efi_nr_tables = systab32->nr_tables; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci efi.runtime_version = hdr->revision; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci efi_systab_report_header(hdr, efi_fw_vendor); 43462306a36Sopenharmony_ci early_memunmap(p, size); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_32) && over4g) { 43762306a36Sopenharmony_ci pr_err("EFI data located above 4GB, disabling EFI.\n"); 43862306a36Sopenharmony_ci return -EINVAL; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic int __init efi_config_init(const efi_config_table_type_t *arch_tables) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci void *config_tables; 44762306a36Sopenharmony_ci int sz, ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (efi_nr_tables == 0) 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (efi_enabled(EFI_64BIT)) 45362306a36Sopenharmony_ci sz = sizeof(efi_config_table_64_t); 45462306a36Sopenharmony_ci else 45562306a36Sopenharmony_ci sz = sizeof(efi_config_table_32_t); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * Let's see what config tables the firmware passed to us. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci config_tables = early_memremap(efi_config_table, efi_nr_tables * sz); 46162306a36Sopenharmony_ci if (config_tables == NULL) { 46262306a36Sopenharmony_ci pr_err("Could not map Configuration table!\n"); 46362306a36Sopenharmony_ci return -ENOMEM; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ret = efi_config_parse_tables(config_tables, efi_nr_tables, 46762306a36Sopenharmony_ci arch_tables); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci early_memunmap(config_tables, efi_nr_tables * sz); 47062306a36Sopenharmony_ci return ret; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_civoid __init efi_init(void) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_32) && 47662306a36Sopenharmony_ci (boot_params.efi_info.efi_systab_hi || 47762306a36Sopenharmony_ci boot_params.efi_info.efi_memmap_hi)) { 47862306a36Sopenharmony_ci pr_info("Table located above 4GB, disabling EFI.\n"); 47962306a36Sopenharmony_ci return; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci efi_systab_phys = boot_params.efi_info.efi_systab | 48362306a36Sopenharmony_ci ((__u64)boot_params.efi_info.efi_systab_hi << 32); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (efi_systab_init(efi_systab_phys)) 48662306a36Sopenharmony_ci return; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (efi_reuse_config(efi_config_table, efi_nr_tables)) 48962306a36Sopenharmony_ci return; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (efi_config_init(arch_tables)) 49262306a36Sopenharmony_ci return; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* 49562306a36Sopenharmony_ci * Note: We currently don't support runtime services on an EFI 49662306a36Sopenharmony_ci * that doesn't match the kernel 32/64-bit mode. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (!efi_runtime_supported()) 50062306a36Sopenharmony_ci pr_err("No EFI runtime due to 32/64-bit mismatch with kernel\n"); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (!efi_runtime_supported() || efi_runtime_disabled()) { 50362306a36Sopenharmony_ci efi_memmap_unmap(); 50462306a36Sopenharmony_ci return; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* Parse the EFI Properties table if it exists */ 50862306a36Sopenharmony_ci if (prop_phys != EFI_INVALID_TABLE_ADDR) { 50962306a36Sopenharmony_ci efi_properties_table_t *tbl; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci tbl = early_memremap_ro(prop_phys, sizeof(*tbl)); 51262306a36Sopenharmony_ci if (tbl == NULL) { 51362306a36Sopenharmony_ci pr_err("Could not map Properties table!\n"); 51462306a36Sopenharmony_ci } else { 51562306a36Sopenharmony_ci if (tbl->memory_protection_attribute & 51662306a36Sopenharmony_ci EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) 51762306a36Sopenharmony_ci set_bit(EFI_NX_PE_DATA, &efi.flags); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci early_memunmap(tbl, sizeof(*tbl)); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci set_bit(EFI_RUNTIME_SERVICES, &efi.flags); 52462306a36Sopenharmony_ci efi_clean_memmap(); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci efi_remove_e820_mmio(); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (efi_enabled(EFI_DBG)) 52962306a36Sopenharmony_ci efi_print_memmap(); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/* Merge contiguous regions of the same type and attribute */ 53362306a36Sopenharmony_cistatic void __init efi_merge_regions(void) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci efi_memory_desc_t *md, *prev_md = NULL; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci for_each_efi_memory_desc(md) { 53862306a36Sopenharmony_ci u64 prev_size; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (!prev_md) { 54162306a36Sopenharmony_ci prev_md = md; 54262306a36Sopenharmony_ci continue; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (prev_md->type != md->type || 54662306a36Sopenharmony_ci prev_md->attribute != md->attribute) { 54762306a36Sopenharmony_ci prev_md = md; 54862306a36Sopenharmony_ci continue; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci prev_size = prev_md->num_pages << EFI_PAGE_SHIFT; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (md->phys_addr == (prev_md->phys_addr + prev_size)) { 55462306a36Sopenharmony_ci prev_md->num_pages += md->num_pages; 55562306a36Sopenharmony_ci md->type = EFI_RESERVED_TYPE; 55662306a36Sopenharmony_ci md->attribute = 0; 55762306a36Sopenharmony_ci continue; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci prev_md = md; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic void *realloc_pages(void *old_memmap, int old_shift) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci void *ret; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci ret = (void *)__get_free_pages(GFP_KERNEL, old_shift + 1); 56862306a36Sopenharmony_ci if (!ret) 56962306a36Sopenharmony_ci goto out; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * A first-time allocation doesn't have anything to copy. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ci if (!old_memmap) 57562306a36Sopenharmony_ci return ret; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci memcpy(ret, old_memmap, PAGE_SIZE << old_shift); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ciout: 58062306a36Sopenharmony_ci free_pages((unsigned long)old_memmap, old_shift); 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/* 58562306a36Sopenharmony_ci * Iterate the EFI memory map in reverse order because the regions 58662306a36Sopenharmony_ci * will be mapped top-down. The end result is the same as if we had 58762306a36Sopenharmony_ci * mapped things forward, but doesn't require us to change the 58862306a36Sopenharmony_ci * existing implementation of efi_map_region(). 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_cistatic inline void *efi_map_next_entry_reverse(void *entry) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci /* Initial call */ 59362306a36Sopenharmony_ci if (!entry) 59462306a36Sopenharmony_ci return efi.memmap.map_end - efi.memmap.desc_size; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci entry -= efi.memmap.desc_size; 59762306a36Sopenharmony_ci if (entry < efi.memmap.map) 59862306a36Sopenharmony_ci return NULL; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return entry; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* 60462306a36Sopenharmony_ci * efi_map_next_entry - Return the next EFI memory map descriptor 60562306a36Sopenharmony_ci * @entry: Previous EFI memory map descriptor 60662306a36Sopenharmony_ci * 60762306a36Sopenharmony_ci * This is a helper function to iterate over the EFI memory map, which 60862306a36Sopenharmony_ci * we do in different orders depending on the current configuration. 60962306a36Sopenharmony_ci * 61062306a36Sopenharmony_ci * To begin traversing the memory map @entry must be %NULL. 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * Returns %NULL when we reach the end of the memory map. 61362306a36Sopenharmony_ci */ 61462306a36Sopenharmony_cistatic void *efi_map_next_entry(void *entry) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci if (efi_enabled(EFI_64BIT)) { 61762306a36Sopenharmony_ci /* 61862306a36Sopenharmony_ci * Starting in UEFI v2.5 the EFI_PROPERTIES_TABLE 61962306a36Sopenharmony_ci * config table feature requires us to map all entries 62062306a36Sopenharmony_ci * in the same order as they appear in the EFI memory 62162306a36Sopenharmony_ci * map. That is to say, entry N must have a lower 62262306a36Sopenharmony_ci * virtual address than entry N+1. This is because the 62362306a36Sopenharmony_ci * firmware toolchain leaves relative references in 62462306a36Sopenharmony_ci * the code/data sections, which are split and become 62562306a36Sopenharmony_ci * separate EFI memory regions. Mapping things 62662306a36Sopenharmony_ci * out-of-order leads to the firmware accessing 62762306a36Sopenharmony_ci * unmapped addresses. 62862306a36Sopenharmony_ci * 62962306a36Sopenharmony_ci * Since we need to map things this way whether or not 63062306a36Sopenharmony_ci * the kernel actually makes use of 63162306a36Sopenharmony_ci * EFI_PROPERTIES_TABLE, let's just switch to this 63262306a36Sopenharmony_ci * scheme by default for 64-bit. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci return efi_map_next_entry_reverse(entry); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Initial call */ 63862306a36Sopenharmony_ci if (!entry) 63962306a36Sopenharmony_ci return efi.memmap.map; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci entry += efi.memmap.desc_size; 64262306a36Sopenharmony_ci if (entry >= efi.memmap.map_end) 64362306a36Sopenharmony_ci return NULL; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return entry; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic bool should_map_region(efi_memory_desc_t *md) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * Runtime regions always require runtime mappings (obviously). 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci if (md->attribute & EFI_MEMORY_RUNTIME) 65462306a36Sopenharmony_ci return true; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* 65762306a36Sopenharmony_ci * 32-bit EFI doesn't suffer from the bug that requires us to 65862306a36Sopenharmony_ci * reserve boot services regions, and mixed mode support 65962306a36Sopenharmony_ci * doesn't exist for 32-bit kernels. 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_32)) 66262306a36Sopenharmony_ci return false; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* 66562306a36Sopenharmony_ci * EFI specific purpose memory may be reserved by default 66662306a36Sopenharmony_ci * depending on kernel config and boot options. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci if (md->type == EFI_CONVENTIONAL_MEMORY && 66962306a36Sopenharmony_ci efi_soft_reserve_enabled() && 67062306a36Sopenharmony_ci (md->attribute & EFI_MEMORY_SP)) 67162306a36Sopenharmony_ci return false; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* 67462306a36Sopenharmony_ci * Map all of RAM so that we can access arguments in the 1:1 67562306a36Sopenharmony_ci * mapping when making EFI runtime calls. 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_ci if (efi_is_mixed()) { 67862306a36Sopenharmony_ci if (md->type == EFI_CONVENTIONAL_MEMORY || 67962306a36Sopenharmony_ci md->type == EFI_LOADER_DATA || 68062306a36Sopenharmony_ci md->type == EFI_LOADER_CODE) 68162306a36Sopenharmony_ci return true; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* 68562306a36Sopenharmony_ci * Map boot services regions as a workaround for buggy 68662306a36Sopenharmony_ci * firmware that accesses them even when they shouldn't. 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * See efi_{reserve,free}_boot_services(). 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ci if (md->type == EFI_BOOT_SERVICES_CODE || 69162306a36Sopenharmony_ci md->type == EFI_BOOT_SERVICES_DATA) 69262306a36Sopenharmony_ci return true; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return false; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/* 69862306a36Sopenharmony_ci * Map the efi memory ranges of the runtime services and update new_mmap with 69962306a36Sopenharmony_ci * virtual addresses. 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_cistatic void * __init efi_map_regions(int *count, int *pg_shift) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci void *p, *new_memmap = NULL; 70462306a36Sopenharmony_ci unsigned long left = 0; 70562306a36Sopenharmony_ci unsigned long desc_size; 70662306a36Sopenharmony_ci efi_memory_desc_t *md; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci desc_size = efi.memmap.desc_size; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci p = NULL; 71162306a36Sopenharmony_ci while ((p = efi_map_next_entry(p))) { 71262306a36Sopenharmony_ci md = p; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (!should_map_region(md)) 71562306a36Sopenharmony_ci continue; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci efi_map_region(md); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (left < desc_size) { 72062306a36Sopenharmony_ci new_memmap = realloc_pages(new_memmap, *pg_shift); 72162306a36Sopenharmony_ci if (!new_memmap) 72262306a36Sopenharmony_ci return NULL; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci left += PAGE_SIZE << *pg_shift; 72562306a36Sopenharmony_ci (*pg_shift)++; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci memcpy(new_memmap + (*count * desc_size), md, desc_size); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci left -= desc_size; 73162306a36Sopenharmony_ci (*count)++; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return new_memmap; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic void __init kexec_enter_virtual_mode(void) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci#ifdef CONFIG_KEXEC_CORE 74062306a36Sopenharmony_ci efi_memory_desc_t *md; 74162306a36Sopenharmony_ci unsigned int num_pages; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* 74462306a36Sopenharmony_ci * We don't do virtual mode, since we don't do runtime services, on 74562306a36Sopenharmony_ci * non-native EFI. 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_ci if (efi_is_mixed()) { 74862306a36Sopenharmony_ci efi_memmap_unmap(); 74962306a36Sopenharmony_ci clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); 75062306a36Sopenharmony_ci return; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (efi_alloc_page_tables()) { 75462306a36Sopenharmony_ci pr_err("Failed to allocate EFI page tables\n"); 75562306a36Sopenharmony_ci clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); 75662306a36Sopenharmony_ci return; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* 76062306a36Sopenharmony_ci * Map efi regions which were passed via setup_data. The virt_addr is a 76162306a36Sopenharmony_ci * fixed addr which was used in first kernel of a kexec boot. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci for_each_efi_memory_desc(md) 76462306a36Sopenharmony_ci efi_map_region_fixed(md); /* FIXME: add error handling */ 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* 76762306a36Sopenharmony_ci * Unregister the early EFI memmap from efi_init() and install 76862306a36Sopenharmony_ci * the new EFI memory map. 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ci efi_memmap_unmap(); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (efi_memmap_init_late(efi.memmap.phys_map, 77362306a36Sopenharmony_ci efi.memmap.desc_size * efi.memmap.nr_map)) { 77462306a36Sopenharmony_ci pr_err("Failed to remap late EFI memory map\n"); 77562306a36Sopenharmony_ci clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); 77662306a36Sopenharmony_ci return; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE); 78062306a36Sopenharmony_ci num_pages >>= PAGE_SHIFT; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (efi_setup_page_tables(efi.memmap.phys_map, num_pages)) { 78362306a36Sopenharmony_ci clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); 78462306a36Sopenharmony_ci return; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci efi_sync_low_kernel_mappings(); 78862306a36Sopenharmony_ci efi_native_runtime_setup(); 78962306a36Sopenharmony_ci#endif 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/* 79362306a36Sopenharmony_ci * This function will switch the EFI runtime services to virtual mode. 79462306a36Sopenharmony_ci * Essentially, we look through the EFI memmap and map every region that 79562306a36Sopenharmony_ci * has the runtime attribute bit set in its memory descriptor into the 79662306a36Sopenharmony_ci * efi_pgd page table. 79762306a36Sopenharmony_ci * 79862306a36Sopenharmony_ci * The new method does a pagetable switch in a preemption-safe manner 79962306a36Sopenharmony_ci * so that we're in a different address space when calling a runtime 80062306a36Sopenharmony_ci * function. For function arguments passing we do copy the PUDs of the 80162306a36Sopenharmony_ci * kernel page table into efi_pgd prior to each call. 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * Specially for kexec boot, efi runtime maps in previous kernel should 80462306a36Sopenharmony_ci * be passed in via setup_data. In that case runtime ranges will be mapped 80562306a36Sopenharmony_ci * to the same virtual addresses as the first kernel, see 80662306a36Sopenharmony_ci * kexec_enter_virtual_mode(). 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_cistatic void __init __efi_enter_virtual_mode(void) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci int count = 0, pg_shift = 0; 81162306a36Sopenharmony_ci void *new_memmap = NULL; 81262306a36Sopenharmony_ci efi_status_t status; 81362306a36Sopenharmony_ci unsigned long pa; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (efi_alloc_page_tables()) { 81662306a36Sopenharmony_ci pr_err("Failed to allocate EFI page tables\n"); 81762306a36Sopenharmony_ci goto err; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci efi_merge_regions(); 82162306a36Sopenharmony_ci new_memmap = efi_map_regions(&count, &pg_shift); 82262306a36Sopenharmony_ci if (!new_memmap) { 82362306a36Sopenharmony_ci pr_err("Error reallocating memory, EFI runtime non-functional!\n"); 82462306a36Sopenharmony_ci goto err; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci pa = __pa(new_memmap); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* 83062306a36Sopenharmony_ci * Unregister the early EFI memmap from efi_init() and install 83162306a36Sopenharmony_ci * the new EFI memory map that we are about to pass to the 83262306a36Sopenharmony_ci * firmware via SetVirtualAddressMap(). 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_ci efi_memmap_unmap(); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (efi_memmap_init_late(pa, efi.memmap.desc_size * count)) { 83762306a36Sopenharmony_ci pr_err("Failed to remap late EFI memory map\n"); 83862306a36Sopenharmony_ci goto err; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (efi_enabled(EFI_DBG)) { 84262306a36Sopenharmony_ci pr_info("EFI runtime memory map:\n"); 84362306a36Sopenharmony_ci efi_print_memmap(); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (efi_setup_page_tables(pa, 1 << pg_shift)) 84762306a36Sopenharmony_ci goto err; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci efi_sync_low_kernel_mappings(); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci status = efi_set_virtual_address_map(efi.memmap.desc_size * count, 85262306a36Sopenharmony_ci efi.memmap.desc_size, 85362306a36Sopenharmony_ci efi.memmap.desc_version, 85462306a36Sopenharmony_ci (efi_memory_desc_t *)pa, 85562306a36Sopenharmony_ci efi_systab_phys); 85662306a36Sopenharmony_ci if (status != EFI_SUCCESS) { 85762306a36Sopenharmony_ci pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n", 85862306a36Sopenharmony_ci status); 85962306a36Sopenharmony_ci goto err; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci efi_check_for_embedded_firmwares(); 86362306a36Sopenharmony_ci efi_free_boot_services(); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (!efi_is_mixed()) 86662306a36Sopenharmony_ci efi_native_runtime_setup(); 86762306a36Sopenharmony_ci else 86862306a36Sopenharmony_ci efi_thunk_runtime_setup(); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* 87162306a36Sopenharmony_ci * Apply more restrictive page table mapping attributes now that 87262306a36Sopenharmony_ci * SVAM() has been called and the firmware has performed all 87362306a36Sopenharmony_ci * necessary relocation fixups for the new virtual addresses. 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_ci efi_runtime_update_mappings(); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci /* clean DUMMY object */ 87862306a36Sopenharmony_ci efi_delete_dummy_variable(); 87962306a36Sopenharmony_ci return; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cierr: 88262306a36Sopenharmony_ci clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_civoid __init efi_enter_virtual_mode(void) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci if (efi_enabled(EFI_PARAVIRT)) 88862306a36Sopenharmony_ci return; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci efi.runtime = (efi_runtime_services_t *)efi_runtime; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (efi_setup) 89362306a36Sopenharmony_ci kexec_enter_virtual_mode(); 89462306a36Sopenharmony_ci else 89562306a36Sopenharmony_ci __efi_enter_virtual_mode(); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci efi_dump_pagetable(); 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cibool efi_is_table_address(unsigned long phys_addr) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci unsigned int i; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (phys_addr == EFI_INVALID_TABLE_ADDR) 90562306a36Sopenharmony_ci return false; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(efi_tables); i++) 90862306a36Sopenharmony_ci if (*(efi_tables[i]) == phys_addr) 90962306a36Sopenharmony_ci return true; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return false; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cichar *efi_systab_show_arch(char *str) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci if (uga_phys != EFI_INVALID_TABLE_ADDR) 91762306a36Sopenharmony_ci str += sprintf(str, "UGA=0x%lx\n", uga_phys); 91862306a36Sopenharmony_ci return str; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci#define EFI_FIELD(var) efi_ ## var 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci#define EFI_ATTR_SHOW(name) \ 92462306a36Sopenharmony_cistatic ssize_t name##_show(struct kobject *kobj, \ 92562306a36Sopenharmony_ci struct kobj_attribute *attr, char *buf) \ 92662306a36Sopenharmony_ci{ \ 92762306a36Sopenharmony_ci return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \ 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ciEFI_ATTR_SHOW(fw_vendor); 93162306a36Sopenharmony_ciEFI_ATTR_SHOW(runtime); 93262306a36Sopenharmony_ciEFI_ATTR_SHOW(config_table); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistruct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor); 93562306a36Sopenharmony_cistruct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime); 93662306a36Sopenharmony_cistruct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ciumode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci if (attr == &efi_attr_fw_vendor.attr) { 94162306a36Sopenharmony_ci if (efi_enabled(EFI_PARAVIRT) || 94262306a36Sopenharmony_ci efi_fw_vendor == EFI_INVALID_TABLE_ADDR) 94362306a36Sopenharmony_ci return 0; 94462306a36Sopenharmony_ci } else if (attr == &efi_attr_runtime.attr) { 94562306a36Sopenharmony_ci if (efi_runtime == EFI_INVALID_TABLE_ADDR) 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci } else if (attr == &efi_attr_config_table.attr) { 94862306a36Sopenharmony_ci if (efi_config_table == EFI_INVALID_TABLE_ADDR) 94962306a36Sopenharmony_ci return 0; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci return attr->mode; 95262306a36Sopenharmony_ci} 953