diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2013-06-21 06:57:56 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-07-11 07:57:36 -0400 |
commit | 1a9b13056dde7e3092304d6041ccc60a913042ea (patch) | |
tree | 3e70b5ee93eb9c0bbc8271b240a19cf69a605bb2 /arch/arm64 | |
parent | 45451914c875bba44903ce4f1445e047b7992bf7 (diff) |
arm64: KVM: split GICv2 world switch from hyp code
Move the GICv2 world switch code into its own file, and add the
necessary indirection to the arm64 switch code.
Also introduce a new type field to the vgic_params structure.
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')
-rw-r--r-- | arch/arm64/include/asm/kvm_asm.h | 4 | ||||
-rw-r--r-- | arch/arm64/include/asm/kvm_host.h | 21 | ||||
-rw-r--r-- | arch/arm64/kernel/asm-offsets.c | 3 | ||||
-rw-r--r-- | arch/arm64/kvm/Makefile | 4 | ||||
-rw-r--r-- | arch/arm64/kvm/hyp.S | 104 | ||||
-rw-r--r-- | arch/arm64/kvm/vgic-v2-switch.S | 133 |
6 files changed, 180 insertions, 89 deletions
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index d0bfc4ba82c0..6252264341c8 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h | |||
@@ -105,6 +105,10 @@ extern void __kvm_flush_vm_context(void); | |||
105 | extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa); | 105 | extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa); |
106 | 106 | ||
107 | extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); | 107 | extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); |
108 | |||
109 | extern char __save_vgic_v2_state[]; | ||
110 | extern char __restore_vgic_v2_state[]; | ||
111 | |||
108 | #endif | 112 | #endif |
109 | 113 | ||
110 | #endif /* __ARM_KVM_ASM_H__ */ | 114 | #endif /* __ARM_KVM_ASM_H__ */ |
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 92242ce06309..4c182d0aae70 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h | |||
@@ -200,4 +200,25 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr, | |||
200 | hyp_stack_ptr, vector_ptr); | 200 | hyp_stack_ptr, vector_ptr); |
201 | } | 201 | } |
202 | 202 | ||
203 | struct vgic_sr_vectors { | ||
204 | void *save_vgic; | ||
205 | void *restore_vgic; | ||
206 | }; | ||
207 | |||
208 | static inline void vgic_arch_setup(const struct vgic_params *vgic) | ||
209 | { | ||
210 | extern struct vgic_sr_vectors __vgic_sr_vectors; | ||
211 | |||
212 | switch(vgic->type) | ||
213 | { | ||
214 | case VGIC_V2: | ||
215 | __vgic_sr_vectors.save_vgic = __save_vgic_v2_state; | ||
216 | __vgic_sr_vectors.restore_vgic = __restore_vgic_v2_state; | ||
217 | break; | ||
218 | |||
219 | default: | ||
220 | BUG(); | ||
221 | } | ||
222 | } | ||
223 | |||
203 | #endif /* __ARM64_KVM_HOST_H__ */ | 224 | #endif /* __ARM64_KVM_HOST_H__ */ |
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 20fd4887aab6..dafc415dd52d 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c | |||
@@ -129,6 +129,9 @@ int main(void) | |||
129 | DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled)); | 129 | DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled)); |
130 | DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm)); | 130 | DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm)); |
131 | DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu)); | 131 | DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu)); |
132 | DEFINE(VGIC_SAVE_FN, offsetof(struct vgic_sr_vectors, save_vgic)); | ||
133 | DEFINE(VGIC_RESTORE_FN, offsetof(struct vgic_sr_vectors, restore_vgic)); | ||
134 | DEFINE(VGIC_SR_VECTOR_SZ, sizeof(struct vgic_sr_vectors)); | ||
132 | DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr)); | 135 | DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr)); |
133 | DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr)); | 136 | DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr)); |
134 | DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr)); | 137 | DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr)); |
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index 7e92952d139e..daf24dc59e2c 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile | |||
@@ -19,5 +19,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o | |||
19 | kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o | 19 | kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o |
20 | kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o | 20 | kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o |
21 | 21 | ||
22 | kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o $(KVM)/arm/vgic-v2.o | 22 | kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o |
23 | kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o | ||
24 | kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o | ||
23 | kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o | 25 | kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o |
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 9c5d0acb3654..56df9a352a81 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S | |||
@@ -16,7 +16,6 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/linkage.h> | 18 | #include <linux/linkage.h> |
19 | #include <linux/irqchip/arm-gic.h> | ||
20 | 19 | ||
21 | #include <asm/assembler.h> | 20 | #include <asm/assembler.h> |
22 | #include <asm/memory.h> | 21 | #include <asm/memory.h> |
@@ -376,100 +375,23 @@ | |||
376 | .endm | 375 | .endm |
377 | 376 | ||
378 | /* | 377 | /* |
379 | * Save the VGIC CPU state into memory | 378 | * Call into the vgic backend for state saving |
380 | * x0: Register pointing to VCPU struct | ||
381 | * Do not corrupt x1!!! | ||
382 | */ | 379 | */ |
383 | .macro save_vgic_state | 380 | .macro save_vgic_state |
384 | /* Get VGIC VCTRL base into x2 */ | 381 | adr x24, __vgic_sr_vectors |
385 | ldr x2, [x0, #VCPU_KVM] | 382 | ldr x24, [x24, VGIC_SAVE_FN] |
386 | kern_hyp_va x2 | 383 | kern_hyp_va x24 |
387 | ldr x2, [x2, #KVM_VGIC_VCTRL] | 384 | blr x24 |
388 | kern_hyp_va x2 | ||
389 | cbz x2, 2f // disabled | ||
390 | |||
391 | /* Compute the address of struct vgic_cpu */ | ||
392 | add x3, x0, #VCPU_VGIC_CPU | ||
393 | |||
394 | /* Save all interesting registers */ | ||
395 | ldr w4, [x2, #GICH_HCR] | ||
396 | ldr w5, [x2, #GICH_VMCR] | ||
397 | ldr w6, [x2, #GICH_MISR] | ||
398 | ldr w7, [x2, #GICH_EISR0] | ||
399 | ldr w8, [x2, #GICH_EISR1] | ||
400 | ldr w9, [x2, #GICH_ELRSR0] | ||
401 | ldr w10, [x2, #GICH_ELRSR1] | ||
402 | ldr w11, [x2, #GICH_APR] | ||
403 | CPU_BE( rev w4, w4 ) | ||
404 | CPU_BE( rev w5, w5 ) | ||
405 | CPU_BE( rev w6, w6 ) | ||
406 | CPU_BE( rev w7, w7 ) | ||
407 | CPU_BE( rev w8, w8 ) | ||
408 | CPU_BE( rev w9, w9 ) | ||
409 | CPU_BE( rev w10, w10 ) | ||
410 | CPU_BE( rev w11, w11 ) | ||
411 | |||
412 | str w4, [x3, #VGIC_V2_CPU_HCR] | ||
413 | str w5, [x3, #VGIC_V2_CPU_VMCR] | ||
414 | str w6, [x3, #VGIC_V2_CPU_MISR] | ||
415 | str w7, [x3, #VGIC_V2_CPU_EISR] | ||
416 | str w8, [x3, #(VGIC_V2_CPU_EISR + 4)] | ||
417 | str w9, [x3, #VGIC_V2_CPU_ELRSR] | ||
418 | str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] | ||
419 | str w11, [x3, #VGIC_V2_CPU_APR] | ||
420 | |||
421 | /* Clear GICH_HCR */ | ||
422 | str wzr, [x2, #GICH_HCR] | ||
423 | |||
424 | /* Save list registers */ | ||
425 | add x2, x2, #GICH_LR0 | ||
426 | ldr w4, [x3, #VGIC_CPU_NR_LR] | ||
427 | add x3, x3, #VGIC_V2_CPU_LR | ||
428 | 1: ldr w5, [x2], #4 | ||
429 | CPU_BE( rev w5, w5 ) | ||
430 | str w5, [x3], #4 | ||
431 | sub w4, w4, #1 | ||
432 | cbnz w4, 1b | ||
433 | 2: | ||
434 | .endm | 385 | .endm |
435 | 386 | ||
436 | /* | 387 | /* |
437 | * Restore the VGIC CPU state from memory | 388 | * Call into the vgic backend for state restoring |
438 | * x0: Register pointing to VCPU struct | ||
439 | */ | 389 | */ |
440 | .macro restore_vgic_state | 390 | .macro restore_vgic_state |
441 | /* Get VGIC VCTRL base into x2 */ | 391 | adr x24, __vgic_sr_vectors |
442 | ldr x2, [x0, #VCPU_KVM] | 392 | ldr x24, [x24, #VGIC_RESTORE_FN] |
443 | kern_hyp_va x2 | 393 | kern_hyp_va x24 |
444 | ldr x2, [x2, #KVM_VGIC_VCTRL] | 394 | blr x24 |
445 | kern_hyp_va x2 | ||
446 | cbz x2, 2f // disabled | ||
447 | |||
448 | /* Compute the address of struct vgic_cpu */ | ||
449 | add x3, x0, #VCPU_VGIC_CPU | ||
450 | |||
451 | /* We only restore a minimal set of registers */ | ||
452 | ldr w4, [x3, #VGIC_V2_CPU_HCR] | ||
453 | ldr w5, [x3, #VGIC_V2_CPU_VMCR] | ||
454 | ldr w6, [x3, #VGIC_V2_CPU_APR] | ||
455 | CPU_BE( rev w4, w4 ) | ||
456 | CPU_BE( rev w5, w5 ) | ||
457 | CPU_BE( rev w6, w6 ) | ||
458 | |||
459 | str w4, [x2, #GICH_HCR] | ||
460 | str w5, [x2, #GICH_VMCR] | ||
461 | str w6, [x2, #GICH_APR] | ||
462 | |||
463 | /* Restore list registers */ | ||
464 | add x2, x2, #GICH_LR0 | ||
465 | ldr w4, [x3, #VGIC_CPU_NR_LR] | ||
466 | add x3, x3, #VGIC_V2_CPU_LR | ||
467 | 1: ldr w5, [x3], #4 | ||
468 | CPU_BE( rev w5, w5 ) | ||
469 | str w5, [x2], #4 | ||
470 | sub w4, w4, #1 | ||
471 | cbnz w4, 1b | ||
472 | 2: | ||
473 | .endm | 395 | .endm |
474 | 396 | ||
475 | .macro save_timer_state | 397 | .macro save_timer_state |
@@ -650,6 +572,12 @@ ENTRY(__kvm_flush_vm_context) | |||
650 | ret | 572 | ret |
651 | ENDPROC(__kvm_flush_vm_context) | 573 | ENDPROC(__kvm_flush_vm_context) |
652 | 574 | ||
575 | // struct vgic_sr_vectors __vgi_sr_vectors; | ||
576 | .align 3 | ||
577 | ENTRY(__vgic_sr_vectors) | ||
578 | .skip VGIC_SR_VECTOR_SZ | ||
579 | ENDPROC(__vgic_sr_vectors) | ||
580 | |||
653 | __kvm_hyp_panic: | 581 | __kvm_hyp_panic: |
654 | // Guess the context by looking at VTTBR: | 582 | // Guess the context by looking at VTTBR: |
655 | // If zero, then we're already a host. | 583 | // If zero, then we're already a host. |
diff --git a/arch/arm64/kvm/vgic-v2-switch.S b/arch/arm64/kvm/vgic-v2-switch.S new file mode 100644 index 000000000000..ae211772f991 --- /dev/null +++ b/arch/arm64/kvm/vgic-v2-switch.S | |||
@@ -0,0 +1,133 @@ | |||
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 | */ | ||
37 | ENTRY(__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] | ||
58 | CPU_BE( rev w4, w4 ) | ||
59 | CPU_BE( rev w5, w5 ) | ||
60 | CPU_BE( rev w6, w6 ) | ||
61 | CPU_BE( rev w7, w7 ) | ||
62 | CPU_BE( rev w8, w8 ) | ||
63 | CPU_BE( rev w9, w9 ) | ||
64 | CPU_BE( rev w10, w10 ) | ||
65 | CPU_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] | ||
70 | str w7, [x3, #VGIC_V2_CPU_EISR] | ||
71 | str w8, [x3, #(VGIC_V2_CPU_EISR + 4)] | ||
72 | str w9, [x3, #VGIC_V2_CPU_ELRSR] | ||
73 | str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] | ||
74 | str w11, [x3, #VGIC_V2_CPU_APR] | ||
75 | |||
76 | /* Clear GICH_HCR */ | ||
77 | str wzr, [x2, #GICH_HCR] | ||
78 | |||
79 | /* Save list registers */ | ||
80 | add x2, x2, #GICH_LR0 | ||
81 | ldr w4, [x3, #VGIC_CPU_NR_LR] | ||
82 | add x3, x3, #VGIC_V2_CPU_LR | ||
83 | 1: ldr w5, [x2], #4 | ||
84 | CPU_BE( rev w5, w5 ) | ||
85 | str w5, [x3], #4 | ||
86 | sub w4, w4, #1 | ||
87 | cbnz w4, 1b | ||
88 | 2: | ||
89 | ret | ||
90 | ENDPROC(__save_vgic_v2_state) | ||
91 | |||
92 | /* | ||
93 | * Restore the VGIC CPU state from memory | ||
94 | * x0: Register pointing to VCPU struct | ||
95 | */ | ||
96 | ENTRY(__restore_vgic_v2_state) | ||
97 | __restore_vgic_v2_state: | ||
98 | /* Get VGIC VCTRL base into x2 */ | ||
99 | ldr x2, [x0, #VCPU_KVM] | ||
100 | kern_hyp_va x2 | ||
101 | ldr x2, [x2, #KVM_VGIC_VCTRL] | ||
102 | kern_hyp_va x2 | ||
103 | cbz x2, 2f // disabled | ||
104 | |||
105 | /* Compute the address of struct vgic_cpu */ | ||
106 | add x3, x0, #VCPU_VGIC_CPU | ||
107 | |||
108 | /* We only restore a minimal set of registers */ | ||
109 | ldr w4, [x3, #VGIC_V2_CPU_HCR] | ||
110 | ldr w5, [x3, #VGIC_V2_CPU_VMCR] | ||
111 | ldr w6, [x3, #VGIC_V2_CPU_APR] | ||
112 | CPU_BE( rev w4, w4 ) | ||
113 | CPU_BE( rev w5, w5 ) | ||
114 | CPU_BE( rev w6, w6 ) | ||
115 | |||
116 | str w4, [x2, #GICH_HCR] | ||
117 | str w5, [x2, #GICH_VMCR] | ||
118 | str w6, [x2, #GICH_APR] | ||
119 | |||
120 | /* Restore list registers */ | ||
121 | add x2, x2, #GICH_LR0 | ||
122 | ldr w4, [x3, #VGIC_CPU_NR_LR] | ||
123 | add x3, x3, #VGIC_V2_CPU_LR | ||
124 | 1: ldr w5, [x3], #4 | ||
125 | CPU_BE( rev w5, w5 ) | ||
126 | str w5, [x2], #4 | ||
127 | sub w4, w4, #1 | ||
128 | cbnz w4, 1b | ||
129 | 2: | ||
130 | ret | ||
131 | ENDPROC(__restore_vgic_v2_state) | ||
132 | |||
133 | .popsection | ||