efi/x86: limit EFI old memory map to SGI UV machines
Subsystems (4)
Ard Biesheuvel
maintainerPATCH v2 1/1 efi/x86: limit EFI old memory map to SGI UV machines
We carry a quirk in the x86 EFI code to switch back to an older method of mapping the EFI runtime services memory regions, because it was deemed risky at the time to implement a new method without providing a fallback to the old method in case problems arose.
Such problems did arise, but they appear to be limited to SGI UV1 machines, and so these are the only ones for which the fallback gets enabled automatically (via a DMI quirk). The fallback can be enabled manually as well, by passing efi=old_map, but there is very little evidence that suggests that this is something that is being relied upon in the field.
Given that UV1 support is not enabled by default by the distros (Ubuntu, Fedora), there is no point in carrying this fallback code all the time if there are no other users. So let's move it into the UV support code, and document that efi=old_map now requires this support code to be enabled.
Note that efi=old_map has been used in the past on other SGI UV machines to work around kernel regressions in production, so we keep the option to enable it by hand, but only if the kernel was built with UV support.
--- Documentation/admin-guide/kernel-parameters.txt | 3 +- arch/x86/include/asm/efi.h | 26 +-- arch/x86/kernel/kexec-bzimage64.c | 2 +- arch/x86/platform/efi/efi.c | 30 ++-- arch/x86/platform/efi/efi_64.c | 166 ++------------------ arch/x86/platform/efi/quirks.c | 21 ++- arch/x86/platform/uv/bios_uv.c | 164 ++++++++++++++++++- 7 files changed, 211 insertions(+), 201 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +1 -2
@@ -1168,8 +1168,7 @@ "nosoftreserve", "disable_early_pci_dma", "no_disable_early_pci_dma" } old_map [X86-64]: switch to the old ioremap-based EFI - runtime services mapping. 32-bit still uses this one by - default. + runtime services mapping. [Needs CONFIG_X86_UV=y] nochunk: disable reading files in "chunks" in the EFI boot stub, as chunking can cause problems with some firmware implementations.
arch/x86/include/asm/efi.h +14 -12
@@ -20,13 +20,16 @@* This is the main reason why we're doing stable VA mappings for RT * services. * -* This flag is used in conjunction with a chicken bit called -* "efi=old_map" which can be used as a fallback to the old runtime -* services mapping method in case there's some b0rkage with a -* particular EFI implementation (haha, it is hard to hold up the -* sarcasm here...). +* SGI UV1 machines are known to be incompatible with this scheme, so we +* provide an opt-out for these machines via a DMI quirk that sets the +* attribute below. */ -#define EFI_OLD_MEMMAP EFI_ARCH_1 +#define EFI_UV1_MEMMAP EFI_ARCH_1 + +static inline bool efi_have_uv1_memmap (void ) +{ +return IS_ENABLED (CONFIG_X86_UV ) &&efi_enabled (EFI_UV1_MEMMAP ); +}#define EFI32_LOADER_SIGNATURE "EL32"#define EFI64_LOADER_SIGNATURE "EL64"
@@ -119,7 +122,7 @@ struct efi_scratch {kernel_fpu_begin (); \firmware_restrict_branch_speculation_start (); \ \ -if (!efi_enabled (EFI_OLD_MEMMAP )) \ +if (!efi_have_uv1_memmap ()) \efi_switch_mm (&efi_mm); \ })
@@ -128,7 +131,7 @@ struct efi_scratch {#define arch_efi_call_virt_teardown () \ ({ \ - if (!efi_enabled(EFI_OLD_MEMMAP)) \ + if (!efi_have_uv1_memmap()) \ efi_switch_mm(efi_scratch.prev_mm); \ \ firmware_restrict_branch_speculation_end(); \
@@ -172,6 +175,8 @@ extern void efi_delete_dummy_variable(void);extern void efi_switch_mm (struct mm_struct *mm);extern void efi_recover_from_page_fault (unsigned long phys_addr);extern void efi_free_boot_services (void ); +extern pgd_t *__init efi_uv1_memmap_phys_prolog (void ); +extern void __init efi_uv1_memmap_phys_epilog (pgd_t *save_pgd);struct efi_setup_data {u64 fw_vendor;
@@ -203,10 +208,7 @@ static inline bool efi_runtime_supported(void)if (IS_ENABLED (CONFIG_X86_64 ) ==efi_enabled (EFI_64BIT ))return true; -if (IS_ENABLED (CONFIG_EFI_MIXED ) && !efi_enabled (EFI_OLD_MEMMAP )) -return true; - -return false; +return IS_ENABLED (CONFIG_EFI_MIXED ); }extern void parse_efi_setup (u64 phys_addr,u32 data_len);
arch/x86/kernel/kexec-bzimage64.c +1 -1
@@ -177,7 +177,7 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr,* acpi_rsdp=<addr> on kernel command line to make second kernel boot * without efi. */ -if (efi_enabled (EFI_OLD_MEMMAP )) +if (efi_have_uv1_memmap ())return 0 ; params->secure_boot = boot_params.secure_boot;
arch/x86/platform/efi/efi.c +10 -20
@@ -497,6 +497,8 @@ void __init efi_init(void)efi_print_memmap (); } +#if defined(CONFIG_X86_32 ) || defined(CONFIG_X86_UV ) +void __init efi_set_executable (efi_memory_desc_t *md,bool executable) {u64 addr, npages;
@@ -561,6 +563,8 @@ void __init old_map_region(efi_memory_desc_t *md) (unsigned long long)md->phys_addr); } +#endif +/* Merge contiguous regions of the same type and attribute */ static void __init efi_merge_regions (void ) {
@@ -659,7 +663,7 @@ static inline void *efi_map_next_entry_reverse(void *entry)*/ static void *efi_map_next_entry (void *entry) { -if (!efi_enabled (EFI_OLD_MEMMAP ) &&efi_enabled (EFI_64BIT )) { +if (!efi_have_uv1_memmap () &&efi_enabled (EFI_64BIT )) {/* * Starting in UEFI v2.5 the EFI_PROPERTIES_TABLE * config table feature requires us to map all entries
@@ -791,11 +795,11 @@ static void __init kexec_enter_virtual_mode(void)/* * We don't do virtual mode, since we don't do runtime services, on -* non-native EFI. With efi=old_map, we don't do runtime services in +* non-native EFI. With the UV1 memmap, we don't do runtime services in * kexec kernel because in the initial boot something else might * have been mapped at these virtual addresses. */ -if (efi_is_mixed () ||efi_enabled (EFI_OLD_MEMMAP )) { +if (efi_is_mixed () ||efi_have_uv1_memmap ()) {efi_memmap_unmap ();clear_bit (EFI_RUNTIME_SERVICES , &efi.flags);return ;
@@ -861,9 +865,9 @@ static void __init kexec_enter_virtual_mode(void)* * The old method which used to update that memory descriptor with the * virtual address obtained from ioremap() is still supported when the -* kernel is booted with efi=old_map on its command line. Same old -* method enabled the runtime services to be called without having to -* thunk back into physical mode for every invocation. +* kernel is booted on SG1 UV1 hardware. Same old method enabled the +* runtime services to be called without having to thunk back into +* physical mode for every invocation. * * 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
@@ -976,20 +980,6 @@ void __init efi_enter_virtual_mode(void)efi_dump_pagetable (); } -static int __init arch_parse_efi_cmdline (char *str) -{ -if (!str) { -pr_warn ("need at least one option\n" ); -return -EINVAL ; - } - -if (parse_option_str (str,"old_map" )) -set_bit (EFI_OLD_MEMMAP , &efi.flags); - -return 0 ; -} -early_param ("efi" , arch_parse_efi_cmdline); -bool efi_is_table_address (unsigned long phys_addr) {unsigned int i;
arch/x86/platform/efi/efi_64.c +9 -157
226 lines not on this page · raw message
arch/x86/platform/efi/quirks.c +14 -7
@@ -384,10 +384,10 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)/* * To Do: Remove this check after adding functionality to unmap EFI boot -* services code/data regions from direct mapping area because -* "efi=old_map" maps EFI regions in swapper_pg_dir. +* services code/data regions from direct mapping area because the UV1 +* memory map maps EFI regions in swapper_pg_dir. */ -if (efi_enabled (EFI_OLD_MEMMAP )) +if (efi_have_uv1_memmap ())return ;/*
@@ -558,7 +558,7 @@ int __init efi_reuse_config(u64 tables, int nr_tables)return ret; } -static const struct dmi_system_id sgi_uv1_dmi[] = { +static const struct dmi_system_id sgi_uv1_dmi[]__initconst = { {NULL ,"SGI UV1" , {DMI_MATCH (DMI_PRODUCT_NAME ,"Stoutland Platform" ),DMI_MATCH (DMI_PRODUCT_VERSION ,"1.0" ),
@@ -581,8 +581,15 @@ void __init efi_apply_memmap_quirks(void) }/* UV2+ BIOS has a fix for this issue. UV1 still needs the quirk. */ -if (dmi_check_system (sgi_uv1_dmi)) -set_bit (EFI_OLD_MEMMAP , &efi.flags); +if (dmi_check_system (sgi_uv1_dmi)) { +if (IS_ENABLED (CONFIG_X86_UV )) { +set_bit (EFI_UV1_MEMMAP , &efi.flags); + }else { +pr_warn ("EFI runtime disabled, needs CONFIG_X86_UV=y on UV1\n" ); +clear_bit (EFI_RUNTIME_SERVICES , &efi.flags); +efi_memmap_unmap (); + } + } }/*
@@ -720,7 +727,7 @@ void efi_recover_from_page_fault(unsigned long phys_addr)/* * Make sure that an efi runtime service caused the page fault. * "efi_mm" cannot be used to check if the page fault had occurred -* in the firmware context because efi=old_map doesn't use efi_pgd. +* in the firmware context because the UV1 memmap doesn't use efi_pgd. */ if (efi_rts_work.efi_rts_id ==EFI_NONE )return ;
arch/x86/platform/uv/bios_uv.c +162 -2
175 lines not on this page · raw message
Signature · 1 line
2.20.1