summaryrefslogtreecommitdiff
path: root/arch/arm/kvm/hyp/entry.S
blob: 21c238871c9e2e11ea02599c20f238cfacda2ba7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * Copyright (C) 2016 - ARM Ltd
 * Author: Marc Zyngier <marc.zyngier@arm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/kvm_arm.h>

	.arch_extension     virt

	.text
	.pushsection	.hyp.text, "ax"

#define USR_REGS_OFFSET		(CPU_CTXT_GP_REGS + GP_REGS_USR)

/* int __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host) */
ENTRY(__guest_enter)
	@ Save host registers
	add	r1, r1, #(USR_REGS_OFFSET + S_R4)
	stm	r1!, {r4-r12}
	str	lr, [r1, #4]	@ Skip SP_usr (already saved)

	@ Restore guest registers
	add	r0, r0,  #(VCPU_GUEST_CTXT + USR_REGS_OFFSET + S_R0)
	ldr	lr, [r0, #S_LR]
	ldm	r0, {r0-r12}

	clrex
	eret
ENDPROC(__guest_enter)

ENTRY(__guest_exit)
	/*
	 * return convention:
	 * guest r0, r1, r2 saved on the stack
	 * r0: vcpu pointer
	 * r1: exception code
	 */

	add	r2, r0, #(VCPU_GUEST_CTXT + USR_REGS_OFFSET + S_R3)
	stm	r2!, {r3-r12}
	str	lr, [r2, #4]
	add	r2, r0, #(VCPU_GUEST_CTXT + USR_REGS_OFFSET + S_R0)
	pop	{r3, r4, r5}		@ r0, r1, r2
	stm	r2, {r3-r5}

	ldr	r0, [r0, #VCPU_HOST_CTXT]
	add	r0, r0, #(USR_REGS_OFFSET + S_R4)
	ldm	r0!, {r4-r12}
	ldr	lr, [r0, #4]

	mov	r0, r1
	bx	lr
ENDPROC(__guest_exit)

/*
 * If VFPv3 support is not available, then we will not switch the VFP
 * registers; however cp10 and cp11 accesses will still trap and fallback
 * to the regular coprocessor emulation code, which currently will
 * inject an undefined exception to the guest.
 */
#ifdef CONFIG_VFPv3
ENTRY(__vfp_guest_restore)
	push	{r3, r4, lr}

	@ NEON/VFP used.  Turn on VFP access.
	mrc	p15, 4, r1, c1, c1, 2		@ HCPTR
	bic	r1, r1, #(HCPTR_TCP(10) | HCPTR_TCP(11))
	mcr	p15, 4, r1, c1, c1, 2		@ HCPTR
	isb

	@ Switch VFP/NEON hardware state to the guest's
	mov	r4, r0
	ldr	r0, [r0, #VCPU_HOST_CTXT]
	add	r0, r0, #CPU_CTXT_VFP
	bl	__vfp_save_state
	add	r0, r4, #(VCPU_GUEST_CTXT + CPU_CTXT_VFP)
	bl	__vfp_restore_state

	pop	{r3, r4, lr}
	pop	{r0, r1, r2}
	clrex
	eret
ENDPROC(__vfp_guest_restore)
#endif

	.popsection