1/*
2 * Copyright (C) 2012,2013 - 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 <linux/linkage.h>
19#include <linux/irqchip/arm-gic.h>
20
21#include <asm/assembler.h>
22#include <asm/memory.h>
23#include <asm/asm-offsets.h>
24#include <asm/kvm.h>
25#include <asm/kvm_asm.h>
26#include <asm/kvm_arm.h>
27#include <asm/kvm_mmu.h>
28
29	.text
30	.pushsection	.hyp.text, "ax"
31
32/*
33 * Save the VGIC CPU state into memory
34 * x0: Register pointing to VCPU struct
35 * Do not corrupt x1!!!
36 */
37ENTRY(__save_vgic_v2_state)
38__save_vgic_v2_state:
39	/* Get VGIC VCTRL base into x2 */
40	ldr	x2, [x0, #VCPU_KVM]
41	kern_hyp_va	x2
42	ldr	x2, [x2, #KVM_VGIC_VCTRL]
43	kern_hyp_va	x2
44	cbz	x2, 2f		// disabled
45
46	/* Compute the address of struct vgic_cpu */
47	add	x3, x0, #VCPU_VGIC_CPU
48
49	/* Save all interesting registers */
50	ldr	w4, [x2, #GICH_HCR]
51	ldr	w5, [x2, #GICH_VMCR]
52	ldr	w6, [x2, #GICH_MISR]
53	ldr	w7, [x2, #GICH_EISR0]
54	ldr	w8, [x2, #GICH_EISR1]
55	ldr	w9, [x2, #GICH_ELRSR0]
56	ldr	w10, [x2, #GICH_ELRSR1]
57	ldr	w11, [x2, #GICH_APR]
58CPU_BE(	rev	w4,  w4  )
59CPU_BE(	rev	w5,  w5  )
60CPU_BE(	rev	w6,  w6  )
61CPU_BE(	rev	w7,  w7  )
62CPU_BE(	rev	w8,  w8  )
63CPU_BE(	rev	w9,  w9  )
64CPU_BE(	rev	w10, w10 )
65CPU_BE(	rev	w11, w11 )
66
67	str	w4, [x3, #VGIC_V2_CPU_HCR]
68	str	w5, [x3, #VGIC_V2_CPU_VMCR]
69	str	w6, [x3, #VGIC_V2_CPU_MISR]
70CPU_LE(	str	w7, [x3, #VGIC_V2_CPU_EISR] )
71CPU_LE(	str	w8, [x3, #(VGIC_V2_CPU_EISR + 4)] )
72CPU_LE(	str	w9, [x3, #VGIC_V2_CPU_ELRSR] )
73CPU_LE(	str	w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
74CPU_BE(	str	w7, [x3, #(VGIC_V2_CPU_EISR + 4)] )
75CPU_BE(	str	w8, [x3, #VGIC_V2_CPU_EISR] )
76CPU_BE(	str	w9, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
77CPU_BE(	str	w10, [x3, #VGIC_V2_CPU_ELRSR] )
78	str	w11, [x3, #VGIC_V2_CPU_APR]
79
80	/* Clear GICH_HCR */
81	str	wzr, [x2, #GICH_HCR]
82
83	/* Save list registers */
84	add	x2, x2, #GICH_LR0
85	ldr	w4, [x3, #VGIC_CPU_NR_LR]
86	add	x3, x3, #VGIC_V2_CPU_LR
871:	ldr	w5, [x2], #4
88CPU_BE(	rev	w5, w5 )
89	str	w5, [x3], #4
90	sub	w4, w4, #1
91	cbnz	w4, 1b
922:
93	ret
94ENDPROC(__save_vgic_v2_state)
95
96/*
97 * Restore the VGIC CPU state from memory
98 * x0: Register pointing to VCPU struct
99 */
100ENTRY(__restore_vgic_v2_state)
101__restore_vgic_v2_state:
102	/* Get VGIC VCTRL base into x2 */
103	ldr	x2, [x0, #VCPU_KVM]
104	kern_hyp_va	x2
105	ldr	x2, [x2, #KVM_VGIC_VCTRL]
106	kern_hyp_va	x2
107	cbz	x2, 2f		// disabled
108
109	/* Compute the address of struct vgic_cpu */
110	add	x3, x0, #VCPU_VGIC_CPU
111
112	/* We only restore a minimal set of registers */
113	ldr	w4, [x3, #VGIC_V2_CPU_HCR]
114	ldr	w5, [x3, #VGIC_V2_CPU_VMCR]
115	ldr	w6, [x3, #VGIC_V2_CPU_APR]
116CPU_BE(	rev	w4, w4 )
117CPU_BE(	rev	w5, w5 )
118CPU_BE(	rev	w6, w6 )
119
120	str	w4, [x2, #GICH_HCR]
121	str	w5, [x2, #GICH_VMCR]
122	str	w6, [x2, #GICH_APR]
123
124	/* Restore list registers */
125	add	x2, x2, #GICH_LR0
126	ldr	w4, [x3, #VGIC_CPU_NR_LR]
127	add	x3, x3, #VGIC_V2_CPU_LR
1281:	ldr	w5, [x3], #4
129CPU_BE(	rev	w5, w5 )
130	str	w5, [x2], #4
131	sub	w4, w4, #1
132	cbnz	w4, 1b
1332:
134	ret
135ENDPROC(__restore_vgic_v2_state)
136
137	.popsection
138