Commit f2001bd5 authored by Will Deacon's avatar Will Deacon

Merge tag 'for-3.19' of git://git.linaro.org/people/ard.biesheuvel/linux-arm into ard/efi-for-3.19

Pull UEFI updates from Ard Biesheuvel:

  - fixes for compliance with PE/COFF and UEFI specs
  - added support for SMBIOS, including upcoming version 3.0
  - cleanups and diagnostic output improvements
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parents cac7f242 0bcaa904
...@@ -401,6 +401,17 @@ config EFI ...@@ -401,6 +401,17 @@ config EFI
allow the kernel to be booted as an EFI application. This allow the kernel to be booted as an EFI application. This
is only useful on systems that have UEFI firmware. is only useful on systems that have UEFI firmware.
config DMI
bool "Enable support for SMBIOS (DMI) tables"
depends on EFI
default y
help
This enables SMBIOS/DMI feature for systems.
This option is only useful on systems that have UEFI firmware.
However, even with this option, the resultant kernel should
continue to boot on existing non-UEFI platforms.
endmenu endmenu
menu "Userspace binary formats" menu "Userspace binary formats"
......
/*
* arch/arm64/include/asm/dmi.h
*
* Copyright (C) 2013 Linaro Limited.
* Written by: Yi Li (yi.li@linaro.org)
*
* based on arch/ia64/include/asm/dmi.h
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#ifndef __ASM_DMI_H
#define __ASM_DMI_H
#include <linux/io.h>
#include <linux/slab.h>
/*
* According to section 2.3.6 of the UEFI spec, the firmware should not
* request a virtual mapping for configuration tables such as SMBIOS.
* This means we have to map them before use.
*/
#define dmi_early_remap(x, l) ioremap_cache(x, l)
#define dmi_early_unmap(x, l) iounmap(x)
#define dmi_remap(x, l) ioremap_cache(x, l)
#define dmi_unmap(x) iounmap(x)
#define dmi_alloc(l) kzalloc(l, GFP_KERNEL)
#endif
...@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry) ...@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry)
*/ */
mov x20, x0 // DTB address mov x20, x0 // DTB address
ldr x0, [sp, #16] // relocated _text address ldr x0, [sp, #16] // relocated _text address
mov x21, x0 ldr x21, =stext_offset
add x21, x0, x21
/* /*
* Flush dcache covering current runtime addresses * Flush dcache covering current runtime addresses
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* *
*/ */
#include <linux/dmi.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/memblock.h> #include <linux/memblock.h>
...@@ -112,8 +113,6 @@ static int __init uefi_init(void) ...@@ -112,8 +113,6 @@ static int __init uefi_init(void)
efi.systab->hdr.revision & 0xffff, vendor); efi.systab->hdr.revision & 0xffff, vendor);
retval = efi_config_init(NULL); retval = efi_config_init(NULL);
if (retval == 0)
set_bit(EFI_CONFIG_TABLES, &efi.flags);
out: out:
early_memunmap(efi.systab, sizeof(efi_system_table_t)); early_memunmap(efi.systab, sizeof(efi_system_table_t));
...@@ -125,17 +124,17 @@ static int __init uefi_init(void) ...@@ -125,17 +124,17 @@ static int __init uefi_init(void)
*/ */
static __init int is_reserve_region(efi_memory_desc_t *md) static __init int is_reserve_region(efi_memory_desc_t *md)
{ {
if (!is_normal_ram(md)) switch (md->type) {
case EFI_LOADER_CODE:
case EFI_LOADER_DATA:
case EFI_BOOT_SERVICES_CODE:
case EFI_BOOT_SERVICES_DATA:
case EFI_CONVENTIONAL_MEMORY:
return 0; return 0;
default:
if (md->attribute & EFI_MEMORY_RUNTIME) break;
return 1; }
return is_normal_ram(md);
if (md->type == EFI_ACPI_RECLAIM_MEMORY ||
md->type == EFI_RESERVED_TYPE)
return 1;
return 0;
} }
static __init void reserve_regions(void) static __init void reserve_regions(void)
...@@ -471,3 +470,17 @@ static int __init arm64_enter_virtual_mode(void) ...@@ -471,3 +470,17 @@ static int __init arm64_enter_virtual_mode(void)
return -1; return -1;
} }
early_initcall(arm64_enter_virtual_mode); early_initcall(arm64_enter_virtual_mode);
static int __init arm64_dmi_init(void)
{
/*
* On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to
* be called early because dmi_id_init(), which is an arch_initcall
* itself, depends on dmi_scan_machine() having been called already.
*/
dmi_scan_machine();
if (dmi_available)
dmi_set_dump_stack_arch_desc();
return 0;
}
core_initcall(arm64_dmi_init);
...@@ -132,6 +132,8 @@ efi_head: ...@@ -132,6 +132,8 @@ efi_head:
#endif #endif
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
.globl stext_offset
.set stext_offset, stext - efi_head
.align 3 .align 3
pe_header: pe_header:
.ascii "PE" .ascii "PE"
...@@ -155,12 +157,12 @@ optional_header: ...@@ -155,12 +157,12 @@ optional_header:
.long 0 // SizeOfInitializedData .long 0 // SizeOfInitializedData
.long 0 // SizeOfUninitializedData .long 0 // SizeOfUninitializedData
.long efi_stub_entry - efi_head // AddressOfEntryPoint .long efi_stub_entry - efi_head // AddressOfEntryPoint
.long stext - efi_head // BaseOfCode .long stext_offset // BaseOfCode
extra_header_fields: extra_header_fields:
.quad 0 // ImageBase .quad 0 // ImageBase
.long 0x20 // SectionAlignment .long 0x1000 // SectionAlignment
.long 0x8 // FileAlignment .long PECOFF_FILE_ALIGNMENT // FileAlignment
.short 0 // MajorOperatingSystemVersion .short 0 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion .short 0 // MajorImageVersion
...@@ -172,7 +174,7 @@ extra_header_fields: ...@@ -172,7 +174,7 @@ extra_header_fields:
.long _end - efi_head // SizeOfImage .long _end - efi_head // SizeOfImage
// Everything before the kernel image is considered part of the header // Everything before the kernel image is considered part of the header
.long stext - efi_head // SizeOfHeaders .long stext_offset // SizeOfHeaders
.long 0 // CheckSum .long 0 // CheckSum
.short 0xa // Subsystem (EFI application) .short 0xa // Subsystem (EFI application)
.short 0 // DllCharacteristics .short 0 // DllCharacteristics
...@@ -217,16 +219,24 @@ section_table: ...@@ -217,16 +219,24 @@ section_table:
.byte 0 .byte 0
.byte 0 // end of 0 padding of section name .byte 0 // end of 0 padding of section name
.long _end - stext // VirtualSize .long _end - stext // VirtualSize
.long stext - efi_head // VirtualAddress .long stext_offset // VirtualAddress
.long _edata - stext // SizeOfRawData .long _edata - stext // SizeOfRawData
.long stext - efi_head // PointerToRawData .long stext_offset // PointerToRawData
.long 0 // PointerToRelocations (0 for executables) .long 0 // PointerToRelocations (0 for executables)
.long 0 // PointerToLineNumbers (0 for executables) .long 0 // PointerToLineNumbers (0 for executables)
.short 0 // NumberOfRelocations (0 for executables) .short 0 // NumberOfRelocations (0 for executables)
.short 0 // NumberOfLineNumbers (0 for executables) .short 0 // NumberOfLineNumbers (0 for executables)
.long 0xe0500020 // Characteristics (section flags) .long 0xe0500020 // Characteristics (section flags)
.align 5
/*
* EFI will load stext onwards at the 4k section alignment
* described in the PE/COFF header. To ensure that instruction
* sequences using an adrp and a :lo12: immediate will function
* correctly at this alignment, we must ensure that stext is
* placed at a 4k boundary in the Image to begin with.
*/
.align 12
#endif #endif
ENTRY(stext) ENTRY(stext)
......
...@@ -32,6 +32,22 @@ jiffies = jiffies_64; ...@@ -32,6 +32,22 @@ jiffies = jiffies_64;
*(.hyp.text) \ *(.hyp.text) \
VMLINUX_SYMBOL(__hyp_text_end) = .; VMLINUX_SYMBOL(__hyp_text_end) = .;
/*
* The size of the PE/COFF section that covers the kernel image, which
* runs from stext to _edata, must be a round multiple of the PE/COFF
* FileAlignment, which we set to its minimum value of 0x200. 'stext'
* itself is 4 KB aligned, so padding out _edata to a 0x200 aligned
* boundary should be sufficient.
*/
PECOFF_FILE_ALIGNMENT = 0x200;
#ifdef CONFIG_EFI
#define PECOFF_EDATA_PADDING \
.pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
#else
#define PECOFF_EDATA_PADDING
#endif
SECTIONS SECTIONS
{ {
/* /*
...@@ -103,6 +119,7 @@ SECTIONS ...@@ -103,6 +119,7 @@ SECTIONS
_data = .; _data = .;
_sdata = .; _sdata = .;
RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE) RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
PECOFF_EDATA_PADDING
_edata = .; _edata = .;
BSS_SECTION(0, 0, 0) BSS_SECTION(0, 0, 0)
......
...@@ -92,6 +92,12 @@ static void dmi_table(u8 *buf, int len, int num, ...@@ -92,6 +92,12 @@ static void dmi_table(u8 *buf, int len, int num,
while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
const struct dmi_header *dm = (const struct dmi_header *)data; const struct dmi_header *dm = (const struct dmi_header *)data;
/*
* 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
*/
if (dm->type == DMI_ENTRY_END_OF_TABLE)
break;
/* /*
* We want to know the total length (formatted area and * We want to know the total length (formatted area and
* strings) before decoding to make sure we won't run off the * strings) before decoding to make sure we won't run off the
...@@ -107,7 +113,7 @@ static void dmi_table(u8 *buf, int len, int num, ...@@ -107,7 +113,7 @@ static void dmi_table(u8 *buf, int len, int num,
} }
} }
static u32 dmi_base; static phys_addr_t dmi_base;
static u16 dmi_len; static u16 dmi_len;
static u16 dmi_num; static u16 dmi_num;
...@@ -467,7 +473,7 @@ static int __init dmi_present(const u8 *buf) ...@@ -467,7 +473,7 @@ static int __init dmi_present(const u8 *buf)
if (memcmp(buf, "_SM_", 4) == 0 && if (memcmp(buf, "_SM_", 4) == 0 &&
buf[5] < 32 && dmi_checksum(buf, buf[5])) { buf[5] < 32 && dmi_checksum(buf, buf[5])) {
smbios_ver = (buf[6] << 8) + buf[7]; smbios_ver = get_unaligned_be16(buf + 6);
/* Some BIOS report weird SMBIOS version, fix that up */ /* Some BIOS report weird SMBIOS version, fix that up */
switch (smbios_ver) { switch (smbios_ver) {
...@@ -489,10 +495,9 @@ static int __init dmi_present(const u8 *buf) ...@@ -489,10 +495,9 @@ static int __init dmi_present(const u8 *buf)
buf += 16; buf += 16;
if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) { if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
dmi_num = (buf[13] << 8) | buf[12]; dmi_num = get_unaligned_le16(buf + 12);
dmi_len = (buf[7] << 8) | buf[6]; dmi_len = get_unaligned_le16(buf + 6);
dmi_base = (buf[11] << 24) | (buf[10] << 16) | dmi_base = get_unaligned_le32(buf + 8);
(buf[9] << 8) | buf[8];
if (dmi_walk_early(dmi_decode) == 0) { if (dmi_walk_early(dmi_decode) == 0) {
if (smbios_ver) { if (smbios_ver) {
...@@ -514,12 +519,72 @@ static int __init dmi_present(const u8 *buf) ...@@ -514,12 +519,72 @@ static int __init dmi_present(const u8 *buf)
return 1; return 1;
} }
/*
* Check for the SMBIOS 3.0 64-bit entry point signature. Unlike the legacy
* 32-bit entry point, there is no embedded DMI header (_DMI_) in here.
*/
static int __init dmi_smbios3_present(const u8 *buf)
{
if (memcmp(buf, "_SM3_", 5) == 0 &&
buf[6] < 32 && dmi_checksum(buf, buf[6])) {
dmi_ver = get_unaligned_be16(buf + 7);
dmi_len = get_unaligned_le32(buf + 12);
dmi_base = get_unaligned_le64(buf + 16);
/*
* The 64-bit SMBIOS 3.0 entry point no longer has a field
* containing the number of structures present in the table.
* Instead, it defines the table size as a maximum size, and
* relies on the end-of-table structure type (#127) to be used
* to signal the end of the table.
* So let's define dmi_num as an upper bound as well: each
* structure has a 4 byte header, so dmi_len / 4 is an upper
* bound for the number of structures in the table.
*/
dmi_num = dmi_len / 4;
if (dmi_walk_early(dmi_decode) == 0) {
pr_info("SMBIOS %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
pr_debug("DMI: %s\n", dmi_ids_string);
return 0;
}
}
return 1;
}
void __init dmi_scan_machine(void) void __init dmi_scan_machine(void)
{ {
char __iomem *p, *q; char __iomem *p, *q;
char buf[32]; char buf[32];
if (efi_enabled(EFI_CONFIG_TABLES)) { if (efi_enabled(EFI_CONFIG_TABLES)) {
/*
* According to the DMTF SMBIOS reference spec v3.0.0, it is
* allowed to define both the 64-bit entry point (smbios3) and
* the 32-bit entry point (smbios), in which case they should
* either both point to the same SMBIOS structure table, or the
* table pointed to by the 64-bit entry point should contain a
* superset of the table contents pointed to by the 32-bit entry
* point (section 5.2)
* This implies that the 64-bit entry point should have
* precedence if it is defined and supported by the OS. If we
* have the 64-bit entry point, but fail to decode it, fall
* back to the legacy one (if available)
*/
if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {
p = dmi_early_remap(efi.smbios3, 32);
if (p == NULL)
goto error;
memcpy_fromio(buf, p, 32);
dmi_early_unmap(p, 32);
if (!dmi_smbios3_present(buf)) {
dmi_available = 1;
goto out;
}
}
if (efi.smbios == EFI_INVALID_TABLE_ADDR) if (efi.smbios == EFI_INVALID_TABLE_ADDR)
goto error; goto error;
...@@ -552,7 +617,7 @@ void __init dmi_scan_machine(void) ...@@ -552,7 +617,7 @@ void __init dmi_scan_machine(void)
memset(buf, 0, 16); memset(buf, 0, 16);
for (q = p; q < p + 0x10000; q += 16) { for (q = p; q < p + 0x10000; q += 16) {
memcpy_fromio(buf + 16, q, 16); memcpy_fromio(buf + 16, q, 16);
if (!dmi_present(buf)) { if (!dmi_smbios3_present(buf) || !dmi_present(buf)) {
dmi_available = 1; dmi_available = 1;
dmi_early_unmap(p, 0x10000); dmi_early_unmap(p, 0x10000);
goto out; goto out;
......
...@@ -30,6 +30,7 @@ struct efi __read_mostly efi = { ...@@ -30,6 +30,7 @@ struct efi __read_mostly efi = {
.acpi = EFI_INVALID_TABLE_ADDR, .acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR, .acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR, .smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR, .sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR, .boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR, .hcdp = EFI_INVALID_TABLE_ADDR,
...@@ -86,6 +87,8 @@ static ssize_t systab_show(struct kobject *kobj, ...@@ -86,6 +87,8 @@ static ssize_t systab_show(struct kobject *kobj,
str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
if (efi.smbios != EFI_INVALID_TABLE_ADDR) if (efi.smbios != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
if (efi.hcdp != EFI_INVALID_TABLE_ADDR) if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
if (efi.boot_info != EFI_INVALID_TABLE_ADDR) if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
...@@ -260,6 +263,7 @@ static __initdata efi_config_table_type_t common_tables[] = { ...@@ -260,6 +263,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{MPS_TABLE_GUID, "MPS", &efi.mps}, {MPS_TABLE_GUID, "MPS", &efi.mps},
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
{NULL_GUID, NULL, NULL}, {NULL_GUID, NULL, NULL},
}; };
......
...@@ -247,9 +247,18 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table, ...@@ -247,9 +247,18 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table,
goto fail_free_cmdline; goto fail_free_cmdline;
} }
} }
if (!fdt_addr)
if (fdt_addr) {
pr_efi(sys_table, "Using DTB from command line\n");
} else {
/* Look for a device tree configuration table entry. */ /* Look for a device tree configuration table entry. */
fdt_addr = (uintptr_t)get_fdt(sys_table); fdt_addr = (uintptr_t)get_fdt(sys_table);
if (fdt_addr)
pr_efi(sys_table, "Using DTB from configuration table\n");
}
if (!fdt_addr)
pr_efi(sys_table, "Generating empty DTB\n");
status = handle_cmdline_files(sys_table, image, cmdline_ptr, status = handle_cmdline_files(sys_table, image, cmdline_ptr,
"initrd=", dram_base + SZ_512M, "initrd=", dram_base + SZ_512M,
......
...@@ -294,6 +294,7 @@ static const struct efi efi_xen __initconst = { ...@@ -294,6 +294,7 @@ static const struct efi efi_xen __initconst = {
.acpi = EFI_INVALID_TABLE_ADDR, .acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR, .acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR, .smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR, .sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR, .boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR, .hcdp = EFI_INVALID_TABLE_ADDR,
......
...@@ -547,6 +547,9 @@ void efi_native_runtime_setup(void); ...@@ -547,6 +547,9 @@ void efi_native_runtime_setup(void);
#define SMBIOS_TABLE_GUID \ #define SMBIOS_TABLE_GUID \
EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
#define SMBIOS3_TABLE_GUID \
EFI_GUID( 0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 )
#define SAL_SYSTEM_TABLE_GUID \ #define SAL_SYSTEM_TABLE_GUID \
EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d ) EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
...@@ -810,7 +813,8 @@ extern struct efi { ...@@ -810,7 +813,8 @@ extern struct efi {
unsigned long mps; /* MPS table */ unsigned long mps; /* MPS table */
unsigned long acpi; /* ACPI table (IA64 ext 0.71) */ unsigned long acpi; /* ACPI table (IA64 ext 0.71) */
unsigned long acpi20; /* ACPI table (ACPI 2.0) */ unsigned long acpi20; /* ACPI table (ACPI 2.0) */
unsigned long smbios; /* SM BIOS table */ unsigned long smbios; /* SMBIOS table (32 bit entry point) */
unsigned long smbios3; /* SMBIOS table (64 bit entry point) */
unsigned long sal_systab; /* SAL system table */ unsigned long sal_systab; /* SAL system table */
unsigned long boot_info; /* boot info table */ unsigned long boot_info; /* boot info table */
unsigned long hcdp; /* HCDP table */ unsigned long hcdp; /* HCDP table */
......
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