arm64: KVM: fault injection into a guest
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / kvm / inject_fault.c
1 /*
2  * Fault injection for 64bit guests.
3  *
4  * Copyright (C) 2012,2013 - ARM Ltd
5  * Author: Marc Zyngier <marc.zyngier@arm.com>
6  *
7  * Based on arch/arm/kvm/emulate.c
8  * Copyright (C) 2012 - Virtual Open Systems and Columbia University
9  * Author: Christoffer Dall <c.dall@virtualopensystems.com>
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <linux/kvm_host.h>
25 #include <asm/kvm_emulate.h>
26 #include <asm/esr.h>
27
28 #define PSTATE_FAULT_BITS_64    (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
29                                  PSR_I_BIT | PSR_D_BIT)
30 #define EL1_EXCEPT_SYNC_OFFSET  0x200
31
32 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
33 {
34         unsigned long cpsr = *vcpu_cpsr(vcpu);
35         bool is_aarch32;
36         u32 esr = 0;
37
38         is_aarch32 = vcpu_mode_is_32bit(vcpu);
39
40         *vcpu_spsr(vcpu) = cpsr;
41         *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
42
43         *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
44         *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
45
46         vcpu_sys_reg(vcpu, FAR_EL1) = addr;
47
48         /*
49          * Build an {i,d}abort, depending on the level and the
50          * instruction set. Report an external synchronous abort.
51          */
52         if (kvm_vcpu_trap_il_is32bit(vcpu))
53                 esr |= ESR_EL1_IL;
54
55         /*
56          * Here, the guest runs in AArch64 mode when in EL1. If we get
57          * an AArch32 fault, it means we managed to trap an EL0 fault.
58          */
59         if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t)
60                 esr |= (ESR_EL1_EC_IABT_EL0 << ESR_EL1_EC_SHIFT);
61         else
62                 esr |= (ESR_EL1_EC_IABT_EL1 << ESR_EL1_EC_SHIFT);
63
64         if (!is_iabt)
65                 esr |= ESR_EL1_EC_DABT_EL0;
66
67         vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_EL2_EC_xABT_xFSR_EXTABT;
68 }
69
70 static void inject_undef64(struct kvm_vcpu *vcpu)
71 {
72         unsigned long cpsr = *vcpu_cpsr(vcpu);
73         u32 esr = (ESR_EL1_EC_UNKNOWN << ESR_EL1_EC_SHIFT);
74
75         *vcpu_spsr(vcpu) = cpsr;
76         *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
77
78         *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
79         *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
80
81         /*
82          * Build an unknown exception, depending on the instruction
83          * set.
84          */
85         if (kvm_vcpu_trap_il_is32bit(vcpu))
86                 esr |= ESR_EL1_IL;
87
88         vcpu_sys_reg(vcpu, ESR_EL1) = esr;
89 }
90
91 /**
92  * kvm_inject_dabt - inject a data abort into the guest
93  * @vcpu: The VCPU to receive the undefined exception
94  * @addr: The address to report in the DFAR
95  *
96  * It is assumed that this code is called from the VCPU thread and that the
97  * VCPU therefore is not currently executing guest code.
98  */
99 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
100 {
101         inject_abt64(vcpu, false, addr);
102 }
103
104 /**
105  * kvm_inject_pabt - inject a prefetch abort into the guest
106  * @vcpu: The VCPU to receive the undefined exception
107  * @addr: The address to report in the DFAR
108  *
109  * It is assumed that this code is called from the VCPU thread and that the
110  * VCPU therefore is not currently executing guest code.
111  */
112 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
113 {
114         inject_abt64(vcpu, true, addr);
115 }
116
117 /**
118  * kvm_inject_undefined - inject an undefined instruction into the guest
119  *
120  * It is assumed that this code is called from the VCPU thread and that the
121  * VCPU therefore is not currently executing guest code.
122  */
123 void kvm_inject_undefined(struct kvm_vcpu *vcpu)
124 {
125         inject_undef64(vcpu);
126 }