2012-02-08 00:27:11

by Olof Johansson

[permalink] [raw]
Subject: [PATCH v4 0/5] [RESEND] x86: efi: cleanups and basic 32/64-bit support

This series allows basic booting of a 32-bit kernel on 64-bit EFI and vice
versa. It's needed by Chrome OS, and we've been carrying a nasty hack
to do it that I've cleaned up and made sure it works in both directions.

Tested on Chrome OS for 64-bit EFI 32-bit kernel. Tested with an old
MacBook for 32-bit EFI, 64-bit kernel.

Note that this is required, but not sufficient, for full platform support for
EFI in a mixed environment. There is no handling of runtime services, and no
thunking for going in and out of firmware in a different mode.


Resend of the last posted version. Acked by Matt, and Matthew seems to be OK
with it as well (see http://marc.info/?l=linux-kernel&m=132578786105542).

Please consider for 3.4 merge window. Thanks!


-Olof


Changelog is:
v4:
* Removed bogus memdesc warning printout
* Fixed up printk formatting, removing redundant EFI output
* Some of the earlier cleanup was accidentally reverted by this patch, fixed.
* Reworded some messages to not have to line wrap printk strings

v3:
* Reorganized to a series of patches to make it easier to review, and
do some of the cleanups I had left out before.

v2:
* Added graceful error handling for 32-bit kernel that gets passed
EFI data above 4GB.
* Removed some warnings that were missed in first version.



2012-02-08 00:27:18

by Olof Johansson

[permalink] [raw]
Subject: [PATCH 3/5] x86: efi: cleanup config table walking

Trivial cleanup, move guid and table pointers to local copies to
make the code cleaner.

Signed-off-by: Olof Johansson <[email protected]>
Acked-by: Matt Fleming <[email protected]>
---
arch/x86/platform/efi/efi.c | 61 +++++++++++++++++++-----------------------
1 files changed, 28 insertions(+), 33 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 777de17..05e543d 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -462,53 +462,48 @@ static void __init efi_systab_init(void *phys)
static void __init efi_config_init(u64 tables, int nr_tables)
{
efi_config_table_t *config_tables;
- int i;
+ int i, sz = sizeof(efi_config_table_t);

/*
* Let's see what config tables the firmware passed to us.
*/
- config_tables = early_ioremap(
- efi.systab->tables,
- efi.systab->nr_tables * sizeof(efi_config_table_t));
+ config_tables = early_ioremap(efi.systab->tables,
+ efi.systab->nr_tables * sz);
if (config_tables == NULL)
pr_err("Could not map Configuration table!\n");

pr_info("");
for (i = 0; i < efi.systab->nr_tables; i++) {
- if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
- efi.mps = config_tables[i].table;
- pr_cont(" MPS=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- ACPI_20_TABLE_GUID)) {
- efi.acpi20 = config_tables[i].table;
- pr_cont(" ACPI 2.0=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- ACPI_TABLE_GUID)) {
- efi.acpi = config_tables[i].table;
- pr_cont(" ACPI=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- SMBIOS_TABLE_GUID)) {
- efi.smbios = config_tables[i].table;
- pr_cont(" SMBIOS=0x%lx ", config_tables[i].table);
+ efi_guid_t guid = config_tables[i].guid;
+ unsigned long table = config_tables[i].table;
+
+ if (!efi_guidcmp(guid, MPS_TABLE_GUID)) {
+ efi.mps = table;
+ pr_cont(" MPS=0x%lx ", table);
+ } else if (!efi_guidcmp(guid, ACPI_20_TABLE_GUID)) {
+ efi.acpi20 = table;
+ pr_cont(" ACPI 2.0=0x%lx ", table);
+ } else if (!efi_guidcmp(guid, ACPI_TABLE_GUID)) {
+ efi.acpi = table;
+ pr_cont(" ACPI=0x%lx ", table);
+ } else if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) {
+ efi.smbios = table;
+ pr_cont(" SMBIOS=0x%lx ", table);
#ifdef CONFIG_X86_UV
- } else if (!efi_guidcmp(config_tables[i].guid,
- UV_SYSTEM_TABLE_GUID)) {
- efi.uv_systab = config_tables[i].table;
- pr_cont(" UVsystab=0x%lx ", config_tables[i].table);
+ } else if (!efi_guidcmp(guid, UV_SYSTEM_TABLE_GUID)) {
+ efi.uv_systab = table;
+ pr_cont(" UVsystab=0x%lx ", table);
#endif
- } else if (!efi_guidcmp(config_tables[i].guid,
- HCDP_TABLE_GUID)) {
- efi.hcdp = config_tables[i].table;
- pr_cont(" HCDP=0x%lx ", config_tables[i].table);
- } else if (!efi_guidcmp(config_tables[i].guid,
- UGA_IO_PROTOCOL_GUID)) {
- efi.uga = config_tables[i].table;
- pr_cont(" UGA=0x%lx ", config_tables[i].table);
+ } else if (!efi_guidcmp(guid, HCDP_TABLE_GUID)) {
+ efi.hcdp = table;
+ pr_cont(" HCDP=0x%lx ", table);
+ } else if (!efi_guidcmp(guid, UGA_IO_PROTOCOL_GUID)) {
+ efi.uga = table;
+ pr_cont(" UGA=0x%lx ", table);
}
}
pr_cont("\n");
- early_iounmap(config_tables,
- efi.systab->nr_tables * sizeof(efi_config_table_t));
+ early_iounmap(config_tables, efi.systab->nr_tables * sz);
}

static void __init efi_runtime_init(void)
--
1.7.9.111.gf3fb0

2012-02-08 00:27:26

by Olof Johansson

[permalink] [raw]
Subject: [PATCH 5/5] x86: efi: allow basic init with mixed 32/64-bit efi/kernel

Traditionally the kernel has refused to setup EFI at all if there's been
a mismatch in 32/64-bit mode between EFI and the kernel.

On some platforms that boot natively through EFI (Chrome OS being one),
we still need to get at least some of the static data such as memory
configuration out of EFI. Runtime services aren't as critical, and
it's a significant amount of work to implement switching between the
operating modes to call between kernel and firmware for thise cases. So
I'm ignoring it for now.

v4:
* Some of the earlier cleanup was accidentally reverted by this patch, fixed.
* Reworded some messages to not have to line wrap printk strings

v3:
* Reorganized to a series of patches to make it easier to review, and
do some of the cleanups I had left out before.

v2:
* Added graceful error handling for 32-bit kernel that gets passed
EFI data above 4GB.
* Removed some warnings that were missed in first version.

Signed-off-by: Olof Johansson <[email protected]>
---
arch/x86/include/asm/efi.h | 2 +-
arch/x86/kernel/setup.c | 10 ++-
arch/x86/platform/efi/efi.c | 164 +++++++++++++++++++++++++++++++++++++------
include/linux/efi.h | 45 ++++++++++++
4 files changed, 195 insertions(+), 26 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 26d8c18..4103e4d 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -90,7 +90,7 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,

extern int add_efi_memmap;
extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
-extern void 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_epilog(void);

diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index e22bb08..a7ce9b5 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -751,10 +751,16 @@ void __init setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_EFI
if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
- EFI_LOADER_SIGNATURE, 4)) {
+ "EL32", 4)) {
efi_enabled = 1;
- efi_memblock_x86_reserve_range();
+ efi_64bit = false;
+ } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
+ "EL64", 4)) {
+ efi_enabled = 1;
+ efi_64bit = true;
}
+ if (efi_enabled && efi_memblock_x86_reserve_range())
+ efi_enabled = 0;
#endif

x86_init.oem.arch_setup();
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index c1111f7..14449b3 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -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;

@@ -346,11 +349,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 |
@@ -362,6 +370,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
@@ -439,14 +449,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.\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;

/*
@@ -467,24 +538,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.\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);
@@ -509,10 +603,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;
}

@@ -576,11 +670,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.\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)) {
@@ -609,19 +711,26 @@ 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 && efi_runtime_init()) {
efi_enabled = 0;
return;
- }
+ } else
+ pr_info("No EFI runtime due to 32/64b mismatch with kernel\n");

if (efi_memmap_init()) {
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
@@ -679,6 +788,13 @@ 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;
@@ -798,6 +914,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);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 37c3007..17385ba 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -315,6 +315,16 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,

typedef struct {
efi_guid_t guid;
+ u64 table;
+} _efi_config_table_64_t;
+
+typedef struct {
+ efi_guid_t guid;
+ u32 table;
+} _efi_config_table_32_t;
+
+typedef struct {
+ efi_guid_t guid;
unsigned long table;
} efi_config_table_t;

@@ -329,6 +339,40 @@ typedef struct {

typedef struct {
efi_table_hdr_t hdr;
+ u64 fw_vendor; /* physical addr of CHAR16 vendor string */
+ u32 fw_revision;
+ u32 __pad1;
+ u64 con_in_handle;
+ u64 con_in;
+ u64 con_out_handle;
+ u64 con_out;
+ u64 stderr_handle;
+ u64 stderr;
+ u64 runtime;
+ u64 boottime;
+ u32 nr_tables;
+ u32 __pad2;
+ u64 tables;
+} _efi_system_table_64_t;
+
+typedef struct {
+ efi_table_hdr_t hdr;
+ u32 fw_vendor; /* physical addr of CHAR16 vendor string */
+ u32 fw_revision;
+ u32 con_in_handle;
+ u32 con_in;
+ u32 con_out_handle;
+ u32 con_out;
+ u32 stderr_handle;
+ u32 stderr;
+ u32 runtime;
+ u32 boottime;
+ u32 nr_tables;
+ u32 tables;
+} _efi_system_table_32_t;
+
+typedef struct {
+ efi_table_hdr_t hdr;
unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */
u32 fw_revision;
unsigned long con_in_handle;
@@ -497,6 +541,7 @@ extern int __init efi_setup_pcdp_console(char *);
#ifdef CONFIG_EFI
# ifdef CONFIG_X86
extern int efi_enabled;
+ extern bool efi_64bit;
# else
# define efi_enabled 1
# endif
--
1.7.9.111.gf3fb0

2012-02-08 00:27:41

by Olof Johansson

[permalink] [raw]
Subject: [PATCH 4/5] x86: efi: add basic error handling

It's not perfect, but way better than before. Mark efi_enabled as false in
case of error and at least stop dereferencing pointers that are known to
be invalid.

The only significant missing piece is the lack of undoing the
memblock_reserve of the memory that efi marks as in use. On the other
hand, it's not a large amount of memory, and leaving it unavailable for
system use should be the safer choice anyway.

Signed-off-by: Olof Johansson <[email protected]>
Acked-by: Matt Fleming <[email protected]>
---
arch/x86/platform/efi/efi.c | 85 +++++++++++++++++++++++++++++--------------
1 files changed, 57 insertions(+), 28 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 05e543d..c1111f7 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -437,12 +437,14 @@ static void __init efi_free_boot_services(void)
}
}

-static void __init efi_systab_init(void *phys)
+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)
+ if (efi.systab == NULL) {
pr_err("Couldn't map the system table!\n");
+ return -ENOMEM;
+ }
memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
early_iounmap(efi.systab, sizeof(efi_system_table_t));
efi.systab = &efi_systab;
@@ -450,16 +452,20 @@ static void __init efi_systab_init(void *phys)
/*
* Verify the EFI Table
*/
- if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+ if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
pr_err("System table signature incorrect!\n");
+ return -EINVAL;
+ }
if ((efi.systab->hdr.revision >> 16) == 0)
pr_err("Warning: System table version "
"%d.%02d, expected 1.00 or greater!\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
+
+ return 0;
}

-static void __init efi_config_init(u64 tables, int nr_tables)
+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);
@@ -469,8 +475,10 @@ static void __init efi_config_init(u64 tables, int nr_tables)
*/
config_tables = early_ioremap(efi.systab->tables,
efi.systab->nr_tables * sz);
- if (config_tables == NULL)
+ if (config_tables == NULL) {
pr_err("Could not map Configuration table!\n");
+ return -ENOMEM;
+ }

pr_info("");
for (i = 0; i < efi.systab->nr_tables; i++) {
@@ -504,9 +512,11 @@ static void __init efi_config_init(u64 tables, int nr_tables)
}
pr_cont("\n");
early_iounmap(config_tables, efi.systab->nr_tables * sz);
+
+ return 0;
}

-static void __init efi_runtime_init(void)
+static int __init efi_runtime_init(void)
{
efi_runtime_services_t *runtime;

@@ -518,37 +528,44 @@ static void __init efi_runtime_init(void)
*/
runtime = early_ioremap((unsigned long)efi.systab->runtime,
sizeof(efi_runtime_services_t));
- if (runtime != NULL) {
- /*
- * We will only need *early* access to the following
- * two EFI runtime services before set_virtual_address_map
- * is invoked.
- */
- efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
- efi_phys.set_virtual_address_map =
- (efi_set_virtual_address_map_t *)
- runtime->set_virtual_address_map;
- /*
- * Make efi_get_time can be called before entering
- * virtual mode.
- */
- efi.get_time = phys_efi_get_time;
- } else
+ if (!runtime) {
pr_err("Could not map the runtime service table!\n");
+ return -ENOMEM;
+ }
+ /*
+ * We will only need *early* access to the following
+ * two EFI runtime services before set_virtual_address_map
+ * is invoked.
+ */
+ efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
+ efi_phys.set_virtual_address_map =
+ (efi_set_virtual_address_map_t *)
+ runtime->set_virtual_address_map;
+ /*
+ * Make efi_get_time can be called before entering
+ * virtual mode.
+ */
+ efi.get_time = phys_efi_get_time;
early_iounmap(runtime, sizeof(efi_runtime_services_t));
+
+ return 0;
}

-static void __init efi_memmap_init(void)
+static int __init efi_memmap_init(void)
{
/* Map the EFI memory map */
memmap.map = early_ioremap((unsigned long)memmap.phys_map,
memmap.nr_map * memmap.desc_size);
- if (memmap.map == NULL)
+ if (memmap.map == NULL) {
pr_err("Could not map the memory map!\n");
+ return -ENOMEM;
+ }
memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);

if (add_efi_memmap)
do_add_efi_memmap();
+
+ return 0;
}

void __init efi_init(void)
@@ -566,7 +583,10 @@ void __init efi_init(void)
((__u64)boot_params.efi_info.efi_systab_hi<<32));
#endif

- efi_systab_init(efi_phys.systab);
+ if (efi_systab_init(efi_phys.systab)) {
+ efi_enabled = 0;
+ return;
+ }

/*
* Show what we know for posterity
@@ -584,11 +604,20 @@ void __init efi_init(void)
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor);

- 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;
+ }

- efi_runtime_init();
+ if (efi_runtime_init()) {
+ efi_enabled = 0;
+ return;
+ }

- efi_memmap_init();
+ if (efi_memmap_init()) {
+ efi_enabled = 0;
+ return;
+ }

#ifdef CONFIG_X86_32
x86_platform.get_wallclock = efi_get_time;
--
1.7.9.111.gf3fb0

2012-02-08 00:27:13

by Olof Johansson

[permalink] [raw]
Subject: [PATCH 1/5] x86: efi: refactor efi_init() a bit

Break out some of the init steps into helper functions.

Only change to execution flow is the removal of the warning when the
kernel memdesc structure differ in size from what firmware specifies
since it's a bogus warning (it's a valid difference per spec).

v4:
* Removed memdesc warning as per above

Signed-off-by: Olof Johansson <[email protected]>
Acked-by: Matt Fleming <[email protected]>
---
arch/x86/platform/efi/efi.c | 89 ++++++++++++++++++++++++++-----------------
1 files changed, 54 insertions(+), 35 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 264cc6e..fec2b2e 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -436,23 +436,8 @@ static void __init efi_free_boot_services(void)
}
}

-void __init efi_init(void)
+static void __init efi_systab_init(void *phys)
{
- efi_config_table_t *config_tables;
- efi_runtime_services_t *runtime;
- efi_char16_t *c16;
- char vendor[100] = "unknown";
- int i = 0;
- void *tmp;
-
-#ifdef CONFIG_X86_32
- efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
-#else
- efi_phys.systab = (efi_system_table_t *)
- (boot_params.efi_info.efi_systab |
- ((__u64)boot_params.efi_info.efi_systab_hi<<32));
-#endif
-
efi.systab = early_ioremap((unsigned long)efi_phys.systab,
sizeof(efi_system_table_t));
if (efi.systab == NULL)
@@ -471,22 +456,12 @@ void __init efi_init(void)
"%d.%02d, expected 1.00 or greater!\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
+}

- /*
- * Show what we know for posterity
- */
- c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
- if (c16) {
- for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
- vendor[i] = *c16++;
- vendor[i] = '\0';
- } else
- printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
- early_iounmap(tmp, 2);
-
- printk(KERN_INFO "EFI v%u.%.02u by %s\n",
- efi.systab->hdr.revision >> 16,
- efi.systab->hdr.revision & 0xffff, vendor);
+static void __init efi_config_init(u64 tables, int nr_tables)
+{
+ efi_config_table_t *config_tables;
+ int i;

/*
* Let's see what config tables the firmware passed to us.
@@ -533,6 +508,11 @@ void __init efi_init(void)
printk("\n");
early_iounmap(config_tables,
efi.systab->nr_tables * sizeof(efi_config_table_t));
+}
+
+static void __init efi_runtime_init(void)
+{
+ efi_runtime_services_t *runtime;

/*
* Check out the runtime services table. We need to map
@@ -561,7 +541,10 @@ void __init efi_init(void)
printk(KERN_ERR "Could not map the EFI runtime service "
"table!\n");
early_iounmap(runtime, sizeof(efi_runtime_services_t));
+}

+static void __init efi_memmap_init(void)
+{
/* Map the EFI memory map */
memmap.map = early_ioremap((unsigned long)memmap.phys_map,
memmap.nr_map * memmap.desc_size);
@@ -569,12 +552,48 @@ void __init efi_init(void)
printk(KERN_ERR "Could not map the EFI memory map!\n");
memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);

- if (memmap.desc_size != sizeof(efi_memory_desc_t))
- printk(KERN_WARNING
- "Kernel-defined memdesc doesn't match the one from EFI!\n");
-
if (add_efi_memmap)
do_add_efi_memmap();
+}
+
+void __init efi_init(void)
+{
+ efi_char16_t *c16;
+ char vendor[100] = "unknown";
+ int i = 0;
+ void *tmp;
+
+#ifdef CONFIG_X86_32
+ efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
+#else
+ efi_phys.systab = (efi_system_table_t *)
+ (boot_params.efi_info.efi_systab |
+ ((__u64)boot_params.efi_info.efi_systab_hi<<32));
+#endif
+
+ efi_systab_init(efi_phys.systab);
+
+ /*
+ * Show what we know for posterity
+ */
+ c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
+ if (c16) {
+ for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
+ vendor[i] = *c16++;
+ vendor[i] = '\0';
+ } else
+ printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
+ early_iounmap(tmp, 2);
+
+ printk(KERN_INFO "EFI v%u.%.02u by %s\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
+
+ efi_config_init(efi.systab->tables, efi.systab->nr_tables);
+
+ efi_runtime_init();
+
+ efi_memmap_init();

#ifdef CONFIG_X86_32
x86_platform.get_wallclock = efi_get_time;
--
1.7.9.111.gf3fb0

2012-02-08 00:27:15

by Olof Johansson

[permalink] [raw]
Subject: [PATCH 2/5] x86: efi: convert printk to pr_*()

Alright, I guess I'll go through and convert them, even though
there's no net gain to speak of.

v4:
* Switched to pr_fmt and removed some redundant use of "EFI" in
messages.

Signed-off-by: Olof Johansson <[email protected]>
Cc: Joe Perches <[email protected]>
---
arch/x86/platform/efi/efi.c | 58 +++++++++++++++++++++---------------------
1 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index fec2b2e..777de17 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -26,6 +26,8 @@
* Skip non-WB memory and ignore empty memory ranges.
*/

+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/efi.h>
@@ -47,7 +49,6 @@
#include <asm/x86_init.h>

#define EFI_DEBUG 1
-#define PFX "EFI: "

int efi_enabled;
EXPORT_SYMBOL(efi_enabled);
@@ -254,7 +255,7 @@ int efi_set_rtc_mmss(unsigned long nowtime)

status = efi.get_time(&eft, &cap);
if (status != EFI_SUCCESS) {
- printk(KERN_ERR "Oops: efitime: can't read time!\n");
+ pr_err("Oops: efitime: can't read time!\n");
return -1;
}

@@ -268,7 +269,7 @@ int efi_set_rtc_mmss(unsigned long nowtime)

status = efi.set_time(&eft);
if (status != EFI_SUCCESS) {
- printk(KERN_ERR "Oops: efitime: can't write time!\n");
+ pr_err("Oops: efitime: can't write time!\n");
return -1;
}
return 0;
@@ -282,7 +283,7 @@ unsigned long efi_get_time(void)

status = efi.get_time(&eft, &cap);
if (status != EFI_SUCCESS)
- printk(KERN_ERR "Oops: efitime: can't read time!\n");
+ pr_err("Oops: efitime: can't read time!\n");

return mktime(eft.year, eft.month, eft.day, eft.hour,
eft.minute, eft.second);
@@ -374,7 +375,7 @@ static void __init print_efi_memmap(void)
p < memmap.map_end;
p += memmap.desc_size, i++) {
md = p;
- printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
+ pr_info("mem%02u: type=%u, attr=0x%llx, "
"range=[0x%016llx-0x%016llx) (%lluMB)\n",
i, md->type, md->attribute, md->phys_addr,
md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
@@ -407,7 +408,7 @@ void __init efi_reserve_boot_services(void)
memblock_is_region_reserved(start, size)) {
/* Could not reserve, skip it */
md->num_pages = 0;
- memblock_dbg(PFX "Could not reserve boot range "
+ memblock_dbg("Could not reserve boot range "
"[0x%010llx-0x%010llx]\n",
start, start+size-1);
} else
@@ -441,7 +442,7 @@ static void __init efi_systab_init(void *phys)
efi.systab = early_ioremap((unsigned long)efi_phys.systab,
sizeof(efi_system_table_t));
if (efi.systab == NULL)
- printk(KERN_ERR "Couldn't map the EFI system table!\n");
+ pr_err("Couldn't map the system table!\n");
memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
early_iounmap(efi.systab, sizeof(efi_system_table_t));
efi.systab = &efi_systab;
@@ -450,9 +451,9 @@ static void __init efi_systab_init(void *phys)
* Verify the EFI Table
*/
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
- printk(KERN_ERR "EFI system table signature incorrect!\n");
+ pr_err("System table signature incorrect!\n");
if ((efi.systab->hdr.revision >> 16) == 0)
- printk(KERN_ERR "Warning: EFI system table version "
+ pr_err("Warning: System table version "
"%d.%02d, expected 1.00 or greater!\n",
efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff);
@@ -470,42 +471,42 @@ static void __init efi_config_init(u64 tables, int nr_tables)
efi.systab->tables,
efi.systab->nr_tables * sizeof(efi_config_table_t));
if (config_tables == NULL)
- printk(KERN_ERR "Could not map EFI Configuration Table!\n");
+ pr_err("Could not map Configuration table!\n");

- printk(KERN_INFO);
+ pr_info("");
for (i = 0; i < efi.systab->nr_tables; i++) {
if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
efi.mps = config_tables[i].table;
- printk(" MPS=0x%lx ", config_tables[i].table);
+ pr_cont(" MPS=0x%lx ", config_tables[i].table);
} else if (!efi_guidcmp(config_tables[i].guid,
ACPI_20_TABLE_GUID)) {
efi.acpi20 = config_tables[i].table;
- printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
+ pr_cont(" ACPI 2.0=0x%lx ", config_tables[i].table);
} else if (!efi_guidcmp(config_tables[i].guid,
ACPI_TABLE_GUID)) {
efi.acpi = config_tables[i].table;
- printk(" ACPI=0x%lx ", config_tables[i].table);
+ pr_cont(" ACPI=0x%lx ", config_tables[i].table);
} else if (!efi_guidcmp(config_tables[i].guid,
SMBIOS_TABLE_GUID)) {
efi.smbios = config_tables[i].table;
- printk(" SMBIOS=0x%lx ", config_tables[i].table);
+ pr_cont(" SMBIOS=0x%lx ", config_tables[i].table);
#ifdef CONFIG_X86_UV
} else if (!efi_guidcmp(config_tables[i].guid,
UV_SYSTEM_TABLE_GUID)) {
efi.uv_systab = config_tables[i].table;
- printk(" UVsystab=0x%lx ", config_tables[i].table);
+ pr_cont(" UVsystab=0x%lx ", config_tables[i].table);
#endif
} else if (!efi_guidcmp(config_tables[i].guid,
HCDP_TABLE_GUID)) {
efi.hcdp = config_tables[i].table;
- printk(" HCDP=0x%lx ", config_tables[i].table);
+ pr_cont(" HCDP=0x%lx ", config_tables[i].table);
} else if (!efi_guidcmp(config_tables[i].guid,
UGA_IO_PROTOCOL_GUID)) {
efi.uga = config_tables[i].table;
- printk(" UGA=0x%lx ", config_tables[i].table);
+ pr_cont(" UGA=0x%lx ", config_tables[i].table);
}
}
- printk("\n");
+ pr_cont("\n");
early_iounmap(config_tables,
efi.systab->nr_tables * sizeof(efi_config_table_t));
}
@@ -538,8 +539,7 @@ static void __init efi_runtime_init(void)
*/
efi.get_time = phys_efi_get_time;
} else
- printk(KERN_ERR "Could not map the EFI runtime service "
- "table!\n");
+ pr_err("Could not map the runtime service table!\n");
early_iounmap(runtime, sizeof(efi_runtime_services_t));
}

@@ -549,7 +549,7 @@ static void __init efi_memmap_init(void)
memmap.map = early_ioremap((unsigned long)memmap.phys_map,
memmap.nr_map * memmap.desc_size);
if (memmap.map == NULL)
- printk(KERN_ERR "Could not map the EFI memory map!\n");
+ pr_err("Could not map the memory map!\n");
memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);

if (add_efi_memmap)
@@ -582,12 +582,12 @@ void __init efi_init(void)
vendor[i] = *c16++;
vendor[i] = '\0';
} else
- printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
+ pr_err("Could not map the firmware vendor!\n");
early_iounmap(tmp, 2);

- printk(KERN_INFO "EFI v%u.%.02u by %s\n",
- efi.systab->hdr.revision >> 16,
- efi.systab->hdr.revision & 0xffff, vendor);
+ pr_info("EFI v%u.%.02u by %s\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);

efi_config_init(efi.systab->tables, efi.systab->nr_tables);

@@ -714,7 +714,7 @@ void __init efi_enter_virtual_mode(void)
md->virt_addr = (u64) (unsigned long) va;

if (!va) {
- printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
+ pr_err("ioremap of 0x%llX failed!\n",
(unsigned long long)md->phys_addr);
continue;
}
@@ -741,8 +741,8 @@ void __init efi_enter_virtual_mode(void)
(efi_memory_desc_t *)__pa(new_memmap));

if (status != EFI_SUCCESS) {
- printk(KERN_ALERT "Unable to switch EFI into virtual mode "
- "(status=%lx)!\n", status);
+ pr_alert("Unable to switch EFI into virtual mode "
+ "(status=%lx)!\n", status);
panic("EFI call to SetVirtualAddressMap() failed!");
}

--
1.7.9.111.gf3fb0

2012-02-08 18:32:08

by Matt Fleming

[permalink] [raw]
Subject: Re: [PATCH 5/5] x86: efi: allow basic init with mixed 32/64-bit efi/kernel

On Tue, 2012-02-07 at 16:25 -0800, Olof Johansson wrote:
> Traditionally the kernel has refused to setup EFI at all if there's been
> a mismatch in 32/64-bit mode between EFI and the kernel.
>
> On some platforms that boot natively through EFI (Chrome OS being one),
> we still need to get at least some of the static data such as memory
> configuration out of EFI. Runtime services aren't as critical, and
> it's a significant amount of work to implement switching between the
> operating modes to call between kernel and firmware for thise cases. So
> I'm ignoring it for now.

Presumably with these patches in mainline you can get rid of the hacks
that ChromeOS currently uses?

> v4:
> * Some of the earlier cleanup was accidentally reverted by this patch, fixed.
> * Reworded some messages to not have to line wrap printk strings
>
> v3:
> * Reorganized to a series of patches to make it easier to review, and
> do some of the cleanups I had left out before.
>
> v2:
> * Added graceful error handling for 32-bit kernel that gets passed
> EFI data above 4GB.
> * Removed some warnings that were missed in first version.
>
> Signed-off-by: Olof Johansson <[email protected]>
> ---
> arch/x86/include/asm/efi.h | 2 +-
> arch/x86/kernel/setup.c | 10 ++-
> arch/x86/platform/efi/efi.c | 164 +++++++++++++++++++++++++++++++++++++------
> include/linux/efi.h | 45 ++++++++++++
> 4 files changed, 195 insertions(+), 26 deletions(-)
>

[...]

> +
> + early_iounmap(systab64, sizeof(*systab64));
> +#ifdef CONFIG_X86_32
> + if (tmp >> 32) {
> + pr_err("EFI data located above 4GB, disabling.\n");
> + return -EINVAL;
> + }
> +#endif

You should really say "disabling EFI" here.

[...]

> +#ifdef CONFIG_X86_32
> + if (table64 >> 32) {
> + pr_cont("\n");
> + pr_err("Table located above 4GB, disabling.\n");
> + early_iounmap(config_tables,
> + efi.systab->nr_tables * sz);
> + return -EINVAL;
> + }
> +#endif

Likewise here, mention that you're disabling EFI.

[...]

> @@ -576,11 +670,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.\n");
> + efi_enabled = 0;
> + return;
> + }
> efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
> + efi_native = !efi_64bit;
> #else

... and here

> 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)) {
> @@ -609,19 +711,26 @@ 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 && efi_runtime_init()) {
> efi_enabled = 0;
> return;
> - }
> + } else
> + pr_info("No EFI runtime due to 32/64b mismatch with kernel\n");

Hmm... this isn't right. efi_runtime_init() returns 0 on success, so
you're printing this warning in the native EFI success path. Also,
please spell out "32/64-bit".

> @@ -679,6 +788,13 @@ 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;
> +

/*
* Multi-line comments should look like this.
*/

> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 37c3007..17385ba 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -315,6 +315,16 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
>
> typedef struct {
> efi_guid_t guid;
> + u64 table;
> +} _efi_config_table_64_t;
> +
> +typedef struct {
> + efi_guid_t guid;
> + u32 table;
> +} _efi_config_table_32_t;
> +
> +typedef struct {
> + efi_guid_t guid;
> unsigned long table;
> } efi_config_table_t;

There's no need for the underscore prefix on these names.
efi_config_table_64_t, etc, is fine. Normally you should try to avoid
adding new typedefs, but I think these make sense because they're an
extension of existing typedefs.

Actually, thinking about it some more, it would make more sense to just
delete efi_config_table_t and efi_system_table_t and make everyone
explicitly pick a size, not least because it will make people adding new
code think long and hard about the mixed mode case.

> @@ -329,6 +339,40 @@ typedef struct {
>
> typedef struct {
> efi_table_hdr_t hdr;
> + u64 fw_vendor; /* physical addr of CHAR16 vendor string */
> + u32 fw_revision;
> + u32 __pad1;
> + u64 con_in_handle;
> + u64 con_in;
> + u64 con_out_handle;
> + u64 con_out;
> + u64 stderr_handle;
> + u64 stderr;
> + u64 runtime;
> + u64 boottime;
> + u32 nr_tables;
> + u32 __pad2;
> + u64 tables;
> +} _efi_system_table_64_t;

No underscore please.

> +typedef struct {
> + efi_table_hdr_t hdr;
> + u32 fw_vendor; /* physical addr of CHAR16 vendor string */
> + u32 fw_revision;
> + u32 con_in_handle;
> + u32 con_in;
> + u32 con_out_handle;
> + u32 con_out;
> + u32 stderr_handle;
> + u32 stderr;
> + u32 runtime;
> + u32 boottime;
> + u32 nr_tables;
> + u32 tables;
> +} _efi_system_table_32_t;

Same here.

2012-02-08 18:54:29

by Olof Johansson

[permalink] [raw]
Subject: Re: [PATCH 5/5] x86: efi: allow basic init with mixed 32/64-bit efi/kernel

On Wed, Feb 08, 2012 at 06:31:54PM +0000, Matt Fleming wrote:
> On Tue, 2012-02-07 at 16:25 -0800, Olof Johansson wrote:
> > Traditionally the kernel has refused to setup EFI at all if there's been
> > a mismatch in 32/64-bit mode between EFI and the kernel.
> >
> > On some platforms that boot natively through EFI (Chrome OS being one),
> > we still need to get at least some of the static data such as memory
> > configuration out of EFI. Runtime services aren't as critical, and
> > it's a significant amount of work to implement switching between the
> > operating modes to call between kernel and firmware for thise cases. So
> > I'm ignoring it for now.
>
> Presumably with these patches in mainline you can get rid of the hacks
> that ChromeOS currently uses?

Yes, that's my personal objective for doing it. The main benefit of that is that it
makes it significantly easier for anyone working on the Chrome OS kernel to
contribute and test upstream if we can boot an unmodified mainline kernel on
our machines.

> > +
> > + early_iounmap(systab64, sizeof(*systab64));
> > +#ifdef CONFIG_X86_32
> > + if (tmp >> 32) {
> > + pr_err("EFI data located above 4GB, disabling.\n");
> > + return -EINVAL;
> > + }
> > +#endif
>
> You should really say "disabling EFI" here.

Sure, I'll change that.

> > +#ifdef CONFIG_X86_32
> > + if (table64 >> 32) {
> > + pr_cont("\n");
> > + pr_err("Table located above 4GB, disabling.\n");
> > + early_iounmap(config_tables,
> > + efi.systab->nr_tables * sz);
> > + return -EINVAL;
> > + }
> > +#endif
>
> Likewise here, mention that you're disabling EFI.

No problem.

> [...]
>
> > @@ -576,11 +670,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.\n");
> > + efi_enabled = 0;
> > + return;
> > + }
> > efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
> > + efi_native = !efi_64bit;
> > #else
>
> ... and here

Yup.

>
> > 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)) {
> > @@ -609,19 +711,26 @@ 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 && efi_runtime_init()) {
> > efi_enabled = 0;
> > return;
> > - }
> > + } else
> > + pr_info("No EFI runtime due to 32/64b mismatch with kernel\n");
>
> Hmm... this isn't right. efi_runtime_init() returns 0 on success, so
> you're printing this warning in the native EFI success path. Also,
> please spell out "32/64-bit".

Uh, yeah, that's obviously broken, I'll fix. And I'll expand the wording.

> >
> > + /* We don't do virtual mode, since we don't do runtime services, on
> > + * non-native EFI
> > + */
> > +
> > + if (!efi_native)
> > + goto out;
> > +
>
> /*
> * Multi-line comments should look like this.
> */

D'oh, of course.

> > +} _efi_config_table_32_t;
> > +
> > +typedef struct {
> > + efi_guid_t guid;
> > unsigned long table;
> > } efi_config_table_t;
>
> There's no need for the underscore prefix on these names.
> efi_config_table_64_t, etc, is fine. Normally you should try to avoid
> adding new typedefs, but I think these make sense because they're an
> extension of existing typedefs.

I just went with the existing convention in the file and added it as
a typedef. The underbar is there, just as in many other cases around
the kernel, to indicate that it's an internal-only version that's not
supposed to be used unless you know what you're doing. But sure, I can
take them off if it makes you happy. ;)

> Actually, thinking about it some more, it would make more sense to just
> delete efi_config_table_t and efi_system_table_t and make everyone
> explicitly pick a size, not least because it will make people adding new
> code think long and hard about the mixed mode case.

I tried that approach and the end result was messier than this is, since
there's no way to know which data type you need until runtime. The
number of people adding code to this module is limited, I'm not so
worried about that.

So, I would prefer keeping the current implementation with the above (and
below) comments fixed.

> > +} _efi_system_table_64_t;
>
> No underscore please.
>
[...]
> > +} _efi_system_table_32_t;
>
> Same here.

Sure.


-Olof