mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
* Fixes and cleanups for SMBIOS 3.0 DMI code - Ivan Khoronzhuk
* A new efi=debug command line option that enables debug output in the EFI boot stub and results in less verbose EFI memory map output by default - Borislav Petkov * Disable interrupts around EFI calls and use a more standard page table saving and restoring idiom when making EFI calls - Ingo Molnar * Reduce the number of memory allocations performed when allocating the FDT in EFI boot stub by retrieving size from the FDT header in the EFI config table - Ard Biesheuvel -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVG9qYAAoJEC84WcCNIz1V8+sP/iKFXQIIXRdlLVSrHHqUPn4K f32qYdfFfJvG5RMF3Y9B4+lUYi5Svr9SHgg9ZxkVW+GcuI5GUdjU9LjaVtDL9kZ0 YepHp7hdrV+mqX/zDC+NaKqOjbF4jR+5JK8cYnzMDt22jCLBV96aREbH75rN43v1 55VJUplDd6JM4h4XuF/LxyKXJf+LOIFLS4p8c0XPVd3ict7ACAi+JgxPl25fRbe4 bGx9D+LvTvQ0am5C1s8dDcpEd53jbIdKiMM+vhVGmjcvtfA2L01i1aA9pw1zVhyn FKZXSKOwWjxDzWa/oTLAUzawcLPS3i/0FsDH5TVBLM57OI7bSP1kqzdgFOfR/X5L KQmuY1TeiYZCeS/JtNHqV1/vap8jucGJEYXcQe/neaD9VvJYGYFEBXFvi9c/68Lk yLJu4NAYmAp5GnkM+AxXO0aKOVvfNJ6YeGvH+Js7jBPlSdCwa93DzUJgGQxIQD3n mGfjNgu8dyK3fHIrXFEH7mzokfNHE3cE/FI+1hGS7TGLGxvfXsatZEX813Wjc9+Q 9cL2jAnWf1kZLkbDSSJ/6XJ2a121MgmaXqLrzmLznpIkUgEuhWmbL7/gyZy4Q4/+ ZKA/PNykRWolnz/DZNbF5XnUnRdGTB/kJ4pVVuZc9U/3QjmIb0BiqPa7ZiOSVLmS P24V+d3LjK2BU8JX3CnE =eapi -----END PGP SIGNATURE----- Merge tag 'efi-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi into core/efi Pull EFI updates from Matt Fleming: - Fixes and cleanups for SMBIOS 3.0 DMI code. (Ivan Khoronzhuk) - A new efi=debug command line option that enables debug output in the EFI boot stub and results in less verbose EFI memory map output by default. (Borislav Petkov) - Disable interrupts around EFI calls and use a more standard page table saving and restoring idiom when making EFI calls. (Ingo Molnar) - Reduce the number of memory allocations performed when allocating the FDT in EFI boot stub by retrieving size from the FDT header in the EFI config table. (Ard Biesheuvel) Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
84a87c628a
@ -1036,7 +1036,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
Format: {"off" | "on" | "skip[mbr]"}
|
||||
|
||||
efi= [EFI]
|
||||
Format: { "old_map", "nochunk", "noruntime" }
|
||||
Format: { "old_map", "nochunk", "noruntime", "debug" }
|
||||
old_map [X86-64]: switch to the old ioremap-based EFI
|
||||
runtime services mapping. 32-bit still uses this one by
|
||||
default.
|
||||
@ -1044,6 +1044,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
boot stub, as chunking can cause problems with some
|
||||
firmware implementations.
|
||||
noruntime : disable EFI runtime services support
|
||||
debug: enable misc debug output
|
||||
|
||||
efi_no_storage_paranoia [EFI; X86]
|
||||
Using this parameter you can use more than 50% of
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define _ASM_X86_EFI_H
|
||||
|
||||
#include <asm/i387.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
/*
|
||||
* We map the EFI regions needed for runtime services non-contiguously,
|
||||
* with preserved alignment on virtual addresses starting from -4G down
|
||||
@ -89,8 +91,8 @@ extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size,
|
||||
extern struct efi_scratch efi_scratch;
|
||||
extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
|
||||
extern int __init efi_memblock_x86_reserve_range(void);
|
||||
extern void __init efi_call_phys_prolog(void);
|
||||
extern void __init efi_call_phys_epilog(void);
|
||||
extern pgd_t * __init efi_call_phys_prolog(void);
|
||||
extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
|
||||
extern void __init efi_unmap_memmap(void);
|
||||
extern void __init efi_memory_uc(u64 addr, unsigned long size);
|
||||
extern void __init efi_map_region(efi_memory_desc_t *md);
|
||||
|
@ -85,12 +85,20 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
|
||||
efi_memory_desc_t *virtual_map)
|
||||
{
|
||||
efi_status_t status;
|
||||
unsigned long flags;
|
||||
pgd_t *save_pgd;
|
||||
|
||||
efi_call_phys_prolog();
|
||||
save_pgd = efi_call_phys_prolog();
|
||||
|
||||
/* Disable interrupts around EFI calls: */
|
||||
local_irq_save(flags);
|
||||
status = efi_call_phys(efi_phys.set_virtual_address_map,
|
||||
memory_map_size, descriptor_size,
|
||||
descriptor_version, virtual_map);
|
||||
efi_call_phys_epilog();
|
||||
local_irq_restore(flags);
|
||||
|
||||
efi_call_phys_epilog(save_pgd);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -491,7 +499,8 @@ void __init efi_init(void)
|
||||
if (efi_memmap_init())
|
||||
return;
|
||||
|
||||
print_efi_memmap();
|
||||
if (efi_enabled(EFI_DBG))
|
||||
print_efi_memmap();
|
||||
}
|
||||
|
||||
void __init efi_late_init(void)
|
||||
@ -939,6 +948,8 @@ static int __init arch_parse_efi_cmdline(char *str)
|
||||
{
|
||||
if (parse_option_str(str, "old_map"))
|
||||
set_bit(EFI_OLD_MEMMAP, &efi.flags);
|
||||
if (parse_option_str(str, "debug"))
|
||||
set_bit(EFI_DBG, &efi.flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,11 +33,10 @@
|
||||
|
||||
/*
|
||||
* To make EFI call EFI runtime service in physical addressing mode we need
|
||||
* prolog/epilog before/after the invocation to disable interrupt, to
|
||||
* claim EFI runtime service handler exclusively and to duplicate a memory in
|
||||
* low memory space say 0 - 3G.
|
||||
* prolog/epilog before/after the invocation to claim the EFI runtime service
|
||||
* handler exclusively and to duplicate a memory mapping in low memory space,
|
||||
* say 0 - 3G.
|
||||
*/
|
||||
static unsigned long efi_rt_eflags;
|
||||
|
||||
void efi_sync_low_kernel_mappings(void) {}
|
||||
void __init efi_dump_pagetable(void) {}
|
||||
@ -57,21 +56,24 @@ void __init efi_map_region(efi_memory_desc_t *md)
|
||||
void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
|
||||
void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
|
||||
|
||||
void __init efi_call_phys_prolog(void)
|
||||
pgd_t * __init efi_call_phys_prolog(void)
|
||||
{
|
||||
struct desc_ptr gdt_descr;
|
||||
pgd_t *save_pgd;
|
||||
|
||||
local_irq_save(efi_rt_eflags);
|
||||
|
||||
/* Current pgd is swapper_pg_dir, we'll restore it later: */
|
||||
save_pgd = swapper_pg_dir;
|
||||
load_cr3(initial_page_table);
|
||||
__flush_tlb_all();
|
||||
|
||||
gdt_descr.address = __pa(get_cpu_gdt_table(0));
|
||||
gdt_descr.size = GDT_SIZE - 1;
|
||||
load_gdt(&gdt_descr);
|
||||
|
||||
return save_pgd;
|
||||
}
|
||||
|
||||
void __init efi_call_phys_epilog(void)
|
||||
void __init efi_call_phys_epilog(pgd_t *save_pgd)
|
||||
{
|
||||
struct desc_ptr gdt_descr;
|
||||
|
||||
@ -79,10 +81,8 @@ void __init efi_call_phys_epilog(void)
|
||||
gdt_descr.size = GDT_SIZE - 1;
|
||||
load_gdt(&gdt_descr);
|
||||
|
||||
load_cr3(swapper_pg_dir);
|
||||
load_cr3(save_pgd);
|
||||
__flush_tlb_all();
|
||||
|
||||
local_irq_restore(efi_rt_eflags);
|
||||
}
|
||||
|
||||
void __init efi_runtime_mkexec(void)
|
||||
|
@ -41,9 +41,6 @@
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
static pgd_t *save_pgd __initdata;
|
||||
static unsigned long efi_flags __initdata;
|
||||
|
||||
/*
|
||||
* We allocate runtime services regions bottom-up, starting from -4G, i.e.
|
||||
* 0xffff_ffff_0000_0000 and limit EFI VA mapping space to 64G.
|
||||
@ -78,17 +75,18 @@ static void __init early_code_mapping_set_exec(int executable)
|
||||
}
|
||||
}
|
||||
|
||||
void __init efi_call_phys_prolog(void)
|
||||
pgd_t * __init efi_call_phys_prolog(void)
|
||||
{
|
||||
unsigned long vaddress;
|
||||
pgd_t *save_pgd;
|
||||
|
||||
int pgd;
|
||||
int n_pgds;
|
||||
|
||||
if (!efi_enabled(EFI_OLD_MEMMAP))
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
early_code_mapping_set_exec(1);
|
||||
local_irq_save(efi_flags);
|
||||
|
||||
n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
|
||||
save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
|
||||
@ -99,24 +97,29 @@ void __init efi_call_phys_prolog(void)
|
||||
set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress));
|
||||
}
|
||||
__flush_tlb_all();
|
||||
|
||||
return save_pgd;
|
||||
}
|
||||
|
||||
void __init efi_call_phys_epilog(void)
|
||||
void __init efi_call_phys_epilog(pgd_t *save_pgd)
|
||||
{
|
||||
/*
|
||||
* After the lock is released, the original page table is restored.
|
||||
*/
|
||||
int pgd;
|
||||
int n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
|
||||
int pgd_idx;
|
||||
int nr_pgds;
|
||||
|
||||
if (!efi_enabled(EFI_OLD_MEMMAP))
|
||||
if (!save_pgd)
|
||||
return;
|
||||
|
||||
for (pgd = 0; pgd < n_pgds; pgd++)
|
||||
set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]);
|
||||
nr_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
|
||||
|
||||
for (pgd_idx = 0; pgd_idx < nr_pgds; pgd_idx++)
|
||||
set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]);
|
||||
|
||||
kfree(save_pgd);
|
||||
|
||||
__flush_tlb_all();
|
||||
local_irq_restore(efi_flags);
|
||||
early_code_mapping_set_exec(0);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,9 @@
|
||||
*/
|
||||
static const char dmi_empty_string[] = " ";
|
||||
|
||||
static u16 __initdata dmi_ver;
|
||||
static u32 dmi_ver __initdata;
|
||||
static u32 dmi_len;
|
||||
static u16 dmi_num;
|
||||
/*
|
||||
* Catch too early calls to dmi_check_system():
|
||||
*/
|
||||
@ -78,7 +80,7 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
|
||||
* We have to be cautious here. We have seen BIOSes with DMI pointers
|
||||
* pointing to completely the wrong place for example
|
||||
*/
|
||||
static void dmi_table(u8 *buf, u32 len, int num,
|
||||
static void dmi_table(u8 *buf,
|
||||
void (*decode)(const struct dmi_header *, void *),
|
||||
void *private_data)
|
||||
{
|
||||
@ -89,7 +91,8 @@ static void dmi_table(u8 *buf, u32 len, int num,
|
||||
* Stop when we see all the items the table claimed to have
|
||||
* OR we run off the end of the table (also happens)
|
||||
*/
|
||||
while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
|
||||
while ((i < dmi_num) && (data - buf + sizeof(struct dmi_header))
|
||||
<= dmi_len) {
|
||||
const struct dmi_header *dm = (const struct dmi_header *)data;
|
||||
|
||||
/*
|
||||
@ -98,9 +101,9 @@ static void dmi_table(u8 *buf, u32 len, int num,
|
||||
* table in dmi_decode or dmi_string
|
||||
*/
|
||||
data += dm->length;
|
||||
while ((data - buf < len - 1) && (data[0] || data[1]))
|
||||
while ((data - buf < dmi_len - 1) && (data[0] || data[1]))
|
||||
data++;
|
||||
if (data - buf < len - 1)
|
||||
if (data - buf < dmi_len - 1)
|
||||
decode(dm, private_data);
|
||||
|
||||
/*
|
||||
@ -115,8 +118,6 @@ static void dmi_table(u8 *buf, u32 len, int num,
|
||||
}
|
||||
|
||||
static phys_addr_t dmi_base;
|
||||
static u32 dmi_len;
|
||||
static u16 dmi_num;
|
||||
|
||||
static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
|
||||
void *))
|
||||
@ -127,7 +128,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
dmi_table(buf, dmi_len, dmi_num, decode, NULL);
|
||||
dmi_table(buf, decode, NULL);
|
||||
|
||||
add_device_randomness(buf, dmi_len);
|
||||
|
||||
@ -198,7 +199,7 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot,
|
||||
* the UUID are supposed to be little-endian encoded. The specification
|
||||
* says that this is the defacto standard.
|
||||
*/
|
||||
if (dmi_ver >= 0x0206)
|
||||
if (dmi_ver >= 0x020600)
|
||||
sprintf(s, "%pUL", d);
|
||||
else
|
||||
sprintf(s, "%pUB", d);
|
||||
@ -470,7 +471,7 @@ static void __init dmi_format_ids(char *buf, size_t len)
|
||||
*/
|
||||
static int __init dmi_present(const u8 *buf)
|
||||
{
|
||||
int smbios_ver;
|
||||
u32 smbios_ver;
|
||||
|
||||
if (memcmp(buf, "_SM_", 4) == 0 &&
|
||||
buf[5] < 32 && dmi_checksum(buf, buf[5])) {
|
||||
@ -503,14 +504,16 @@ static int __init dmi_present(const u8 *buf)
|
||||
if (dmi_walk_early(dmi_decode) == 0) {
|
||||
if (smbios_ver) {
|
||||
dmi_ver = smbios_ver;
|
||||
pr_info("SMBIOS %d.%d present.\n",
|
||||
dmi_ver >> 8, dmi_ver & 0xFF);
|
||||
pr_info("SMBIOS %d.%d%s present.\n",
|
||||
dmi_ver >> 8, dmi_ver & 0xFF,
|
||||
(dmi_ver < 0x0300) ? "" : ".x");
|
||||
} else {
|
||||
dmi_ver = (buf[14] & 0xF0) << 4 |
|
||||
(buf[14] & 0x0F);
|
||||
pr_info("Legacy DMI %d.%d present.\n",
|
||||
dmi_ver >> 8, dmi_ver & 0xFF);
|
||||
}
|
||||
dmi_ver <<= 8;
|
||||
dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
|
||||
printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
|
||||
return 0;
|
||||
@ -528,7 +531,8 @@ 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_ver = get_unaligned_be32(buf + 6);
|
||||
dmi_ver &= 0xFFFFFF;
|
||||
dmi_len = get_unaligned_le32(buf + 12);
|
||||
dmi_base = get_unaligned_le64(buf + 16);
|
||||
|
||||
@ -545,8 +549,9 @@ static int __init dmi_smbios3_present(const u8 *buf)
|
||||
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);
|
||||
pr_info("SMBIOS %d.%d.%d present.\n",
|
||||
dmi_ver >> 16, (dmi_ver >> 8) & 0xFF,
|
||||
dmi_ver & 0xFF);
|
||||
dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
|
||||
pr_debug("DMI: %s\n", dmi_ids_string);
|
||||
return 0;
|
||||
@ -901,7 +906,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
dmi_table(buf, dmi_len, dmi_num, decode, private_data);
|
||||
dmi_table(buf, decode, private_data);
|
||||
|
||||
dmi_unmap(buf);
|
||||
return 0;
|
||||
|
@ -175,7 +175,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
|
||||
unsigned long initrd_addr;
|
||||
u64 initrd_size = 0;
|
||||
unsigned long fdt_addr = 0; /* Original DTB */
|
||||
u64 fdt_size = 0; /* We don't get size from configuration table */
|
||||
unsigned long fdt_size = 0;
|
||||
char *cmdline_ptr = NULL;
|
||||
int cmdline_size = 0;
|
||||
unsigned long new_fdt_addr;
|
||||
@ -239,8 +239,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
|
||||
} else {
|
||||
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
|
||||
"dtb=",
|
||||
~0UL, (unsigned long *)&fdt_addr,
|
||||
(unsigned long *)&fdt_size);
|
||||
~0UL, &fdt_addr, &fdt_size);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err(sys_table, "Failed to load device tree!\n");
|
||||
@ -252,7 +251,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
|
||||
pr_efi(sys_table, "Using DTB from command line\n");
|
||||
} else {
|
||||
/* Look for a device tree configuration table entry. */
|
||||
fdt_addr = (uintptr_t)get_fdt(sys_table);
|
||||
fdt_addr = (uintptr_t)get_fdt(sys_table, &fdt_size);
|
||||
if (fdt_addr)
|
||||
pr_efi(sys_table, "Using DTB from configuration table\n");
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
||||
unsigned long fdt_addr,
|
||||
unsigned long fdt_size);
|
||||
|
||||
void *get_fdt(efi_system_table_t *sys_table);
|
||||
void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size);
|
||||
|
||||
void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
|
||||
unsigned long desc_size, efi_memory_desc_t *runtime_map,
|
||||
|
@ -323,7 +323,7 @@ fail:
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
void *get_fdt(efi_system_table_t *sys_table)
|
||||
void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size)
|
||||
{
|
||||
efi_guid_t fdt_guid = DEVICE_TREE_GUID;
|
||||
efi_config_table_t *tables;
|
||||
@ -336,6 +336,11 @@ void *get_fdt(efi_system_table_t *sys_table)
|
||||
for (i = 0; i < sys_table->nr_tables; i++)
|
||||
if (efi_guidcmp(tables[i].guid, fdt_guid) == 0) {
|
||||
fdt = (void *) tables[i].table;
|
||||
if (fdt_check_header(fdt) != 0) {
|
||||
pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
|
||||
return NULL;
|
||||
}
|
||||
*fdt_size = fdt_totalsize(fdt);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -942,6 +942,7 @@ extern int __init efi_setup_pcdp_console(char *);
|
||||
#define EFI_64BIT 5 /* Is the firmware 64-bit? */
|
||||
#define EFI_PARAVIRT 6 /* Access is via a paravirt interface */
|
||||
#define EFI_ARCH_1 7 /* First arch-specific bit */
|
||||
#define EFI_DBG 8 /* Print additional debug info at runtime */
|
||||
|
||||
#ifdef CONFIG_EFI
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user