]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - arch/arm/kvm/interrupts.S
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-artful-kernel.git] / arch / arm / kvm / interrupts.S
CommitLineData
749cf76c
CD
1/*
2 * Copyright (C) 2012 - Virtual Open Systems and Columbia University
3 * Author: Christoffer Dall <c.dall@virtualopensystems.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, write to the Free Software
16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
342cd0ab
CD
18
19#include <linux/linkage.h>
20#include <linux/const.h>
21#include <asm/unified.h>
22#include <asm/page.h>
f7ed45be 23#include <asm/ptrace.h>
749cf76c
CD
24#include <asm/asm-offsets.h>
25#include <asm/kvm_asm.h>
342cd0ab 26#include <asm/kvm_arm.h>
f7ed45be
CD
27#include <asm/vfpmacros.h>
28#include "interrupts_head.S"
342cd0ab
CD
29
30 .text
31
32__kvm_hyp_code_start:
33 .globl __kvm_hyp_code_start
34
35/********************************************************************
36 * Flush per-VMID TLBs
f7ed45be 37 *
48762767 38 * void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
f7ed45be
CD
39 *
40 * We rely on the hardware to broadcast the TLB invalidation to all CPUs
41 * inside the inner-shareable domain (which is the case for all v7
42 * implementations). If we come across a non-IS SMP implementation, we'll
43 * have to use an IPI based mechanism. Until then, we stick to the simple
44 * hardware assisted version.
48762767
MZ
45 *
46 * As v7 does not support flushing per IPA, just nuke the whole TLB
47 * instead, ignoring the ipa value.
342cd0ab 48 */
48762767 49ENTRY(__kvm_tlb_flush_vmid_ipa)
f7ed45be
CD
50 push {r2, r3}
51
479c5ae2 52 dsb ishst
f7ed45be
CD
53 add r0, r0, #KVM_VTTBR
54 ldrd r2, r3, [r0]
19b0e60a 55 mcrr p15, 6, rr_lo_hi(r2, r3), c2 @ Write VTTBR
f7ed45be
CD
56 isb
57 mcr p15, 0, r0, c8, c3, 0 @ TLBIALLIS (rt ignored)
e3ab547f 58 dsb ish
f7ed45be
CD
59 isb
60 mov r2, #0
61 mov r3, #0
62 mcrr p15, 6, r2, r3, c2 @ Back to VMID #0
63 isb @ Not necessary if followed by eret
64
65 pop {r2, r3}
d5d8184d 66 bx lr
48762767 67ENDPROC(__kvm_tlb_flush_vmid_ipa)
d5d8184d 68
72fc36b6
MS
69/**
70 * void __kvm_tlb_flush_vmid(struct kvm *kvm) - Flush per-VMID TLBs
71 *
72 * Reuses __kvm_tlb_flush_vmid_ipa() for ARMv7, without passing address
73 * parameter
74 */
75
76ENTRY(__kvm_tlb_flush_vmid)
77 b __kvm_tlb_flush_vmid_ipa
78ENDPROC(__kvm_tlb_flush_vmid)
79
d5d8184d 80/********************************************************************
f7ed45be
CD
81 * Flush TLBs and instruction caches of all CPUs inside the inner-shareable
82 * domain, for all VMIDs
83 *
84 * void __kvm_flush_vm_context(void);
d5d8184d 85 */
342cd0ab 86ENTRY(__kvm_flush_vm_context)
f7ed45be
CD
87 mov r0, #0 @ rn parameter for c15 flushes is SBZ
88
89 /* Invalidate NS Non-Hyp TLB Inner Shareable (TLBIALLNSNHIS) */
90 mcr p15, 4, r0, c8, c3, 4
91 /* Invalidate instruction caches Inner Shareable (ICIALLUIS) */
92 mcr p15, 0, r0, c7, c1, 0
e3ab547f 93 dsb ish
f7ed45be
CD
94 isb @ Not necessary if followed by eret
95
342cd0ab
CD
96 bx lr
97ENDPROC(__kvm_flush_vm_context)
98
f7ed45be 99
342cd0ab
CD
100/********************************************************************
101 * Hypervisor world-switch code
f7ed45be
CD
102 *
103 *
104 * int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
342cd0ab
CD
105 */
106ENTRY(__kvm_vcpu_run)
f7ed45be
CD
107 @ Save the vcpu pointer
108 mcr p15, 4, vcpu, c13, c0, 2 @ HTPIDR
109
110 save_host_regs
111
1a89dd91 112 restore_vgic_state
53e72406 113 restore_timer_state
1a89dd91 114
f7ed45be
CD
115 @ Store hardware CP15 state and load guest state
116 read_cp15_state store_to_vcpu = 0
117 write_cp15_state read_from_vcpu = 1
118
119 @ If the host kernel has not been configured with VFPv3 support,
120 @ then it is safer if we deny guests from using it as well.
121#ifdef CONFIG_VFPv3
122 @ Set FPEXC_EN so the guest doesn't trap floating point instructions
123 VFPFMRX r2, FPEXC @ VMRS
124 push {r2}
125 orr r2, r2, #FPEXC_EN
126 VFPFMXR FPEXC, r2 @ VMSR
127#endif
128
129 @ Configure Hyp-role
130 configure_hyp_role vmentry
131
132 @ Trap coprocessor CRx accesses
133 set_hstr vmentry
134 set_hcptr vmentry, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
135 set_hdcr vmentry
136
137 @ Write configured ID register into MIDR alias
138 ldr r1, [vcpu, #VCPU_MIDR]
139 mcr p15, 4, r1, c0, c0, 0
140
141 @ Write guest view of MPIDR into VMPIDR
142 ldr r1, [vcpu, #CP15_OFFSET(c0_MPIDR)]
143 mcr p15, 4, r1, c0, c0, 5
144
145 @ Set up guest memory translation
146 ldr r1, [vcpu, #VCPU_KVM]
147 add r1, r1, #KVM_VTTBR
148 ldrd r2, r3, [r1]
19b0e60a 149 mcrr p15, 6, rr_lo_hi(r2, r3), c2 @ Write VTTBR
f7ed45be
CD
150
151 @ We're all done, just restore the GPRs and go to the guest
152 restore_guest_regs
153 clrex @ Clear exclusive monitor
154 eret
155
156__kvm_vcpu_return:
157 /*
158 * return convention:
159 * guest r0, r1, r2 saved on the stack
160 * r0: vcpu pointer
161 * r1: exception code
162 */
163 save_guest_regs
164
165 @ Set VMID == 0
166 mov r2, #0
167 mov r3, #0
168 mcrr p15, 6, r2, r3, c2 @ Write VTTBR
169
170 @ Don't trap coprocessor accesses for host kernel
171 set_hstr vmexit
172 set_hdcr vmexit
173 set_hcptr vmexit, (HCPTR_TTA | HCPTR_TCP(10) | HCPTR_TCP(11))
174
175#ifdef CONFIG_VFPv3
176 @ Save floating point registers we if let guest use them.
177 tst r2, #(HCPTR_TCP(10) | HCPTR_TCP(11))
178 bne after_vfp_restore
179
180 @ Switch VFP/NEON hardware state to the host's
181 add r7, vcpu, #VCPU_VFP_GUEST
182 store_vfp_state r7
183 add r7, vcpu, #VCPU_VFP_HOST
184 ldr r7, [r7]
185 restore_vfp_state r7
186
187after_vfp_restore:
188 @ Restore FPEXC_EN which we clobbered on entry
189 pop {r2}
190 VFPFMXR FPEXC, r2
191#endif
192
193 @ Reset Hyp-role
194 configure_hyp_role vmexit
195
196 @ Let host read hardware MIDR
197 mrc p15, 0, r2, c0, c0, 0
198 mcr p15, 4, r2, c0, c0, 0
199
200 @ Back to hardware MPIDR
201 mrc p15, 0, r2, c0, c0, 5
202 mcr p15, 4, r2, c0, c0, 5
203
204 @ Store guest CP15 state and restore host state
205 read_cp15_state store_to_vcpu = 1
206 write_cp15_state read_from_vcpu = 0
207
53e72406 208 save_timer_state
1a89dd91
MZ
209 save_vgic_state
210
f7ed45be
CD
211 restore_host_regs
212 clrex @ Clear exclusive monitor
6d7311b5 213#ifndef CONFIG_CPU_ENDIAN_BE8
f7ed45be
CD
214 mov r0, r1 @ Return the return code
215 mov r1, #0 @ Clear upper bits in return value
6d7311b5
VK
216#else
217 @ r1 already has return code
218 mov r0, #0 @ Clear upper bits in return value
219#endif /* CONFIG_CPU_ENDIAN_BE8 */
f7ed45be 220 bx lr @ return to IOCTL
342cd0ab
CD
221
222/********************************************************************
223 * Call function in Hyp mode
224 *
225 *
226 * u64 kvm_call_hyp(void *hypfn, ...);
227 *
228 * This is not really a variadic function in the classic C-way and care must
229 * be taken when calling this to ensure parameters are passed in registers
230 * only, since the stack will change between the caller and the callee.
231 *
232 * Call the function with the first argument containing a pointer to the
233 * function you wish to call in Hyp mode, and subsequent arguments will be
234 * passed as r0, r1, and r2 (a maximum of 3 arguments in addition to the
235 * function pointer can be passed). The function being called must be mapped
236 * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
237 * passed in r0 and r1.
238 *
b20c9f29
MZ
239 * A function pointer with a value of 0xffffffff has a special meaning,
240 * and is used to implement __hyp_get_vectors in the same way as in
241 * arch/arm/kernel/hyp_stub.S.
242 *
342cd0ab
CD
243 * The calling convention follows the standard AAPCS:
244 * r0 - r3: caller save
245 * r12: caller save
246 * rest: callee save
247 */
248ENTRY(kvm_call_hyp)
249 hvc #0
250 bx lr
251
252/********************************************************************
253 * Hypervisor exception vector and handlers
f7ed45be
CD
254 *
255 *
256 * The KVM/ARM Hypervisor ABI is defined as follows:
257 *
258 * Entry to Hyp mode from the host kernel will happen _only_ when an HVC
259 * instruction is issued since all traps are disabled when running the host
260 * kernel as per the Hyp-mode initialization at boot time.
261 *
0b5e3bac 262 * HVC instructions cause a trap to the vector page + offset 0x14 (see hyp_hvc
f7ed45be 263 * below) when the HVC instruction is called from SVC mode (i.e. a guest or the
0b5e3bac 264 * host kernel) and they cause a trap to the vector page + offset 0x8 when HVC
f7ed45be
CD
265 * instructions are called from within Hyp-mode.
266 *
267 * Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
268 * Switching to Hyp mode is done through a simple HVC #0 instruction. The
269 * exception vector code will check that the HVC comes from VMID==0 and if
270 * so will push the necessary state (SPSR, lr_usr) on the Hyp stack.
271 * - r0 contains a pointer to a HYP function
272 * - r1, r2, and r3 contain arguments to the above function.
273 * - The HYP function will be called with its arguments in r0, r1 and r2.
274 * On HYP function return, we return directly to SVC.
275 *
276 * Note that the above is used to execute code in Hyp-mode from a host-kernel
277 * point of view, and is a different concept from performing a world-switch and
278 * executing guest code SVC mode (with a VMID != 0).
342cd0ab
CD
279 */
280
f7ed45be
CD
281/* Handle undef, svc, pabt, or dabt by crashing with a user notice */
282.macro bad_exception exception_code, panic_str
283 push {r0-r2}
284 mrrc p15, 6, r0, r1, c2 @ Read VTTBR
285 lsr r1, r1, #16
286 ands r1, r1, #0xff
287 beq 99f
288
289 load_vcpu @ Load VCPU pointer
290 .if \exception_code == ARM_EXCEPTION_DATA_ABORT
291 mrc p15, 4, r2, c5, c2, 0 @ HSR
292 mrc p15, 4, r1, c6, c0, 0 @ HDFAR
293 str r2, [vcpu, #VCPU_HSR]
294 str r1, [vcpu, #VCPU_HxFAR]
295 .endif
296 .if \exception_code == ARM_EXCEPTION_PREF_ABORT
297 mrc p15, 4, r2, c5, c2, 0 @ HSR
298 mrc p15, 4, r1, c6, c0, 2 @ HIFAR
299 str r2, [vcpu, #VCPU_HSR]
300 str r1, [vcpu, #VCPU_HxFAR]
301 .endif
302 mov r1, #\exception_code
303 b __kvm_vcpu_return
304
305 @ We were in the host already. Let's craft a panic-ing return to SVC.
30699: mrs r2, cpsr
307 bic r2, r2, #MODE_MASK
308 orr r2, r2, #SVC_MODE
309THUMB( orr r2, r2, #PSR_T_BIT )
310 msr spsr_cxsf, r2
311 mrs r1, ELR_hyp
312 ldr r2, =BSYM(panic)
313 msr ELR_hyp, r2
314 ldr r0, =\panic_str
22cfbb6d 315 clrex @ Clear exclusive monitor
f7ed45be
CD
316 eret
317.endm
318
319 .text
320
342cd0ab
CD
321 .align 5
322__kvm_hyp_vector:
323 .globl __kvm_hyp_vector
f7ed45be
CD
324
325 @ Hyp-mode exception vector
326 W(b) hyp_reset
327 W(b) hyp_undef
328 W(b) hyp_svc
329 W(b) hyp_pabt
330 W(b) hyp_dabt
331 W(b) hyp_hvc
332 W(b) hyp_irq
333 W(b) hyp_fiq
334
335 .align
336hyp_reset:
337 b hyp_reset
338
339 .align
340hyp_undef:
341 bad_exception ARM_EXCEPTION_UNDEFINED, und_die_str
342
343 .align
344hyp_svc:
345 bad_exception ARM_EXCEPTION_HVC, svc_die_str
346
347 .align
348hyp_pabt:
349 bad_exception ARM_EXCEPTION_PREF_ABORT, pabt_die_str
350
351 .align
352hyp_dabt:
353 bad_exception ARM_EXCEPTION_DATA_ABORT, dabt_die_str
354
355 .align
356hyp_hvc:
357 /*
358 * Getting here is either becuase of a trap from a guest or from calling
359 * HVC from the host kernel, which means "switch to Hyp mode".
360 */
361 push {r0, r1, r2}
362
363 @ Check syndrome register
364 mrc p15, 4, r1, c5, c2, 0 @ HSR
365 lsr r0, r1, #HSR_EC_SHIFT
366#ifdef CONFIG_VFPv3
367 cmp r0, #HSR_EC_CP_0_13
368 beq switch_to_guest_vfp
369#endif
370 cmp r0, #HSR_EC_HVC
371 bne guest_trap @ Not HVC instr.
372
373 /*
374 * Let's check if the HVC came from VMID 0 and allow simple
375 * switch to Hyp mode
376 */
377 mrrc p15, 6, r0, r2, c2
378 lsr r2, r2, #16
379 and r2, r2, #0xff
380 cmp r2, #0
381 bne guest_trap @ Guest called HVC
382
383host_switch_to_hyp:
384 pop {r0, r1, r2}
385
b20c9f29
MZ
386 /* Check for __hyp_get_vectors */
387 cmp r0, #-1
388 mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR
389 beq 1f
390
f7ed45be
CD
391 push {lr}
392 mrs lr, SPSR
393 push {lr}
394
395 mov lr, r0
396 mov r0, r1
397 mov r1, r2
398 mov r2, r3
399
400THUMB( orr lr, #1)
401 blx lr @ Call the HYP function
402
403 pop {lr}
404 msr SPSR_csxf, lr
405 pop {lr}
b20c9f29 4061: eret
f7ed45be
CD
407
408guest_trap:
409 load_vcpu @ Load VCPU pointer to r0
410 str r1, [vcpu, #VCPU_HSR]
411
412 @ Check if we need the fault information
413 lsr r1, r1, #HSR_EC_SHIFT
414 cmp r1, #HSR_EC_IABT
415 mrceq p15, 4, r2, c6, c0, 2 @ HIFAR
416 beq 2f
417 cmp r1, #HSR_EC_DABT
418 bne 1f
419 mrc p15, 4, r2, c6, c0, 0 @ HDFAR
420
4212: str r2, [vcpu, #VCPU_HxFAR]
422
423 /*
424 * B3.13.5 Reporting exceptions taken to the Non-secure PL2 mode:
425 *
426 * Abort on the stage 2 translation for a memory access from a
427 * Non-secure PL1 or PL0 mode:
428 *
429 * For any Access flag fault or Translation fault, and also for any
430 * Permission fault on the stage 2 translation of a memory access
431 * made as part of a translation table walk for a stage 1 translation,
432 * the HPFAR holds the IPA that caused the fault. Otherwise, the HPFAR
433 * is UNKNOWN.
434 */
435
436 /* Check for permission fault, and S1PTW */
437 mrc p15, 4, r1, c5, c2, 0 @ HSR
438 and r0, r1, #HSR_FSC_TYPE
439 cmp r0, #FSC_PERM
440 tsteq r1, #(1 << 7) @ S1PTW
441 mrcne p15, 4, r2, c6, c0, 4 @ HPFAR
442 bne 3f
443
6a077e4a
MZ
444 /* Preserve PAR */
445 mrrc p15, 0, r0, r1, c7 @ PAR
446 push {r0, r1}
447
f7ed45be
CD
448 /* Resolve IPA using the xFAR */
449 mcr p15, 0, r2, c7, c8, 0 @ ATS1CPR
450 isb
451 mrrc p15, 0, r0, r1, c7 @ PAR
452 tst r0, #1
453 bne 4f @ Failed translation
454 ubfx r2, r0, #12, #20
455 lsl r2, r2, #4
456 orr r2, r2, r1, lsl #24
457
6a077e4a
MZ
458 /* Restore PAR */
459 pop {r0, r1}
460 mcrr p15, 0, r0, r1, c7 @ PAR
461
f7ed45be
CD
4623: load_vcpu @ Load VCPU pointer to r0
463 str r2, [r0, #VCPU_HPFAR]
464
4651: mov r1, #ARM_EXCEPTION_HVC
466 b __kvm_vcpu_return
467
6a077e4a
MZ
4684: pop {r0, r1} @ Failed translation, return to guest
469 mcrr p15, 0, r0, r1, c7 @ PAR
22cfbb6d 470 clrex
6a077e4a 471 pop {r0, r1, r2}
f7ed45be
CD
472 eret
473
474/*
475 * If VFPv3 support is not available, then we will not switch the VFP
476 * registers; however cp10 and cp11 accesses will still trap and fallback
477 * to the regular coprocessor emulation code, which currently will
478 * inject an undefined exception to the guest.
479 */
480#ifdef CONFIG_VFPv3
481switch_to_guest_vfp:
482 load_vcpu @ Load VCPU pointer to r0
483 push {r3-r7}
484
485 @ NEON/VFP used. Turn on VFP access.
486 set_hcptr vmexit, (HCPTR_TCP(10) | HCPTR_TCP(11))
487
488 @ Switch VFP/NEON hardware state to the guest's
489 add r7, r0, #VCPU_VFP_HOST
490 ldr r7, [r7]
491 store_vfp_state r7
492 add r7, r0, #VCPU_VFP_GUEST
493 restore_vfp_state r7
494
495 pop {r3-r7}
496 pop {r0-r2}
22cfbb6d 497 clrex
f7ed45be
CD
498 eret
499#endif
500
501 .align
502hyp_irq:
503 push {r0, r1, r2}
504 mov r1, #ARM_EXCEPTION_IRQ
505 load_vcpu @ Load VCPU pointer to r0
506 b __kvm_vcpu_return
507
508 .align
509hyp_fiq:
510 b hyp_fiq
511
512 .ltorg
342cd0ab
CD
513
514__kvm_hyp_code_end:
515 .globl __kvm_hyp_code_end
f7ed45be
CD
516
517 .section ".rodata"
518
519und_die_str:
1fe40f6d 520 .ascii "unexpected undefined exception in Hyp mode at: %#08x\n"
f7ed45be 521pabt_die_str:
1fe40f6d 522 .ascii "unexpected prefetch abort in Hyp mode at: %#08x\n"
f7ed45be 523dabt_die_str:
1fe40f6d 524 .ascii "unexpected data abort in Hyp mode at: %#08x\n"
f7ed45be 525svc_die_str:
1fe40f6d 526 .ascii "unexpected HVC/SVC trap in Hyp mode at: %#08x\n"