Merge branch 'cec-defines' into for-linus
[sfrench/cifs-2.6.git] / arch / arm / kvm / hyp / switch.c
1 /*
2  * Copyright (C) 2015 - ARM Ltd
3  * Author: Marc Zyngier <marc.zyngier@arm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <asm/kvm_asm.h>
19 #include <asm/kvm_hyp.h>
20
21 __asm__(".arch_extension     virt");
22
23 /*
24  * Activate the traps, saving the host's fpexc register before
25  * overwriting it. We'll restore it on VM exit.
26  */
27 static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu, u32 *fpexc_host)
28 {
29         u32 val;
30
31         /*
32          * We are about to set HCPTR.TCP10/11 to trap all floating point
33          * register accesses to HYP, however, the ARM ARM clearly states that
34          * traps are only taken to HYP if the operation would not otherwise
35          * trap to SVC.  Therefore, always make sure that for 32-bit guests,
36          * we set FPEXC.EN to prevent traps to SVC, when setting the TCP bits.
37          */
38         val = read_sysreg(VFP_FPEXC);
39         *fpexc_host = val;
40         if (!(val & FPEXC_EN)) {
41                 write_sysreg(val | FPEXC_EN, VFP_FPEXC);
42                 isb();
43         }
44
45         write_sysreg(vcpu->arch.hcr | vcpu->arch.irq_lines, HCR);
46         /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
47         write_sysreg(HSTR_T(15), HSTR);
48         write_sysreg(HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11), HCPTR);
49         val = read_sysreg(HDCR);
50         write_sysreg(val | HDCR_TPM | HDCR_TPMCR, HDCR);
51 }
52
53 static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
54 {
55         u32 val;
56
57         write_sysreg(0, HCR);
58         write_sysreg(0, HSTR);
59         val = read_sysreg(HDCR);
60         write_sysreg(val & ~(HDCR_TPM | HDCR_TPMCR), HDCR);
61         write_sysreg(0, HCPTR);
62 }
63
64 static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
65 {
66         struct kvm *kvm = kern_hyp_va(vcpu->kvm);
67         write_sysreg(kvm->arch.vttbr, VTTBR);
68         write_sysreg(vcpu->arch.midr, VPIDR);
69 }
70
71 static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
72 {
73         write_sysreg(0, VTTBR);
74         write_sysreg(read_sysreg(MIDR), VPIDR);
75 }
76
77 static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
78 {
79         __vgic_v2_save_state(vcpu);
80 }
81
82 static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
83 {
84         __vgic_v2_restore_state(vcpu);
85 }
86
87 static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
88 {
89         u32 hsr = read_sysreg(HSR);
90         u8 ec = hsr >> HSR_EC_SHIFT;
91         u32 hpfar, far;
92
93         vcpu->arch.fault.hsr = hsr;
94
95         if (ec == HSR_EC_IABT)
96                 far = read_sysreg(HIFAR);
97         else if (ec == HSR_EC_DABT)
98                 far = read_sysreg(HDFAR);
99         else
100                 return true;
101
102         /*
103          * B3.13.5 Reporting exceptions taken to the Non-secure PL2 mode:
104          *
105          * Abort on the stage 2 translation for a memory access from a
106          * Non-secure PL1 or PL0 mode:
107          *
108          * For any Access flag fault or Translation fault, and also for any
109          * Permission fault on the stage 2 translation of a memory access
110          * made as part of a translation table walk for a stage 1 translation,
111          * the HPFAR holds the IPA that caused the fault. Otherwise, the HPFAR
112          * is UNKNOWN.
113          */
114         if (!(hsr & HSR_DABT_S1PTW) && (hsr & HSR_FSC_TYPE) == FSC_PERM) {
115                 u64 par, tmp;
116
117                 par = read_sysreg(PAR);
118                 write_sysreg(far, ATS1CPR);
119                 isb();
120
121                 tmp = read_sysreg(PAR);
122                 write_sysreg(par, PAR);
123
124                 if (unlikely(tmp & 1))
125                         return false; /* Translation failed, back to guest */
126
127                 hpfar = ((tmp >> 12) & ((1UL << 28) - 1)) << 4;
128         } else {
129                 hpfar = read_sysreg(HPFAR);
130         }
131
132         vcpu->arch.fault.hxfar = far;
133         vcpu->arch.fault.hpfar = hpfar;
134         return true;
135 }
136
137 static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
138 {
139         struct kvm_cpu_context *host_ctxt;
140         struct kvm_cpu_context *guest_ctxt;
141         bool fp_enabled;
142         u64 exit_code;
143         u32 fpexc;
144
145         vcpu = kern_hyp_va(vcpu);
146         write_sysreg(vcpu, HTPIDR);
147
148         host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
149         guest_ctxt = &vcpu->arch.ctxt;
150
151         __sysreg_save_state(host_ctxt);
152         __banked_save_state(host_ctxt);
153
154         __activate_traps(vcpu, &fpexc);
155         __activate_vm(vcpu);
156
157         __vgic_restore_state(vcpu);
158         __timer_restore_state(vcpu);
159
160         __sysreg_restore_state(guest_ctxt);
161         __banked_restore_state(guest_ctxt);
162
163         /* Jump in the fire! */
164 again:
165         exit_code = __guest_enter(vcpu, host_ctxt);
166         /* And we're baaack! */
167
168         if (exit_code == ARM_EXCEPTION_HVC && !__populate_fault_info(vcpu))
169                 goto again;
170
171         fp_enabled = __vfp_enabled();
172
173         __banked_save_state(guest_ctxt);
174         __sysreg_save_state(guest_ctxt);
175         __timer_save_state(vcpu);
176         __vgic_save_state(vcpu);
177
178         __deactivate_traps(vcpu);
179         __deactivate_vm(vcpu);
180
181         __banked_restore_state(host_ctxt);
182         __sysreg_restore_state(host_ctxt);
183
184         if (fp_enabled) {
185                 __vfp_save_state(&guest_ctxt->vfp);
186                 __vfp_restore_state(&host_ctxt->vfp);
187         }
188
189         write_sysreg(fpexc, VFP_FPEXC);
190
191         return exit_code;
192 }
193
194 __alias(__guest_run) int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
195
196 static const char * const __hyp_panic_string[] = {
197         [ARM_EXCEPTION_RESET]      = "\nHYP panic: RST   PC:%08x CPSR:%08x",
198         [ARM_EXCEPTION_UNDEFINED]  = "\nHYP panic: UNDEF PC:%08x CPSR:%08x",
199         [ARM_EXCEPTION_SOFTWARE]   = "\nHYP panic: SVC   PC:%08x CPSR:%08x",
200         [ARM_EXCEPTION_PREF_ABORT] = "\nHYP panic: PABRT PC:%08x CPSR:%08x",
201         [ARM_EXCEPTION_DATA_ABORT] = "\nHYP panic: DABRT PC:%08x ADDR:%08x",
202         [ARM_EXCEPTION_IRQ]        = "\nHYP panic: IRQ   PC:%08x CPSR:%08x",
203         [ARM_EXCEPTION_FIQ]        = "\nHYP panic: FIQ   PC:%08x CPSR:%08x",
204         [ARM_EXCEPTION_HVC]        = "\nHYP panic: HVC   PC:%08x CPSR:%08x",
205 };
206
207 void __hyp_text __noreturn __hyp_panic(int cause)
208 {
209         u32 elr = read_special(ELR_hyp);
210         u32 val;
211
212         if (cause == ARM_EXCEPTION_DATA_ABORT)
213                 val = read_sysreg(HDFAR);
214         else
215                 val = read_special(SPSR);
216
217         if (read_sysreg(VTTBR)) {
218                 struct kvm_vcpu *vcpu;
219                 struct kvm_cpu_context *host_ctxt;
220
221                 vcpu = (struct kvm_vcpu *)read_sysreg(HTPIDR);
222                 host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
223                 __deactivate_traps(vcpu);
224                 __deactivate_vm(vcpu);
225                 __sysreg_restore_state(host_ctxt);
226         }
227
228         /* Call panic for real */
229         __hyp_do_panic(__hyp_panic_string[cause], elr, val);
230
231         unreachable();
232 }