arm64: acpi: fix DAIF manipulation with pNMI
authorMark Rutland <mark.rutland@arm.com>
Wed, 22 Jan 2020 12:45:46 +0000 (12:45 +0000)
committerWill Deacon <will@kernel.org>
Wed, 22 Jan 2020 14:41:22 +0000 (14:41 +0000)
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>
arch/arm64/include/asm/daifflags.h
arch/arm64/kernel/acpi.c

index 72acd2db167f03a72c5bdfeccb9cbe58a33e9c82..ec213b4a165021be50b64f47d97b7018fb0326c7 100644 (file)
@@ -38,7 +38,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;
 
@@ -50,6 +50,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;
index 3a58e9db5cfe79e17354f1950b5f07282f9e23e5..a100483b47c429f56fcc7e1dd951c4e16f7c312b 100644 (file)
@@ -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