| From 2e6ed97877c4304a1dee4a896624aa0f594e76dd Mon Sep 17 00:00:00 2001 |
| From: Mark Rutland <mark.rutland@arm.com> |
| Date: Wed, 22 Jan 2020 12:45:46 +0000 |
| Subject: [PATCH] arm64: acpi: fix DAIF manipulation with pNMI |
| |
| commit e533dbe9dcb199bb637a2c465f3a6e70564994fe upstream. |
| |
| Since commit: |
| |
| d44f1b8dd7e66d80 ("arm64: KVM/mm: Move SEA handling behind a single 'claim' interface") |
| |
| ... the top-level APEI SEA handler has the shape: |
| |
| 1. current_flags = arch_local_save_flags() |
| 2. local_daif_restore(DAIF_ERRCTX) |
| 3. <GHES handler> |
| 4. local_daif_restore(current_flags) |
| |
| However, since commit: |
| |
| 4a503217ce37e1f4 ("arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking") |
| |
| ... when pseudo-NMIs (pNMIs) are in use, arch_local_save_flags() will save |
| the PMR value rather than the DAIF flags. |
| |
| The combination of these two commits means that the APEI SEA handler will |
| erroneously attempt to restore the PMR value into DAIF. Fix this by |
| factoring local_daif_save_flags() out of local_daif_save(), so that we |
| can consistently save DAIF in step #1, regardless of whether pNMIs are in |
| use. |
| |
| Both commits were introduced concurrently in v5.0. |
| |
| Cc: <stable@vger.kernel.org> |
| Fixes: 4a503217ce37e1f4 ("arm64: irqflags: Use ICC_PMR_EL1 for interrupt masking") |
| Fixes: d44f1b8dd7e66d80 ("arm64: KVM/mm: Move SEA handling behind a single 'claim' interface") |
| Signed-off-by: Mark Rutland <mark.rutland@arm.com> |
| Cc: Catalin Marinas <catalin.marinas@arm.com> |
| Cc: James Morse <james.morse@arm.com> |
| Cc: Julien Thierry <julien.thierry.kdev@gmail.com> |
| Cc: Will Deacon <will@kernel.org> |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h |
| index 9c0e0178ea29..c9db3a5704a9 100644 |
| --- a/arch/arm64/include/asm/daifflags.h |
| +++ b/arch/arm64/include/asm/daifflags.h |
| @@ -32,7 +32,7 @@ static inline void local_daif_mask(void) |
| trace_hardirqs_off(); |
| } |
| |
| -static inline unsigned long local_daif_save(void) |
| +static inline unsigned long local_daif_save_flags(void) |
| { |
| unsigned long flags; |
| |
| @@ -44,6 +44,15 @@ static inline unsigned long local_daif_save(void) |
| flags |= PSR_I_BIT; |
| } |
| |
| + return flags; |
| +} |
| + |
| +static inline unsigned long local_daif_save(void) |
| +{ |
| + unsigned long flags; |
| + |
| + flags = local_daif_save_flags(); |
| + |
| local_daif_mask(); |
| |
| return flags; |
| diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c |
| index 3a58e9db5cfe..a100483b47c4 100644 |
| --- a/arch/arm64/kernel/acpi.c |
| +++ b/arch/arm64/kernel/acpi.c |
| @@ -274,7 +274,7 @@ int apei_claim_sea(struct pt_regs *regs) |
| if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) |
| return err; |
| |
| - current_flags = arch_local_save_flags(); |
| + current_flags = local_daif_save_flags(); |
| |
| /* |
| * SEA can interrupt SError, mask it and describe this as an NMI so |
| -- |
| 2.7.4 |
| |