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/include/kvm_emulate.h
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#ifndef __ARM64_KVM_EMULATE_H__
1262306a36Sopenharmony_ci#define __ARM64_KVM_EMULATE_H__
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/kvm_host.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <asm/debug-monitors.h>
1762306a36Sopenharmony_ci#include <asm/esr.h>
1862306a36Sopenharmony_ci#include <asm/kvm_arm.h>
1962306a36Sopenharmony_ci#include <asm/kvm_hyp.h>
2062306a36Sopenharmony_ci#include <asm/ptrace.h>
2162306a36Sopenharmony_ci#include <asm/cputype.h>
2262306a36Sopenharmony_ci#include <asm/virt.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define CURRENT_EL_SP_EL0_VECTOR	0x0
2562306a36Sopenharmony_ci#define CURRENT_EL_SP_ELx_VECTOR	0x200
2662306a36Sopenharmony_ci#define LOWER_EL_AArch64_VECTOR		0x400
2762306a36Sopenharmony_ci#define LOWER_EL_AArch32_VECTOR		0x600
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cienum exception_type {
3062306a36Sopenharmony_ci	except_type_sync	= 0,
3162306a36Sopenharmony_ci	except_type_irq		= 0x80,
3262306a36Sopenharmony_ci	except_type_fiq		= 0x100,
3362306a36Sopenharmony_ci	except_type_serror	= 0x180,
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define kvm_exception_type_names		\
3762306a36Sopenharmony_ci	{ except_type_sync,	"SYNC"   },	\
3862306a36Sopenharmony_ci	{ except_type_irq,	"IRQ"    },	\
3962306a36Sopenharmony_ci	{ except_type_fiq,	"FIQ"    },	\
4062306a36Sopenharmony_ci	{ except_type_serror,	"SERROR" }
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cibool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
4362306a36Sopenharmony_civoid kvm_skip_instr32(struct kvm_vcpu *vcpu);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid kvm_inject_undefined(struct kvm_vcpu *vcpu);
4662306a36Sopenharmony_civoid kvm_inject_vabt(struct kvm_vcpu *vcpu);
4762306a36Sopenharmony_civoid kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
4862306a36Sopenharmony_civoid kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
4962306a36Sopenharmony_civoid kvm_inject_size_fault(struct kvm_vcpu *vcpu);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_civoid kvm_vcpu_wfi(struct kvm_vcpu *vcpu);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_civoid kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
5462306a36Sopenharmony_ciint kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
5562306a36Sopenharmony_ciint kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__)
5862306a36Sopenharmony_cistatic __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	return !(vcpu->arch.hcr_el2 & HCR_RW);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci#else
6362306a36Sopenharmony_cistatic __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	return test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
7262306a36Sopenharmony_ci	if (has_vhe() || has_hvhe())
7362306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_E2H;
7462306a36Sopenharmony_ci	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) {
7562306a36Sopenharmony_ci		/* route synchronous external abort exceptions to EL2 */
7662306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TEA;
7762306a36Sopenharmony_ci		/* trap error record accesses */
7862306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TERR;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
8262306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_FWB;
8362306a36Sopenharmony_ci	} else {
8462306a36Sopenharmony_ci		/*
8562306a36Sopenharmony_ci		 * For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C
8662306a36Sopenharmony_ci		 * get set in SCTLR_EL1 such that we can detect when the guest
8762306a36Sopenharmony_ci		 * MMU gets turned on and do the necessary cache maintenance
8862306a36Sopenharmony_ci		 * then.
8962306a36Sopenharmony_ci		 */
9062306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TVM;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (cpus_have_final_cap(ARM64_HAS_EVT) &&
9462306a36Sopenharmony_ci	    !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE))
9562306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TID4;
9662306a36Sopenharmony_ci	else
9762306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TID2;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (vcpu_el1_is_32bit(vcpu))
10062306a36Sopenharmony_ci		vcpu->arch.hcr_el2 &= ~HCR_RW;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (kvm_has_mte(vcpu->kvm))
10362306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_ATA;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	return (unsigned long *)&vcpu->arch.hcr_el2;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic inline void vcpu_clear_wfx_traps(struct kvm_vcpu *vcpu)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	vcpu->arch.hcr_el2 &= ~HCR_TWE;
11462306a36Sopenharmony_ci	if (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) ||
11562306a36Sopenharmony_ci	    vcpu->kvm->arch.vgic.nassgireq)
11662306a36Sopenharmony_ci		vcpu->arch.hcr_el2 &= ~HCR_TWI;
11762306a36Sopenharmony_ci	else
11862306a36Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TWI;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline void vcpu_set_wfx_traps(struct kvm_vcpu *vcpu)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	vcpu->arch.hcr_el2 |= HCR_TWE;
12462306a36Sopenharmony_ci	vcpu->arch.hcr_el2 |= HCR_TWI;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic inline void vcpu_ptrauth_enable(struct kvm_vcpu *vcpu)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic inline void vcpu_ptrauth_disable(struct kvm_vcpu *vcpu)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	vcpu->arch.hcr_el2 &= ~(HCR_API | HCR_APK);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	return vcpu->arch.vsesr_el2;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	vcpu->arch.vsesr_el2 = vsesr;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	return (unsigned long *)&vcpu_gp_regs(vcpu)->pc;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	return (unsigned long *)&vcpu_gp_regs(vcpu)->pstate;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu))
16562306a36Sopenharmony_ci		return kvm_condition_valid32(vcpu);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return true;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	*vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci * vcpu_get_reg and vcpu_set_reg should always be passed a register number
17762306a36Sopenharmony_ci * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
17862306a36Sopenharmony_ci * AArch32 with banked registers.
17962306a36Sopenharmony_ci */
18062306a36Sopenharmony_cistatic __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
18162306a36Sopenharmony_ci					 u8 reg_num)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs[reg_num];
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
18762306a36Sopenharmony_ci				unsigned long val)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	if (reg_num != 31)
19062306a36Sopenharmony_ci		vcpu_gp_regs(vcpu)->regs[reg_num] = val;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	switch (ctxt->regs.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) {
19662306a36Sopenharmony_ci	case PSR_MODE_EL2h:
19762306a36Sopenharmony_ci	case PSR_MODE_EL2t:
19862306a36Sopenharmony_ci		return true;
19962306a36Sopenharmony_ci	default:
20062306a36Sopenharmony_ci		return false;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	return vcpu_is_el2_ctxt(&vcpu->arch.ctxt);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic inline bool __vcpu_el2_e2h_is_set(const struct kvm_cpu_context *ctxt)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	return __vcpu_el2_e2h_is_set(&vcpu->arch.ctxt);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic inline bool __vcpu_el2_tge_is_set(const struct kvm_cpu_context *ctxt)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_TGE;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return __vcpu_el2_tge_is_set(&vcpu->arch.ctxt);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	/*
23262306a36Sopenharmony_ci	 * We are in a hypervisor context if the vcpu mode is EL2 or
23362306a36Sopenharmony_ci	 * E2H and TGE bits are set. The latter means we are in the user space
23462306a36Sopenharmony_ci	 * of the VHE kernel. ARMv8.1 ARM describes this as 'InHost'
23562306a36Sopenharmony_ci	 *
23662306a36Sopenharmony_ci	 * Note that the HCR_EL2.{E2H,TGE}={0,1} isn't really handled in the
23762306a36Sopenharmony_ci	 * rest of the KVM code, and will result in a misbehaving guest.
23862306a36Sopenharmony_ci	 */
23962306a36Sopenharmony_ci	return vcpu_is_el2_ctxt(ctxt) ||
24062306a36Sopenharmony_ci		(__vcpu_el2_e2h_is_set(ctxt) && __vcpu_el2_tge_is_set(ctxt)) ||
24162306a36Sopenharmony_ci		__vcpu_el2_tge_is_set(ctxt);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return __is_hyp_ctxt(&vcpu->arch.ctxt);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*
25062306a36Sopenharmony_ci * The layout of SPSR for an AArch32 state is different when observed from an
25162306a36Sopenharmony_ci * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
25262306a36Sopenharmony_ci * view given an AArch64 view.
25362306a36Sopenharmony_ci *
25462306a36Sopenharmony_ci * In ARM DDI 0487E.a see:
25562306a36Sopenharmony_ci *
25662306a36Sopenharmony_ci * - The AArch64 view (SPSR_EL2) in section C5.2.18, page C5-426
25762306a36Sopenharmony_ci * - The AArch32 view (SPSR_abt) in section G8.2.126, page G8-6256
25862306a36Sopenharmony_ci * - The AArch32 view (SPSR_und) in section G8.2.132, page G8-6280
25962306a36Sopenharmony_ci *
26062306a36Sopenharmony_ci * Which show the following differences:
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * | Bit | AA64 | AA32 | Notes                       |
26362306a36Sopenharmony_ci * +-----+------+------+-----------------------------|
26462306a36Sopenharmony_ci * | 24  | DIT  | J    | J is RES0 in ARMv8          |
26562306a36Sopenharmony_ci * | 21  | SS   | DIT  | SS doesn't exist in AArch32 |
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * ... and all other bits are (currently) common.
26862306a36Sopenharmony_ci */
26962306a36Sopenharmony_cistatic inline unsigned long host_spsr_to_spsr32(unsigned long spsr)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	const unsigned long overlap = BIT(24) | BIT(21);
27262306a36Sopenharmony_ci	unsigned long dit = !!(spsr & PSR_AA32_DIT_BIT);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	spsr &= ~overlap;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	spsr |= dit << 21;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return spsr;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	u32 mode;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu)) {
28662306a36Sopenharmony_ci		mode = *vcpu_cpsr(vcpu) & PSR_AA32_MODE_MASK;
28762306a36Sopenharmony_ci		return mode > PSR_AA32_MODE_USR;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return mode != PSR_MODE_EL0t;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic __always_inline u64 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	return vcpu->arch.fault.esr_el2;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	u64 esr = kvm_vcpu_get_esr(vcpu);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (esr & ESR_ELx_CV)
30562306a36Sopenharmony_ci		return (esr & ESR_ELx_COND_MASK) >> ESR_ELx_COND_SHIFT;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return -1;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	return vcpu->arch.fault.far_el2;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	return vcpu->arch.fault.disr_el1;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_ISV);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & (ESR_ELx_CM | ESR_ELx_WNR | ESR_ELx_FSC);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SSE);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SF);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci/* Always check for S1PTW *before* using this. */
36162306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_CM);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	return 1 << ((kvm_vcpu_get_esr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci/* This one is not specific to Data Abort */
37762306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_IL);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	return ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	switch (kvm_vcpu_trap_get_fault(vcpu)) {
41562306a36Sopenharmony_ci	case ESR_ELx_FSC_EXTABT:
41662306a36Sopenharmony_ci	case ESR_ELx_FSC_SEA_TTW0:
41762306a36Sopenharmony_ci	case ESR_ELx_FSC_SEA_TTW1:
41862306a36Sopenharmony_ci	case ESR_ELx_FSC_SEA_TTW2:
41962306a36Sopenharmony_ci	case ESR_ELx_FSC_SEA_TTW3:
42062306a36Sopenharmony_ci	case ESR_ELx_FSC_SECC:
42162306a36Sopenharmony_ci	case ESR_ELx_FSC_SECC_TTW0:
42262306a36Sopenharmony_ci	case ESR_ELx_FSC_SECC_TTW1:
42362306a36Sopenharmony_ci	case ESR_ELx_FSC_SECC_TTW2:
42462306a36Sopenharmony_ci	case ESR_ELx_FSC_SECC_TTW3:
42562306a36Sopenharmony_ci		return true;
42662306a36Sopenharmony_ci	default:
42762306a36Sopenharmony_ci		return false;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	u64 esr = kvm_vcpu_get_esr(vcpu);
43462306a36Sopenharmony_ci	return ESR_ELx_SYS64_ISS_RT(esr);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	if (kvm_vcpu_abt_iss1tw(vcpu)) {
44062306a36Sopenharmony_ci		/*
44162306a36Sopenharmony_ci		 * Only a permission fault on a S1PTW should be
44262306a36Sopenharmony_ci		 * considered as a write. Otherwise, page tables baked
44362306a36Sopenharmony_ci		 * in a read-only memslot will result in an exception
44462306a36Sopenharmony_ci		 * being delivered in the guest.
44562306a36Sopenharmony_ci		 *
44662306a36Sopenharmony_ci		 * The drawback is that we end-up faulting twice if the
44762306a36Sopenharmony_ci		 * guest is using any of HW AF/DB: a translation fault
44862306a36Sopenharmony_ci		 * to map the page containing the PT (read only at
44962306a36Sopenharmony_ci		 * first), then a permission fault to allow the flags
45062306a36Sopenharmony_ci		 * to be set.
45162306a36Sopenharmony_ci		 */
45262306a36Sopenharmony_ci		switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
45362306a36Sopenharmony_ci		case ESR_ELx_FSC_PERM:
45462306a36Sopenharmony_ci			return true;
45562306a36Sopenharmony_ci		default:
45662306a36Sopenharmony_ci			return false;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (kvm_vcpu_trap_is_iabt(vcpu))
46162306a36Sopenharmony_ci		return false;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return kvm_vcpu_dabt_iswrite(vcpu);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu)) {
47462306a36Sopenharmony_ci		*vcpu_cpsr(vcpu) |= PSR_AA32_E_BIT;
47562306a36Sopenharmony_ci	} else {
47662306a36Sopenharmony_ci		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
47762306a36Sopenharmony_ci		sctlr |= SCTLR_ELx_EE;
47862306a36Sopenharmony_ci		vcpu_write_sys_reg(vcpu, sctlr, SCTLR_EL1);
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu))
48562306a36Sopenharmony_ci		return !!(*vcpu_cpsr(vcpu) & PSR_AA32_E_BIT);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (vcpu_mode_priv(vcpu))
48862306a36Sopenharmony_ci		return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_ELx_EE);
48962306a36Sopenharmony_ci	else
49062306a36Sopenharmony_ci		return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & SCTLR_EL1_E0E);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
49462306a36Sopenharmony_ci						    unsigned long data,
49562306a36Sopenharmony_ci						    unsigned int len)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	if (kvm_vcpu_is_be(vcpu)) {
49862306a36Sopenharmony_ci		switch (len) {
49962306a36Sopenharmony_ci		case 1:
50062306a36Sopenharmony_ci			return data & 0xff;
50162306a36Sopenharmony_ci		case 2:
50262306a36Sopenharmony_ci			return be16_to_cpu(data & 0xffff);
50362306a36Sopenharmony_ci		case 4:
50462306a36Sopenharmony_ci			return be32_to_cpu(data & 0xffffffff);
50562306a36Sopenharmony_ci		default:
50662306a36Sopenharmony_ci			return be64_to_cpu(data);
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci	} else {
50962306a36Sopenharmony_ci		switch (len) {
51062306a36Sopenharmony_ci		case 1:
51162306a36Sopenharmony_ci			return data & 0xff;
51262306a36Sopenharmony_ci		case 2:
51362306a36Sopenharmony_ci			return le16_to_cpu(data & 0xffff);
51462306a36Sopenharmony_ci		case 4:
51562306a36Sopenharmony_ci			return le32_to_cpu(data & 0xffffffff);
51662306a36Sopenharmony_ci		default:
51762306a36Sopenharmony_ci			return le64_to_cpu(data);
51862306a36Sopenharmony_ci		}
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return data;		/* Leave LE untouched */
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
52562306a36Sopenharmony_ci						    unsigned long data,
52662306a36Sopenharmony_ci						    unsigned int len)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	if (kvm_vcpu_is_be(vcpu)) {
52962306a36Sopenharmony_ci		switch (len) {
53062306a36Sopenharmony_ci		case 1:
53162306a36Sopenharmony_ci			return data & 0xff;
53262306a36Sopenharmony_ci		case 2:
53362306a36Sopenharmony_ci			return cpu_to_be16(data & 0xffff);
53462306a36Sopenharmony_ci		case 4:
53562306a36Sopenharmony_ci			return cpu_to_be32(data & 0xffffffff);
53662306a36Sopenharmony_ci		default:
53762306a36Sopenharmony_ci			return cpu_to_be64(data);
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci	} else {
54062306a36Sopenharmony_ci		switch (len) {
54162306a36Sopenharmony_ci		case 1:
54262306a36Sopenharmony_ci			return data & 0xff;
54362306a36Sopenharmony_ci		case 2:
54462306a36Sopenharmony_ci			return cpu_to_le16(data & 0xffff);
54562306a36Sopenharmony_ci		case 4:
54662306a36Sopenharmony_ci			return cpu_to_le32(data & 0xffffffff);
54762306a36Sopenharmony_ci		default:
54862306a36Sopenharmony_ci			return cpu_to_le64(data);
54962306a36Sopenharmony_ci		}
55062306a36Sopenharmony_ci	}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return data;		/* Leave LE untouched */
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	WARN_ON(vcpu_get_flag(vcpu, PENDING_EXCEPTION));
55862306a36Sopenharmony_ci	vcpu_set_flag(vcpu, INCREMENT_PC);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci#define kvm_pend_exception(v, e)					\
56262306a36Sopenharmony_ci	do {								\
56362306a36Sopenharmony_ci		WARN_ON(vcpu_get_flag((v), INCREMENT_PC));		\
56462306a36Sopenharmony_ci		vcpu_set_flag((v), PENDING_EXCEPTION);			\
56562306a36Sopenharmony_ci		vcpu_set_flag((v), e);					\
56662306a36Sopenharmony_ci	} while (0)
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	return test_bit(feature, vcpu->arch.features);
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic __always_inline void kvm_write_cptr_el2(u64 val)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	if (has_vhe() || has_hvhe())
57762306a36Sopenharmony_ci		write_sysreg(val, cpacr_el1);
57862306a36Sopenharmony_ci	else
57962306a36Sopenharmony_ci		write_sysreg(val, cptr_el2);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic __always_inline u64 kvm_get_reset_cptr_el2(struct kvm_vcpu *vcpu)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	u64 val;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (has_vhe()) {
58762306a36Sopenharmony_ci		val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |
58862306a36Sopenharmony_ci		       CPACR_EL1_ZEN_EL1EN);
58962306a36Sopenharmony_ci		if (cpus_have_final_cap(ARM64_SME))
59062306a36Sopenharmony_ci			val |= CPACR_EL1_SMEN_EL1EN;
59162306a36Sopenharmony_ci	} else if (has_hvhe()) {
59262306a36Sopenharmony_ci		val = (CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		if (!vcpu_has_sve(vcpu) ||
59562306a36Sopenharmony_ci		    (vcpu->arch.fp_state != FP_STATE_GUEST_OWNED))
59662306a36Sopenharmony_ci			val |= CPACR_EL1_ZEN_EL1EN | CPACR_EL1_ZEN_EL0EN;
59762306a36Sopenharmony_ci		if (cpus_have_final_cap(ARM64_SME))
59862306a36Sopenharmony_ci			val |= CPACR_EL1_SMEN_EL1EN | CPACR_EL1_SMEN_EL0EN;
59962306a36Sopenharmony_ci	} else {
60062306a36Sopenharmony_ci		val = CPTR_NVHE_EL2_RES1;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		if (vcpu_has_sve(vcpu) &&
60362306a36Sopenharmony_ci		    (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED))
60462306a36Sopenharmony_ci			val |= CPTR_EL2_TZ;
60562306a36Sopenharmony_ci		if (cpus_have_final_cap(ARM64_SME))
60662306a36Sopenharmony_ci			val &= ~CPTR_EL2_TSM;
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return val;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic __always_inline void kvm_reset_cptr_el2(struct kvm_vcpu *vcpu)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	u64 val = kvm_get_reset_cptr_el2(vcpu);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	kvm_write_cptr_el2(val);
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci#endif /* __ARM64_KVM_EMULATE_H__ */
619