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	w5, [x2, #GICH_VMCR]
51	ldr	w6, [x2, #GICH_MISR]
52	ldr	w7, [x2, #GICH_EISR0]
53	ldr	w8, [x2, #GICH_EISR1]
54	ldr	w9, [x2, #GICH_ELRSR0]
55	ldr	w10, [x2, #GICH_ELRSR1]
56	ldr	w11, [x2, #GICH_APR]
57CPU_BE(	rev	w5,  w5  )
58CPU_BE(	rev	w6,  w6  )
59CPU_BE(	rev	w7,  w7  )
60CPU_BE(	rev	w8,  w8  )
61CPU_BE(	rev	w9,  w9  )
62CPU_BE(	rev	w10, w10 )
63CPU_BE(	rev	w11, w11 )
64
65	str	w5, [x3, #VGIC_V2_CPU_VMCR]
66	str	w6, [x3, #VGIC_V2_CPU_MISR]
67CPU_LE(	str	w7, [x3, #VGIC_V2_CPU_EISR] )
68CPU_LE(	str	w8, [x3, #(VGIC_V2_CPU_EISR + 4)] )
69CPU_LE(	str	w9, [x3, #VGIC_V2_CPU_ELRSR] )
70CPU_LE(	str	w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
71CPU_BE(	str	w7, [x3, #(VGIC_V2_CPU_EISR + 4)] )
72CPU_BE(	str	w8, [x3, #VGIC_V2_CPU_EISR] )
73CPU_BE(	str	w9, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
74CPU_BE(	str	w10, [x3, #VGIC_V2_CPU_ELRSR] )
75	str	w11, [x3, #VGIC_V2_CPU_APR]
76
77	/* Clear GICH_HCR */
78	str	wzr, [x2, #GICH_HCR]
79
80	/* Save list registers */
81	add	x2, x2, #GICH_LR0
82	ldr	w4, [x3, #VGIC_CPU_NR_LR]
83	add	x3, x3, #VGIC_V2_CPU_LR
841:	ldr	w5, [x2], #4
85CPU_BE(	rev	w5, w5 )
86	str	w5, [x3], #4
87	sub	w4, w4, #1
88	cbnz	w4, 1b
892:
90	ret
91ENDPROC(__save_vgic_v2_state)
92
93/*
94 * Restore the VGIC CPU state from memory
95 * x0: Register pointing to VCPU struct
96 */
97ENTRY(__restore_vgic_v2_state)
98__restore_vgic_v2_state:
99	/* Get VGIC VCTRL base into x2 */
100	ldr	x2, [x0, #VCPU_KVM]
101	kern_hyp_va	x2
102	ldr	x2, [x2, #KVM_VGIC_VCTRL]
103	kern_hyp_va	x2
104	cbz	x2, 2f		// disabled
105
106	/* Compute the address of struct vgic_cpu */
107	add	x3, x0, #VCPU_VGIC_CPU
108
109	/* We only restore a minimal set of registers */
110	ldr	w4, [x3, #VGIC_V2_CPU_HCR]
111	ldr	w5, [x3, #VGIC_V2_CPU_VMCR]
112	ldr	w6, [x3, #VGIC_V2_CPU_APR]
113CPU_BE(	rev	w4, w4 )
114CPU_BE(	rev	w5, w5 )
115CPU_BE(	rev	w6, w6 )
116
117	str	w4, [x2, #GICH_HCR]
118	str	w5, [x2, #GICH_VMCR]
119	str	w6, [x2, #GICH_APR]
120
121	/* Restore list registers */
122	add	x2, x2, #GICH_LR0
123	ldr	w4, [x3, #VGIC_CPU_NR_LR]
124	add	x3, x3, #VGIC_V2_CPU_LR
1251:	ldr	w5, [x3], #4
126CPU_BE(	rev	w5, w5 )
127	str	w5, [x2], #4
128	sub	w4, w4, #1
129	cbnz	w4, 1b
1302:
131	ret
132ENDPROC(__restore_vgic_v2_state)
133
134	.popsection
135