summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-16 19:47:38 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-16 19:47:38 -0400
commitcc9b499a1f71696054a2771aae504c53eecff31d (patch)
tree96b18e65c38bfcacd2f03a9012bd5384e1c54bf2
parent98c82b4b8be60b05bc96aa4ab664ca0b0e39001f (diff)
parentd3dc0168e93233ba4d4ed9a2c506c9d2b8d8cd33 (diff)
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
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-efi8
-rw-r--r--arch/ia64/include/asm/sal.h1
-rw-r--r--arch/ia64/kernel/efi.c3
-rw-r--r--arch/ia64/kernel/setup.c2
-rw-r--r--arch/x86/include/asm/efi.h5
-rw-r--r--arch/x86/include/asm/uv/uv.h4
-rw-r--r--arch/x86/mm/ioremap.c1
-rw-r--r--arch/x86/platform/efi/efi.c39
-rw-r--r--arch/x86/platform/uv/bios_uv.c10
-rw-r--r--drivers/firmware/efi/Kconfig13
-rw-r--r--drivers/firmware/efi/Makefile1
-rw-r--r--drivers/firmware/efi/cper.c15
-rw-r--r--drivers/firmware/efi/efi.c39
-rw-r--r--drivers/firmware/efi/rci2-table.c147
-rw-r--r--include/linux/efi.h14
15 files changed, 250 insertions, 52 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-efi b/Documentation/ABI/testing/sysfs-firmware-efi
index e794eac32a90..5e4d0b27cdfe 100644
--- a/Documentation/ABI/testing/sysfs-firmware-efi
+++ b/Documentation/ABI/testing/sysfs-firmware-efi
@@ -28,3 +28,11 @@ Description: Displays the physical addresses of all EFI Configuration
28 versions are always printed first, i.e. ACPI20 comes 28 versions are always printed first, i.e. ACPI20 comes
29 before ACPI. 29 before ACPI.
30Users: dmidecode 30Users: dmidecode
31
32What: /sys/firmware/efi/tables/rci2
33Date: July 2019
34Contact: Narendra K <Narendra.K@dell.com>, linux-bugs@dell.com
35Description: Displays the content of the Runtime Configuration Interface
36 Table version 2 on Dell EMC PowerEdge systems in binary format
37Users: It is used by Dell EMC OpenManage Server Administrator tool to
38 populate BIOS setup page.
diff --git a/arch/ia64/include/asm/sal.h b/arch/ia64/include/asm/sal.h
index 588f33156da6..08f5b6aaed73 100644
--- a/arch/ia64/include/asm/sal.h
+++ b/arch/ia64/include/asm/sal.h
@@ -43,6 +43,7 @@
43#include <asm/pal.h> 43#include <asm/pal.h>
44#include <asm/fpu.h> 44#include <asm/fpu.h>
45 45
46extern unsigned long sal_systab_phys;
46extern spinlock_t sal_lock; 47extern spinlock_t sal_lock;
47 48
48/* SAL spec _requires_ eight args for each call. */ 49/* SAL spec _requires_ eight args for each call. */
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 3795d18276c4..0a34dcc435c6 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -47,8 +47,11 @@
47 47
48static __initdata unsigned long palo_phys; 48static __initdata unsigned long palo_phys;
49 49
50unsigned long sal_systab_phys = EFI_INVALID_TABLE_ADDR;
51
50static __initdata efi_config_table_type_t arch_tables[] = { 52static __initdata efi_config_table_type_t arch_tables[] = {
51 {PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys}, 53 {PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys},
54 {SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys},
52 {NULL_GUID, NULL, 0}, 55 {NULL_GUID, NULL, 0},
53}; 56};
54 57
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 18de565d5825..8eb276aac5ce 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -586,7 +586,7 @@ setup_arch (char **cmdline_p)
586 find_memory(); 586 find_memory();
587 587
588 /* process SAL system table: */ 588 /* process SAL system table: */
589 ia64_sal_init(__va(efi.sal_systab)); 589 ia64_sal_init(__va(sal_systab_phys));
590 590
591#ifdef CONFIG_ITANIUM 591#ifdef CONFIG_ITANIUM
592 ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist); 592 ia64_patch_rse((u64) __start___rse_patchlist, (u64) __end___rse_patchlist);
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 606a4b6a9812..43a82e59c59d 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -242,6 +242,7 @@ static inline bool efi_is_64bit(void)
242 __efi_early()->runtime_services), __VA_ARGS__) 242 __efi_early()->runtime_services), __VA_ARGS__)
243 243
244extern bool efi_reboot_required(void); 244extern bool efi_reboot_required(void);
245extern bool efi_is_table_address(unsigned long phys_addr);
245 246
246#else 247#else
247static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} 248static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
@@ -249,6 +250,10 @@ static inline bool efi_reboot_required(void)
249{ 250{
250 return false; 251 return false;
251} 252}
253static inline bool efi_is_table_address(unsigned long phys_addr)
254{
255 return false;
256}
252#endif /* CONFIG_EFI */ 257#endif /* CONFIG_EFI */
253 258
254#endif /* _ASM_X86_EFI_H */ 259#endif /* _ASM_X86_EFI_H */
diff --git a/arch/x86/include/asm/uv/uv.h b/arch/x86/include/asm/uv/uv.h
index e60c45fd3679..6bc6d89d8e2a 100644
--- a/arch/x86/include/asm/uv/uv.h
+++ b/arch/x86/include/asm/uv/uv.h
@@ -12,10 +12,12 @@ struct mm_struct;
12#ifdef CONFIG_X86_UV 12#ifdef CONFIG_X86_UV
13#include <linux/efi.h> 13#include <linux/efi.h>
14 14
15extern unsigned long uv_systab_phys;
16
15extern enum uv_system_type get_uv_system_type(void); 17extern enum uv_system_type get_uv_system_type(void);
16static inline bool is_early_uv_system(void) 18static inline bool is_early_uv_system(void)
17{ 19{
18 return !((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || !efi.uv_systab); 20 return uv_systab_phys && uv_systab_phys != EFI_INVALID_TABLE_ADDR;
19} 21}
20extern int is_uv_system(void); 22extern int is_uv_system(void);
21extern int is_uv_hubless(void); 23extern int is_uv_hubless(void);
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 63e99f15d7cf..a39dcdb5ae34 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -19,6 +19,7 @@
19 19
20#include <asm/set_memory.h> 20#include <asm/set_memory.h>
21#include <asm/e820/api.h> 21#include <asm/e820/api.h>
22#include <asm/efi.h>
22#include <asm/fixmap.h> 23#include <asm/fixmap.h>
23#include <asm/pgtable.h> 24#include <asm/pgtable.h>
24#include <asm/tlbflush.h> 25#include <asm/tlbflush.h>
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index a7189a3b4d70..c202e1b07e29 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -59,11 +59,34 @@ static efi_system_table_t efi_systab __initdata;
59 59
60static efi_config_table_type_t arch_tables[] __initdata = { 60static efi_config_table_type_t arch_tables[] __initdata = {
61#ifdef CONFIG_X86_UV 61#ifdef CONFIG_X86_UV
62 {UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab}, 62 {UV_SYSTEM_TABLE_GUID, "UVsystab", &uv_systab_phys},
63#endif 63#endif
64 {NULL_GUID, NULL, NULL}, 64 {NULL_GUID, NULL, NULL},
65}; 65};
66 66
67static const unsigned long * const efi_tables[] = {
68 &efi.mps,
69 &efi.acpi,
70 &efi.acpi20,
71 &efi.smbios,
72 &efi.smbios3,
73 &efi.boot_info,
74 &efi.hcdp,
75 &efi.uga,
76#ifdef CONFIG_X86_UV
77 &uv_systab_phys,
78#endif
79 &efi.fw_vendor,
80 &efi.runtime,
81 &efi.config_table,
82 &efi.esrt,
83 &efi.properties_table,
84 &efi.mem_attr_table,
85#ifdef CONFIG_EFI_RCI2_TABLE
86 &rci2_table_phys,
87#endif
88};
89
67u64 efi_setup; /* efi setup_data physical address */ 90u64 efi_setup; /* efi setup_data physical address */
68 91
69static int add_efi_memmap __initdata; 92static int add_efi_memmap __initdata;
@@ -1049,3 +1072,17 @@ static int __init arch_parse_efi_cmdline(char *str)
1049 return 0; 1072 return 0;
1050} 1073}
1051early_param("efi", arch_parse_efi_cmdline); 1074early_param("efi", arch_parse_efi_cmdline);
1075
1076bool efi_is_table_address(unsigned long phys_addr)
1077{
1078 unsigned int i;
1079
1080 if (phys_addr == EFI_INVALID_TABLE_ADDR)
1081 return false;
1082
1083 for (i = 0; i < ARRAY_SIZE(efi_tables); i++)
1084 if (*(efi_tables[i]) == phys_addr)
1085 return true;
1086
1087 return false;
1088}
diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c
index 7c69652ffeea..c2ee31953372 100644
--- a/arch/x86/platform/uv/bios_uv.c
+++ b/arch/x86/platform/uv/bios_uv.c
@@ -14,6 +14,8 @@
14#include <asm/uv/bios.h> 14#include <asm/uv/bios.h>
15#include <asm/uv/uv_hub.h> 15#include <asm/uv/uv_hub.h>
16 16
17unsigned long uv_systab_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
18
17struct uv_systab *uv_systab; 19struct uv_systab *uv_systab;
18 20
19static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, 21static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
@@ -185,13 +187,13 @@ EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
185void uv_bios_init(void) 187void uv_bios_init(void)
186{ 188{
187 uv_systab = NULL; 189 uv_systab = NULL;
188 if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) || 190 if ((uv_systab_phys == EFI_INVALID_TABLE_ADDR) ||
189 !efi.uv_systab || efi_runtime_disabled()) { 191 !uv_systab_phys || efi_runtime_disabled()) {
190 pr_crit("UV: UVsystab: missing\n"); 192 pr_crit("UV: UVsystab: missing\n");
191 return; 193 return;
192 } 194 }
193 195
194 uv_systab = ioremap(efi.uv_systab, sizeof(struct uv_systab)); 196 uv_systab = ioremap(uv_systab_phys, sizeof(struct uv_systab));
195 if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) { 197 if (!uv_systab || strncmp(uv_systab->signature, UV_SYSTAB_SIG, 4)) {
196 pr_err("UV: UVsystab: bad signature!\n"); 198 pr_err("UV: UVsystab: bad signature!\n");
197 iounmap(uv_systab); 199 iounmap(uv_systab);
@@ -203,7 +205,7 @@ void uv_bios_init(void)
203 int size = uv_systab->size; 205 int size = uv_systab->size;
204 206
205 iounmap(uv_systab); 207 iounmap(uv_systab);
206 uv_systab = ioremap(efi.uv_systab, size); 208 uv_systab = ioremap(uv_systab_phys, size);
207 if (!uv_systab) { 209 if (!uv_systab) {
208 pr_err("UV: UVsystab: ioremap(%d) failed!\n", size); 210 pr_err("UV: UVsystab: ioremap(%d) failed!\n", size);
209 return; 211 return;
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index d4ea929e8b34..178ee8106828 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -180,6 +180,19 @@ config RESET_ATTACK_MITIGATION
180 have been evicted, since otherwise it will trigger even on clean 180 have been evicted, since otherwise it will trigger even on clean
181 reboots. 181 reboots.
182 182
183config EFI_RCI2_TABLE
184 bool "EFI Runtime Configuration Interface Table Version 2 Support"
185 help
186 Displays the content of the Runtime Configuration Interface
187 Table version 2 on Dell EMC PowerEdge systems as a binary
188 attribute 'rci2' under /sys/firmware/efi/tables directory.
189
190 RCI2 table contains BIOS HII in XML format and is used to populate
191 BIOS setup page in Dell EMC OpenManage Server Administrator tool.
192 The BIOS setup page contains BIOS tokens which can be configured.
193
194 Say Y here for Dell EMC PowerEdge systems.
195
183endmenu 196endmenu
184 197
185config UEFI_CPER 198config UEFI_CPER
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index d2d0d2030620..4ac2de4dfa72 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
25obj-$(CONFIG_EFI_TEST) += test/ 25obj-$(CONFIG_EFI_TEST) += test/
26obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o 26obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
27obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o 27obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
28obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
28 29
29arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o 30arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
30obj-$(CONFIG_ARM) += $(arm-obj-y) 31obj-$(CONFIG_ARM) += $(arm-obj-y)
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 8fa977c7861f..addf0749dd8b 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -390,6 +390,21 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
390 printk( 390 printk(
391 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 391 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
392 pfx, pcie->bridge.secondary_status, pcie->bridge.control); 392 pfx, pcie->bridge.secondary_status, pcie->bridge.control);
393
394 /* Fatal errors call __ghes_panic() before AER handler prints this */
395 if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
396 (gdata->error_severity & CPER_SEV_FATAL)) {
397 struct aer_capability_regs *aer;
398
399 aer = (struct aer_capability_regs *)pcie->aer_info;
400 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
401 pfx, aer->uncor_status, aer->uncor_mask);
402 printk("%saer_uncor_severity: 0x%08x\n",
403 pfx, aer->uncor_severity);
404 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
405 aer->header_log.dw0, aer->header_log.dw1,
406 aer->header_log.dw2, aer->header_log.dw3);
407 }
393} 408}
394 409
395static void cper_print_tstamp(const char *pfx, 410static void cper_print_tstamp(const char *pfx,
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index ad3b1f4866b3..8f1ab04f6743 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -39,11 +39,9 @@ struct efi __read_mostly efi = {
39 .acpi20 = EFI_INVALID_TABLE_ADDR, 39 .acpi20 = EFI_INVALID_TABLE_ADDR,
40 .smbios = EFI_INVALID_TABLE_ADDR, 40 .smbios = EFI_INVALID_TABLE_ADDR,
41 .smbios3 = EFI_INVALID_TABLE_ADDR, 41 .smbios3 = EFI_INVALID_TABLE_ADDR,
42 .sal_systab = EFI_INVALID_TABLE_ADDR,
43 .boot_info = EFI_INVALID_TABLE_ADDR, 42 .boot_info = EFI_INVALID_TABLE_ADDR,
44 .hcdp = EFI_INVALID_TABLE_ADDR, 43 .hcdp = EFI_INVALID_TABLE_ADDR,
45 .uga = EFI_INVALID_TABLE_ADDR, 44 .uga = EFI_INVALID_TABLE_ADDR,
46 .uv_systab = EFI_INVALID_TABLE_ADDR,
47 .fw_vendor = EFI_INVALID_TABLE_ADDR, 45 .fw_vendor = EFI_INVALID_TABLE_ADDR,
48 .runtime = EFI_INVALID_TABLE_ADDR, 46 .runtime = EFI_INVALID_TABLE_ADDR,
49 .config_table = EFI_INVALID_TABLE_ADDR, 47 .config_table = EFI_INVALID_TABLE_ADDR,
@@ -57,25 +55,6 @@ struct efi __read_mostly efi = {
57}; 55};
58EXPORT_SYMBOL(efi); 56EXPORT_SYMBOL(efi);
59 57
60static unsigned long *efi_tables[] = {
61 &efi.mps,
62 &efi.acpi,
63 &efi.acpi20,
64 &efi.smbios,
65 &efi.smbios3,
66 &efi.sal_systab,
67 &efi.boot_info,
68 &efi.hcdp,
69 &efi.uga,
70 &efi.uv_systab,
71 &efi.fw_vendor,
72 &efi.runtime,
73 &efi.config_table,
74 &efi.esrt,
75 &efi.properties_table,
76 &efi.mem_attr_table,
77};
78
79struct mm_struct efi_mm = { 58struct mm_struct efi_mm = {
80 .mm_rb = RB_ROOT, 59 .mm_rb = RB_ROOT,
81 .mm_users = ATOMIC_INIT(2), 60 .mm_users = ATOMIC_INIT(2),
@@ -476,7 +455,6 @@ static __initdata efi_config_table_type_t common_tables[] = {
476 {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, 455 {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
477 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp}, 456 {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
478 {MPS_TABLE_GUID, "MPS", &efi.mps}, 457 {MPS_TABLE_GUID, "MPS", &efi.mps},
479 {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
480 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, 458 {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
481 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, 459 {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
482 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, 460 {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
@@ -487,6 +465,9 @@ static __initdata efi_config_table_type_t common_tables[] = {
487 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log}, 465 {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
488 {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log}, 466 {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
489 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve}, 467 {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
468#ifdef CONFIG_EFI_RCI2_TABLE
469 {DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
470#endif
490 {NULL_GUID, NULL, NULL}, 471 {NULL_GUID, NULL, NULL},
491}; 472};
492 473
@@ -964,20 +945,6 @@ int efi_status_to_err(efi_status_t status)
964 return err; 945 return err;
965} 946}
966 947
967bool efi_is_table_address(unsigned long phys_addr)
968{
969 unsigned int i;
970
971 if (phys_addr == EFI_INVALID_TABLE_ADDR)
972 return false;
973
974 for (i = 0; i < ARRAY_SIZE(efi_tables); i++)
975 if (*(efi_tables[i]) == phys_addr)
976 return true;
977
978 return false;
979}
980
981static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock); 948static DEFINE_SPINLOCK(efi_mem_reserve_persistent_lock);
982static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init; 949static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
983 950
diff --git a/drivers/firmware/efi/rci2-table.c b/drivers/firmware/efi/rci2-table.c
new file mode 100644
index 000000000000..3e290f96620a
--- /dev/null
+++ b/drivers/firmware/efi/rci2-table.c
@@ -0,0 +1,147 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Export Runtime Configuration Interface Table Version 2 (RCI2)
4 * to sysfs
5 *
6 * Copyright (C) 2019 Dell Inc
7 * by Narendra K <Narendra.K@dell.com>
8 *
9 * System firmware advertises the address of the RCI2 Table via
10 * an EFI Configuration Table entry. This code retrieves the RCI2
11 * table from the address and exports it to sysfs as a binary
12 * attribute 'rci2' under /sys/firmware/efi/tables directory.
13 */
14
15#include <linux/kobject.h>
16#include <linux/device.h>
17#include <linux/sysfs.h>
18#include <linux/efi.h>
19#include <linux/types.h>
20#include <linux/io.h>
21
22#define RCI_SIGNATURE "_RC_"
23
24struct rci2_table_global_hdr {
25 u16 type;
26 u16 resvd0;
27 u16 hdr_len;
28 u8 rci2_sig[4];
29 u16 resvd1;
30 u32 resvd2;
31 u32 resvd3;
32 u8 major_rev;
33 u8 minor_rev;
34 u16 num_of_structs;
35 u32 rci2_len;
36 u16 rci2_chksum;
37} __packed;
38
39static u8 *rci2_base;
40static u32 rci2_table_len;
41unsigned long rci2_table_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
42
43static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
44 struct bin_attribute *attr, char *buf,
45 loff_t pos, size_t count)
46{
47 memcpy(buf, attr->private + pos, count);
48 return count;
49}
50
51static BIN_ATTR(rci2, S_IRUSR, raw_table_read, NULL, 0);
52
53static u16 checksum(void)
54{
55 u8 len_is_odd = rci2_table_len % 2;
56 u32 chksum_len = rci2_table_len;
57 u16 *base = (u16 *)rci2_base;
58 u8 buf[2] = {0};
59 u32 offset = 0;
60 u16 chksum = 0;
61
62 if (len_is_odd)
63 chksum_len -= 1;
64
65 while (offset < chksum_len) {
66 chksum += *base;
67 offset += 2;
68 base++;
69 }
70
71 if (len_is_odd) {
72 buf[0] = *(u8 *)base;
73 chksum += *(u16 *)(buf);
74 }
75
76 return chksum;
77}
78
79int __init efi_rci2_sysfs_init(void)
80{
81 struct kobject *tables_kobj;
82 int ret = -ENOMEM;
83
84 rci2_base = memremap(rci2_table_phys,
85 sizeof(struct rci2_table_global_hdr),
86 MEMREMAP_WB);
87 if (!rci2_base) {
88 pr_debug("RCI2 table init failed - could not map RCI2 table\n");
89 goto err;
90 }
91
92 if (strncmp(rci2_base +
93 offsetof(struct rci2_table_global_hdr, rci2_sig),
94 RCI_SIGNATURE, 4)) {
95 pr_debug("RCI2 table init failed - incorrect signature\n");
96 ret = -ENODEV;
97 goto err_unmap;
98 }
99
100 rci2_table_len = *(u32 *)(rci2_base +
101 offsetof(struct rci2_table_global_hdr,
102 rci2_len));
103
104 memunmap(rci2_base);
105
106 if (!rci2_table_len) {
107 pr_debug("RCI2 table init failed - incorrect table length\n");
108 goto err;
109 }
110
111 rci2_base = memremap(rci2_table_phys, rci2_table_len, MEMREMAP_WB);
112 if (!rci2_base) {
113 pr_debug("RCI2 table - could not map RCI2 table\n");
114 goto err;
115 }
116
117 if (checksum() != 0) {
118 pr_debug("RCI2 table - incorrect checksum\n");
119 ret = -ENODEV;
120 goto err_unmap;
121 }
122
123 tables_kobj = kobject_create_and_add("tables", efi_kobj);
124 if (!tables_kobj) {
125 pr_debug("RCI2 table - tables_kobj creation failed\n");
126 goto err_unmap;
127 }
128
129 bin_attr_rci2.size = rci2_table_len;
130 bin_attr_rci2.private = rci2_base;
131 ret = sysfs_create_bin_file(tables_kobj, &bin_attr_rci2);
132 if (ret != 0) {
133 pr_debug("RCI2 table - rci2 sysfs bin file creation failed\n");
134 kobject_del(tables_kobj);
135 kobject_put(tables_kobj);
136 goto err_unmap;
137 }
138
139 return 0;
140
141 err_unmap:
142 memunmap(rci2_base);
143 err:
144 pr_debug("RCI2 table - sysfs initialization failed\n");
145 return ret;
146}
147late_initcall(efi_rci2_sysfs_init);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index f87fabea4a85..bd3837022307 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -692,6 +692,9 @@ void efi_native_runtime_setup(void);
692#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25) 692#define LINUX_EFI_TPM_FINAL_LOG_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
693#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2) 693#define LINUX_EFI_MEMRESERVE_TABLE_GUID EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5, 0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
694 694
695/* OEM GUIDs */
696#define DELLEMC_EFI_RCI2_TABLE_GUID EFI_GUID(0x2d9f28a2, 0xa886, 0x456a, 0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
697
695typedef struct { 698typedef struct {
696 efi_guid_t guid; 699 efi_guid_t guid;
697 u64 table; 700 u64 table;
@@ -984,11 +987,9 @@ extern struct efi {
984 unsigned long acpi20; /* ACPI table (ACPI 2.0) */ 987 unsigned long acpi20; /* ACPI table (ACPI 2.0) */
985 unsigned long smbios; /* SMBIOS table (32 bit entry point) */ 988 unsigned long smbios; /* SMBIOS table (32 bit entry point) */
986 unsigned long smbios3; /* SMBIOS table (64 bit entry point) */ 989 unsigned long smbios3; /* SMBIOS table (64 bit entry point) */
987 unsigned long sal_systab; /* SAL system table */
988 unsigned long boot_info; /* boot info table */ 990 unsigned long boot_info; /* boot info table */
989 unsigned long hcdp; /* HCDP table */ 991 unsigned long hcdp; /* HCDP table */
990 unsigned long uga; /* UGA table */ 992 unsigned long uga; /* UGA table */
991 unsigned long uv_systab; /* UV system table */
992 unsigned long fw_vendor; /* fw_vendor */ 993 unsigned long fw_vendor; /* fw_vendor */
993 unsigned long runtime; /* runtime table */ 994 unsigned long runtime; /* runtime table */
994 unsigned long config_table; /* config tables */ 995 unsigned long config_table; /* config tables */
@@ -1211,8 +1212,6 @@ static inline bool efi_enabled(int feature)
1211 return test_bit(feature, &efi.flags) != 0; 1212 return test_bit(feature, &efi.flags) != 0;
1212} 1213}
1213extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused); 1214extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused);
1214
1215extern bool efi_is_table_address(unsigned long phys_addr);
1216#else 1215#else
1217static inline bool efi_enabled(int feature) 1216static inline bool efi_enabled(int feature)
1218{ 1217{
@@ -1226,11 +1225,6 @@ efi_capsule_pending(int *reset_type)
1226{ 1225{
1227 return false; 1226 return false;
1228} 1227}
1229
1230static inline bool efi_is_table_address(unsigned long phys_addr)
1231{
1232 return false;
1233}
1234#endif 1228#endif
1235 1229
1236extern int efi_status_to_err(efi_status_t status); 1230extern int efi_status_to_err(efi_status_t status);
@@ -1722,6 +1716,8 @@ struct efi_tcg2_final_events_table {
1722}; 1716};
1723extern int efi_tpm_final_log_size; 1717extern int efi_tpm_final_log_size;
1724 1718
1719extern unsigned long rci2_table_phys;
1720
1725/* 1721/*
1726 * efi_runtime_service() function identifiers. 1722 * efi_runtime_service() function identifiers.
1727 * "NONE" is used by efi_recover_from_page_fault() to check if the page 1723 * "NONE" is used by efi_recover_from_page_fault() to check if the page