arm64: KVM/mm: Move SEA handling behind a single 'claim' interface

To split up APEIs in_nmi() path, the caller needs to always be
in_nmi(). Add a helper to do the work and claim the notification.

When KVM or the arch code takes an exception that might be a RAS
notification, it asks the APEI firmware-first code whether it wants
to claim the exception. A future kernel-first mechanism may be queried
afterwards, and claim the notification, otherwise we fall through
to the existing default behaviour.

The NOTIFY_SEA code was merged before considering multiple, possibly
interacting, NMI-like notifications and the need to consider kernel
first in the future. Make the 'claiming' behaviour explicit.

Restructuring the APEI code to allow multiple NMI-like notifications
means any notification that might interrupt interrupts-masked
code must always be wrapped in nmi_enter()/nmi_exit(). This will
allow APEI to use in_nmi() to use the right fixmap entries.

Mask SError over this window to prevent an asynchronous RAS error
arriving and tripping 'nmi_enter()'s BUG_ON(in_nmi()).

Signed-off-by: James Morse <james.morse@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Tested-by: Tyler Baicar <tbaicar@codeaurora.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
James Morse
2019-01-29 18:48:50 +00:00
committed by Rafael J. Wysocki
parent 0db5e02230
commit d44f1b8dd7
5 changed files with 55 additions and 21 deletions

View File

@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/acpi.h>
#include <linux/extable.h>
#include <linux/signal.h>
#include <linux/mm.h>
@@ -33,6 +34,7 @@
#include <linux/preempt.h>
#include <linux/hugetlb.h>
#include <asm/acpi.h>
#include <asm/bug.h>
#include <asm/cmpxchg.h>
#include <asm/cpufeature.h>
@@ -47,8 +49,6 @@
#include <asm/tlbflush.h>
#include <asm/traps.h>
#include <acpi/ghes.h>
struct fault_info {
int (*fn)(unsigned long addr, unsigned int esr,
struct pt_regs *regs);
@@ -643,19 +643,10 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
inf = esr_to_fault_info(esr);
/*
* Synchronous aborts may interrupt code which had interrupts masked.
* Before calling out into the wider kernel tell the interested
* subsystems.
* Return value ignored as we rely on signal merging.
* Future patches will make this more robust.
*/
if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
if (interrupts_enabled(regs))
nmi_enter();
ghes_notify_sea();
if (interrupts_enabled(regs))
nmi_exit();
}
apei_claim_sea(regs);
if (esr & ESR_ELx_FnV)
siaddr = NULL;
@@ -733,11 +724,6 @@ static const struct fault_info fault_info[] = {
{ do_bad, SIGKILL, SI_KERNEL, "unknown 63" },
};
int kvm_handle_guest_sea(phys_addr_t addr, unsigned int esr)
{
return ghes_notify_sea();
}
asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
struct pt_regs *regs)
{