162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Fault injection for both 32 and 64bit guests.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd
662306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on arch/arm/kvm/emulate.c
962306a36Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University
1062306a36Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <hyp/adjust_pc.h>
1462306a36Sopenharmony_ci#include <linux/kvm_host.h>
1562306a36Sopenharmony_ci#include <asm/kvm_emulate.h>
1662306a36Sopenharmony_ci#include <asm/kvm_mmu.h>
1762306a36Sopenharmony_ci#include <asm/kvm_nested.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#if !defined (__KVM_NVHE_HYPERVISOR__) && !defined (__KVM_VHE_HYPERVISOR__)
2062306a36Sopenharmony_ci#error Hypervisor code only!
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic inline u64 __vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	u64 val;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (unlikely(vcpu_has_nv(vcpu)))
2862306a36Sopenharmony_ci		return vcpu_read_sys_reg(vcpu, reg);
2962306a36Sopenharmony_ci	else if (__vcpu_read_sys_reg_from_cpu(reg, &val))
3062306a36Sopenharmony_ci		return val;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	return __vcpu_sys_reg(vcpu, reg);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline void __vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	if (unlikely(vcpu_has_nv(vcpu)))
3862306a36Sopenharmony_ci		vcpu_write_sys_reg(vcpu, val, reg);
3962306a36Sopenharmony_ci	else if (!__vcpu_write_sys_reg_to_cpu(val, reg))
4062306a36Sopenharmony_ci		__vcpu_sys_reg(vcpu, reg) = val;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void __vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long target_mode,
4462306a36Sopenharmony_ci			      u64 val)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	if (unlikely(vcpu_has_nv(vcpu))) {
4762306a36Sopenharmony_ci		if (target_mode == PSR_MODE_EL1h)
4862306a36Sopenharmony_ci			vcpu_write_sys_reg(vcpu, val, SPSR_EL1);
4962306a36Sopenharmony_ci		else
5062306a36Sopenharmony_ci			vcpu_write_sys_reg(vcpu, val, SPSR_EL2);
5162306a36Sopenharmony_ci	} else if (has_vhe()) {
5262306a36Sopenharmony_ci		write_sysreg_el1(val, SYS_SPSR);
5362306a36Sopenharmony_ci	} else {
5462306a36Sopenharmony_ci		__vcpu_sys_reg(vcpu, SPSR_EL1) = val;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void __vcpu_write_spsr_abt(struct kvm_vcpu *vcpu, u64 val)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	if (has_vhe())
6162306a36Sopenharmony_ci		write_sysreg(val, spsr_abt);
6262306a36Sopenharmony_ci	else
6362306a36Sopenharmony_ci		vcpu->arch.ctxt.spsr_abt = val;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic void __vcpu_write_spsr_und(struct kvm_vcpu *vcpu, u64 val)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	if (has_vhe())
6962306a36Sopenharmony_ci		write_sysreg(val, spsr_und);
7062306a36Sopenharmony_ci	else
7162306a36Sopenharmony_ci		vcpu->arch.ctxt.spsr_und = val;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci * This performs the exception entry at a given EL (@target_mode), stashing PC
7662306a36Sopenharmony_ci * and PSTATE into ELR and SPSR respectively, and compute the new PC/PSTATE.
7762306a36Sopenharmony_ci * The EL passed to this function *must* be a non-secure, privileged mode with
7862306a36Sopenharmony_ci * bit 0 being set (PSTATE.SP == 1).
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * When an exception is taken, most PSTATE fields are left unchanged in the
8162306a36Sopenharmony_ci * handler. However, some are explicitly overridden (e.g. M[4:0]). Luckily all
8262306a36Sopenharmony_ci * of the inherited bits have the same position in the AArch64/AArch32 SPSR_ELx
8362306a36Sopenharmony_ci * layouts, so we don't need to shuffle these for exceptions from AArch32 EL0.
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * For the SPSR_ELx layout for AArch64, see ARM DDI 0487E.a page C5-429.
8662306a36Sopenharmony_ci * For the SPSR_ELx layout for AArch32, see ARM DDI 0487E.a page C5-426.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Here we manipulate the fields in order of the AArch64 SPSR_ELx layout, from
8962306a36Sopenharmony_ci * MSB to LSB.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistatic void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode,
9262306a36Sopenharmony_ci			      enum exception_type type)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	unsigned long sctlr, vbar, old, new, mode;
9562306a36Sopenharmony_ci	u64 exc_offset;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	mode = *vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if      (mode == target_mode)
10062306a36Sopenharmony_ci		exc_offset = CURRENT_EL_SP_ELx_VECTOR;
10162306a36Sopenharmony_ci	else if ((mode | PSR_MODE_THREAD_BIT) == target_mode)
10262306a36Sopenharmony_ci		exc_offset = CURRENT_EL_SP_EL0_VECTOR;
10362306a36Sopenharmony_ci	else if (!(mode & PSR_MODE32_BIT))
10462306a36Sopenharmony_ci		exc_offset = LOWER_EL_AArch64_VECTOR;
10562306a36Sopenharmony_ci	else
10662306a36Sopenharmony_ci		exc_offset = LOWER_EL_AArch32_VECTOR;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	switch (target_mode) {
10962306a36Sopenharmony_ci	case PSR_MODE_EL1h:
11062306a36Sopenharmony_ci		vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL1);
11162306a36Sopenharmony_ci		sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1);
11262306a36Sopenharmony_ci		__vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL1);
11362306a36Sopenharmony_ci		break;
11462306a36Sopenharmony_ci	case PSR_MODE_EL2h:
11562306a36Sopenharmony_ci		vbar = __vcpu_read_sys_reg(vcpu, VBAR_EL2);
11662306a36Sopenharmony_ci		sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL2);
11762306a36Sopenharmony_ci		__vcpu_write_sys_reg(vcpu, *vcpu_pc(vcpu), ELR_EL2);
11862306a36Sopenharmony_ci		break;
11962306a36Sopenharmony_ci	default:
12062306a36Sopenharmony_ci		/* Don't do that */
12162306a36Sopenharmony_ci		BUG();
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	*vcpu_pc(vcpu) = vbar + exc_offset + type;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	old = *vcpu_cpsr(vcpu);
12762306a36Sopenharmony_ci	new = 0;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	new |= (old & PSR_N_BIT);
13062306a36Sopenharmony_ci	new |= (old & PSR_Z_BIT);
13162306a36Sopenharmony_ci	new |= (old & PSR_C_BIT);
13262306a36Sopenharmony_ci	new |= (old & PSR_V_BIT);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (kvm_has_mte(kern_hyp_va(vcpu->kvm)))
13562306a36Sopenharmony_ci		new |= PSR_TCO_BIT;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	new |= (old & PSR_DIT_BIT);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	// PSTATE.UAO is set to zero upon any exception to AArch64
14062306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page D5-2579.
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	// PSTATE.PAN is unchanged unless SCTLR_ELx.SPAN == 0b0
14362306a36Sopenharmony_ci	// SCTLR_ELx.SPAN is RES1 when ARMv8.1-PAN is not implemented
14462306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page D5-2578.
14562306a36Sopenharmony_ci	new |= (old & PSR_PAN_BIT);
14662306a36Sopenharmony_ci	if (!(sctlr & SCTLR_EL1_SPAN))
14762306a36Sopenharmony_ci		new |= PSR_PAN_BIT;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	// PSTATE.SS is set to zero upon any exception to AArch64
15062306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page D2-2452.
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	// PSTATE.IL is set to zero upon any exception to AArch64
15362306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page D1-2306.
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	// PSTATE.SSBS is set to SCTLR_ELx.DSSBS upon any exception to AArch64
15662306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page D13-3258
15762306a36Sopenharmony_ci	if (sctlr & SCTLR_ELx_DSSBS)
15862306a36Sopenharmony_ci		new |= PSR_SSBS_BIT;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	// PSTATE.BTYPE is set to zero upon any exception to AArch64
16162306a36Sopenharmony_ci	// See ARM DDI 0487E.a, pages D1-2293 to D1-2294.
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	new |= PSR_D_BIT;
16462306a36Sopenharmony_ci	new |= PSR_A_BIT;
16562306a36Sopenharmony_ci	new |= PSR_I_BIT;
16662306a36Sopenharmony_ci	new |= PSR_F_BIT;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	new |= target_mode;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	*vcpu_cpsr(vcpu) = new;
17162306a36Sopenharmony_ci	__vcpu_write_spsr(vcpu, target_mode, old);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * When an exception is taken, most CPSR fields are left unchanged in the
17662306a36Sopenharmony_ci * handler. However, some are explicitly overridden (e.g. M[4:0]).
17762306a36Sopenharmony_ci *
17862306a36Sopenharmony_ci * The SPSR/SPSR_ELx layouts differ, and the below is intended to work with
17962306a36Sopenharmony_ci * either format. Note: SPSR.J bit doesn't exist in SPSR_ELx, but this bit was
18062306a36Sopenharmony_ci * obsoleted by the ARMv7 virtualization extensions and is RES0.
18162306a36Sopenharmony_ci *
18262306a36Sopenharmony_ci * For the SPSR layout seen from AArch32, see:
18362306a36Sopenharmony_ci * - ARM DDI 0406C.d, page B1-1148
18462306a36Sopenharmony_ci * - ARM DDI 0487E.a, page G8-6264
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * For the SPSR_ELx layout for AArch32 seen from AArch64, see:
18762306a36Sopenharmony_ci * - ARM DDI 0487E.a, page C5-426
18862306a36Sopenharmony_ci *
18962306a36Sopenharmony_ci * Here we manipulate the fields in order of the AArch32 SPSR_ELx layout, from
19062306a36Sopenharmony_ci * MSB to LSB.
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_cistatic unsigned long get_except32_cpsr(struct kvm_vcpu *vcpu, u32 mode)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u32 sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1);
19562306a36Sopenharmony_ci	unsigned long old, new;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	old = *vcpu_cpsr(vcpu);
19862306a36Sopenharmony_ci	new = 0;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	new |= (old & PSR_AA32_N_BIT);
20162306a36Sopenharmony_ci	new |= (old & PSR_AA32_Z_BIT);
20262306a36Sopenharmony_ci	new |= (old & PSR_AA32_C_BIT);
20362306a36Sopenharmony_ci	new |= (old & PSR_AA32_V_BIT);
20462306a36Sopenharmony_ci	new |= (old & PSR_AA32_Q_BIT);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	// CPSR.IT[7:0] are set to zero upon any exception
20762306a36Sopenharmony_ci	// See ARM DDI 0487E.a, section G1.12.3
20862306a36Sopenharmony_ci	// See ARM DDI 0406C.d, section B1.8.3
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	new |= (old & PSR_AA32_DIT_BIT);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	// CPSR.SSBS is set to SCTLR.DSSBS upon any exception
21362306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page G8-6244
21462306a36Sopenharmony_ci	if (sctlr & BIT(31))
21562306a36Sopenharmony_ci		new |= PSR_AA32_SSBS_BIT;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	// CPSR.PAN is unchanged unless SCTLR.SPAN == 0b0
21862306a36Sopenharmony_ci	// SCTLR.SPAN is RES1 when ARMv8.1-PAN is not implemented
21962306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page G8-6246
22062306a36Sopenharmony_ci	new |= (old & PSR_AA32_PAN_BIT);
22162306a36Sopenharmony_ci	if (!(sctlr & BIT(23)))
22262306a36Sopenharmony_ci		new |= PSR_AA32_PAN_BIT;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	// SS does not exist in AArch32, so ignore
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	// CPSR.IL is set to zero upon any exception
22762306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page G1-5527
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	new |= (old & PSR_AA32_GE_MASK);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	// CPSR.IT[7:0] are set to zero upon any exception
23262306a36Sopenharmony_ci	// See prior comment above
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	// CPSR.E is set to SCTLR.EE upon any exception
23562306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page G8-6245
23662306a36Sopenharmony_ci	// See ARM DDI 0406C.d, page B4-1701
23762306a36Sopenharmony_ci	if (sctlr & BIT(25))
23862306a36Sopenharmony_ci		new |= PSR_AA32_E_BIT;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	// CPSR.A is unchanged upon an exception to Undefined, Supervisor
24162306a36Sopenharmony_ci	// CPSR.A is set upon an exception to other modes
24262306a36Sopenharmony_ci	// See ARM DDI 0487E.a, pages G1-5515 to G1-5516
24362306a36Sopenharmony_ci	// See ARM DDI 0406C.d, page B1-1182
24462306a36Sopenharmony_ci	new |= (old & PSR_AA32_A_BIT);
24562306a36Sopenharmony_ci	if (mode != PSR_AA32_MODE_UND && mode != PSR_AA32_MODE_SVC)
24662306a36Sopenharmony_ci		new |= PSR_AA32_A_BIT;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	// CPSR.I is set upon any exception
24962306a36Sopenharmony_ci	// See ARM DDI 0487E.a, pages G1-5515 to G1-5516
25062306a36Sopenharmony_ci	// See ARM DDI 0406C.d, page B1-1182
25162306a36Sopenharmony_ci	new |= PSR_AA32_I_BIT;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	// CPSR.F is set upon an exception to FIQ
25462306a36Sopenharmony_ci	// CPSR.F is unchanged upon an exception to other modes
25562306a36Sopenharmony_ci	// See ARM DDI 0487E.a, pages G1-5515 to G1-5516
25662306a36Sopenharmony_ci	// See ARM DDI 0406C.d, page B1-1182
25762306a36Sopenharmony_ci	new |= (old & PSR_AA32_F_BIT);
25862306a36Sopenharmony_ci	if (mode == PSR_AA32_MODE_FIQ)
25962306a36Sopenharmony_ci		new |= PSR_AA32_F_BIT;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	// CPSR.T is set to SCTLR.TE upon any exception
26262306a36Sopenharmony_ci	// See ARM DDI 0487E.a, page G8-5514
26362306a36Sopenharmony_ci	// See ARM DDI 0406C.d, page B1-1181
26462306a36Sopenharmony_ci	if (sctlr & BIT(30))
26562306a36Sopenharmony_ci		new |= PSR_AA32_T_BIT;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	new |= mode;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return new;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/*
27362306a36Sopenharmony_ci * Table taken from ARMv8 ARM DDI0487B-B, table G1-10.
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_cistatic const u8 return_offsets[8][2] = {
27662306a36Sopenharmony_ci	[0] = { 0, 0 },		/* Reset, unused */
27762306a36Sopenharmony_ci	[1] = { 4, 2 },		/* Undefined */
27862306a36Sopenharmony_ci	[2] = { 0, 0 },		/* SVC, unused */
27962306a36Sopenharmony_ci	[3] = { 4, 4 },		/* Prefetch abort */
28062306a36Sopenharmony_ci	[4] = { 8, 8 },		/* Data abort */
28162306a36Sopenharmony_ci	[5] = { 0, 0 },		/* HVC, unused */
28262306a36Sopenharmony_ci	[6] = { 4, 4 },		/* IRQ, unused */
28362306a36Sopenharmony_ci	[7] = { 4, 4 },		/* FIQ, unused */
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic void enter_exception32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	unsigned long spsr = *vcpu_cpsr(vcpu);
28962306a36Sopenharmony_ci	bool is_thumb = (spsr & PSR_AA32_T_BIT);
29062306a36Sopenharmony_ci	u32 sctlr = __vcpu_read_sys_reg(vcpu, SCTLR_EL1);
29162306a36Sopenharmony_ci	u32 return_address;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	*vcpu_cpsr(vcpu) = get_except32_cpsr(vcpu, mode);
29462306a36Sopenharmony_ci	return_address   = *vcpu_pc(vcpu);
29562306a36Sopenharmony_ci	return_address  += return_offsets[vect_offset >> 2][is_thumb];
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* KVM only enters the ABT and UND modes, so only deal with those */
29862306a36Sopenharmony_ci	switch(mode) {
29962306a36Sopenharmony_ci	case PSR_AA32_MODE_ABT:
30062306a36Sopenharmony_ci		__vcpu_write_spsr_abt(vcpu, host_spsr_to_spsr32(spsr));
30162306a36Sopenharmony_ci		vcpu_gp_regs(vcpu)->compat_lr_abt = return_address;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	case PSR_AA32_MODE_UND:
30562306a36Sopenharmony_ci		__vcpu_write_spsr_und(vcpu, host_spsr_to_spsr32(spsr));
30662306a36Sopenharmony_ci		vcpu_gp_regs(vcpu)->compat_lr_und = return_address;
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* Branch to exception vector */
31162306a36Sopenharmony_ci	if (sctlr & (1 << 13))
31262306a36Sopenharmony_ci		vect_offset += 0xffff0000;
31362306a36Sopenharmony_ci	else /* always have security exceptions */
31462306a36Sopenharmony_ci		vect_offset += __vcpu_read_sys_reg(vcpu, VBAR_EL1);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	*vcpu_pc(vcpu) = vect_offset;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic void kvm_inject_exception(struct kvm_vcpu *vcpu)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	if (vcpu_el1_is_32bit(vcpu)) {
32262306a36Sopenharmony_ci		switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
32362306a36Sopenharmony_ci		case unpack_vcpu_flag(EXCEPT_AA32_UND):
32462306a36Sopenharmony_ci			enter_exception32(vcpu, PSR_AA32_MODE_UND, 4);
32562306a36Sopenharmony_ci			break;
32662306a36Sopenharmony_ci		case unpack_vcpu_flag(EXCEPT_AA32_IABT):
32762306a36Sopenharmony_ci			enter_exception32(vcpu, PSR_AA32_MODE_ABT, 12);
32862306a36Sopenharmony_ci			break;
32962306a36Sopenharmony_ci		case unpack_vcpu_flag(EXCEPT_AA32_DABT):
33062306a36Sopenharmony_ci			enter_exception32(vcpu, PSR_AA32_MODE_ABT, 16);
33162306a36Sopenharmony_ci			break;
33262306a36Sopenharmony_ci		default:
33362306a36Sopenharmony_ci			/* Err... */
33462306a36Sopenharmony_ci			break;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci	} else {
33762306a36Sopenharmony_ci		switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
33862306a36Sopenharmony_ci		case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC):
33962306a36Sopenharmony_ci			enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync);
34062306a36Sopenharmony_ci			break;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC):
34362306a36Sopenharmony_ci			enter_exception64(vcpu, PSR_MODE_EL2h, except_type_sync);
34462306a36Sopenharmony_ci			break;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		case unpack_vcpu_flag(EXCEPT_AA64_EL2_IRQ):
34762306a36Sopenharmony_ci			enter_exception64(vcpu, PSR_MODE_EL2h, except_type_irq);
34862306a36Sopenharmony_ci			break;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		default:
35162306a36Sopenharmony_ci			/*
35262306a36Sopenharmony_ci			 * Only EL1_SYNC and EL2_{SYNC,IRQ} makes
35362306a36Sopenharmony_ci			 * sense so far. Everything else gets silently
35462306a36Sopenharmony_ci			 * ignored.
35562306a36Sopenharmony_ci			 */
35662306a36Sopenharmony_ci			break;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci/*
36262306a36Sopenharmony_ci * Adjust the guest PC (and potentially exception state) depending on
36362306a36Sopenharmony_ci * flags provided by the emulation code.
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_civoid __kvm_adjust_pc(struct kvm_vcpu *vcpu)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	if (vcpu_get_flag(vcpu, PENDING_EXCEPTION)) {
36862306a36Sopenharmony_ci		kvm_inject_exception(vcpu);
36962306a36Sopenharmony_ci		vcpu_clear_flag(vcpu, PENDING_EXCEPTION);
37062306a36Sopenharmony_ci		vcpu_clear_flag(vcpu, EXCEPT_MASK);
37162306a36Sopenharmony_ci	} else if (vcpu_get_flag(vcpu, INCREMENT_PC)) {
37262306a36Sopenharmony_ci		kvm_skip_instr(vcpu);
37362306a36Sopenharmony_ci		vcpu_clear_flag(vcpu, INCREMENT_PC);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci}
376