Commit | Line | Data |
---|---|---|
caab277b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
aa8eff9b | 2 | /* |
e82e0305 | 3 | * Fault injection for both 32 and 64bit guests. |
aa8eff9b MZ |
4 | * |
5 | * Copyright (C) 2012,2013 - ARM Ltd | |
6 | * Author: Marc Zyngier <marc.zyngier@arm.com> | |
7 | * | |
8 | * Based on arch/arm/kvm/emulate.c | |
9 | * Copyright (C) 2012 - Virtual Open Systems and Columbia University | |
10 | * Author: Christoffer Dall <c.dall@virtualopensystems.com> | |
aa8eff9b MZ |
11 | */ |
12 | ||
13 | #include <linux/kvm_host.h> | |
14 | #include <asm/kvm_emulate.h> | |
15 | #include <asm/esr.h> | |
16 | ||
aa8eff9b MZ |
17 | static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr) |
18 | { | |
19 | unsigned long cpsr = *vcpu_cpsr(vcpu); | |
89581f06 | 20 | bool is_aarch32 = vcpu_mode_is_32bit(vcpu); |
aa8eff9b MZ |
21 | u32 esr = 0; |
22 | ||
bb666c47 MZ |
23 | vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1 | |
24 | KVM_ARM64_EXCEPT_AA64_ELx_SYNC | | |
25 | KVM_ARM64_PENDING_EXCEPTION); | |
aa8eff9b | 26 | |
8d404c4c | 27 | vcpu_write_sys_reg(vcpu, addr, FAR_EL1); |
aa8eff9b MZ |
28 | |
29 | /* | |
30 | * Build an {i,d}abort, depending on the level and the | |
31 | * instruction set. Report an external synchronous abort. | |
32 | */ | |
33 | if (kvm_vcpu_trap_il_is32bit(vcpu)) | |
c6d01a94 | 34 | esr |= ESR_ELx_IL; |
aa8eff9b MZ |
35 | |
36 | /* | |
37 | * Here, the guest runs in AArch64 mode when in EL1. If we get | |
38 | * an AArch32 fault, it means we managed to trap an EL0 fault. | |
39 | */ | |
40 | if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t) | |
c6d01a94 | 41 | esr |= (ESR_ELx_EC_IABT_LOW << ESR_ELx_EC_SHIFT); |
aa8eff9b | 42 | else |
c6d01a94 | 43 | esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT); |
aa8eff9b MZ |
44 | |
45 | if (!is_iabt) | |
e4fe9e7d | 46 | esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT; |
aa8eff9b | 47 | |
8d404c4c | 48 | vcpu_write_sys_reg(vcpu, esr | ESR_ELx_FSC_EXTABT, ESR_EL1); |
aa8eff9b MZ |
49 | } |
50 | ||
51 | static void inject_undef64(struct kvm_vcpu *vcpu) | |
52 | { | |
c6d01a94 | 53 | u32 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT); |
aa8eff9b | 54 | |
bb666c47 MZ |
55 | vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1 | |
56 | KVM_ARM64_EXCEPT_AA64_ELx_SYNC | | |
57 | KVM_ARM64_PENDING_EXCEPTION); | |
aa8eff9b MZ |
58 | |
59 | /* | |
60 | * Build an unknown exception, depending on the instruction | |
61 | * set. | |
62 | */ | |
63 | if (kvm_vcpu_trap_il_is32bit(vcpu)) | |
c6d01a94 | 64 | esr |= ESR_ELx_IL; |
aa8eff9b | 65 | |
8d404c4c | 66 | vcpu_write_sys_reg(vcpu, esr, ESR_EL1); |
aa8eff9b MZ |
67 | } |
68 | ||
69 | /** | |
70 | * kvm_inject_dabt - inject a data abort into the guest | |
da345174 | 71 | * @vcpu: The VCPU to receive the data abort |
aa8eff9b MZ |
72 | * @addr: The address to report in the DFAR |
73 | * | |
74 | * It is assumed that this code is called from the VCPU thread and that the | |
75 | * VCPU therefore is not currently executing guest code. | |
76 | */ | |
77 | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr) | |
78 | { | |
e72341c5 | 79 | if (vcpu_el1_is_32bit(vcpu)) |
74a64a98 | 80 | kvm_inject_dabt32(vcpu, addr); |
126c69a0 MZ |
81 | else |
82 | inject_abt64(vcpu, false, addr); | |
aa8eff9b MZ |
83 | } |
84 | ||
85 | /** | |
86 | * kvm_inject_pabt - inject a prefetch abort into the guest | |
da345174 | 87 | * @vcpu: The VCPU to receive the prefetch abort |
aa8eff9b MZ |
88 | * @addr: The address to report in the DFAR |
89 | * | |
90 | * It is assumed that this code is called from the VCPU thread and that the | |
91 | * VCPU therefore is not currently executing guest code. | |
92 | */ | |
93 | void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr) | |
94 | { | |
e72341c5 | 95 | if (vcpu_el1_is_32bit(vcpu)) |
74a64a98 | 96 | kvm_inject_pabt32(vcpu, addr); |
126c69a0 MZ |
97 | else |
98 | inject_abt64(vcpu, true, addr); | |
aa8eff9b MZ |
99 | } |
100 | ||
101 | /** | |
102 | * kvm_inject_undefined - inject an undefined instruction into the guest | |
8a4374f9 | 103 | * @vcpu: The vCPU in which to inject the exception |
aa8eff9b MZ |
104 | * |
105 | * It is assumed that this code is called from the VCPU thread and that the | |
106 | * VCPU therefore is not currently executing guest code. | |
107 | */ | |
108 | void kvm_inject_undefined(struct kvm_vcpu *vcpu) | |
109 | { | |
e72341c5 | 110 | if (vcpu_el1_is_32bit(vcpu)) |
74a64a98 | 111 | kvm_inject_undef32(vcpu); |
126c69a0 MZ |
112 | else |
113 | inject_undef64(vcpu); | |
aa8eff9b | 114 | } |
10cf3390 | 115 | |
b7b27fac | 116 | void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr) |
4715c14b | 117 | { |
b7b27fac | 118 | vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK); |
3df59d8d | 119 | *vcpu_hcr(vcpu) |= HCR_VSE; |
4715c14b JM |
120 | } |
121 | ||
10cf3390 MZ |
122 | /** |
123 | * kvm_inject_vabt - inject an async abort / SError into the guest | |
124 | * @vcpu: The VCPU to receive the exception | |
125 | * | |
126 | * It is assumed that this code is called from the VCPU thread and that the | |
127 | * VCPU therefore is not currently executing guest code. | |
4715c14b JM |
128 | * |
129 | * Systems with the RAS Extensions specify an imp-def ESR (ISV/IDS = 1) with | |
130 | * the remaining ISS all-zeros so that this error is not interpreted as an | |
131 | * uncategorized RAS error. Without the RAS Extensions we can't specify an ESR | |
132 | * value, so the CPU generates an imp-def value. | |
10cf3390 MZ |
133 | */ |
134 | void kvm_inject_vabt(struct kvm_vcpu *vcpu) | |
135 | { | |
b7b27fac | 136 | kvm_set_sei_esr(vcpu, ESR_ELx_ISV); |
10cf3390 | 137 | } |