Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull EFI updates from Ingo Molnar:

 - refactor the EFI config table handling across architectures

 - add support for the Dell EMC OEM config table

 - include AER diagnostic output to CPER handling of fatal PCIe errors

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efi: cper: print AER info of PCIe fatal error
  efi: Export Runtime Configuration Interface table to sysfs
  efi: ia64: move SAL systab handling out of generic EFI code
  efi/x86: move UV_SYSTAB handling into arch/x86
  efi: x86: move efi_is_table_address() into arch/x86
This commit is contained in:
Linus Torvalds
2019-09-16 16:47:38 -07:00
15 changed files with 250 additions and 52 deletions

View File

@@ -180,6 +180,19 @@ config RESET_ATTACK_MITIGATION
have been evicted, since otherwise it will trigger even on clean
reboots.
config EFI_RCI2_TABLE
bool "EFI Runtime Configuration Interface Table Version 2 Support"
help
Displays the content of the Runtime Configuration Interface
Table version 2 on Dell EMC PowerEdge systems as a binary
attribute 'rci2' under /sys/firmware/efi/tables directory.
RCI2 table contains BIOS HII in XML format and is used to populate
BIOS setup page in Dell EMC OpenManage Server Administrator tool.
The BIOS setup page contains BIOS tokens which can be configured.
Say Y here for Dell EMC PowerEdge systems.
endmenu
config UEFI_CPER

View File

@@ -25,6 +25,7 @@ obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
obj-$(CONFIG_EFI_TEST) += test/
obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
obj-$(CONFIG_ARM) += $(arm-obj-y)

View File

@@ -390,6 +390,21 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
printk(
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
/* Fatal errors call __ghes_panic() before AER handler prints this */
if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
(gdata->error_severity & CPER_SEV_FATAL)) {
struct aer_capability_regs *aer;
aer = (struct aer_capability_regs *)pcie->aer_info;
printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
pfx, aer->uncor_status, aer->uncor_mask);
printk("%saer_uncor_severity: 0x%08x\n",
pfx, aer->uncor_severity);
printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
aer->header_log.dw0, aer->header_log.dw1,
aer->header_log.dw2, aer->header_log.dw3);
}
}
static void cper_print_tstamp(const char *pfx,

View File

@@ -39,11 +39,9 @@ struct efi __read_mostly efi = {
.acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR,
.uga = EFI_INVALID_TABLE_ADDR,
.uv_systab = EFI_INVALID_TABLE_ADDR,
.fw_vendor = EFI_INVALID_TABLE_ADDR,
.runtime = EFI_INVALID_TABLE_ADDR,
.config_table = EFI_INVALID_TABLE_ADDR,
@@ -57,25 +55,6 @@ struct efi __read_mostly efi = {
};
EXPORT_SYMBOL(efi);
static unsigned long *efi_tables[] = {
&efi.mps,
&efi.acpi,
&efi.acpi20,
&efi.smbios,
&efi.smbios3,
&efi.sal_systab,
&efi.boot_info,
&efi.hcdp,
&efi.uga,
&efi.uv_systab,
&efi.fw_vendor,
&efi.runtime,
&efi.config_table,
&efi.esrt,
&efi.properties_table,
&efi.mem_attr_table,
};
struct mm_struct efi_mm = {
.mm_rb = RB_ROOT,
.mm_users = ATOMIC_INIT(2),
@@ -476,7 +455,6 @@ static __initdata efi_config_table_type_t common_tables[] = {
{ACPI_TABLE_GUID, "ACPI", &efi.acpi},
{HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
{MPS_TABLE_GUID, "MPS", &efi.mps},
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
@@ -487,6 +465,9 @@ static __initdata efi_config_table_type_t common_tables[] = {
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
{LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
{LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
#ifdef CONFIG_EFI_RCI2_TABLE
{DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
#endif
{NULL_GUID, NULL, NULL},
};
@@ -964,20 +945,6 @@ int efi_status_to_err(efi_status_t status)
return err;
}
bool efi_is_table_address(unsigned long phys_addr)
{
unsigned int i;
if (phys_addr == EFI_INVALID_TABLE_ADDR)
return false;
for (i = 0; i < ARRAY_SIZE(efi_tables); i++)
if (*(efi_tables[i]) == phys_addr)
return true;
return false;
}
static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;

View File

@@ -0,0 +1,147 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Export Runtime Configuration Interface Table Version 2 (RCI2)
* to sysfs
*
* Copyright (C) 2019 Dell Inc
* by Narendra K <Narendra.K@dell.com>
*
* System firmware advertises the address of the RCI2 Table via
* an EFI Configuration Table entry. This code retrieves the RCI2
* table from the address and exports it to sysfs as a binary
* attribute 'rci2' under /sys/firmware/efi/tables directory.
*/
#include <linux/kobject.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/efi.h>
#include <linux/types.h>
#include <linux/io.h>
#define RCI_SIGNATURE "_RC_"
struct rci2_table_global_hdr {
u16 type;
u16 resvd0;
u16 hdr_len;
u8 rci2_sig[4];
u16 resvd1;
u32 resvd2;
u32 resvd3;
u8 major_rev;
u8 minor_rev;
u16 num_of_structs;
u32 rci2_len;
u16 rci2_chksum;
} __packed;
static u8 *rci2_base;
static u32 rci2_table_len;
unsigned long rci2_table_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t pos, size_t count)
{
memcpy(buf, attr->private + pos, count);
return count;
}
static BIN_ATTR(rci2, S_IRUSR, raw_table_read, NULL, 0);
static u16 checksum(void)
{
u8 len_is_odd = rci2_table_len % 2;
u32 chksum_len = rci2_table_len;
u16 *base = (u16 *)rci2_base;
u8 buf[2] = {0};
u32 offset = 0;
u16 chksum = 0;
if (len_is_odd)
chksum_len -= 1;
while (offset < chksum_len) {
chksum += *base;
offset += 2;
base++;
}
if (len_is_odd) {
buf[0] = *(u8 *)base;
chksum += *(u16 *)(buf);
}
return chksum;
}
int __init efi_rci2_sysfs_init(void)
{
struct kobject *tables_kobj;
int ret = -ENOMEM;
rci2_base = memremap(rci2_table_phys,
sizeof(struct rci2_table_global_hdr),
MEMREMAP_WB);
if (!rci2_base) {
pr_debug("RCI2 table init failed - could not map RCI2 table\n");
goto err;
}
if (strncmp(rci2_base +
offsetof(struct rci2_table_global_hdr, rci2_sig),
RCI_SIGNATURE, 4)) {
pr_debug("RCI2 table init failed - incorrect signature\n");
ret = -ENODEV;
goto err_unmap;
}
rci2_table_len = *(u32 *)(rci2_base +
offsetof(struct rci2_table_global_hdr,
rci2_len));
memunmap(rci2_base);
if (!rci2_table_len) {
pr_debug("RCI2 table init failed - incorrect table length\n");
goto err;
}
rci2_base = memremap(rci2_table_phys, rci2_table_len, MEMREMAP_WB);
if (!rci2_base) {
pr_debug("RCI2 table - could not map RCI2 table\n");
goto err;
}
if (checksum() != 0) {
pr_debug("RCI2 table - incorrect checksum\n");
ret = -ENODEV;
goto err_unmap;
}
tables_kobj = kobject_create_and_add("tables", efi_kobj);
if (!tables_kobj) {
pr_debug("RCI2 table - tables_kobj creation failed\n");
goto err_unmap;
}
bin_attr_rci2.size = rci2_table_len;
bin_attr_rci2.private = rci2_base;
ret = sysfs_create_bin_file(tables_kobj, &bin_attr_rci2);
if (ret != 0) {
pr_debug("RCI2 table - rci2 sysfs bin file creation failed\n");
kobject_del(tables_kobj);
kobject_put(tables_kobj);
goto err_unmap;
}
return 0;
err_unmap:
memunmap(rci2_base);
err:
pr_debug("RCI2 table - sysfs initialization failed\n");
return ret;
}
late_initcall(efi_rci2_sysfs_init);