diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2015-10-19 16:02:46 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2015-12-14 06:30:40 -0500 |
commit | 8eb992674c9e69d57af199f36b6455dbc00ac9f9 (patch) | |
tree | e14a38969f8237f7d8b1da4bd1bd4d9e8c338094 /arch/arm64/kvm | |
parent | c209ec85a2a7d2fd38bca0a44b7e70abd079c178 (diff) |
arm64: KVM: Implement debug save/restore
Implement the debug save restore as a direct translation of
the assembly code version.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Tested-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'arch/arm64/kvm')
-rw-r--r-- | arch/arm64/kvm/hyp/Makefile | 1 | ||||
-rw-r--r-- | arch/arm64/kvm/hyp/debug-sr.c | 137 | ||||
-rw-r--r-- | arch/arm64/kvm/hyp/hyp.h | 9 |
3 files changed, 147 insertions, 0 deletions
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index ec94200e1e50..ec14cacc21a6 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o | |||
6 | obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o | 6 | obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o |
7 | obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o | 7 | obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o |
8 | obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o | 8 | obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o |
9 | obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o | ||
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c new file mode 100644 index 000000000000..7848322deed6 --- /dev/null +++ b/arch/arm64/kvm/hyp/debug-sr.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 - 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/compiler.h> | ||
19 | #include <linux/kvm_host.h> | ||
20 | |||
21 | #include <asm/kvm_mmu.h> | ||
22 | |||
23 | #include "hyp.h" | ||
24 | |||
25 | #define read_debug(r,n) read_sysreg(r##n##_el1) | ||
26 | #define write_debug(v,r,n) write_sysreg(v, r##n##_el1) | ||
27 | |||
28 | #define save_debug(ptr,reg,nr) \ | ||
29 | switch (nr) { \ | ||
30 | case 15: ptr[15] = read_debug(reg, 15); \ | ||
31 | case 14: ptr[14] = read_debug(reg, 14); \ | ||
32 | case 13: ptr[13] = read_debug(reg, 13); \ | ||
33 | case 12: ptr[12] = read_debug(reg, 12); \ | ||
34 | case 11: ptr[11] = read_debug(reg, 11); \ | ||
35 | case 10: ptr[10] = read_debug(reg, 10); \ | ||
36 | case 9: ptr[9] = read_debug(reg, 9); \ | ||
37 | case 8: ptr[8] = read_debug(reg, 8); \ | ||
38 | case 7: ptr[7] = read_debug(reg, 7); \ | ||
39 | case 6: ptr[6] = read_debug(reg, 6); \ | ||
40 | case 5: ptr[5] = read_debug(reg, 5); \ | ||
41 | case 4: ptr[4] = read_debug(reg, 4); \ | ||
42 | case 3: ptr[3] = read_debug(reg, 3); \ | ||
43 | case 2: ptr[2] = read_debug(reg, 2); \ | ||
44 | case 1: ptr[1] = read_debug(reg, 1); \ | ||
45 | default: ptr[0] = read_debug(reg, 0); \ | ||
46 | } | ||
47 | |||
48 | #define restore_debug(ptr,reg,nr) \ | ||
49 | switch (nr) { \ | ||
50 | case 15: write_debug(ptr[15], reg, 15); \ | ||
51 | case 14: write_debug(ptr[14], reg, 14); \ | ||
52 | case 13: write_debug(ptr[13], reg, 13); \ | ||
53 | case 12: write_debug(ptr[12], reg, 12); \ | ||
54 | case 11: write_debug(ptr[11], reg, 11); \ | ||
55 | case 10: write_debug(ptr[10], reg, 10); \ | ||
56 | case 9: write_debug(ptr[9], reg, 9); \ | ||
57 | case 8: write_debug(ptr[8], reg, 8); \ | ||
58 | case 7: write_debug(ptr[7], reg, 7); \ | ||
59 | case 6: write_debug(ptr[6], reg, 6); \ | ||
60 | case 5: write_debug(ptr[5], reg, 5); \ | ||
61 | case 4: write_debug(ptr[4], reg, 4); \ | ||
62 | case 3: write_debug(ptr[3], reg, 3); \ | ||
63 | case 2: write_debug(ptr[2], reg, 2); \ | ||
64 | case 1: write_debug(ptr[1], reg, 1); \ | ||
65 | default: write_debug(ptr[0], reg, 0); \ | ||
66 | } | ||
67 | |||
68 | void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu, | ||
69 | struct kvm_guest_debug_arch *dbg, | ||
70 | struct kvm_cpu_context *ctxt) | ||
71 | { | ||
72 | u64 aa64dfr0; | ||
73 | int brps, wrps; | ||
74 | |||
75 | if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)) | ||
76 | return; | ||
77 | |||
78 | aa64dfr0 = read_sysreg(id_aa64dfr0_el1); | ||
79 | brps = (aa64dfr0 >> 12) & 0xf; | ||
80 | wrps = (aa64dfr0 >> 20) & 0xf; | ||
81 | |||
82 | save_debug(dbg->dbg_bcr, dbgbcr, brps); | ||
83 | save_debug(dbg->dbg_bvr, dbgbvr, brps); | ||
84 | save_debug(dbg->dbg_wcr, dbgwcr, wrps); | ||
85 | save_debug(dbg->dbg_wvr, dbgwvr, wrps); | ||
86 | |||
87 | ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1); | ||
88 | } | ||
89 | |||
90 | void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu, | ||
91 | struct kvm_guest_debug_arch *dbg, | ||
92 | struct kvm_cpu_context *ctxt) | ||
93 | { | ||
94 | u64 aa64dfr0; | ||
95 | int brps, wrps; | ||
96 | |||
97 | if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)) | ||
98 | return; | ||
99 | |||
100 | aa64dfr0 = read_sysreg(id_aa64dfr0_el1); | ||
101 | |||
102 | brps = (aa64dfr0 >> 12) & 0xf; | ||
103 | wrps = (aa64dfr0 >> 20) & 0xf; | ||
104 | |||
105 | restore_debug(dbg->dbg_bcr, dbgbcr, brps); | ||
106 | restore_debug(dbg->dbg_bvr, dbgbvr, brps); | ||
107 | restore_debug(dbg->dbg_wcr, dbgwcr, wrps); | ||
108 | restore_debug(dbg->dbg_wvr, dbgwvr, wrps); | ||
109 | |||
110 | write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1); | ||
111 | } | ||
112 | |||
113 | void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu) | ||
114 | { | ||
115 | /* If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY is set, perform | ||
116 | * a full save/restore cycle. */ | ||
117 | if ((vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_KDE) || | ||
118 | (vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_MDE)) | ||
119 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | ||
120 | |||
121 | __debug_save_state(vcpu, &vcpu->arch.host_debug_state, | ||
122 | kern_hyp_va(vcpu->arch.host_cpu_context)); | ||
123 | } | ||
124 | |||
125 | void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu) | ||
126 | { | ||
127 | __debug_restore_state(vcpu, &vcpu->arch.host_debug_state, | ||
128 | kern_hyp_va(vcpu->arch.host_cpu_context)); | ||
129 | |||
130 | if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY) | ||
131 | vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY; | ||
132 | } | ||
133 | |||
134 | u32 __hyp_text __debug_read_mdcr_el2(void) | ||
135 | { | ||
136 | return read_sysreg(mdcr_el2); | ||
137 | } | ||
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h index bffd30834eb8..454e46f9c15e 100644 --- a/arch/arm64/kvm/hyp/hyp.h +++ b/arch/arm64/kvm/hyp/hyp.h | |||
@@ -43,5 +43,14 @@ void __sysreg_restore_state(struct kvm_cpu_context *ctxt); | |||
43 | void __sysreg32_save_state(struct kvm_vcpu *vcpu); | 43 | void __sysreg32_save_state(struct kvm_vcpu *vcpu); |
44 | void __sysreg32_restore_state(struct kvm_vcpu *vcpu); | 44 | void __sysreg32_restore_state(struct kvm_vcpu *vcpu); |
45 | 45 | ||
46 | void __debug_save_state(struct kvm_vcpu *vcpu, | ||
47 | struct kvm_guest_debug_arch *dbg, | ||
48 | struct kvm_cpu_context *ctxt); | ||
49 | void __debug_restore_state(struct kvm_vcpu *vcpu, | ||
50 | struct kvm_guest_debug_arch *dbg, | ||
51 | struct kvm_cpu_context *ctxt); | ||
52 | void __debug_cond_save_host_state(struct kvm_vcpu *vcpu); | ||
53 | void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu); | ||
54 | |||
46 | #endif /* __ARM64_KVM_HYP_H__ */ | 55 | #endif /* __ARM64_KVM_HYP_H__ */ |
47 | 56 | ||