Skip to content

Commit dcaed59

Browse files
committed
Merge branch 'acpi-apei'
* acpi-apei: (29 commits) efi: cper: Fix possible out-of-bounds access ACPI: APEI: Fix possible out-of-bounds access to BERT region MAINTAINERS: Add James Morse to the list of APEI reviewers ACPI / APEI: Add support for the SDEI GHES Notification type firmware: arm_sdei: Add ACPI GHES registration helper ACPI / APEI: Use separate fixmap pages for arm64 NMI-like notifications ACPI / APEI: Only use queued estatus entry during in_nmi_queue_one_entry() ACPI / APEI: Split ghes_read_estatus() to allow a peek at the CPER length ACPI / APEI: Make GHES estatus header validation more user friendly ACPI / APEI: Pass ghes and estatus separately to avoid a later copy ACPI / APEI: Let the notification helper specify the fixmap slot ACPI / APEI: Move locking to the notification helper arm64: KVM/mm: Move SEA handling behind a single 'claim' interface KVM: arm/arm64: Add kvm_ras.h to collect kvm specific RAS plumbing ACPI / APEI: Switch NOTIFY_SEA to use the estatus queue ACPI / APEI: Move NOTIFY_SEA between the estatus-queue and NOTIFY_NMI ACPI / APEI: Don't allow ghes_ack_error() to mask earlier errors ACPI / APEI: Generalise the estatus queue's notify code ACPI / APEI: Don't update struct ghes' flags in read/clear estatus ACPI / APEI: Remove spurious GHES_TO_CLEAR check ...
2 parents 511514f + 45b14a4 commit dcaed59

File tree

21 files changed

+591
-368
lines changed

21 files changed

+591
-368
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ ACPI APEI
331331
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
332332
M: Len Brown <lenb@kernel.org>
333333
L: linux-acpi@vger.kernel.org
334+
R: James Morse <james.morse@arm.com>
334335
R: Tony Luck <tony.luck@intel.com>
335336
R: Borislav Petkov <bp@alien8.de>
336337
F: drivers/acpi/apei/

arch/arm/include/asm/kvm_ras.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (C) 2018 - Arm Ltd */
3+
4+
#ifndef __ARM_KVM_RAS_H__
5+
#define __ARM_KVM_RAS_H__
6+
7+
#include <linux/types.h>
8+
9+
static inline int kvm_handle_guest_sea(phys_addr_t addr, unsigned int esr)
10+
{
11+
return -1;
12+
}
13+
14+
#endif /* __ARM_KVM_RAS_H__ */

arch/arm/include/asm/system_misc.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,6 @@ static inline void harden_branch_predictor(void)
3838

3939
extern unsigned int user_debug;
4040

41-
static inline int handle_guest_sea(phys_addr_t addr, unsigned int esr)
42-
{
43-
return -1;
44-
}
45-
4641
#endif /* !__ASSEMBLY__ */
4742

4843
#endif /* __ASM_ARM_SYSTEM_MISC_H */

arch/arm64/include/asm/acpi.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <asm/cputype.h>
2020
#include <asm/io.h>
21+
#include <asm/ptrace.h>
2122
#include <asm/smp_plat.h>
2223
#include <asm/tlbflush.h>
2324

@@ -110,9 +111,10 @@ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
110111

111112
static inline void arch_fix_phys_package_id(int num, u32 slot) { }
112113
void __init acpi_init_cpus(void);
113-
114+
int apei_claim_sea(struct pt_regs *regs);
114115
#else
115116
static inline void acpi_init_cpus(void) { }
117+
static inline int apei_claim_sea(struct pt_regs *regs) { return -ENOENT; }
116118
#endif /* CONFIG_ACPI */
117119

118120
#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL

arch/arm64/include/asm/daifflags.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#define DAIF_PROCCTX 0
2222
#define DAIF_PROCCTX_NOIRQ PSR_I_BIT
23+
#define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT)
2324

2425
/* mask/save/unmask/restore all exceptions, including interrupts. */
2526
static inline void local_daif_mask(void)

arch/arm64/include/asm/fixmap.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ enum fixed_addresses {
5555
#ifdef CONFIG_ACPI_APEI_GHES
5656
/* Used for GHES mapping from assorted contexts */
5757
FIX_APEI_GHES_IRQ,
58-
FIX_APEI_GHES_NMI,
58+
FIX_APEI_GHES_SEA,
59+
#ifdef CONFIG_ARM_SDE_INTERFACE
60+
FIX_APEI_GHES_SDEI_NORMAL,
61+
FIX_APEI_GHES_SDEI_CRITICAL,
62+
#endif
5963
#endif /* CONFIG_ACPI_APEI_GHES */
6064

6165
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0

arch/arm64/include/asm/kvm_ras.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (C) 2018 - Arm Ltd */
3+
4+
#ifndef __ARM64_KVM_RAS_H__
5+
#define __ARM64_KVM_RAS_H__
6+
7+
#include <linux/acpi.h>
8+
#include <linux/errno.h>
9+
#include <linux/types.h>
10+
11+
#include <asm/acpi.h>
12+
13+
/*
14+
* Was this synchronous external abort a RAS notification?
15+
* Returns '0' for errors handled by some RAS subsystem, or -ENOENT.
16+
*/
17+
static inline int kvm_handle_guest_sea(phys_addr_t addr, unsigned int esr)
18+
{
19+
/* apei_claim_sea(NULL) expects to mask interrupts itself */
20+
lockdep_assert_irqs_enabled();
21+
22+
return apei_claim_sea(NULL);
23+
}
24+
25+
#endif /* __ARM64_KVM_RAS_H__ */

arch/arm64/include/asm/system_misc.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ extern void __show_regs(struct pt_regs *);
4646

4747
extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
4848

49-
int handle_guest_sea(phys_addr_t addr, unsigned int esr);
50-
5149
#endif /* __ASSEMBLY__ */
5250

5351
#endif /* __ASM_SYSTEM_MISC_H */

arch/arm64/kernel/acpi.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
#include <linux/smp.h>
2828
#include <linux/serial_core.h>
2929

30+
#include <acpi/ghes.h>
3031
#include <asm/cputype.h>
3132
#include <asm/cpu_ops.h>
33+
#include <asm/daifflags.h>
3234
#include <asm/pgtable.h>
3335
#include <asm/smp_plat.h>
3436

@@ -256,3 +258,32 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
256258
return __pgprot(PROT_NORMAL_NC);
257259
return __pgprot(PROT_DEVICE_nGnRnE);
258260
}
261+
262+
/*
263+
* Claim Synchronous External Aborts as a firmware first notification.
264+
*
265+
* Used by KVM and the arch do_sea handler.
266+
* @regs may be NULL when called from process context.
267+
*/
268+
int apei_claim_sea(struct pt_regs *regs)
269+
{
270+
int err = -ENOENT;
271+
unsigned long current_flags;
272+
273+
if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
274+
return err;
275+
276+
current_flags = arch_local_save_flags();
277+
278+
/*
279+
* SEA can interrupt SError, mask it and describe this as an NMI so
280+
* that APEI defers the handling.
281+
*/
282+
local_daif_restore(DAIF_ERRCTX);
283+
nmi_enter();
284+
err = ghes_notify_sea();
285+
nmi_exit();
286+
local_daif_restore(current_flags);
287+
288+
return err;
289+
}

arch/arm64/mm/fault.c

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1919
*/
2020

21+
#include <linux/acpi.h>
2122
#include <linux/extable.h>
2223
#include <linux/signal.h>
2324
#include <linux/mm.h>
@@ -33,6 +34,7 @@
3334
#include <linux/preempt.h>
3435
#include <linux/hugetlb.h>
3536

37+
#include <asm/acpi.h>
3638
#include <asm/bug.h>
3739
#include <asm/cmpxchg.h>
3840
#include <asm/cpufeature.h>
@@ -47,8 +49,6 @@
4749
#include <asm/tlbflush.h>
4850
#include <asm/traps.h>
4951

50-
#include <acpi/ghes.h>
51-
5252
struct fault_info {
5353
int (*fn)(unsigned long addr, unsigned int esr,
5454
struct pt_regs *regs);
@@ -643,19 +643,10 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
643643
inf = esr_to_fault_info(esr);
644644

645645
/*
646-
* Synchronous aborts may interrupt code which had interrupts masked.
647-
* Before calling out into the wider kernel tell the interested
648-
* subsystems.
646+
* Return value ignored as we rely on signal merging.
647+
* Future patches will make this more robust.
649648
*/
650-
if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
651-
if (interrupts_enabled(regs))
652-
nmi_enter();
653-
654-
ghes_notify_sea();
655-
656-
if (interrupts_enabled(regs))
657-
nmi_exit();
658-
}
649+
apei_claim_sea(regs);
659650

660651
if (esr & ESR_ELx_FnV)
661652
siaddr = NULL;
@@ -733,11 +724,6 @@ static const struct fault_info fault_info[] = {
733724
{ do_bad, SIGKILL, SI_KERNEL, "unknown 63" },
734725
};
735726

736-
int handle_guest_sea(phys_addr_t addr, unsigned int esr)
737-
{
738-
return ghes_notify_sea();
739-
}
740-
741727
asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
742728
struct pt_regs *regs)
743729
{

drivers/acpi/apei/Kconfig

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,9 @@ config ACPI_APEI_PCIEAER
4141
Turn on this option to enable the corresponding support.
4242

4343
config ACPI_APEI_SEA
44-
bool "APEI Synchronous External Abort logging/recovering support"
44+
bool
4545
depends on ARM64 && ACPI_APEI_GHES
4646
default y
47-
help
48-
This option should be enabled if the system supports
49-
firmware first handling of SEA (Synchronous External Abort).
50-
SEA happens with certain faults of data abort or instruction
51-
abort synchronous exceptions on ARMv8 systems. If a system
52-
supports firmware first handling of SEA, the platform analyzes
53-
and handles hardware error notifications from SEA, and it may then
54-
form a HW error record for the OS to parse and handle. This
55-
option allows the OS to look for such hardware error record, and
56-
take appropriate action.
5747

5848
config ACPI_APEI_MEMORY_FAILURE
5949
bool "APEI memory error recovering support"

drivers/acpi/apei/bert.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,23 @@ static void __init bert_print_all(struct acpi_bert_region *region,
4242
int remain = region_len;
4343
u32 estatus_len;
4444

45-
if (!estatus->block_status)
46-
return;
47-
48-
while (remain > sizeof(struct acpi_bert_region)) {
49-
if (cper_estatus_check(estatus)) {
50-
pr_err(FW_BUG "Invalid error record.\n");
51-
return;
52-
}
53-
45+
while (remain >= sizeof(struct acpi_bert_region)) {
5446
estatus_len = cper_estatus_len(estatus);
5547
if (remain < estatus_len) {
5648
pr_err(FW_BUG "Truncated status block (length: %u).\n",
5749
estatus_len);
5850
return;
5951
}
6052

53+
/* No more error records. */
54+
if (!estatus->block_status)
55+
return;
56+
57+
if (cper_estatus_check(estatus)) {
58+
pr_err(FW_BUG "Invalid error record.\n");
59+
return;
60+
}
61+
6162
pr_info_once("Error records from previous boot:\n");
6263

6364
cper_estatus_print(KERN_INFO HW_ERR, estatus);
@@ -70,10 +71,6 @@ static void __init bert_print_all(struct acpi_bert_region *region,
7071
estatus->block_status = 0;
7172

7273
estatus = (void *)estatus + estatus_len;
73-
/* No more error records. */
74-
if (!estatus->block_status)
75-
return;
76-
7774
remain -= estatus_len;
7875
}
7976
}

drivers/acpi/apei/einj.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -644,8 +644,8 @@ static int error_type_set(void *data, u64 val)
644644
return 0;
645645
}
646646

647-
DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get,
648-
error_type_set, "0x%llx\n");
647+
DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set,
648+
"0x%llx\n");
649649

650650
static int error_inject_set(void *data, u64 val)
651651
{
@@ -656,8 +656,7 @@ static int error_inject_set(void *data, u64 val)
656656
error_param3, error_param4);
657657
}
658658

659-
DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
660-
error_inject_set, "%llu\n");
659+
DEFINE_DEBUGFS_ATTRIBUTE(error_inject_fops, NULL, error_inject_set, "%llu\n");
661660

662661
static int einj_check_table(struct acpi_table_einj *einj_tab)
663662
{
@@ -709,10 +708,10 @@ static int __init einj_init(void)
709708

710709
debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir,
711710
NULL, &available_error_type_fops);
712-
debugfs_create_file("error_type", S_IRUSR | S_IWUSR, einj_debug_dir,
713-
NULL, &error_type_fops);
714-
debugfs_create_file("error_inject", S_IWUSR, einj_debug_dir,
715-
NULL, &error_inject_fops);
711+
debugfs_create_file_unsafe("error_type", 0600, einj_debug_dir,
712+
NULL, &error_type_fops);
713+
debugfs_create_file_unsafe("error_inject", 0200, einj_debug_dir,
714+
NULL, &error_inject_fops);
716715

717716
apei_resources_init(&einj_resources);
718717
einj_exec_ctx_init(&ctx);

drivers/acpi/apei/erst.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -938,17 +938,17 @@ static struct pstore_info erst_info = {
938938
};
939939

940940
#define CPER_CREATOR_PSTORE \
941-
UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
942-
0x64, 0x90, 0xb8, 0x9d)
941+
GUID_INIT(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
942+
0x64, 0x90, 0xb8, 0x9d)
943943
#define CPER_SECTION_TYPE_DMESG \
944-
UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
945-
0x94, 0x19, 0xeb, 0x12)
944+
GUID_INIT(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
945+
0x94, 0x19, 0xeb, 0x12)
946946
#define CPER_SECTION_TYPE_DMESG_Z \
947-
UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \
948-
0x34, 0xdd, 0xfa, 0xc6)
947+
GUID_INIT(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \
948+
0x34, 0xdd, 0xfa, 0xc6)
949949
#define CPER_SECTION_TYPE_MCE \
950-
UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
951-
0x04, 0x4a, 0x38, 0xfc)
950+
GUID_INIT(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
951+
0x04, 0x4a, 0x38, 0xfc)
952952

953953
struct cper_pstore_record {
954954
struct cper_record_header hdr;
@@ -1012,7 +1012,7 @@ static ssize_t erst_reader(struct pstore_record *record)
10121012
rc = -EIO;
10131013
goto out;
10141014
}
1015-
if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0)
1015+
if (!guid_equal(&rcd->hdr.creator_id, &CPER_CREATOR_PSTORE))
10161016
goto skip;
10171017

10181018
record->buf = kmalloc(len, GFP_KERNEL);
@@ -1024,15 +1024,12 @@ static ssize_t erst_reader(struct pstore_record *record)
10241024
record->id = record_id;
10251025
record->compressed = false;
10261026
record->ecc_notice_size = 0;
1027-
if (uuid_le_cmp(rcd->sec_hdr.section_type,
1028-
CPER_SECTION_TYPE_DMESG_Z) == 0) {
1027+
if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG_Z)) {
10291028
record->type = PSTORE_TYPE_DMESG;
10301029
record->compressed = true;
1031-
} else if (uuid_le_cmp(rcd->sec_hdr.section_type,
1032-
CPER_SECTION_TYPE_DMESG) == 0)
1030+
} else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG))
10331031
record->type = PSTORE_TYPE_DMESG;
1034-
else if (uuid_le_cmp(rcd->sec_hdr.section_type,
1035-
CPER_SECTION_TYPE_MCE) == 0)
1032+
else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_MCE))
10361033
record->type = PSTORE_TYPE_MCE;
10371034
else
10381035
record->type = PSTORE_TYPE_MAX;

0 commit comments

Comments
 (0)