18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd
48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Derived from arch/arm/include/kvm_emulate.h
78c2ecf20Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University
88c2ecf20Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifndef __ARM64_KVM_EMULATE_H__
128c2ecf20Sopenharmony_ci#define __ARM64_KVM_EMULATE_H__
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <asm/debug-monitors.h>
178c2ecf20Sopenharmony_ci#include <asm/esr.h>
188c2ecf20Sopenharmony_ci#include <asm/kvm_arm.h>
198c2ecf20Sopenharmony_ci#include <asm/kvm_hyp.h>
208c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
218c2ecf20Sopenharmony_ci#include <asm/cputype.h>
228c2ecf20Sopenharmony_ci#include <asm/virt.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ciunsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
258c2ecf20Sopenharmony_ciunsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
268c2ecf20Sopenharmony_civoid vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cibool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
298c2ecf20Sopenharmony_civoid kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_civoid kvm_inject_undefined(struct kvm_vcpu *vcpu);
328c2ecf20Sopenharmony_civoid kvm_inject_vabt(struct kvm_vcpu *vcpu);
338c2ecf20Sopenharmony_civoid kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
348c2ecf20Sopenharmony_civoid kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
358c2ecf20Sopenharmony_civoid kvm_inject_undef32(struct kvm_vcpu *vcpu);
368c2ecf20Sopenharmony_civoid kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
378c2ecf20Sopenharmony_civoid kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	return !(vcpu->arch.hcr_el2 & HCR_RW);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
478c2ecf20Sopenharmony_ci	if (is_kernel_in_hyp_mode())
488c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_E2H;
498c2ecf20Sopenharmony_ci	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) {
508c2ecf20Sopenharmony_ci		/* route synchronous external abort exceptions to EL2 */
518c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TEA;
528c2ecf20Sopenharmony_ci		/* trap error record accesses */
538c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TERR;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
578c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_FWB;
588c2ecf20Sopenharmony_ci	} else {
598c2ecf20Sopenharmony_ci		/*
608c2ecf20Sopenharmony_ci		 * For non-FWB CPUs, we trap VM ops (HCR_EL2.TVM) until M+C
618c2ecf20Sopenharmony_ci		 * get set in SCTLR_EL1 such that we can detect when the guest
628c2ecf20Sopenharmony_ci		 * MMU gets turned on and do the necessary cache maintenance
638c2ecf20Sopenharmony_ci		 * then.
648c2ecf20Sopenharmony_ci		 */
658c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TVM;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features))
698c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 &= ~HCR_RW;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * TID3: trap feature register accesses that we virtualise.
738c2ecf20Sopenharmony_ci	 * For now this is conditional, since no AArch32 feature regs
748c2ecf20Sopenharmony_ci	 * are currently virtualised.
758c2ecf20Sopenharmony_ci	 */
768c2ecf20Sopenharmony_ci	if (!vcpu_el1_is_32bit(vcpu))
778c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TID3;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) ||
808c2ecf20Sopenharmony_ci	    vcpu_el1_is_32bit(vcpu))
818c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TID2;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return (unsigned long *)&vcpu->arch.hcr_el2;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic inline void vcpu_clear_wfx_traps(struct kvm_vcpu *vcpu)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	vcpu->arch.hcr_el2 &= ~HCR_TWE;
928c2ecf20Sopenharmony_ci	if (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) ||
938c2ecf20Sopenharmony_ci	    vcpu->kvm->arch.vgic.nassgireq)
948c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 &= ~HCR_TWI;
958c2ecf20Sopenharmony_ci	else
968c2ecf20Sopenharmony_ci		vcpu->arch.hcr_el2 |= HCR_TWI;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic inline void vcpu_set_wfx_traps(struct kvm_vcpu *vcpu)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	vcpu->arch.hcr_el2 |= HCR_TWE;
1028c2ecf20Sopenharmony_ci	vcpu->arch.hcr_el2 |= HCR_TWI;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic inline void vcpu_ptrauth_enable(struct kvm_vcpu *vcpu)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic inline void vcpu_ptrauth_disable(struct kvm_vcpu *vcpu)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	vcpu->arch.hcr_el2 &= ~(HCR_API | HCR_APK);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	return vcpu->arch.vsesr_el2;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	vcpu->arch.vsesr_el2 = vsesr;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	return (unsigned long *)&vcpu_gp_regs(vcpu)->pc;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	return (unsigned long *)&vcpu_gp_regs(vcpu)->pstate;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu))
1438c2ecf20Sopenharmony_ci		return kvm_condition_valid32(vcpu);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return true;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	*vcpu_cpsr(vcpu) |= PSR_AA32_T_BIT;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * vcpu_get_reg and vcpu_set_reg should always be passed a register number
1558c2ecf20Sopenharmony_ci * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
1568c2ecf20Sopenharmony_ci * AArch32 with banked registers.
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_cistatic __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
1598c2ecf20Sopenharmony_ci					 u8 reg_num)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs[reg_num];
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
1658c2ecf20Sopenharmony_ci				unsigned long val)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	if (reg_num != 31)
1688c2ecf20Sopenharmony_ci		vcpu_gp_regs(vcpu)->regs[reg_num] = val;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu))
1748c2ecf20Sopenharmony_ci		return vcpu_read_spsr32(vcpu);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (vcpu->arch.sysregs_loaded_on_cpu)
1778c2ecf20Sopenharmony_ci		return read_sysreg_el1(SYS_SPSR);
1788c2ecf20Sopenharmony_ci	else
1798c2ecf20Sopenharmony_ci		return __vcpu_sys_reg(vcpu, SPSR_EL1);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu)) {
1858c2ecf20Sopenharmony_ci		vcpu_write_spsr32(vcpu, v);
1868c2ecf20Sopenharmony_ci		return;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (vcpu->arch.sysregs_loaded_on_cpu)
1908c2ecf20Sopenharmony_ci		write_sysreg_el1(v, SYS_SPSR);
1918c2ecf20Sopenharmony_ci	else
1928c2ecf20Sopenharmony_ci		__vcpu_sys_reg(vcpu, SPSR_EL1) = v;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/*
1968c2ecf20Sopenharmony_ci * The layout of SPSR for an AArch32 state is different when observed from an
1978c2ecf20Sopenharmony_ci * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
1988c2ecf20Sopenharmony_ci * view given an AArch64 view.
1998c2ecf20Sopenharmony_ci *
2008c2ecf20Sopenharmony_ci * In ARM DDI 0487E.a see:
2018c2ecf20Sopenharmony_ci *
2028c2ecf20Sopenharmony_ci * - The AArch64 view (SPSR_EL2) in section C5.2.18, page C5-426
2038c2ecf20Sopenharmony_ci * - The AArch32 view (SPSR_abt) in section G8.2.126, page G8-6256
2048c2ecf20Sopenharmony_ci * - The AArch32 view (SPSR_und) in section G8.2.132, page G8-6280
2058c2ecf20Sopenharmony_ci *
2068c2ecf20Sopenharmony_ci * Which show the following differences:
2078c2ecf20Sopenharmony_ci *
2088c2ecf20Sopenharmony_ci * | Bit | AA64 | AA32 | Notes                       |
2098c2ecf20Sopenharmony_ci * +-----+------+------+-----------------------------|
2108c2ecf20Sopenharmony_ci * | 24  | DIT  | J    | J is RES0 in ARMv8          |
2118c2ecf20Sopenharmony_ci * | 21  | SS   | DIT  | SS doesn't exist in AArch32 |
2128c2ecf20Sopenharmony_ci *
2138c2ecf20Sopenharmony_ci * ... and all other bits are (currently) common.
2148c2ecf20Sopenharmony_ci */
2158c2ecf20Sopenharmony_cistatic inline unsigned long host_spsr_to_spsr32(unsigned long spsr)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	const unsigned long overlap = BIT(24) | BIT(21);
2188c2ecf20Sopenharmony_ci	unsigned long dit = !!(spsr & PSR_AA32_DIT_BIT);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	spsr &= ~overlap;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	spsr |= dit << 21;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return spsr;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	u32 mode;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu)) {
2328c2ecf20Sopenharmony_ci		mode = *vcpu_cpsr(vcpu) & PSR_AA32_MODE_MASK;
2338c2ecf20Sopenharmony_ci		return mode > PSR_AA32_MODE_USR;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return mode != PSR_MODE_EL0t;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic __always_inline u32 kvm_vcpu_get_esr(const struct kvm_vcpu *vcpu)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	return vcpu->arch.fault.esr_el2;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u32 esr = kvm_vcpu_get_esr(vcpu);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (esr & ESR_ELx_CV)
2518c2ecf20Sopenharmony_ci		return (esr & ESR_ELx_COND_MASK) >> ESR_ELx_COND_SHIFT;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return -1;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	return vcpu->arch.fault.far_el2;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic inline u64 kvm_vcpu_get_disr(const struct kvm_vcpu *vcpu)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	return vcpu->arch.fault.disr_el1;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_xVC_IMM_MASK;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_ISV);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic inline unsigned long kvm_vcpu_dabt_iss_nisv_sanitized(const struct kvm_vcpu *vcpu)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & (ESR_ELx_CM | ESR_ELx_WNR | ESR_ELx_FSC);
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SSE);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_SF);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	return (kvm_vcpu_get_esr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcpu)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/* Always check for S1PTW *before* using this. */
3078c2ecf20Sopenharmony_cistatic __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_CM);
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	return 1 << ((kvm_vcpu_get_esr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/* This one is not specific to Data Abort */
3238c2ecf20Sopenharmony_cistatic __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_IL);
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	return ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	switch (kvm_vcpu_trap_get_fault(vcpu)) {
3618c2ecf20Sopenharmony_ci	case FSC_SEA:
3628c2ecf20Sopenharmony_ci	case FSC_SEA_TTW0:
3638c2ecf20Sopenharmony_ci	case FSC_SEA_TTW1:
3648c2ecf20Sopenharmony_ci	case FSC_SEA_TTW2:
3658c2ecf20Sopenharmony_ci	case FSC_SEA_TTW3:
3668c2ecf20Sopenharmony_ci	case FSC_SECC:
3678c2ecf20Sopenharmony_ci	case FSC_SECC_TTW0:
3688c2ecf20Sopenharmony_ci	case FSC_SECC_TTW1:
3698c2ecf20Sopenharmony_ci	case FSC_SECC_TTW2:
3708c2ecf20Sopenharmony_ci	case FSC_SECC_TTW3:
3718c2ecf20Sopenharmony_ci		return true;
3728c2ecf20Sopenharmony_ci	default:
3738c2ecf20Sopenharmony_ci		return false;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	u32 esr = kvm_vcpu_get_esr(vcpu);
3808c2ecf20Sopenharmony_ci	return ESR_ELx_SYS64_ISS_RT(esr);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	if (kvm_vcpu_abt_iss1tw(vcpu)) {
3868c2ecf20Sopenharmony_ci		/*
3878c2ecf20Sopenharmony_ci		 * Only a permission fault on a S1PTW should be
3888c2ecf20Sopenharmony_ci		 * considered as a write. Otherwise, page tables baked
3898c2ecf20Sopenharmony_ci		 * in a read-only memslot will result in an exception
3908c2ecf20Sopenharmony_ci		 * being delivered in the guest.
3918c2ecf20Sopenharmony_ci		 *
3928c2ecf20Sopenharmony_ci		 * The drawback is that we end-up faulting twice if the
3938c2ecf20Sopenharmony_ci		 * guest is using any of HW AF/DB: a translation fault
3948c2ecf20Sopenharmony_ci		 * to map the page containing the PT (read only at
3958c2ecf20Sopenharmony_ci		 * first), then a permission fault to allow the flags
3968c2ecf20Sopenharmony_ci		 * to be set.
3978c2ecf20Sopenharmony_ci		 */
3988c2ecf20Sopenharmony_ci		switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
3998c2ecf20Sopenharmony_ci		case ESR_ELx_FSC_PERM:
4008c2ecf20Sopenharmony_ci			return true;
4018c2ecf20Sopenharmony_ci		default:
4028c2ecf20Sopenharmony_ci			return false;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (kvm_vcpu_trap_is_iabt(vcpu))
4078c2ecf20Sopenharmony_ci		return false;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return kvm_vcpu_dabt_iswrite(vcpu);
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu)) {
4208c2ecf20Sopenharmony_ci		*vcpu_cpsr(vcpu) |= PSR_AA32_E_BIT;
4218c2ecf20Sopenharmony_ci	} else {
4228c2ecf20Sopenharmony_ci		u64 sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1);
4238c2ecf20Sopenharmony_ci		sctlr |= (1 << 25);
4248c2ecf20Sopenharmony_ci		vcpu_write_sys_reg(vcpu, sctlr, SCTLR_EL1);
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu))
4318c2ecf20Sopenharmony_ci		return !!(*vcpu_cpsr(vcpu) & PSR_AA32_E_BIT);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return !!(vcpu_read_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
4378c2ecf20Sopenharmony_ci						    unsigned long data,
4388c2ecf20Sopenharmony_ci						    unsigned int len)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	if (kvm_vcpu_is_be(vcpu)) {
4418c2ecf20Sopenharmony_ci		switch (len) {
4428c2ecf20Sopenharmony_ci		case 1:
4438c2ecf20Sopenharmony_ci			return data & 0xff;
4448c2ecf20Sopenharmony_ci		case 2:
4458c2ecf20Sopenharmony_ci			return be16_to_cpu(data & 0xffff);
4468c2ecf20Sopenharmony_ci		case 4:
4478c2ecf20Sopenharmony_ci			return be32_to_cpu(data & 0xffffffff);
4488c2ecf20Sopenharmony_ci		default:
4498c2ecf20Sopenharmony_ci			return be64_to_cpu(data);
4508c2ecf20Sopenharmony_ci		}
4518c2ecf20Sopenharmony_ci	} else {
4528c2ecf20Sopenharmony_ci		switch (len) {
4538c2ecf20Sopenharmony_ci		case 1:
4548c2ecf20Sopenharmony_ci			return data & 0xff;
4558c2ecf20Sopenharmony_ci		case 2:
4568c2ecf20Sopenharmony_ci			return le16_to_cpu(data & 0xffff);
4578c2ecf20Sopenharmony_ci		case 4:
4588c2ecf20Sopenharmony_ci			return le32_to_cpu(data & 0xffffffff);
4598c2ecf20Sopenharmony_ci		default:
4608c2ecf20Sopenharmony_ci			return le64_to_cpu(data);
4618c2ecf20Sopenharmony_ci		}
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return data;		/* Leave LE untouched */
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
4688c2ecf20Sopenharmony_ci						    unsigned long data,
4698c2ecf20Sopenharmony_ci						    unsigned int len)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	if (kvm_vcpu_is_be(vcpu)) {
4728c2ecf20Sopenharmony_ci		switch (len) {
4738c2ecf20Sopenharmony_ci		case 1:
4748c2ecf20Sopenharmony_ci			return data & 0xff;
4758c2ecf20Sopenharmony_ci		case 2:
4768c2ecf20Sopenharmony_ci			return cpu_to_be16(data & 0xffff);
4778c2ecf20Sopenharmony_ci		case 4:
4788c2ecf20Sopenharmony_ci			return cpu_to_be32(data & 0xffffffff);
4798c2ecf20Sopenharmony_ci		default:
4808c2ecf20Sopenharmony_ci			return cpu_to_be64(data);
4818c2ecf20Sopenharmony_ci		}
4828c2ecf20Sopenharmony_ci	} else {
4838c2ecf20Sopenharmony_ci		switch (len) {
4848c2ecf20Sopenharmony_ci		case 1:
4858c2ecf20Sopenharmony_ci			return data & 0xff;
4868c2ecf20Sopenharmony_ci		case 2:
4878c2ecf20Sopenharmony_ci			return cpu_to_le16(data & 0xffff);
4888c2ecf20Sopenharmony_ci		case 4:
4898c2ecf20Sopenharmony_ci			return cpu_to_le32(data & 0xffffffff);
4908c2ecf20Sopenharmony_ci		default:
4918c2ecf20Sopenharmony_ci			return cpu_to_le64(data);
4928c2ecf20Sopenharmony_ci		}
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return data;		/* Leave LE untouched */
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic __always_inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	if (vcpu_mode_is_32bit(vcpu)) {
5018c2ecf20Sopenharmony_ci		kvm_skip_instr32(vcpu, is_wide_instr);
5028c2ecf20Sopenharmony_ci	} else {
5038c2ecf20Sopenharmony_ci		*vcpu_pc(vcpu) += 4;
5048c2ecf20Sopenharmony_ci		*vcpu_cpsr(vcpu) &= ~PSR_BTYPE_MASK;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/* advance the singlestep state machine */
5088c2ecf20Sopenharmony_ci	*vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci/*
5128c2ecf20Sopenharmony_ci * Skip an instruction which has been emulated at hyp while most guest sysregs
5138c2ecf20Sopenharmony_ci * are live.
5148c2ecf20Sopenharmony_ci */
5158c2ecf20Sopenharmony_cistatic __always_inline void __kvm_skip_instr(struct kvm_vcpu *vcpu)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	*vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
5188c2ecf20Sopenharmony_ci	vcpu_gp_regs(vcpu)->pstate = read_sysreg_el2(SYS_SPSR);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	write_sysreg_el2(vcpu_gp_regs(vcpu)->pstate, SYS_SPSR);
5238c2ecf20Sopenharmony_ci	write_sysreg_el2(*vcpu_pc(vcpu), SYS_ELR);
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	return test_bit(feature, vcpu->arch.features);
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci#endif /* __ARM64_KVM_EMULATE_H__ */
532