aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kvm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-10-19 16:02:46 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2015-12-14 06:30:40 -0500
commit8eb992674c9e69d57af199f36b6455dbc00ac9f9 (patch)
treee14a38969f8237f7d8b1da4bd1bd4d9e8c338094 /arch/arm64/kvm
parentc209ec85a2a7d2fd38bca0a44b7e70abd079c178 (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/Makefile1
-rw-r--r--arch/arm64/kvm/hyp/debug-sr.c137
-rw-r--r--arch/arm64/kvm/hyp/hyp.h9
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
6obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o 6obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
7obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o 7obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
8obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o 8obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
9obj-$(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
68void __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
90void __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
113void __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
125void __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
134u32 __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);
43void __sysreg32_save_state(struct kvm_vcpu *vcpu); 43void __sysreg32_save_state(struct kvm_vcpu *vcpu);
44void __sysreg32_restore_state(struct kvm_vcpu *vcpu); 44void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
45 45
46void __debug_save_state(struct kvm_vcpu *vcpu,
47 struct kvm_guest_debug_arch *dbg,
48 struct kvm_cpu_context *ctxt);
49void __debug_restore_state(struct kvm_vcpu *vcpu,
50 struct kvm_guest_debug_arch *dbg,
51 struct kvm_cpu_context *ctxt);
52void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
53void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
54
46#endif /* __ARM64_KVM_HYP_H__ */ 55#endif /* __ARM64_KVM_HYP_H__ */
47 56