// SPDX-License-Identifier: GPL-2.0 /* * Common EFI (Extensible Firmware Interface) support functions * Based on Extensible Firmware Interface Specification version 1.0 * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <[email protected]> * Copyright (C) 1999-2002 Hewlett-Packard Co. * David Mosberger-Tang <[email protected]> * Stephane Eranian <[email protected]> * Copyright (C) 2005-2008 Intel Co. * Fenghua Yu <[email protected]> * Bibo Mao <[email protected]> * Chandramouli Narayanan <[email protected]> * Huang Ying <[email protected]> * Copyright (C) 2013 SuSE Labs * Borislav Petkov <[email protected]> - runtime services VA mapping * * Copied from efi_32.c to eliminate the duplicated code between EFI * 32/64 support code. --ying 2007-10-26 * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed * in a future version. --drummond 1999-07-20 * * Implemented EFI runtime services and virtual mode calls. --davidm * * Goutham Rao: <[email protected]> * Skip non-WB memory and ignore empty memory ranges. */ #define pr_fmt(fmt) … #include <linux/kernel.h> #include <linux/init.h> #include <linux/efi.h> #include <linux/efi-bgrt.h> #include <linux/export.h> #include <linux/memblock.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/uaccess.h> #include <linux/time.h> #include <linux/io.h> #include <linux/reboot.h> #include <linux/bcd.h> #include <asm/setup.h> #include <asm/efi.h> #include <asm/e820/api.h> #include <asm/time.h> #include <asm/tlbflush.h> #include <asm/x86_init.h> #include <asm/uv/uv.h> static unsigned long efi_systab_phys __initdata; static unsigned long prop_phys = …; static unsigned long uga_phys = …; static unsigned long efi_runtime, efi_nr_tables; unsigned long efi_fw_vendor, efi_config_table; static const efi_config_table_type_t arch_tables[] __initconst = …; static const unsigned long * const efi_tables[] = …; u64 efi_setup; /* efi setup_data physical address */ static int add_efi_memmap __initdata; static int __init setup_add_efi_memmap(char *arg) { … } early_param(…); /* * Tell the kernel about the EFI memory map. This might include * more than the max 128 entries that can fit in the passed in e820 * legacy (zeropage) memory map, but the kernel's e820 table can hold * E820_MAX_ENTRIES. */ static void __init do_add_efi_memmap(void) { … } /* * Given add_efi_memmap defaults to 0 and there is no alternative * e820 mechanism for soft-reserved memory, import the full EFI memory * map if soft reservations are present and enabled. Otherwise, the * mechanism to disable the kernel's consideration of EFI_MEMORY_SP is * the efi=nosoftreserve option. */ static bool do_efi_soft_reserve(void) { … } int __init efi_memblock_x86_reserve_range(void) { … } #define OVERFLOW_ADDR_SHIFT … #define OVERFLOW_ADDR_MASK … #define U64_HIGH_BIT … static bool __init efi_memmap_entry_valid(const efi_memory_desc_t *md, int i) { … } static void __init efi_clean_memmap(void) { … } /* * Firmware can use EfiMemoryMappedIO to request that MMIO regions be * mapped by the OS so they can be accessed by EFI runtime services, but * should have no other significance to the OS (UEFI r2.10, sec 7.2). * However, most bootloaders and EFI stubs convert EfiMemoryMappedIO * regions to E820_TYPE_RESERVED entries, which prevent Linux from * allocating space from them (see remove_e820_regions()). * * Some platforms use EfiMemoryMappedIO entries for PCI MMCONFIG space and * PCI host bridge windows, which means Linux can't allocate BAR space for * hot-added devices. * * Remove large EfiMemoryMappedIO regions from the E820 map to avoid this * problem. * * Retain small EfiMemoryMappedIO regions because on some platforms, these * describe non-window space that's included in host bridge _CRS. If we * assign that space to PCI devices, they don't work. */ static void __init efi_remove_e820_mmio(void) { … } void __init efi_print_memmap(void) { … } static int __init efi_systab_init(unsigned long phys) { … } static int __init efi_config_init(const efi_config_table_type_t *arch_tables) { … } void __init efi_init(void) { … } /* Merge contiguous regions of the same type and attribute */ static void __init efi_merge_regions(void) { … } static void *realloc_pages(void *old_memmap, int old_shift) { … } /* * Iterate the EFI memory map in reverse order because the regions * will be mapped top-down. The end result is the same as if we had * mapped things forward, but doesn't require us to change the * existing implementation of efi_map_region(). */ static inline void *efi_map_next_entry_reverse(void *entry) { … } /* * efi_map_next_entry - Return the next EFI memory map descriptor * @entry: Previous EFI memory map descriptor * * This is a helper function to iterate over the EFI memory map, which * we do in different orders depending on the current configuration. * * To begin traversing the memory map @entry must be %NULL. * * Returns %NULL when we reach the end of the memory map. */ static void *efi_map_next_entry(void *entry) { … } static bool should_map_region(efi_memory_desc_t *md) { … } /* * Map the efi memory ranges of the runtime services and update new_mmap with * virtual addresses. */ static void * __init efi_map_regions(int *count, int *pg_shift) { … } static void __init kexec_enter_virtual_mode(void) { … } /* * This function will switch the EFI runtime services to virtual mode. * Essentially, we look through the EFI memmap and map every region that * has the runtime attribute bit set in its memory descriptor into the * efi_pgd page table. * * The new method does a pagetable switch in a preemption-safe manner * so that we're in a different address space when calling a runtime * function. For function arguments passing we do copy the PUDs of the * kernel page table into efi_pgd prior to each call. * * Specially for kexec boot, efi runtime maps in previous kernel should * be passed in via setup_data. In that case runtime ranges will be mapped * to the same virtual addresses as the first kernel, see * kexec_enter_virtual_mode(). */ static void __init __efi_enter_virtual_mode(void) { … } void __init efi_enter_virtual_mode(void) { … } bool efi_is_table_address(unsigned long phys_addr) { … } char *efi_systab_show_arch(char *str) { … } #define EFI_FIELD(var) … #define EFI_ATTR_SHOW(name) … EFI_ATTR_SHOW(fw_vendor); EFI_ATTR_SHOW(runtime); EFI_ATTR_SHOW(config_table); struct kobj_attribute efi_attr_fw_vendor = …; struct kobj_attribute efi_attr_runtime = …; struct kobj_attribute efi_attr_config_table = …; umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { … } enum efi_secureboot_mode __x86_ima_efi_boot_mode(void) { … }