|
@@ -68,6 +68,9 @@ EXPORT_SYMBOL(efi);
|
|
|
|
|
|
struct efi_memory_map memmap;
|
|
|
|
|
|
+bool efi_64bit;
|
|
|
+static bool efi_native;
|
|
|
+
|
|
|
static struct efi efi_phys __initdata;
|
|
|
static efi_system_table_t efi_systab __initdata;
|
|
|
|
|
@@ -339,11 +342,16 @@ static void __init do_add_efi_memmap(void)
|
|
|
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
|
|
|
}
|
|
|
|
|
|
-void __init efi_memblock_x86_reserve_range(void)
|
|
|
+int __init efi_memblock_x86_reserve_range(void)
|
|
|
{
|
|
|
unsigned long pmap;
|
|
|
|
|
|
#ifdef CONFIG_X86_32
|
|
|
+ /* Can't handle data above 4GB at this time */
|
|
|
+ if (boot_params.efi_info.efi_memmap_hi) {
|
|
|
+ pr_err("Memory map is above 4GB, disabling EFI.\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
pmap = boot_params.efi_info.efi_memmap;
|
|
|
#else
|
|
|
pmap = (boot_params.efi_info.efi_memmap |
|
|
@@ -355,6 +363,8 @@ void __init efi_memblock_x86_reserve_range(void)
|
|
|
memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
|
|
|
memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
|
|
|
memblock_reserve(pmap, memmap.nr_map * memmap.desc_size);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#if EFI_DEBUG
|
|
@@ -432,14 +442,75 @@ static void __init efi_free_boot_services(void)
|
|
|
|
|
|
static int __init efi_systab_init(void *phys)
|
|
|
{
|
|
|
- efi.systab = early_ioremap((unsigned long)efi_phys.systab,
|
|
|
- sizeof(efi_system_table_t));
|
|
|
- if (efi.systab == NULL) {
|
|
|
- pr_err("Couldn't map the system table!\n");
|
|
|
- return -ENOMEM;
|
|
|
+ if (efi_64bit) {
|
|
|
+ efi_system_table_64_t *systab64;
|
|
|
+ u64 tmp = 0;
|
|
|
+
|
|
|
+ systab64 = early_ioremap((unsigned long)phys,
|
|
|
+ sizeof(*systab64));
|
|
|
+ if (systab64 == NULL) {
|
|
|
+ pr_err("Couldn't map the system table!\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ efi_systab.hdr = systab64->hdr;
|
|
|
+ efi_systab.fw_vendor = systab64->fw_vendor;
|
|
|
+ tmp |= systab64->fw_vendor;
|
|
|
+ efi_systab.fw_revision = systab64->fw_revision;
|
|
|
+ efi_systab.con_in_handle = systab64->con_in_handle;
|
|
|
+ tmp |= systab64->con_in_handle;
|
|
|
+ efi_systab.con_in = systab64->con_in;
|
|
|
+ tmp |= systab64->con_in;
|
|
|
+ efi_systab.con_out_handle = systab64->con_out_handle;
|
|
|
+ tmp |= systab64->con_out_handle;
|
|
|
+ efi_systab.con_out = systab64->con_out;
|
|
|
+ tmp |= systab64->con_out;
|
|
|
+ efi_systab.stderr_handle = systab64->stderr_handle;
|
|
|
+ tmp |= systab64->stderr_handle;
|
|
|
+ efi_systab.stderr = systab64->stderr;
|
|
|
+ tmp |= systab64->stderr;
|
|
|
+ efi_systab.runtime = (void *)(unsigned long)systab64->runtime;
|
|
|
+ tmp |= systab64->runtime;
|
|
|
+ efi_systab.boottime = (void *)(unsigned long)systab64->boottime;
|
|
|
+ tmp |= systab64->boottime;
|
|
|
+ efi_systab.nr_tables = systab64->nr_tables;
|
|
|
+ efi_systab.tables = systab64->tables;
|
|
|
+ tmp |= systab64->tables;
|
|
|
+
|
|
|
+ early_iounmap(systab64, sizeof(*systab64));
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ if (tmp >> 32) {
|
|
|
+ pr_err("EFI data located above 4GB, disabling EFI.\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ } else {
|
|
|
+ efi_system_table_32_t *systab32;
|
|
|
+
|
|
|
+ systab32 = early_ioremap((unsigned long)phys,
|
|
|
+ sizeof(*systab32));
|
|
|
+ if (systab32 == NULL) {
|
|
|
+ pr_err("Couldn't map the system table!\n");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ efi_systab.hdr = systab32->hdr;
|
|
|
+ efi_systab.fw_vendor = systab32->fw_vendor;
|
|
|
+ efi_systab.fw_revision = systab32->fw_revision;
|
|
|
+ efi_systab.con_in_handle = systab32->con_in_handle;
|
|
|
+ efi_systab.con_in = systab32->con_in;
|
|
|
+ efi_systab.con_out_handle = systab32->con_out_handle;
|
|
|
+ efi_systab.con_out = systab32->con_out;
|
|
|
+ efi_systab.stderr_handle = systab32->stderr_handle;
|
|
|
+ efi_systab.stderr = systab32->stderr;
|
|
|
+ efi_systab.runtime = (void *)(unsigned long)systab32->runtime;
|
|
|
+ efi_systab.boottime = (void *)(unsigned long)systab32->boottime;
|
|
|
+ efi_systab.nr_tables = systab32->nr_tables;
|
|
|
+ efi_systab.tables = systab32->tables;
|
|
|
+
|
|
|
+ early_iounmap(systab32, sizeof(*systab32));
|
|
|
}
|
|
|
- memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
|
|
|
- early_iounmap(efi.systab, sizeof(efi_system_table_t));
|
|
|
+
|
|
|
efi.systab = &efi_systab;
|
|
|
|
|
|
/*
|
|
@@ -460,24 +531,47 @@ static int __init efi_systab_init(void *phys)
|
|
|
|
|
|
static int __init efi_config_init(u64 tables, int nr_tables)
|
|
|
{
|
|
|
- efi_config_table_t *config_tables;
|
|
|
- int i, sz = sizeof(efi_config_table_t);
|
|
|
+ void *config_tables, *tablep;
|
|
|
+ int i, sz;
|
|
|
+
|
|
|
+ if (efi_64bit)
|
|
|
+ sz = sizeof(efi_config_table_64_t);
|
|
|
+ else
|
|
|
+ sz = sizeof(efi_config_table_32_t);
|
|
|
|
|
|
/*
|
|
|
* Let's see what config tables the firmware passed to us.
|
|
|
*/
|
|
|
- config_tables = early_ioremap(efi.systab->tables,
|
|
|
- efi.systab->nr_tables * sz);
|
|
|
+ config_tables = early_ioremap(tables, nr_tables * sz);
|
|
|
if (config_tables == NULL) {
|
|
|
pr_err("Could not map Configuration table!\n");
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
+ tablep = config_tables;
|
|
|
pr_info("");
|
|
|
for (i = 0; i < efi.systab->nr_tables; i++) {
|
|
|
- efi_guid_t guid = config_tables[i].guid;
|
|
|
- unsigned long table = config_tables[i].table;
|
|
|
-
|
|
|
+ efi_guid_t guid;
|
|
|
+ unsigned long table;
|
|
|
+
|
|
|
+ if (efi_64bit) {
|
|
|
+ u64 table64;
|
|
|
+ guid = ((efi_config_table_64_t *)tablep)->guid;
|
|
|
+ table64 = ((efi_config_table_64_t *)tablep)->table;
|
|
|
+ table = table64;
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ if (table64 >> 32) {
|
|
|
+ pr_cont("\n");
|
|
|
+ pr_err("Table located above 4GB, disabling EFI.\n");
|
|
|
+ early_iounmap(config_tables,
|
|
|
+ efi.systab->nr_tables * sz);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ } else {
|
|
|
+ guid = ((efi_config_table_32_t *)tablep)->guid;
|
|
|
+ table = ((efi_config_table_32_t *)tablep)->table;
|
|
|
+ }
|
|
|
if (!efi_guidcmp(guid, MPS_TABLE_GUID)) {
|
|
|
efi.mps = table;
|
|
|
pr_cont(" MPS=0x%lx ", table);
|
|
@@ -502,10 +596,10 @@ static int __init efi_config_init(u64 tables, int nr_tables)
|
|
|
efi.uga = table;
|
|
|
pr_cont(" UGA=0x%lx ", table);
|
|
|
}
|
|
|
+ tablep += sz;
|
|
|
}
|
|
|
pr_cont("\n");
|
|
|
early_iounmap(config_tables, efi.systab->nr_tables * sz);
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -569,11 +663,19 @@ void __init efi_init(void)
|
|
|
void *tmp;
|
|
|
|
|
|
#ifdef CONFIG_X86_32
|
|
|
+ if (boot_params.efi_info.efi_systab_hi ||
|
|
|
+ boot_params.efi_info.efi_memmap_hi) {
|
|
|
+ pr_info("Table located above 4GB, disabling EFI.\n");
|
|
|
+ efi_enabled = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
|
|
|
+ efi_native = !efi_64bit;
|
|
|
#else
|
|
|
efi_phys.systab = (efi_system_table_t *)
|
|
|
- (boot_params.efi_info.efi_systab |
|
|
|
- ((__u64)boot_params.efi_info.efi_systab_hi<<32));
|
|
|
+ (boot_params.efi_info.efi_systab |
|
|
|
+ ((__u64)boot_params.efi_info.efi_systab_hi<<32));
|
|
|
+ efi_native = efi_64bit;
|
|
|
#endif
|
|
|
|
|
|
if (efi_systab_init(efi_phys.systab)) {
|
|
@@ -602,7 +704,14 @@ void __init efi_init(void)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (efi_runtime_init()) {
|
|
|
+ /*
|
|
|
+ * Note: We currently don't support runtime services on an EFI
|
|
|
+ * that doesn't match the kernel 32/64-bit mode.
|
|
|
+ */
|
|
|
+
|
|
|
+ if (!efi_native)
|
|
|
+ pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
|
|
|
+ else if (efi_runtime_init()) {
|
|
|
efi_enabled = 0;
|
|
|
return;
|
|
|
}
|
|
@@ -611,10 +720,11 @@ void __init efi_init(void)
|
|
|
efi_enabled = 0;
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
#ifdef CONFIG_X86_32
|
|
|
- x86_platform.get_wallclock = efi_get_time;
|
|
|
- x86_platform.set_wallclock = efi_set_rtc_mmss;
|
|
|
+ if (efi_native) {
|
|
|
+ x86_platform.get_wallclock = efi_get_time;
|
|
|
+ x86_platform.set_wallclock = efi_set_rtc_mmss;
|
|
|
+ }
|
|
|
#endif
|
|
|
|
|
|
#if EFI_DEBUG
|
|
@@ -672,6 +782,14 @@ void __init efi_enter_virtual_mode(void)
|
|
|
|
|
|
efi.systab = NULL;
|
|
|
|
|
|
+ /*
|
|
|
+ * We don't do virtual mode, since we don't do runtime services, on
|
|
|
+ * non-native EFI
|
|
|
+ */
|
|
|
+
|
|
|
+ if (!efi_native)
|
|
|
+ goto out;
|
|
|
+
|
|
|
/* Merge contiguous regions of the same type and attribute */
|
|
|
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
|
|
|
u64 prev_size;
|
|
@@ -787,6 +905,8 @@ void __init efi_enter_virtual_mode(void)
|
|
|
efi.query_capsule_caps = virt_efi_query_capsule_caps;
|
|
|
if (__supported_pte_mask & _PAGE_NX)
|
|
|
runtime_code_page_mkexec();
|
|
|
+
|
|
|
+out:
|
|
|
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
|
|
|
memmap.map = NULL;
|
|
|
kfree(new_memmap);
|