162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Extensible Firmware Interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on Extensible Firmware Interface Specification version 2.4 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2013 - 2015 Linaro Ltd. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) "efi: " fmt 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/efi.h> 1362306a36Sopenharmony_ci#include <linux/fwnode.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/memblock.h> 1662306a36Sopenharmony_ci#include <linux/mm_types.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_address.h> 1962306a36Sopenharmony_ci#include <linux/of_fdt.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/screen_info.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/efi.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciunsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int __init is_memory(efi_memory_desc_t *md) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC)) 3062306a36Sopenharmony_ci return 1; 3162306a36Sopenharmony_ci return 0; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * Translate a EFI virtual address into a physical address: this is necessary, 3662306a36Sopenharmony_ci * as some data members of the EFI system table are virtually remapped after 3762306a36Sopenharmony_ci * SetVirtualAddressMap() has been called. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic phys_addr_t __init efi_to_phys(unsigned long addr) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci efi_memory_desc_t *md; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci for_each_efi_memory_desc(md) { 4462306a36Sopenharmony_ci if (!(md->attribute & EFI_MEMORY_RUNTIME)) 4562306a36Sopenharmony_ci continue; 4662306a36Sopenharmony_ci if (md->virt_addr == 0) 4762306a36Sopenharmony_ci /* no virtual mapping has been installed by the stub */ 4862306a36Sopenharmony_ci break; 4962306a36Sopenharmony_ci if (md->virt_addr <= addr && 5062306a36Sopenharmony_ci (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT)) 5162306a36Sopenharmony_ci return md->phys_addr + addr - md->virt_addr; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci return addr; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciextern __weak const efi_config_table_type_t efi_arch_tables[]; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic void __init init_screen_info(void) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct screen_info *si; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (screen_info_table != EFI_INVALID_TABLE_ADDR) { 6362306a36Sopenharmony_ci si = early_memremap(screen_info_table, sizeof(*si)); 6462306a36Sopenharmony_ci if (!si) { 6562306a36Sopenharmony_ci pr_err("Could not map screen_info config table\n"); 6662306a36Sopenharmony_ci return; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci screen_info = *si; 6962306a36Sopenharmony_ci memset(si, 0, sizeof(*si)); 7062306a36Sopenharmony_ci early_memunmap(si, sizeof(*si)); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (memblock_is_map_memory(screen_info.lfb_base)) 7362306a36Sopenharmony_ci memblock_mark_nomap(screen_info.lfb_base, 7462306a36Sopenharmony_ci screen_info.lfb_size); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_EFI_EARLYCON)) 7762306a36Sopenharmony_ci efi_earlycon_reprobe(); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int __init uefi_init(u64 efi_system_table) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci efi_config_table_t *config_tables; 8462306a36Sopenharmony_ci efi_system_table_t *systab; 8562306a36Sopenharmony_ci size_t table_size; 8662306a36Sopenharmony_ci int retval; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t)); 8962306a36Sopenharmony_ci if (systab == NULL) { 9062306a36Sopenharmony_ci pr_warn("Unable to map EFI system table.\n"); 9162306a36Sopenharmony_ci return -ENOMEM; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci set_bit(EFI_BOOT, &efi.flags); 9562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) 9662306a36Sopenharmony_ci set_bit(EFI_64BIT, &efi.flags); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci retval = efi_systab_check_header(&systab->hdr); 9962306a36Sopenharmony_ci if (retval) 10062306a36Sopenharmony_ci goto out; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci efi.runtime = systab->runtime; 10362306a36Sopenharmony_ci efi.runtime_version = systab->hdr.revision; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor)); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci table_size = sizeof(efi_config_table_t) * systab->nr_tables; 10862306a36Sopenharmony_ci config_tables = early_memremap_ro(efi_to_phys(systab->tables), 10962306a36Sopenharmony_ci table_size); 11062306a36Sopenharmony_ci if (config_tables == NULL) { 11162306a36Sopenharmony_ci pr_warn("Unable to map EFI config table array.\n"); 11262306a36Sopenharmony_ci retval = -ENOMEM; 11362306a36Sopenharmony_ci goto out; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci retval = efi_config_parse_tables(config_tables, systab->nr_tables, 11662306a36Sopenharmony_ci efi_arch_tables); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci early_memunmap(config_tables, table_size); 11962306a36Sopenharmony_ciout: 12062306a36Sopenharmony_ci early_memunmap(systab, sizeof(efi_system_table_t)); 12162306a36Sopenharmony_ci return retval; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* 12562306a36Sopenharmony_ci * Return true for regions that can be used as System RAM. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistatic __init int is_usable_memory(efi_memory_desc_t *md) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci switch (md->type) { 13062306a36Sopenharmony_ci case EFI_LOADER_CODE: 13162306a36Sopenharmony_ci case EFI_LOADER_DATA: 13262306a36Sopenharmony_ci case EFI_ACPI_RECLAIM_MEMORY: 13362306a36Sopenharmony_ci case EFI_BOOT_SERVICES_CODE: 13462306a36Sopenharmony_ci case EFI_BOOT_SERVICES_DATA: 13562306a36Sopenharmony_ci case EFI_CONVENTIONAL_MEMORY: 13662306a36Sopenharmony_ci case EFI_PERSISTENT_MEMORY: 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * According to the spec, these regions are no longer reserved 13962306a36Sopenharmony_ci * after calling ExitBootServices(). However, we can only use 14062306a36Sopenharmony_ci * them as System RAM if they can be mapped writeback cacheable. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci return (md->attribute & EFI_MEMORY_WB); 14362306a36Sopenharmony_ci default: 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci return false; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic __init void reserve_regions(void) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci efi_memory_desc_t *md; 15262306a36Sopenharmony_ci u64 paddr, npages, size; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (efi_enabled(EFI_DBG)) 15562306a36Sopenharmony_ci pr_info("Processing EFI memory map:\n"); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * Discard memblocks discovered so far: if there are any at this 15962306a36Sopenharmony_ci * point, they originate from memory nodes in the DT, and UEFI 16062306a36Sopenharmony_ci * uses its own memory map instead. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci memblock_dump_all(); 16362306a36Sopenharmony_ci memblock_remove(0, PHYS_ADDR_MAX); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for_each_efi_memory_desc(md) { 16662306a36Sopenharmony_ci paddr = md->phys_addr; 16762306a36Sopenharmony_ci npages = md->num_pages; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (efi_enabled(EFI_DBG)) { 17062306a36Sopenharmony_ci char buf[64]; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci pr_info(" 0x%012llx-0x%012llx %s\n", 17362306a36Sopenharmony_ci paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, 17462306a36Sopenharmony_ci efi_md_typeattr_format(buf, sizeof(buf), md)); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci memrange_efi_to_native(&paddr, &npages); 17862306a36Sopenharmony_ci size = npages << PAGE_SHIFT; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (is_memory(md)) { 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * Special purpose memory is 'soft reserved', which 18362306a36Sopenharmony_ci * means it is set aside initially. Don't add a memblock 18462306a36Sopenharmony_ci * for it now so that it can be hotplugged back in or 18562306a36Sopenharmony_ci * be assigned to the dax driver after boot. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci if (efi_soft_reserve_enabled() && 18862306a36Sopenharmony_ci (md->attribute & EFI_MEMORY_SP)) 18962306a36Sopenharmony_ci continue; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci early_init_dt_add_memory_arch(paddr, size); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!is_usable_memory(md)) 19462306a36Sopenharmony_ci memblock_mark_nomap(paddr, size); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* keep ACPI reclaim memory intact for kexec etc. */ 19762306a36Sopenharmony_ci if (md->type == EFI_ACPI_RECLAIM_MEMORY) 19862306a36Sopenharmony_ci memblock_reserve(paddr, size); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_civoid __init efi_init(void) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct efi_memory_map_data data; 20662306a36Sopenharmony_ci u64 efi_system_table; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Grab UEFI information placed in FDT by stub */ 20962306a36Sopenharmony_ci efi_system_table = efi_get_fdt_params(&data); 21062306a36Sopenharmony_ci if (!efi_system_table) 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (efi_memmap_init_early(&data) < 0) { 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * If we are booting via UEFI, the UEFI memory map is the only 21662306a36Sopenharmony_ci * description of memory we have, so there is little point in 21762306a36Sopenharmony_ci * proceeding if we cannot access it. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci panic("Unable to map EFI memory map.\n"); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci WARN(efi.memmap.desc_version != 1, 22362306a36Sopenharmony_ci "Unexpected EFI_MEMORY_DESCRIPTOR version %ld", 22462306a36Sopenharmony_ci efi.memmap.desc_version); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (uefi_init(efi_system_table) < 0) { 22762306a36Sopenharmony_ci efi_memmap_unmap(); 22862306a36Sopenharmony_ci return; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci reserve_regions(); 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * For memblock manipulation, the cap should come after the memblock_add(). 23462306a36Sopenharmony_ci * And now, memblock is fully populated, it is time to do capping. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci early_init_dt_check_for_usable_mem_range(); 23762306a36Sopenharmony_ci efi_find_mirror(); 23862306a36Sopenharmony_ci efi_esrt_init(); 23962306a36Sopenharmony_ci efi_mokvar_table_init(); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci memblock_reserve(data.phys_map & PAGE_MASK, 24262306a36Sopenharmony_ci PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK))); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci init_screen_info(); 24562306a36Sopenharmony_ci} 246