diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2013-07-09 05:45:49 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-07-11 07:57:37 -0400 |
commit | 754d37726010d872f1f714a8ce8920acdfa4978c (patch) | |
tree | 0b312f8190980040a52dbc8667d5a78f10fe72be /arch/arm64/kvm/vgic-v3-switch.S | |
parent | b2fb1c0d378399e1427a91bb991c094f2ca09a2f (diff) |
arm64: KVM: vgic: add GICv3 world switch
Introduce the GICv3 world switch code used to save/restore the
GICv3 context.
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm64/kvm/vgic-v3-switch.S')
-rw-r--r-- | arch/arm64/kvm/vgic-v3-switch.S | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S index 9fbf27350c84..21e68f606a8f 100644 --- a/arch/arm64/kvm/vgic-v3-switch.S +++ b/arch/arm64/kvm/vgic-v3-switch.S | |||
@@ -18,9 +18,247 @@ | |||
18 | #include <linux/linkage.h> | 18 | #include <linux/linkage.h> |
19 | #include <linux/irqchip/arm-gic-v3.h> | 19 | #include <linux/irqchip/arm-gic-v3.h> |
20 | 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 | |||
21 | .text | 28 | .text |
22 | .pushsection .hyp.text, "ax" | 29 | .pushsection .hyp.text, "ax" |
23 | 30 | ||
31 | /* | ||
32 | * We store LRs in reverse order to let the CPU deal with streaming | ||
33 | * access. Use this macro to make it look saner... | ||
34 | */ | ||
35 | #define LR_OFFSET(n) (VGIC_V3_CPU_LR + (15 - n) * 8) | ||
36 | |||
37 | /* | ||
38 | * Save the VGIC CPU state into memory | ||
39 | * x0: Register pointing to VCPU struct | ||
40 | * Do not corrupt x1!!! | ||
41 | */ | ||
42 | .macro save_vgic_v3_state | ||
43 | // Compute the address of struct vgic_cpu | ||
44 | add x3, x0, #VCPU_VGIC_CPU | ||
45 | |||
46 | // Make sure stores to the GIC via the memory mapped interface | ||
47 | // are now visible to the system register interface | ||
48 | dsb st | ||
49 | |||
50 | // Save all interesting registers | ||
51 | mrs x4, ICH_HCR_EL2 | ||
52 | mrs x5, ICH_VMCR_EL2 | ||
53 | mrs x6, ICH_MISR_EL2 | ||
54 | mrs x7, ICH_EISR_EL2 | ||
55 | mrs x8, ICH_ELSR_EL2 | ||
56 | |||
57 | str w4, [x3, #VGIC_V3_CPU_HCR] | ||
58 | str w5, [x3, #VGIC_V3_CPU_VMCR] | ||
59 | str w6, [x3, #VGIC_V3_CPU_MISR] | ||
60 | str w7, [x3, #VGIC_V3_CPU_EISR] | ||
61 | str w8, [x3, #VGIC_V3_CPU_ELRSR] | ||
62 | |||
63 | msr ICH_HCR_EL2, xzr | ||
64 | |||
65 | mrs x21, ICH_VTR_EL2 | ||
66 | mvn w22, w21 | ||
67 | ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4 | ||
68 | |||
69 | adr x24, 1f | ||
70 | add x24, x24, x23 | ||
71 | br x24 | ||
72 | |||
73 | 1: | ||
74 | mrs x20, ICH_LR15_EL2 | ||
75 | mrs x19, ICH_LR14_EL2 | ||
76 | mrs x18, ICH_LR13_EL2 | ||
77 | mrs x17, ICH_LR12_EL2 | ||
78 | mrs x16, ICH_LR11_EL2 | ||
79 | mrs x15, ICH_LR10_EL2 | ||
80 | mrs x14, ICH_LR9_EL2 | ||
81 | mrs x13, ICH_LR8_EL2 | ||
82 | mrs x12, ICH_LR7_EL2 | ||
83 | mrs x11, ICH_LR6_EL2 | ||
84 | mrs x10, ICH_LR5_EL2 | ||
85 | mrs x9, ICH_LR4_EL2 | ||
86 | mrs x8, ICH_LR3_EL2 | ||
87 | mrs x7, ICH_LR2_EL2 | ||
88 | mrs x6, ICH_LR1_EL2 | ||
89 | mrs x5, ICH_LR0_EL2 | ||
90 | |||
91 | adr x24, 1f | ||
92 | add x24, x24, x23 | ||
93 | br x24 | ||
94 | |||
95 | 1: | ||
96 | str x20, [x3, #LR_OFFSET(15)] | ||
97 | str x19, [x3, #LR_OFFSET(14)] | ||
98 | str x18, [x3, #LR_OFFSET(13)] | ||
99 | str x17, [x3, #LR_OFFSET(12)] | ||
100 | str x16, [x3, #LR_OFFSET(11)] | ||
101 | str x15, [x3, #LR_OFFSET(10)] | ||
102 | str x14, [x3, #LR_OFFSET(9)] | ||
103 | str x13, [x3, #LR_OFFSET(8)] | ||
104 | str x12, [x3, #LR_OFFSET(7)] | ||
105 | str x11, [x3, #LR_OFFSET(6)] | ||
106 | str x10, [x3, #LR_OFFSET(5)] | ||
107 | str x9, [x3, #LR_OFFSET(4)] | ||
108 | str x8, [x3, #LR_OFFSET(3)] | ||
109 | str x7, [x3, #LR_OFFSET(2)] | ||
110 | str x6, [x3, #LR_OFFSET(1)] | ||
111 | str x5, [x3, #LR_OFFSET(0)] | ||
112 | |||
113 | tbnz w21, #29, 6f // 6 bits | ||
114 | tbz w21, #30, 5f // 5 bits | ||
115 | // 7 bits | ||
116 | mrs x20, ICH_AP0R3_EL2 | ||
117 | str w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)] | ||
118 | mrs x19, ICH_AP0R2_EL2 | ||
119 | str w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)] | ||
120 | 6: mrs x18, ICH_AP0R1_EL2 | ||
121 | str w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)] | ||
122 | 5: mrs x17, ICH_AP0R0_EL2 | ||
123 | str w17, [x3, #VGIC_V3_CPU_AP0R] | ||
124 | |||
125 | tbnz w21, #29, 6f // 6 bits | ||
126 | tbz w21, #30, 5f // 5 bits | ||
127 | // 7 bits | ||
128 | mrs x20, ICH_AP1R3_EL2 | ||
129 | str w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)] | ||
130 | mrs x19, ICH_AP1R2_EL2 | ||
131 | str w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)] | ||
132 | 6: mrs x18, ICH_AP1R1_EL2 | ||
133 | str w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)] | ||
134 | 5: mrs x17, ICH_AP1R0_EL2 | ||
135 | str w17, [x3, #VGIC_V3_CPU_AP1R] | ||
136 | |||
137 | // Restore SRE_EL1 access and re-enable SRE at EL1. | ||
138 | mrs x5, ICC_SRE_EL2 | ||
139 | orr x5, x5, #ICC_SRE_EL2_ENABLE | ||
140 | msr ICC_SRE_EL2, x5 | ||
141 | isb | ||
142 | mov x5, #1 | ||
143 | msr ICC_SRE_EL1, x5 | ||
144 | .endm | ||
145 | |||
146 | /* | ||
147 | * Restore the VGIC CPU state from memory | ||
148 | * x0: Register pointing to VCPU struct | ||
149 | */ | ||
150 | .macro restore_vgic_v3_state | ||
151 | // Disable SRE_EL1 access. Necessary, otherwise | ||
152 | // ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens... | ||
153 | msr ICC_SRE_EL1, xzr | ||
154 | isb | ||
155 | |||
156 | // Compute the address of struct vgic_cpu | ||
157 | add x3, x0, #VCPU_VGIC_CPU | ||
158 | |||
159 | // Restore all interesting registers | ||
160 | ldr w4, [x3, #VGIC_V3_CPU_HCR] | ||
161 | ldr w5, [x3, #VGIC_V3_CPU_VMCR] | ||
162 | |||
163 | msr ICH_HCR_EL2, x4 | ||
164 | msr ICH_VMCR_EL2, x5 | ||
165 | |||
166 | mrs x21, ICH_VTR_EL2 | ||
167 | |||
168 | tbnz w21, #29, 6f // 6 bits | ||
169 | tbz w21, #30, 5f // 5 bits | ||
170 | // 7 bits | ||
171 | ldr w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)] | ||
172 | msr ICH_AP1R3_EL2, x20 | ||
173 | ldr w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)] | ||
174 | msr ICH_AP1R2_EL2, x19 | ||
175 | 6: ldr w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)] | ||
176 | msr ICH_AP1R1_EL2, x18 | ||
177 | 5: ldr w17, [x3, #VGIC_V3_CPU_AP1R] | ||
178 | msr ICH_AP1R0_EL2, x17 | ||
179 | |||
180 | tbnz w21, #29, 6f // 6 bits | ||
181 | tbz w21, #30, 5f // 5 bits | ||
182 | // 7 bits | ||
183 | ldr w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)] | ||
184 | msr ICH_AP0R3_EL2, x20 | ||
185 | ldr w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)] | ||
186 | msr ICH_AP0R2_EL2, x19 | ||
187 | 6: ldr w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)] | ||
188 | msr ICH_AP0R1_EL2, x18 | ||
189 | 5: ldr w17, [x3, #VGIC_V3_CPU_AP0R] | ||
190 | msr ICH_AP0R0_EL2, x17 | ||
191 | |||
192 | and w22, w21, #0xf | ||
193 | mvn w22, w21 | ||
194 | ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4 | ||
195 | |||
196 | adr x24, 1f | ||
197 | add x24, x24, x23 | ||
198 | br x24 | ||
199 | |||
200 | 1: | ||
201 | ldr x20, [x3, #LR_OFFSET(15)] | ||
202 | ldr x19, [x3, #LR_OFFSET(14)] | ||
203 | ldr x18, [x3, #LR_OFFSET(13)] | ||
204 | ldr x17, [x3, #LR_OFFSET(12)] | ||
205 | ldr x16, [x3, #LR_OFFSET(11)] | ||
206 | ldr x15, [x3, #LR_OFFSET(10)] | ||
207 | ldr x14, [x3, #LR_OFFSET(9)] | ||
208 | ldr x13, [x3, #LR_OFFSET(8)] | ||
209 | ldr x12, [x3, #LR_OFFSET(7)] | ||
210 | ldr x11, [x3, #LR_OFFSET(6)] | ||
211 | ldr x10, [x3, #LR_OFFSET(5)] | ||
212 | ldr x9, [x3, #LR_OFFSET(4)] | ||
213 | ldr x8, [x3, #LR_OFFSET(3)] | ||
214 | ldr x7, [x3, #LR_OFFSET(2)] | ||
215 | ldr x6, [x3, #LR_OFFSET(1)] | ||
216 | ldr x5, [x3, #LR_OFFSET(0)] | ||
217 | |||
218 | adr x24, 1f | ||
219 | add x24, x24, x23 | ||
220 | br x24 | ||
221 | |||
222 | 1: | ||
223 | msr ICH_LR15_EL2, x20 | ||
224 | msr ICH_LR14_EL2, x19 | ||
225 | msr ICH_LR13_EL2, x18 | ||
226 | msr ICH_LR12_EL2, x17 | ||
227 | msr ICH_LR11_EL2, x16 | ||
228 | msr ICH_LR10_EL2, x15 | ||
229 | msr ICH_LR9_EL2, x14 | ||
230 | msr ICH_LR8_EL2, x13 | ||
231 | msr ICH_LR7_EL2, x12 | ||
232 | msr ICH_LR6_EL2, x11 | ||
233 | msr ICH_LR5_EL2, x10 | ||
234 | msr ICH_LR4_EL2, x9 | ||
235 | msr ICH_LR3_EL2, x8 | ||
236 | msr ICH_LR2_EL2, x7 | ||
237 | msr ICH_LR1_EL2, x6 | ||
238 | msr ICH_LR0_EL2, x5 | ||
239 | |||
240 | // Ensure that the above will have reached the | ||
241 | // (re)distributors. This ensure the guest will read | ||
242 | // the correct values from the memory-mapped interface. | ||
243 | isb | ||
244 | dsb sy | ||
245 | |||
246 | // Prevent the guest from touching the GIC system registers | ||
247 | mrs x5, ICC_SRE_EL2 | ||
248 | and x5, x5, #~ICC_SRE_EL2_ENABLE | ||
249 | msr ICC_SRE_EL2, x5 | ||
250 | .endm | ||
251 | |||
252 | ENTRY(__save_vgic_v3_state) | ||
253 | save_vgic_v3_state | ||
254 | ret | ||
255 | ENDPROC(__save_vgic_v3_state) | ||
256 | |||
257 | ENTRY(__restore_vgic_v3_state) | ||
258 | restore_vgic_v3_state | ||
259 | ret | ||
260 | ENDPROC(__restore_vgic_v3_state) | ||
261 | |||
24 | ENTRY(__vgic_v3_get_ich_vtr_el2) | 262 | ENTRY(__vgic_v3_get_ich_vtr_el2) |
25 | mrs x0, ICH_VTR_EL2 | 263 | mrs x0, ICH_VTR_EL2 |
26 | ret | 264 | ret |