aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-11-14 04:42:35 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2013-01-30 14:51:59 -0500
commit83e68189745ad931c2afd45d8ee3303929233e7f (patch)
tree35673a4eebff4c71bda4b1023ccc7cbea36f84b2 /arch
parentf44310b98ddb7f0d06550d73ed67df5865e3eda5 (diff)
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: Matt Fleming <matt.fleming@intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/efi.h1
-rw-r--r--arch/x86/kernel/reboot.c2
-rw-r--r--arch/x86/kernel/setup.c28
-rw-r--r--arch/x86/platform/efi/efi.c57
4 files changed, 50 insertions, 38 deletions
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 6e8fdf5ad113..28677c55113f 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -94,6 +94,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
94#endif /* CONFIG_X86_32 */ 94#endif /* CONFIG_X86_32 */
95 95
96extern int add_efi_memmap; 96extern int add_efi_memmap;
97extern unsigned long x86_efi_facility;
97extern void efi_set_executable(efi_memory_desc_t *md, bool executable); 98extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
98extern int efi_memblock_x86_reserve_range(void); 99extern int efi_memblock_x86_reserve_range(void);
99extern void efi_call_phys_prelog(void); 100extern void efi_call_phys_prelog(void);
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 4e8ba39eaf0f..76fa1e9a2b39 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -584,7 +584,7 @@ static void native_machine_emergency_restart(void)
584 break; 584 break;
585 585
586 case BOOT_EFI: 586 case BOOT_EFI:
587 if (efi_enabled) 587 if (efi_enabled(EFI_RUNTIME_SERVICES))
588 efi.reset_system(reboot_mode ? 588 efi.reset_system(reboot_mode ?
589 EFI_RESET_WARM : 589 EFI_RESET_WARM :
590 EFI_RESET_COLD, 590 EFI_RESET_COLD,
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 00f6c1472b85..8b24289cc10c 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -807,15 +807,15 @@ void __init setup_arch(char **cmdline_p)
807#ifdef CONFIG_EFI 807#ifdef CONFIG_EFI
808 if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, 808 if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
809 "EL32", 4)) { 809 "EL32", 4)) {
810 efi_enabled = 1; 810 set_bit(EFI_BOOT, &x86_efi_facility);
811 efi_64bit = false;
812 } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, 811 } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
813 "EL64", 4)) { 812 "EL64", 4)) {
814 efi_enabled = 1; 813 set_bit(EFI_BOOT, &x86_efi_facility);
815 efi_64bit = true; 814 set_bit(EFI_64BIT, &x86_efi_facility);
816 } 815 }
817 if (efi_enabled && efi_memblock_x86_reserve_range()) 816
818 efi_enabled = 0; 817 if (efi_enabled(EFI_BOOT))
818 efi_memblock_x86_reserve_range();
819#endif 819#endif
820 820
821 x86_init.oem.arch_setup(); 821 x86_init.oem.arch_setup();
@@ -888,7 +888,7 @@ void __init setup_arch(char **cmdline_p)
888 888
889 finish_e820_parsing(); 889 finish_e820_parsing();
890 890
891 if (efi_enabled) 891 if (efi_enabled(EFI_BOOT))
892 efi_init(); 892 efi_init();
893 893
894 dmi_scan_machine(); 894 dmi_scan_machine();
@@ -971,7 +971,7 @@ void __init setup_arch(char **cmdline_p)
971 * The EFI specification says that boot service code won't be called 971 * The EFI specification says that boot service code won't be called
972 * after ExitBootServices(). This is, in fact, a lie. 972 * after ExitBootServices(). This is, in fact, a lie.
973 */ 973 */
974 if (efi_enabled) 974 if (efi_enabled(EFI_MEMMAP))
975 efi_reserve_boot_services(); 975 efi_reserve_boot_services();
976 976
977 /* preallocate 4k for mptable mpc */ 977 /* preallocate 4k for mptable mpc */
@@ -1114,7 +1114,7 @@ void __init setup_arch(char **cmdline_p)
1114 1114
1115#ifdef CONFIG_VT 1115#ifdef CONFIG_VT
1116#if defined(CONFIG_VGA_CONSOLE) 1116#if defined(CONFIG_VGA_CONSOLE)
1117 if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) 1117 if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
1118 conswitchp = &vga_con; 1118 conswitchp = &vga_con;
1119#elif defined(CONFIG_DUMMY_CONSOLE) 1119#elif defined(CONFIG_DUMMY_CONSOLE)
1120 conswitchp = &dummy_con; 1120 conswitchp = &dummy_con;
@@ -1131,14 +1131,14 @@ void __init setup_arch(char **cmdline_p)
1131 register_refined_jiffies(CLOCK_TICK_RATE); 1131 register_refined_jiffies(CLOCK_TICK_RATE);
1132 1132
1133#ifdef CONFIG_EFI 1133#ifdef CONFIG_EFI
1134 /* Once setup is done above, disable efi_enabled on mismatched 1134 /* Once setup is done above, unmap the EFI memory map on
1135 * firmware/kernel archtectures since there is no support for 1135 * mismatched firmware/kernel archtectures since there is no
1136 * runtime services. 1136 * support for runtime services.
1137 */ 1137 */
1138 if (efi_enabled && IS_ENABLED(CONFIG_X86_64) != efi_64bit) { 1138 if (efi_enabled(EFI_BOOT) &&
1139 IS_ENABLED(CONFIG_X86_64) != efi_enabled(EFI_64BIT)) {
1139 pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); 1140 pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
1140 efi_unmap_memmap(); 1141 efi_unmap_memmap();
1141 efi_enabled = 0;
1142 } 1142 }
1143#endif 1143#endif
1144} 1144}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index ad4439145f85..5426e482db6e 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -51,9 +51,6 @@
51 51
52#define EFI_DEBUG 1 52#define EFI_DEBUG 1
53 53
54int efi_enabled;
55EXPORT_SYMBOL(efi_enabled);
56
57struct efi __read_mostly efi = { 54struct efi __read_mostly efi = {
58 .mps = EFI_INVALID_TABLE_ADDR, 55 .mps = EFI_INVALID_TABLE_ADDR,
59 .acpi = EFI_INVALID_TABLE_ADDR, 56 .acpi = EFI_INVALID_TABLE_ADDR,
@@ -69,19 +66,28 @@ EXPORT_SYMBOL(efi);
69 66
70struct efi_memory_map memmap; 67struct efi_memory_map memmap;
71 68
72bool efi_64bit;
73
74static struct efi efi_phys __initdata; 69static struct efi efi_phys __initdata;
75static efi_system_table_t efi_systab __initdata; 70static efi_system_table_t efi_systab __initdata;
76 71
77static inline bool efi_is_native(void) 72static inline bool efi_is_native(void)
78{ 73{
79 return IS_ENABLED(CONFIG_X86_64) == efi_64bit; 74 return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
75}
76
77unsigned long x86_efi_facility;
78
79/*
80 * Returns 1 if 'facility' is enabled, 0 otherwise.
81 */
82int efi_enabled(int facility)
83{
84 return test_bit(facility, &x86_efi_facility) != 0;
80} 85}
86EXPORT_SYMBOL(efi_enabled);
81 87
82static int __init setup_noefi(char *arg) 88static int __init setup_noefi(char *arg)
83{ 89{
84 efi_enabled = 0; 90 clear_bit(EFI_BOOT, &x86_efi_facility);
85 return 0; 91 return 0;
86} 92}
87early_param("noefi", setup_noefi); 93early_param("noefi", setup_noefi);
@@ -426,6 +432,7 @@ void __init efi_reserve_boot_services(void)
426 432
427void __init efi_unmap_memmap(void) 433void __init efi_unmap_memmap(void)
428{ 434{
435 clear_bit(EFI_MEMMAP, &x86_efi_facility);
429 if (memmap.map) { 436 if (memmap.map) {
430 early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); 437 early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
431 memmap.map = NULL; 438 memmap.map = NULL;
@@ -460,7 +467,7 @@ void __init efi_free_boot_services(void)
460 467
461static int __init efi_systab_init(void *phys) 468static int __init efi_systab_init(void *phys)
462{ 469{
463 if (efi_64bit) { 470 if (efi_enabled(EFI_64BIT)) {
464 efi_system_table_64_t *systab64; 471 efi_system_table_64_t *systab64;
465 u64 tmp = 0; 472 u64 tmp = 0;
466 473
@@ -552,7 +559,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
552 void *config_tables, *tablep; 559 void *config_tables, *tablep;
553 int i, sz; 560 int i, sz;
554 561
555 if (efi_64bit) 562 if (efi_enabled(EFI_64BIT))
556 sz = sizeof(efi_config_table_64_t); 563 sz = sizeof(efi_config_table_64_t);
557 else 564 else
558 sz = sizeof(efi_config_table_32_t); 565 sz = sizeof(efi_config_table_32_t);
@@ -572,7 +579,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
572 efi_guid_t guid; 579 efi_guid_t guid;
573 unsigned long table; 580 unsigned long table;
574 581
575 if (efi_64bit) { 582 if (efi_enabled(EFI_64BIT)) {
576 u64 table64; 583 u64 table64;
577 guid = ((efi_config_table_64_t *)tablep)->guid; 584 guid = ((efi_config_table_64_t *)tablep)->guid;
578 table64 = ((efi_config_table_64_t *)tablep)->table; 585 table64 = ((efi_config_table_64_t *)tablep)->table;
@@ -684,7 +691,6 @@ void __init efi_init(void)
684 if (boot_params.efi_info.efi_systab_hi || 691 if (boot_params.efi_info.efi_systab_hi ||
685 boot_params.efi_info.efi_memmap_hi) { 692 boot_params.efi_info.efi_memmap_hi) {
686 pr_info("Table located above 4GB, disabling EFI.\n"); 693 pr_info("Table located above 4GB, disabling EFI.\n");
687 efi_enabled = 0;
688 return; 694 return;
689 } 695 }
690 efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; 696 efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
@@ -694,10 +700,10 @@ void __init efi_init(void)
694 ((__u64)boot_params.efi_info.efi_systab_hi<<32)); 700 ((__u64)boot_params.efi_info.efi_systab_hi<<32));
695#endif 701#endif
696 702
697 if (efi_systab_init(efi_phys.systab)) { 703 if (efi_systab_init(efi_phys.systab))
698 efi_enabled = 0;
699 return; 704 return;
700 } 705
706 set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
701 707
702 /* 708 /*
703 * Show what we know for posterity 709 * Show what we know for posterity
@@ -715,10 +721,10 @@ void __init efi_init(void)
715 efi.systab->hdr.revision >> 16, 721 efi.systab->hdr.revision >> 16,
716 efi.systab->hdr.revision & 0xffff, vendor); 722 efi.systab->hdr.revision & 0xffff, vendor);
717 723
718 if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) { 724 if (efi_config_init(efi.systab->tables, efi.systab->nr_tables))
719 efi_enabled = 0;
720 return; 725 return;
721 } 726
727 set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
722 728
723 /* 729 /*
724 * Note: We currently don't support runtime services on an EFI 730 * Note: We currently don't support runtime services on an EFI
@@ -727,15 +733,17 @@ void __init efi_init(void)
727 733
728 if (!efi_is_native()) 734 if (!efi_is_native())
729 pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); 735 pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
730 else if (efi_runtime_init()) { 736 else {
731 efi_enabled = 0; 737 if (efi_runtime_init())
732 return; 738 return;
739 set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
733 } 740 }
734 741
735 if (efi_memmap_init()) { 742 if (efi_memmap_init())
736 efi_enabled = 0;
737 return; 743 return;
738 } 744
745 set_bit(EFI_MEMMAP, &x86_efi_facility);
746
739#ifdef CONFIG_X86_32 747#ifdef CONFIG_X86_32
740 if (efi_is_native()) { 748 if (efi_is_native()) {
741 x86_platform.get_wallclock = efi_get_time; 749 x86_platform.get_wallclock = efi_get_time;
@@ -969,6 +977,9 @@ u32 efi_mem_type(unsigned long phys_addr)
969 efi_memory_desc_t *md; 977 efi_memory_desc_t *md;
970 void *p; 978 void *p;
971 979
980 if (!efi_enabled(EFI_MEMMAP))
981 return 0;
982
972 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 983 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
973 md = p; 984 md = p;
974 if ((md->phys_addr <= phys_addr) && 985 if ((md->phys_addr <= phys_addr) &&