Commit 83e68189 authored by Matt Fleming's avatar Matt Fleming Committed by H. Peter Anvin

efi: Make 'efi_enabled' a function to query EFI facilities

Originally 'efi_enabled' indicated whether a kernel was booted from
EFI firmware. Over time its semantics have changed, and it now
indicates whether or not we are booted on an EFI machine with
bit-native firmware, e.g. 64-bit kernel with 64-bit firmware.

The immediate motivation for this patch is the bug report at,

    https://bugs.launchpad.net/ubuntu-cdimage/+bug/1040557

which details how running a platform driver on an EFI machine that is
designed to run under BIOS can cause the machine to become
bricked. Also, the following report,

    https://bugzilla.kernel.org/show_bug.cgi?id=47121

details how running said driver can also cause Machine Check
Exceptions. Drivers need a new means of detecting whether they're
running on an EFI machine, as sadly the expression,

    if (!efi_enabled)

hasn't been a sufficient condition for quite some time.

Users actually want to query 'efi_enabled' for different reasons -
what they really want access to is the list of available EFI
facilities.

For instance, the x86 reboot code needs to know whether it can invoke
the ResetSystem() function provided by the EFI runtime services, while
the ACPI OSL code wants to know whether the EFI config tables were
mapped successfully. There are also checks in some of the platform
driver code to simply see if they're running on an EFI machine (which
would make it a bad idea to do BIOS-y things).

This patch is a prereq for the samsung-laptop fix patch.

Cc: David Airlie <airlied@linux.ie>
Cc: Corentin Chary <corentincj@iksaif.net>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Dave Jiang <dave.jiang@intel.com>
Cc: Olof Johansson <olof@lixom.net>
Cc: Peter Jones <pjones@redhat.com>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: Steve Langasek <steve.langasek@canonical.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Konrad Rzeszutek Wilk <konrad@kernel.org>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent f44310b9
...@@ -94,6 +94,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, ...@@ -94,6 +94,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
extern int add_efi_memmap; extern int add_efi_memmap;
extern unsigned long x86_efi_facility;
extern void efi_set_executable(efi_memory_desc_t *md, bool executable); extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
extern int efi_memblock_x86_reserve_range(void); extern int efi_memblock_x86_reserve_range(void);
extern void efi_call_phys_prelog(void); extern void efi_call_phys_prelog(void);
......
...@@ -584,7 +584,7 @@ static void native_machine_emergency_restart(void) ...@@ -584,7 +584,7 @@ static void native_machine_emergency_restart(void)
break; break;
case BOOT_EFI: case BOOT_EFI:
if (efi_enabled) if (efi_enabled(EFI_RUNTIME_SERVICES))
efi.reset_system(reboot_mode ? efi.reset_system(reboot_mode ?
EFI_RESET_WARM : EFI_RESET_WARM :
EFI_RESET_COLD, EFI_RESET_COLD,
......
...@@ -807,15 +807,15 @@ void __init setup_arch(char **cmdline_p) ...@@ -807,15 +807,15 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL32", 4)) { "EL32", 4)) {
efi_enabled = 1; set_bit(EFI_BOOT, &x86_efi_facility);
efi_64bit = false;
} else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
"EL64", 4)) { "EL64", 4)) {
efi_enabled = 1; set_bit(EFI_BOOT, &x86_efi_facility);
efi_64bit = true; set_bit(EFI_64BIT, &x86_efi_facility);
} }
if (efi_enabled && efi_memblock_x86_reserve_range())
efi_enabled = 0; if (efi_enabled(EFI_BOOT))
efi_memblock_x86_reserve_range();
#endif #endif
x86_init.oem.arch_setup(); x86_init.oem.arch_setup();
...@@ -888,7 +888,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -888,7 +888,7 @@ void __init setup_arch(char **cmdline_p)
finish_e820_parsing(); finish_e820_parsing();
if (efi_enabled) if (efi_enabled(EFI_BOOT))
efi_init(); efi_init();
dmi_scan_machine(); dmi_scan_machine();
...@@ -971,7 +971,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -971,7 +971,7 @@ void __init setup_arch(char **cmdline_p)
* The EFI specification says that boot service code won't be called * The EFI specification says that boot service code won't be called
* after ExitBootServices(). This is, in fact, a lie. * after ExitBootServices(). This is, in fact, a lie.
*/ */
if (efi_enabled) if (efi_enabled(EFI_MEMMAP))
efi_reserve_boot_services(); efi_reserve_boot_services();
/* preallocate 4k for mptable mpc */ /* preallocate 4k for mptable mpc */
...@@ -1114,7 +1114,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -1114,7 +1114,7 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_VT #ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE) #if defined(CONFIG_VGA_CONSOLE)
if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
conswitchp = &vga_con; conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE) #elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con; conswitchp = &dummy_con;
...@@ -1131,14 +1131,14 @@ void __init setup_arch(char **cmdline_p) ...@@ -1131,14 +1131,14 @@ void __init setup_arch(char **cmdline_p)
register_refined_jiffies(CLOCK_TICK_RATE); register_refined_jiffies(CLOCK_TICK_RATE);
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
/* Once setup is done above, disable efi_enabled on mismatched /* Once setup is done above, unmap the EFI memory map on
* firmware/kernel archtectures since there is no support for * mismatched firmware/kernel archtectures since there is no
* runtime services. * support for runtime services.
*/ */
if (efi_enabled && IS_ENABLED(CONFIG_X86_64) != efi_64bit) { if (efi_enabled(EFI_BOOT) &&
IS_ENABLED(CONFIG_X86_64) != efi_enabled(EFI_64BIT)) {
pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
efi_unmap_memmap(); efi_unmap_memmap();
efi_enabled = 0;
} }
#endif #endif
} }
......
...@@ -51,9 +51,6 @@ ...@@ -51,9 +51,6 @@
#define EFI_DEBUG 1 #define EFI_DEBUG 1
int efi_enabled;
EXPORT_SYMBOL(efi_enabled);
struct efi __read_mostly efi = { struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR, .mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR, .acpi = EFI_INVALID_TABLE_ADDR,
...@@ -69,19 +66,28 @@ EXPORT_SYMBOL(efi); ...@@ -69,19 +66,28 @@ EXPORT_SYMBOL(efi);
struct efi_memory_map memmap; struct efi_memory_map memmap;
bool efi_64bit;
static struct efi efi_phys __initdata; static struct efi efi_phys __initdata;
static efi_system_table_t efi_systab __initdata; static efi_system_table_t efi_systab __initdata;
static inline bool efi_is_native(void) static inline bool efi_is_native(void)
{ {
return IS_ENABLED(CONFIG_X86_64) == efi_64bit; return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
}
unsigned long x86_efi_facility;
/*
* Returns 1 if 'facility' is enabled, 0 otherwise.
*/
int efi_enabled(int facility)
{
return test_bit(facility, &x86_efi_facility) != 0;
} }
EXPORT_SYMBOL(efi_enabled);
static int __init setup_noefi(char *arg) static int __init setup_noefi(char *arg)
{ {
efi_enabled = 0; clear_bit(EFI_BOOT, &x86_efi_facility);
return 0; return 0;
} }
early_param("noefi", setup_noefi); early_param("noefi", setup_noefi);
...@@ -426,6 +432,7 @@ void __init efi_reserve_boot_services(void) ...@@ -426,6 +432,7 @@ void __init efi_reserve_boot_services(void)
void __init efi_unmap_memmap(void) void __init efi_unmap_memmap(void)
{ {
clear_bit(EFI_MEMMAP, &x86_efi_facility);
if (memmap.map) { if (memmap.map) {
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL; memmap.map = NULL;
...@@ -460,7 +467,7 @@ void __init efi_free_boot_services(void) ...@@ -460,7 +467,7 @@ void __init efi_free_boot_services(void)
static int __init efi_systab_init(void *phys) static int __init efi_systab_init(void *phys)
{ {
if (efi_64bit) { if (efi_enabled(EFI_64BIT)) {
efi_system_table_64_t *systab64; efi_system_table_64_t *systab64;
u64 tmp = 0; u64 tmp = 0;
...@@ -552,7 +559,7 @@ static int __init efi_config_init(u64 tables, int nr_tables) ...@@ -552,7 +559,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
void *config_tables, *tablep; void *config_tables, *tablep;
int i, sz; int i, sz;
if (efi_64bit) if (efi_enabled(EFI_64BIT))
sz = sizeof(efi_config_table_64_t); sz = sizeof(efi_config_table_64_t);
else else
sz = sizeof(efi_config_table_32_t); sz = sizeof(efi_config_table_32_t);
...@@ -572,7 +579,7 @@ static int __init efi_config_init(u64 tables, int nr_tables) ...@@ -572,7 +579,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
efi_guid_t guid; efi_guid_t guid;
unsigned long table; unsigned long table;
if (efi_64bit) { if (efi_enabled(EFI_64BIT)) {
u64 table64; u64 table64;
guid = ((efi_config_table_64_t *)tablep)->guid; guid = ((efi_config_table_64_t *)tablep)->guid;
table64 = ((efi_config_table_64_t *)tablep)->table; table64 = ((efi_config_table_64_t *)tablep)->table;
...@@ -684,7 +691,6 @@ void __init efi_init(void) ...@@ -684,7 +691,6 @@ void __init efi_init(void)
if (boot_params.efi_info.efi_systab_hi || if (boot_params.efi_info.efi_systab_hi ||
boot_params.efi_info.efi_memmap_hi) { boot_params.efi_info.efi_memmap_hi) {
pr_info("Table located above 4GB, disabling EFI.\n"); pr_info("Table located above 4GB, disabling EFI.\n");
efi_enabled = 0;
return; return;
} }
efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
...@@ -694,10 +700,10 @@ void __init efi_init(void) ...@@ -694,10 +700,10 @@ void __init efi_init(void)
((__u64)boot_params.efi_info.efi_systab_hi<<32)); ((__u64)boot_params.efi_info.efi_systab_hi<<32));
#endif #endif
if (efi_systab_init(efi_phys.systab)) { if (efi_systab_init(efi_phys.systab))
efi_enabled = 0;
return; return;
}
set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
/* /*
* Show what we know for posterity * Show what we know for posterity
...@@ -715,10 +721,10 @@ void __init efi_init(void) ...@@ -715,10 +721,10 @@ void __init efi_init(void)
efi.systab->hdr.revision >> 16, efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor); efi.systab->hdr.revision & 0xffff, vendor);
if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) { if (efi_config_init(efi.systab->tables, efi.systab->nr_tables))
efi_enabled = 0;
return; return;
}
set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
/* /*
* Note: We currently don't support runtime services on an EFI * Note: We currently don't support runtime services on an EFI
...@@ -727,15 +733,17 @@ void __init efi_init(void) ...@@ -727,15 +733,17 @@ void __init efi_init(void)
if (!efi_is_native()) if (!efi_is_native())
pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
else if (efi_runtime_init()) { else {
efi_enabled = 0; if (efi_runtime_init())
return; return;
set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
} }
if (efi_memmap_init()) { if (efi_memmap_init())
efi_enabled = 0;
return; return;
}
set_bit(EFI_MEMMAP, &x86_efi_facility);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (efi_is_native()) { if (efi_is_native()) {
x86_platform.get_wallclock = efi_get_time; x86_platform.get_wallclock = efi_get_time;
...@@ -969,6 +977,9 @@ u32 efi_mem_type(unsigned long phys_addr) ...@@ -969,6 +977,9 @@ u32 efi_mem_type(unsigned long phys_addr)
efi_memory_desc_t *md; efi_memory_desc_t *md;
void *p; void *p;
if (!efi_enabled(EFI_MEMMAP))
return 0;
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p; md = p;
if ((md->phys_addr <= phys_addr) && if ((md->phys_addr <= phys_addr) &&
......
...@@ -250,7 +250,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) ...@@ -250,7 +250,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
return acpi_rsdp; return acpi_rsdp;
#endif #endif
if (efi_enabled) { if (efi_enabled(EFI_CONFIG_TABLES)) {
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
return efi.acpi20; return efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR) else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
......
...@@ -471,7 +471,7 @@ void __init dmi_scan_machine(void) ...@@ -471,7 +471,7 @@ void __init dmi_scan_machine(void)
char __iomem *p, *q; char __iomem *p, *q;
int rc; int rc;
if (efi_enabled) { if (efi_enabled(EFI_CONFIG_TABLES)) {
if (efi.smbios == EFI_INVALID_TABLE_ADDR) if (efi.smbios == EFI_INVALID_TABLE_ADDR)
goto error; goto error;
......
...@@ -1782,7 +1782,7 @@ efivars_init(void) ...@@ -1782,7 +1782,7 @@ efivars_init(void)
printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
EFIVARS_DATE); EFIVARS_DATE);
if (!efi_enabled) if (!efi_enabled(EFI_RUNTIME_SERVICES))
return 0; return 0;
/* For now we'll register the efi directory at /sys/firmware/efi */ /* For now we'll register the efi directory at /sys/firmware/efi */
...@@ -1822,7 +1822,7 @@ efivars_init(void) ...@@ -1822,7 +1822,7 @@ efivars_init(void)
static void __exit static void __exit
efivars_exit(void) efivars_exit(void)
{ {
if (efi_enabled) { if (efi_enabled(EFI_RUNTIME_SERVICES)) {
unregister_efivars(&__efivars); unregister_efivars(&__efivars);
kobject_put(efi_kobj); kobject_put(efi_kobj);
} }
......
...@@ -99,7 +99,7 @@ unsigned long __init find_ibft_region(unsigned long *sizep) ...@@ -99,7 +99,7 @@ unsigned long __init find_ibft_region(unsigned long *sizep)
/* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
* only use ACPI for this */ * only use ACPI for this */
if (!efi_enabled) if (!efi_enabled(EFI_BOOT))
find_ibft_in_mem(); find_ibft_in_mem();
if (ibft_addr) { if (ibft_addr) {
......
...@@ -429,7 +429,8 @@ bool radeon_card_posted(struct radeon_device *rdev) ...@@ -429,7 +429,8 @@ bool radeon_card_posted(struct radeon_device *rdev)
{ {
uint32_t reg; uint32_t reg;
if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) if (efi_enabled(EFI_BOOT) &&
rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
return false; return false;
/* first check CRTCs */ /* first check CRTCs */
......
...@@ -244,7 +244,7 @@ static int __init ibm_rtl_init(void) { ...@@ -244,7 +244,7 @@ static int __init ibm_rtl_init(void) {
if (force) if (force)
pr_warn("module loaded by force\n"); pr_warn("module loaded by force\n");
/* first ensure that we are running on IBM HW */ /* first ensure that we are running on IBM HW */
else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table)) else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table))
return -ENODEV; return -ENODEV;
/* Get the address for the Extended BIOS Data Area */ /* Get the address for the Extended BIOS Data Area */
......
...@@ -633,7 +633,7 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -633,7 +633,7 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM; return -ENOMEM;
pci_set_drvdata(pdev, pci_info); pci_set_drvdata(pdev, pci_info);
if (efi_enabled) if (efi_enabled(EFI_RUNTIME_SERVICES))
orom = isci_get_efi_var(pdev); orom = isci_get_efi_var(pdev);
if (!orom) if (!orom)
......
...@@ -618,18 +618,30 @@ extern int __init efi_setup_pcdp_console(char *); ...@@ -618,18 +618,30 @@ extern int __init efi_setup_pcdp_console(char *);
#endif #endif
/* /*
* We play games with efi_enabled so that the compiler will, if possible, remove * We play games with efi_enabled so that the compiler will, if
* EFI-related code altogether. * possible, remove EFI-related code altogether.
*/ */
#define EFI_BOOT 0 /* Were we booted from EFI? */
#define EFI_SYSTEM_TABLES 1 /* Can we use EFI system tables? */
#define EFI_CONFIG_TABLES 2 /* Can we use EFI config tables? */
#define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */
#define EFI_MEMMAP 4 /* Can we use EFI memory map? */
#define EFI_64BIT 5 /* Is the firmware 64-bit? */
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
# ifdef CONFIG_X86 # ifdef CONFIG_X86
extern int efi_enabled; extern int efi_enabled(int facility);
extern bool efi_64bit;
# else # else
# define efi_enabled 1 static inline int efi_enabled(int facility)
{
return 1;
}
# endif # endif
#else #else
# define efi_enabled 0 static inline int efi_enabled(int facility)
{
return 0;
}
#endif #endif
/* /*
......
...@@ -604,7 +604,7 @@ asmlinkage void __init start_kernel(void) ...@@ -604,7 +604,7 @@ asmlinkage void __init start_kernel(void)
pidmap_init(); pidmap_init();
anon_vma_init(); anon_vma_init();
#ifdef CONFIG_X86 #ifdef CONFIG_X86
if (efi_enabled) if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode(); efi_enter_virtual_mode();
#endif #endif
thread_info_cache_init(); thread_info_cache_init();
...@@ -632,7 +632,7 @@ asmlinkage void __init start_kernel(void) ...@@ -632,7 +632,7 @@ asmlinkage void __init start_kernel(void)
acpi_early_init(); /* before LAPIC and SMP init */ acpi_early_init(); /* before LAPIC and SMP init */
sfi_init_late(); sfi_init_late();
if (efi_enabled) { if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_late_init(); efi_late_init();
efi_free_boot_services(); efi_free_boot_services();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment