• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
18
19#include <linux/linkage.h>
20#include <asm/kvm_arm.h>
21#include <asm/kvm_asm.h>
22
23	.arch_extension     virt
24
25	.text
26	.pushsection	.hyp.text, "ax"
27
28.macro load_vcpu	reg
29	mrc	p15, 4, \reg, c13, c0, 2	@ HTPIDR
30.endm
31
32/********************************************************************
33 * Hypervisor exception vector and handlers
34 *
35 *
36 * The KVM/ARM Hypervisor ABI is defined as follows:
37 *
38 * Entry to Hyp mode from the host kernel will happen _only_ when an HVC
39 * instruction is issued since all traps are disabled when running the host
40 * kernel as per the Hyp-mode initialization at boot time.
41 *
42 * HVC instructions cause a trap to the vector page + offset 0x14 (see hyp_hvc
43 * below) when the HVC instruction is called from SVC mode (i.e. a guest or the
44 * host kernel) and they cause a trap to the vector page + offset 0x8 when HVC
45 * instructions are called from within Hyp-mode.
46 *
47 * Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
48 *    Switching to Hyp mode is done through a simple HVC #0 instruction. The
49 *    exception vector code will check that the HVC comes from VMID==0.
50 *    - r0 contains a pointer to a HYP function
51 *    - r1, r2, and r3 contain arguments to the above function.
52 *    - The HYP function will be called with its arguments in r0, r1 and r2.
53 *    On HYP function return, we return directly to SVC.
54 *
55 * Note that the above is used to execute code in Hyp-mode from a host-kernel
56 * point of view, and is a different concept from performing a world-switch and
57 * executing guest code SVC mode (with a VMID != 0).
58 */
59
60	.align 5
61__kvm_hyp_vector:
62	.global __kvm_hyp_vector
63
64	@ Hyp-mode exception vector
65	W(b)	hyp_reset
66	W(b)	hyp_undef
67	W(b)	hyp_svc
68	W(b)	hyp_pabt
69	W(b)	hyp_dabt
70	W(b)	hyp_hvc
71	W(b)	hyp_irq
72	W(b)	hyp_fiq
73
74.macro invalid_vector label, cause
75	.align
76\label:	mov	r0, #\cause
77	b	__hyp_panic
78.endm
79
80	invalid_vector	hyp_reset	ARM_EXCEPTION_RESET
81	invalid_vector	hyp_undef	ARM_EXCEPTION_UNDEFINED
82	invalid_vector	hyp_svc		ARM_EXCEPTION_SOFTWARE
83	invalid_vector	hyp_pabt	ARM_EXCEPTION_PREF_ABORT
84	invalid_vector	hyp_fiq		ARM_EXCEPTION_FIQ
85
86ENTRY(__hyp_do_panic)
87	mrs	lr, cpsr
88	bic	lr, lr, #MODE_MASK
89	orr	lr, lr, #SVC_MODE
90THUMB(	orr	lr, lr, #PSR_T_BIT	)
91	msr	spsr_cxsf, lr
92	ldr	lr, =panic
93	msr	ELR_hyp, lr
94	ldr	lr, =kvm_call_hyp
95	clrex
96	eret
97ENDPROC(__hyp_do_panic)
98
99hyp_hvc:
100	/*
101	 * Getting here is either because of a trap from a guest,
102	 * or from executing HVC from the host kernel, which means
103	 * "do something in Hyp mode".
104	 */
105	push	{r0, r1, r2}
106
107	@ Check syndrome register
108	mrc	p15, 4, r1, c5, c2, 0	@ HSR
109	lsr	r0, r1, #HSR_EC_SHIFT
110	cmp	r0, #HSR_EC_HVC
111	bne	guest_trap		@ Not HVC instr.
112
113	/*
114	 * Let's check if the HVC came from VMID 0 and allow simple
115	 * switch to Hyp mode
116	 */
117	mrrc    p15, 6, r0, r2, c2
118	lsr     r2, r2, #16
119	and     r2, r2, #0xff
120	cmp     r2, #0
121	bne	guest_trap		@ Guest called HVC
122
123	/*
124	 * Getting here means host called HVC, we shift parameters and branch
125	 * to Hyp function.
126	 */
127	pop	{r0, r1, r2}
128
129	/* Check for __hyp_get_vectors */
130	cmp	r0, #-1
131	mrceq	p15, 4, r0, c12, c0, 0	@ get HVBAR
132	beq	1f
133
134	push	{lr}
135
136	mov	lr, r0
137	mov	r0, r1
138	mov	r1, r2
139	mov	r2, r3
140
141THUMB(	orr	lr, #1)
142	blx	lr			@ Call the HYP function
143
144	pop	{lr}
1451:	eret
146
147guest_trap:
148	load_vcpu r0			@ Load VCPU pointer to r0
149
150#ifdef CONFIG_VFPv3
151	@ Check for a VFP access
152	lsr	r1, r1, #HSR_EC_SHIFT
153	cmp	r1, #HSR_EC_CP_0_13
154	beq	__vfp_guest_restore
155#endif
156
157	mov	r1, #ARM_EXCEPTION_HVC
158	b	__guest_exit
159
160hyp_irq:
161	push	{r0, r1, r2}
162	mov	r1, #ARM_EXCEPTION_IRQ
163	load_vcpu r0			@ Load VCPU pointer to r0
164	b	__guest_exit
165
166hyp_dabt:
167	push	{r0, r1}
168	mrs	r0, ELR_hyp
169	ldr	r1, =abort_guest_exit_start
170THUMB(	add	r1, r1, #1)
171	cmp	r0, r1
172	ldrne	r1, =abort_guest_exit_end
173THUMB(	addne	r1, r1, #1)
174	cmpne	r0, r1
175	pop	{r0, r1}
176	bne	__hyp_panic
177
178	orr	r0, r0, #(1 << ARM_EXIT_WITH_ABORT_BIT)
179	eret
180
181	.ltorg
182
183	.popsection
184