162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd
462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Derived from arch/arm/kvm/handle_exit.c:
762306a36Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University
862306a36Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kvm.h>
1262306a36Sopenharmony_ci#include <linux/kvm_host.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <asm/esr.h>
1562306a36Sopenharmony_ci#include <asm/exception.h>
1662306a36Sopenharmony_ci#include <asm/kvm_asm.h>
1762306a36Sopenharmony_ci#include <asm/kvm_emulate.h>
1862306a36Sopenharmony_ci#include <asm/kvm_mmu.h>
1962306a36Sopenharmony_ci#include <asm/kvm_nested.h>
2062306a36Sopenharmony_ci#include <asm/debug-monitors.h>
2162306a36Sopenharmony_ci#include <asm/stacktrace/nvhe.h>
2262306a36Sopenharmony_ci#include <asm/traps.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <kvm/arm_hypercalls.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
2762306a36Sopenharmony_ci#include "trace_handle_exit.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_citypedef int (*exit_handle_fn)(struct kvm_vcpu *);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void kvm_handle_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(NULL, esr))
3462306a36Sopenharmony_ci		kvm_inject_vabt(vcpu);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int handle_hvc(struct kvm_vcpu *vcpu)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0),
4062306a36Sopenharmony_ci			    kvm_vcpu_hvc_get_imm(vcpu));
4162306a36Sopenharmony_ci	vcpu->stat.hvc_exit_stat++;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/* Forward hvc instructions to the virtual EL2 if the guest has EL2. */
4462306a36Sopenharmony_ci	if (vcpu_has_nv(vcpu)) {
4562306a36Sopenharmony_ci		if (vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_HCD)
4662306a36Sopenharmony_ci			kvm_inject_undefined(vcpu);
4762306a36Sopenharmony_ci		else
4862306a36Sopenharmony_ci			kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci		return 1;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return kvm_smccc_call_handler(vcpu);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int handle_smc(struct kvm_vcpu *vcpu)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	/*
5962306a36Sopenharmony_ci	 * "If an SMC instruction executed at Non-secure EL1 is
6062306a36Sopenharmony_ci	 * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
6162306a36Sopenharmony_ci	 * Trap exception, not a Secure Monitor Call exception [...]"
6262306a36Sopenharmony_ci	 *
6362306a36Sopenharmony_ci	 * We need to advance the PC after the trap, as it would
6462306a36Sopenharmony_ci	 * otherwise return to the same address. Furthermore, pre-incrementing
6562306a36Sopenharmony_ci	 * the PC before potentially exiting to userspace maintains the same
6662306a36Sopenharmony_ci	 * abstraction for both SMCs and HVCs.
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	kvm_incr_pc(vcpu);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * SMCs with a nonzero immediate are reserved according to DEN0028E 2.9
7262306a36Sopenharmony_ci	 * "SMC and HVC immediate value".
7362306a36Sopenharmony_ci	 */
7462306a36Sopenharmony_ci	if (kvm_vcpu_hvc_get_imm(vcpu)) {
7562306a36Sopenharmony_ci		vcpu_set_reg(vcpu, 0, ~0UL);
7662306a36Sopenharmony_ci		return 1;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/*
8062306a36Sopenharmony_ci	 * If imm is zero then it is likely an SMCCC call.
8162306a36Sopenharmony_ci	 *
8262306a36Sopenharmony_ci	 * Note that on ARMv8.3, even if EL3 is not implemented, SMC executed
8362306a36Sopenharmony_ci	 * at Non-secure EL1 is trapped to EL2 if HCR_EL2.TSC==1, rather than
8462306a36Sopenharmony_ci	 * being treated as UNDEFINED.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	return kvm_smccc_call_handler(vcpu);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci * Guest access to FP/ASIMD registers are routed to this handler only
9162306a36Sopenharmony_ci * when the system doesn't support FP/ASIMD.
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_cistatic int handle_no_fpsimd(struct kvm_vcpu *vcpu)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	kvm_inject_undefined(vcpu);
9662306a36Sopenharmony_ci	return 1;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/**
10062306a36Sopenharmony_ci * kvm_handle_wfx - handle a wait-for-interrupts or wait-for-event
10162306a36Sopenharmony_ci *		    instruction executed by a guest
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * @vcpu:	the vcpu pointer
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * WFE[T]: Yield the CPU and come back to this vcpu when the scheduler
10662306a36Sopenharmony_ci * decides to.
10762306a36Sopenharmony_ci * WFI: Simply call kvm_vcpu_halt(), which will halt execution of
10862306a36Sopenharmony_ci * world-switches and schedule other host processes until there is an
10962306a36Sopenharmony_ci * incoming IRQ or FIQ to the VM.
11062306a36Sopenharmony_ci * WFIT: Same as WFI, with a timed wakeup implemented as a background timer
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * WF{I,E}T can immediately return if the deadline has already expired.
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_cistatic int kvm_handle_wfx(struct kvm_vcpu *vcpu)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	u64 esr = kvm_vcpu_get_esr(vcpu);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (esr & ESR_ELx_WFx_ISS_WFE) {
11962306a36Sopenharmony_ci		trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
12062306a36Sopenharmony_ci		vcpu->stat.wfe_exit_stat++;
12162306a36Sopenharmony_ci	} else {
12262306a36Sopenharmony_ci		trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false);
12362306a36Sopenharmony_ci		vcpu->stat.wfi_exit_stat++;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (esr & ESR_ELx_WFx_ISS_WFxT) {
12762306a36Sopenharmony_ci		if (esr & ESR_ELx_WFx_ISS_RV) {
12862306a36Sopenharmony_ci			u64 val, now;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci			now = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_TIMER_CNT);
13162306a36Sopenharmony_ci			val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu));
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci			if (now >= val)
13462306a36Sopenharmony_ci				goto out;
13562306a36Sopenharmony_ci		} else {
13662306a36Sopenharmony_ci			/* Treat WFxT as WFx if RN is invalid */
13762306a36Sopenharmony_ci			esr &= ~ESR_ELx_WFx_ISS_WFxT;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (esr & ESR_ELx_WFx_ISS_WFE) {
14262306a36Sopenharmony_ci		kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu));
14362306a36Sopenharmony_ci	} else {
14462306a36Sopenharmony_ci		if (esr & ESR_ELx_WFx_ISS_WFxT)
14562306a36Sopenharmony_ci			vcpu_set_flag(vcpu, IN_WFIT);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		kvm_vcpu_wfi(vcpu);
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ciout:
15062306a36Sopenharmony_ci	kvm_incr_pc(vcpu);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return 1;
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/**
15662306a36Sopenharmony_ci * kvm_handle_guest_debug - handle a debug exception instruction
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * @vcpu:	the vcpu pointer
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci * We route all debug exceptions through the same handler. If both the
16162306a36Sopenharmony_ci * guest and host are using the same debug facilities it will be up to
16262306a36Sopenharmony_ci * userspace to re-inject the correct exception for guest delivery.
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * @return: 0 (while setting vcpu->run->exit_reason)
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_cistatic int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
16962306a36Sopenharmony_ci	u64 esr = kvm_vcpu_get_esr(vcpu);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	run->exit_reason = KVM_EXIT_DEBUG;
17262306a36Sopenharmony_ci	run->debug.arch.hsr = lower_32_bits(esr);
17362306a36Sopenharmony_ci	run->debug.arch.hsr_high = upper_32_bits(esr);
17462306a36Sopenharmony_ci	run->flags = KVM_DEBUG_ARCH_HSR_HIGH_VALID;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	switch (ESR_ELx_EC(esr)) {
17762306a36Sopenharmony_ci	case ESR_ELx_EC_WATCHPT_LOW:
17862306a36Sopenharmony_ci		run->debug.arch.far = vcpu->arch.fault.far_el2;
17962306a36Sopenharmony_ci		break;
18062306a36Sopenharmony_ci	case ESR_ELx_EC_SOFTSTP_LOW:
18162306a36Sopenharmony_ci		vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING);
18262306a36Sopenharmony_ci		break;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return 0;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	u64 esr = kvm_vcpu_get_esr(vcpu);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	kvm_pr_unimpl("Unknown exception class: esr: %#016llx -- %s\n",
19362306a36Sopenharmony_ci		      esr, esr_get_class_string(esr));
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	kvm_inject_undefined(vcpu);
19662306a36Sopenharmony_ci	return 1;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/*
20062306a36Sopenharmony_ci * Guest access to SVE registers should be routed to this handler only
20162306a36Sopenharmony_ci * when the system doesn't support SVE.
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_cistatic int handle_sve(struct kvm_vcpu *vcpu)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	kvm_inject_undefined(vcpu);
20662306a36Sopenharmony_ci	return 1;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/*
21062306a36Sopenharmony_ci * Guest usage of a ptrauth instruction (which the guest EL1 did not turn into
21162306a36Sopenharmony_ci * a NOP). If we get here, it is that we didn't fixup ptrauth on exit, and all
21262306a36Sopenharmony_ci * that we can do is give the guest an UNDEF.
21362306a36Sopenharmony_ci */
21462306a36Sopenharmony_cistatic int kvm_handle_ptrauth(struct kvm_vcpu *vcpu)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	kvm_inject_undefined(vcpu);
21762306a36Sopenharmony_ci	return 1;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic int kvm_handle_eret(struct kvm_vcpu *vcpu)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	if (kvm_vcpu_get_esr(vcpu) & ESR_ELx_ERET_ISS_ERET)
22362306a36Sopenharmony_ci		return kvm_handle_ptrauth(vcpu);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/*
22662306a36Sopenharmony_ci	 * If we got here, two possibilities:
22762306a36Sopenharmony_ci	 *
22862306a36Sopenharmony_ci	 * - the guest is in EL2, and we need to fully emulate ERET
22962306a36Sopenharmony_ci	 *
23062306a36Sopenharmony_ci	 * - the guest is in EL1, and we need to reinject the
23162306a36Sopenharmony_ci         *   exception into the L1 hypervisor.
23262306a36Sopenharmony_ci	 *
23362306a36Sopenharmony_ci	 * If KVM ever traps ERET for its own use, we'll have to
23462306a36Sopenharmony_ci	 * revisit this.
23562306a36Sopenharmony_ci	 */
23662306a36Sopenharmony_ci	if (is_hyp_ctxt(vcpu))
23762306a36Sopenharmony_ci		kvm_emulate_nested_eret(vcpu);
23862306a36Sopenharmony_ci	else
23962306a36Sopenharmony_ci		kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 1;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int handle_svc(struct kvm_vcpu *vcpu)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	/*
24762306a36Sopenharmony_ci	 * So far, SVC traps only for NV via HFGITR_EL2. A SVC from a
24862306a36Sopenharmony_ci	 * 32bit guest would be caught by vpcu_mode_is_bad_32bit(), so
24962306a36Sopenharmony_ci	 * we should only have to deal with a 64 bit exception.
25062306a36Sopenharmony_ci	 */
25162306a36Sopenharmony_ci	kvm_inject_nested_sync(vcpu, kvm_vcpu_get_esr(vcpu));
25262306a36Sopenharmony_ci	return 1;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic exit_handle_fn arm_exit_handlers[] = {
25662306a36Sopenharmony_ci	[0 ... ESR_ELx_EC_MAX]	= kvm_handle_unknown_ec,
25762306a36Sopenharmony_ci	[ESR_ELx_EC_WFx]	= kvm_handle_wfx,
25862306a36Sopenharmony_ci	[ESR_ELx_EC_CP15_32]	= kvm_handle_cp15_32,
25962306a36Sopenharmony_ci	[ESR_ELx_EC_CP15_64]	= kvm_handle_cp15_64,
26062306a36Sopenharmony_ci	[ESR_ELx_EC_CP14_MR]	= kvm_handle_cp14_32,
26162306a36Sopenharmony_ci	[ESR_ELx_EC_CP14_LS]	= kvm_handle_cp14_load_store,
26262306a36Sopenharmony_ci	[ESR_ELx_EC_CP10_ID]	= kvm_handle_cp10_id,
26362306a36Sopenharmony_ci	[ESR_ELx_EC_CP14_64]	= kvm_handle_cp14_64,
26462306a36Sopenharmony_ci	[ESR_ELx_EC_HVC32]	= handle_hvc,
26562306a36Sopenharmony_ci	[ESR_ELx_EC_SMC32]	= handle_smc,
26662306a36Sopenharmony_ci	[ESR_ELx_EC_HVC64]	= handle_hvc,
26762306a36Sopenharmony_ci	[ESR_ELx_EC_SMC64]	= handle_smc,
26862306a36Sopenharmony_ci	[ESR_ELx_EC_SVC64]	= handle_svc,
26962306a36Sopenharmony_ci	[ESR_ELx_EC_SYS64]	= kvm_handle_sys_reg,
27062306a36Sopenharmony_ci	[ESR_ELx_EC_SVE]	= handle_sve,
27162306a36Sopenharmony_ci	[ESR_ELx_EC_ERET]	= kvm_handle_eret,
27262306a36Sopenharmony_ci	[ESR_ELx_EC_IABT_LOW]	= kvm_handle_guest_abort,
27362306a36Sopenharmony_ci	[ESR_ELx_EC_DABT_LOW]	= kvm_handle_guest_abort,
27462306a36Sopenharmony_ci	[ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
27562306a36Sopenharmony_ci	[ESR_ELx_EC_WATCHPT_LOW]= kvm_handle_guest_debug,
27662306a36Sopenharmony_ci	[ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug,
27762306a36Sopenharmony_ci	[ESR_ELx_EC_BKPT32]	= kvm_handle_guest_debug,
27862306a36Sopenharmony_ci	[ESR_ELx_EC_BRK64]	= kvm_handle_guest_debug,
27962306a36Sopenharmony_ci	[ESR_ELx_EC_FP_ASIMD]	= handle_no_fpsimd,
28062306a36Sopenharmony_ci	[ESR_ELx_EC_PAC]	= kvm_handle_ptrauth,
28162306a36Sopenharmony_ci};
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	u64 esr = kvm_vcpu_get_esr(vcpu);
28662306a36Sopenharmony_ci	u8 esr_ec = ESR_ELx_EC(esr);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return arm_exit_handlers[esr_ec];
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/*
29262306a36Sopenharmony_ci * We may be single-stepping an emulated instruction. If the emulation
29362306a36Sopenharmony_ci * has been completed in the kernel, we can return to userspace with a
29462306a36Sopenharmony_ci * KVM_EXIT_DEBUG, otherwise userspace needs to complete its
29562306a36Sopenharmony_ci * emulation first.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic int handle_trap_exceptions(struct kvm_vcpu *vcpu)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	int handled;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/*
30262306a36Sopenharmony_ci	 * See ARM ARM B1.14.1: "Hyp traps on instructions
30362306a36Sopenharmony_ci	 * that fail their condition code check"
30462306a36Sopenharmony_ci	 */
30562306a36Sopenharmony_ci	if (!kvm_condition_valid(vcpu)) {
30662306a36Sopenharmony_ci		kvm_incr_pc(vcpu);
30762306a36Sopenharmony_ci		handled = 1;
30862306a36Sopenharmony_ci	} else {
30962306a36Sopenharmony_ci		exit_handle_fn exit_handler;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		exit_handler = kvm_get_exit_handler(vcpu);
31262306a36Sopenharmony_ci		handled = exit_handler(vcpu);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return handled;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/*
31962306a36Sopenharmony_ci * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
32062306a36Sopenharmony_ci * proper exit to userspace.
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_ciint handle_exit(struct kvm_vcpu *vcpu, int exception_index)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct kvm_run *run = vcpu->run;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (ARM_SERROR_PENDING(exception_index)) {
32762306a36Sopenharmony_ci		/*
32862306a36Sopenharmony_ci		 * The SError is handled by handle_exit_early(). If the guest
32962306a36Sopenharmony_ci		 * survives it will re-execute the original instruction.
33062306a36Sopenharmony_ci		 */
33162306a36Sopenharmony_ci		return 1;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	exception_index = ARM_EXCEPTION_CODE(exception_index);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	switch (exception_index) {
33762306a36Sopenharmony_ci	case ARM_EXCEPTION_IRQ:
33862306a36Sopenharmony_ci		return 1;
33962306a36Sopenharmony_ci	case ARM_EXCEPTION_EL1_SERROR:
34062306a36Sopenharmony_ci		return 1;
34162306a36Sopenharmony_ci	case ARM_EXCEPTION_TRAP:
34262306a36Sopenharmony_ci		return handle_trap_exceptions(vcpu);
34362306a36Sopenharmony_ci	case ARM_EXCEPTION_HYP_GONE:
34462306a36Sopenharmony_ci		/*
34562306a36Sopenharmony_ci		 * EL2 has been reset to the hyp-stub. This happens when a guest
34662306a36Sopenharmony_ci		 * is pre-emptied by kvm_reboot()'s shutdown call.
34762306a36Sopenharmony_ci		 */
34862306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_FAIL_ENTRY;
34962306a36Sopenharmony_ci		return 0;
35062306a36Sopenharmony_ci	case ARM_EXCEPTION_IL:
35162306a36Sopenharmony_ci		/*
35262306a36Sopenharmony_ci		 * We attempted an illegal exception return.  Guest state must
35362306a36Sopenharmony_ci		 * have been corrupted somehow.  Give up.
35462306a36Sopenharmony_ci		 */
35562306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_FAIL_ENTRY;
35662306a36Sopenharmony_ci		return -EINVAL;
35762306a36Sopenharmony_ci	default:
35862306a36Sopenharmony_ci		kvm_pr_unimpl("Unsupported exception type: %d",
35962306a36Sopenharmony_ci			      exception_index);
36062306a36Sopenharmony_ci		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
36162306a36Sopenharmony_ci		return 0;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/* For exit types that need handling before we can be preempted */
36662306a36Sopenharmony_civoid handle_exit_early(struct kvm_vcpu *vcpu, int exception_index)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	if (ARM_SERROR_PENDING(exception_index)) {
36962306a36Sopenharmony_ci		if (this_cpu_has_cap(ARM64_HAS_RAS_EXTN)) {
37062306a36Sopenharmony_ci			u64 disr = kvm_vcpu_get_disr(vcpu);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci			kvm_handle_guest_serror(vcpu, disr_to_esr(disr));
37362306a36Sopenharmony_ci		} else {
37462306a36Sopenharmony_ci			kvm_inject_vabt(vcpu);
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		return;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	exception_index = ARM_EXCEPTION_CODE(exception_index);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (exception_index == ARM_EXCEPTION_EL1_SERROR)
38362306a36Sopenharmony_ci		kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu));
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_civoid __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr,
38762306a36Sopenharmony_ci					      u64 elr_virt, u64 elr_phys,
38862306a36Sopenharmony_ci					      u64 par, uintptr_t vcpu,
38962306a36Sopenharmony_ci					      u64 far, u64 hpfar) {
39062306a36Sopenharmony_ci	u64 elr_in_kimg = __phys_to_kimg(elr_phys);
39162306a36Sopenharmony_ci	u64 hyp_offset = elr_in_kimg - kaslr_offset() - elr_virt;
39262306a36Sopenharmony_ci	u64 mode = spsr & PSR_MODE_MASK;
39362306a36Sopenharmony_ci	u64 panic_addr = elr_virt + hyp_offset;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (mode != PSR_MODE_EL2t && mode != PSR_MODE_EL2h) {
39662306a36Sopenharmony_ci		kvm_err("Invalid host exception to nVHE hyp!\n");
39762306a36Sopenharmony_ci	} else if (ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 &&
39862306a36Sopenharmony_ci		   (esr & ESR_ELx_BRK64_ISS_COMMENT_MASK) == BUG_BRK_IMM) {
39962306a36Sopenharmony_ci		const char *file = NULL;
40062306a36Sopenharmony_ci		unsigned int line = 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		/* All hyp bugs, including warnings, are treated as fatal. */
40362306a36Sopenharmony_ci		if (!is_protected_kvm_enabled() ||
40462306a36Sopenharmony_ci		    IS_ENABLED(CONFIG_NVHE_EL2_DEBUG)) {
40562306a36Sopenharmony_ci			struct bug_entry *bug = find_bug(elr_in_kimg);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci			if (bug)
40862306a36Sopenharmony_ci				bug_get_file_line(bug, &file, &line);
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci		if (file)
41262306a36Sopenharmony_ci			kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line);
41362306a36Sopenharmony_ci		else
41462306a36Sopenharmony_ci			kvm_err("nVHE hyp BUG at: [<%016llx>] %pB!\n", panic_addr,
41562306a36Sopenharmony_ci					(void *)(panic_addr + kaslr_offset()));
41662306a36Sopenharmony_ci	} else {
41762306a36Sopenharmony_ci		kvm_err("nVHE hyp panic at: [<%016llx>] %pB!\n", panic_addr,
41862306a36Sopenharmony_ci				(void *)(panic_addr + kaslr_offset()));
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Dump the nVHE hypervisor backtrace */
42262306a36Sopenharmony_ci	kvm_nvhe_dump_backtrace(hyp_offset);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/*
42562306a36Sopenharmony_ci	 * Hyp has panicked and we're going to handle that by panicking the
42662306a36Sopenharmony_ci	 * kernel. The kernel offset will be revealed in the panic so we're
42762306a36Sopenharmony_ci	 * also safe to reveal the hyp offset as a debugging aid for translating
42862306a36Sopenharmony_ci	 * hyp VAs to vmlinux addresses.
42962306a36Sopenharmony_ci	 */
43062306a36Sopenharmony_ci	kvm_err("Hyp Offset: 0x%llx\n", hyp_offset);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	panic("HYP panic:\nPS:%08llx PC:%016llx ESR:%016llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%016lx\n",
43362306a36Sopenharmony_ci	      spsr, elr_virt, esr, far, hpfar, par, vcpu);
43462306a36Sopenharmony_ci}
435