]>
Commit | Line | Data |
---|---|---|
caab277b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
8eb99267 MZ |
2 | /* |
3 | * Copyright (C) 2015 - ARM Ltd | |
4 | * Author: Marc Zyngier <marc.zyngier@arm.com> | |
8eb99267 MZ |
5 | */ |
6 | ||
7 | #include <linux/compiler.h> | |
8 | #include <linux/kvm_host.h> | |
9 | ||
03336b1d | 10 | #include <asm/debug-monitors.h> |
9d8415d6 | 11 | #include <asm/kvm_asm.h> |
13720a56 | 12 | #include <asm/kvm_hyp.h> |
d6811986 | 13 | #include <asm/kvm_mmu.h> |
8eb99267 MZ |
14 | |
15 | #define read_debug(r,n) read_sysreg(r##n##_el1) | |
16 | #define write_debug(v,r,n) write_sysreg(v, r##n##_el1) | |
17 | ||
18 | #define save_debug(ptr,reg,nr) \ | |
19 | switch (nr) { \ | |
20 | case 15: ptr[15] = read_debug(reg, 15); \ | |
cdb2d3ee | 21 | /* Fall through */ \ |
8eb99267 | 22 | case 14: ptr[14] = read_debug(reg, 14); \ |
cdb2d3ee | 23 | /* Fall through */ \ |
8eb99267 | 24 | case 13: ptr[13] = read_debug(reg, 13); \ |
cdb2d3ee | 25 | /* Fall through */ \ |
8eb99267 | 26 | case 12: ptr[12] = read_debug(reg, 12); \ |
cdb2d3ee | 27 | /* Fall through */ \ |
8eb99267 | 28 | case 11: ptr[11] = read_debug(reg, 11); \ |
cdb2d3ee | 29 | /* Fall through */ \ |
8eb99267 | 30 | case 10: ptr[10] = read_debug(reg, 10); \ |
cdb2d3ee | 31 | /* Fall through */ \ |
8eb99267 | 32 | case 9: ptr[9] = read_debug(reg, 9); \ |
cdb2d3ee | 33 | /* Fall through */ \ |
8eb99267 | 34 | case 8: ptr[8] = read_debug(reg, 8); \ |
cdb2d3ee | 35 | /* Fall through */ \ |
8eb99267 | 36 | case 7: ptr[7] = read_debug(reg, 7); \ |
cdb2d3ee | 37 | /* Fall through */ \ |
8eb99267 | 38 | case 6: ptr[6] = read_debug(reg, 6); \ |
cdb2d3ee | 39 | /* Fall through */ \ |
8eb99267 | 40 | case 5: ptr[5] = read_debug(reg, 5); \ |
cdb2d3ee | 41 | /* Fall through */ \ |
8eb99267 | 42 | case 4: ptr[4] = read_debug(reg, 4); \ |
cdb2d3ee | 43 | /* Fall through */ \ |
8eb99267 | 44 | case 3: ptr[3] = read_debug(reg, 3); \ |
cdb2d3ee | 45 | /* Fall through */ \ |
8eb99267 | 46 | case 2: ptr[2] = read_debug(reg, 2); \ |
cdb2d3ee | 47 | /* Fall through */ \ |
8eb99267 | 48 | case 1: ptr[1] = read_debug(reg, 1); \ |
cdb2d3ee | 49 | /* Fall through */ \ |
8eb99267 MZ |
50 | default: ptr[0] = read_debug(reg, 0); \ |
51 | } | |
52 | ||
53 | #define restore_debug(ptr,reg,nr) \ | |
54 | switch (nr) { \ | |
55 | case 15: write_debug(ptr[15], reg, 15); \ | |
cdb2d3ee | 56 | /* Fall through */ \ |
8eb99267 | 57 | case 14: write_debug(ptr[14], reg, 14); \ |
cdb2d3ee | 58 | /* Fall through */ \ |
8eb99267 | 59 | case 13: write_debug(ptr[13], reg, 13); \ |
cdb2d3ee | 60 | /* Fall through */ \ |
8eb99267 | 61 | case 12: write_debug(ptr[12], reg, 12); \ |
cdb2d3ee | 62 | /* Fall through */ \ |
8eb99267 | 63 | case 11: write_debug(ptr[11], reg, 11); \ |
cdb2d3ee | 64 | /* Fall through */ \ |
8eb99267 | 65 | case 10: write_debug(ptr[10], reg, 10); \ |
cdb2d3ee | 66 | /* Fall through */ \ |
8eb99267 | 67 | case 9: write_debug(ptr[9], reg, 9); \ |
cdb2d3ee | 68 | /* Fall through */ \ |
8eb99267 | 69 | case 8: write_debug(ptr[8], reg, 8); \ |
cdb2d3ee | 70 | /* Fall through */ \ |
8eb99267 | 71 | case 7: write_debug(ptr[7], reg, 7); \ |
cdb2d3ee | 72 | /* Fall through */ \ |
8eb99267 | 73 | case 6: write_debug(ptr[6], reg, 6); \ |
cdb2d3ee | 74 | /* Fall through */ \ |
8eb99267 | 75 | case 5: write_debug(ptr[5], reg, 5); \ |
cdb2d3ee | 76 | /* Fall through */ \ |
8eb99267 | 77 | case 4: write_debug(ptr[4], reg, 4); \ |
cdb2d3ee | 78 | /* Fall through */ \ |
8eb99267 | 79 | case 3: write_debug(ptr[3], reg, 3); \ |
cdb2d3ee | 80 | /* Fall through */ \ |
8eb99267 | 81 | case 2: write_debug(ptr[2], reg, 2); \ |
cdb2d3ee | 82 | /* Fall through */ \ |
8eb99267 | 83 | case 1: write_debug(ptr[1], reg, 1); \ |
cdb2d3ee | 84 | /* Fall through */ \ |
8eb99267 MZ |
85 | default: write_debug(ptr[0], reg, 0); \ |
86 | } | |
87 | ||
f85279b4 WD |
88 | static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1) |
89 | { | |
90 | u64 reg; | |
91 | ||
bfe766cf JT |
92 | /* Clear pmscr in case of early return */ |
93 | *pmscr_el1 = 0; | |
94 | ||
f85279b4 WD |
95 | /* SPE present on this CPU? */ |
96 | if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1), | |
97 | ID_AA64DFR0_PMSVER_SHIFT)) | |
98 | return; | |
99 | ||
100 | /* Yes; is it owned by EL3? */ | |
a173c390 WD |
101 | reg = read_sysreg_s(SYS_PMBIDR_EL1); |
102 | if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT)) | |
f85279b4 WD |
103 | return; |
104 | ||
105 | /* No; is the host actually using the thing? */ | |
a173c390 WD |
106 | reg = read_sysreg_s(SYS_PMBLIMITR_EL1); |
107 | if (!(reg & BIT(SYS_PMBLIMITR_EL1_E_SHIFT))) | |
f85279b4 WD |
108 | return; |
109 | ||
110 | /* Yes; save the control register and disable data generation */ | |
a173c390 WD |
111 | *pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1); |
112 | write_sysreg_s(0, SYS_PMSCR_EL1); | |
f85279b4 WD |
113 | isb(); |
114 | ||
115 | /* Now drain all buffered data to memory */ | |
116 | psb_csync(); | |
117 | dsb(nsh); | |
118 | } | |
119 | ||
5742d049 | 120 | static void __hyp_text __debug_restore_spe_nvhe(u64 pmscr_el1) |
f85279b4 WD |
121 | { |
122 | if (!pmscr_el1) | |
123 | return; | |
124 | ||
125 | /* The host page table is installed, but not yet synchronised */ | |
126 | isb(); | |
127 | ||
128 | /* Re-enable data generation */ | |
a173c390 | 129 | write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1); |
f85279b4 WD |
130 | } |
131 | ||
014c4c77 CD |
132 | static void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu, |
133 | struct kvm_guest_debug_arch *dbg, | |
134 | struct kvm_cpu_context *ctxt) | |
8eb99267 MZ |
135 | { |
136 | u64 aa64dfr0; | |
137 | int brps, wrps; | |
138 | ||
8eb99267 MZ |
139 | aa64dfr0 = read_sysreg(id_aa64dfr0_el1); |
140 | brps = (aa64dfr0 >> 12) & 0xf; | |
141 | wrps = (aa64dfr0 >> 20) & 0xf; | |
142 | ||
143 | save_debug(dbg->dbg_bcr, dbgbcr, brps); | |
144 | save_debug(dbg->dbg_bvr, dbgbvr, brps); | |
145 | save_debug(dbg->dbg_wcr, dbgwcr, wrps); | |
146 | save_debug(dbg->dbg_wvr, dbgwvr, wrps); | |
147 | ||
148 | ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1); | |
149 | } | |
150 | ||
014c4c77 CD |
151 | static void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu, |
152 | struct kvm_guest_debug_arch *dbg, | |
153 | struct kvm_cpu_context *ctxt) | |
8eb99267 MZ |
154 | { |
155 | u64 aa64dfr0; | |
156 | int brps, wrps; | |
157 | ||
8eb99267 MZ |
158 | aa64dfr0 = read_sysreg(id_aa64dfr0_el1); |
159 | ||
160 | brps = (aa64dfr0 >> 12) & 0xf; | |
161 | wrps = (aa64dfr0 >> 20) & 0xf; | |
162 | ||
163 | restore_debug(dbg->dbg_bcr, dbgbcr, brps); | |
164 | restore_debug(dbg->dbg_bvr, dbgbvr, brps); | |
165 | restore_debug(dbg->dbg_wcr, dbgwcr, wrps); | |
166 | restore_debug(dbg->dbg_wvr, dbgwvr, wrps); | |
167 | ||
168 | write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1); | |
169 | } | |
170 | ||
014c4c77 | 171 | void __hyp_text __debug_switch_to_guest(struct kvm_vcpu *vcpu) |
8eb99267 | 172 | { |
014c4c77 CD |
173 | struct kvm_cpu_context *host_ctxt; |
174 | struct kvm_cpu_context *guest_ctxt; | |
175 | struct kvm_guest_debug_arch *host_dbg; | |
176 | struct kvm_guest_debug_arch *guest_dbg; | |
5742d049 CD |
177 | |
178 | /* | |
179 | * Non-VHE: Disable and flush SPE data generation | |
180 | * VHE: The vcpu can run, but it can't hide. | |
181 | */ | |
182 | if (!has_vhe()) | |
183 | __debug_save_spe_nvhe(&vcpu->arch.host_debug_state.pmscr_el1); | |
014c4c77 | 184 | |
fa89d31c | 185 | if (!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY)) |
014c4c77 CD |
186 | return; |
187 | ||
07da1ffa | 188 | host_ctxt = &__hyp_this_cpu_ptr(kvm_host_data)->host_ctxt; |
014c4c77 CD |
189 | guest_ctxt = &vcpu->arch.ctxt; |
190 | host_dbg = &vcpu->arch.host_debug_state.regs; | |
191 | guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr); | |
192 | ||
193 | __debug_save_state(vcpu, host_dbg, host_ctxt); | |
194 | __debug_restore_state(vcpu, guest_dbg, guest_ctxt); | |
8eb99267 MZ |
195 | } |
196 | ||
014c4c77 | 197 | void __hyp_text __debug_switch_to_host(struct kvm_vcpu *vcpu) |
8eb99267 | 198 | { |
014c4c77 CD |
199 | struct kvm_cpu_context *host_ctxt; |
200 | struct kvm_cpu_context *guest_ctxt; | |
201 | struct kvm_guest_debug_arch *host_dbg; | |
202 | struct kvm_guest_debug_arch *guest_dbg; | |
203 | ||
5742d049 CD |
204 | if (!has_vhe()) |
205 | __debug_restore_spe_nvhe(vcpu->arch.host_debug_state.pmscr_el1); | |
206 | ||
fa89d31c | 207 | if (!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY)) |
014c4c77 CD |
208 | return; |
209 | ||
07da1ffa | 210 | host_ctxt = &__hyp_this_cpu_ptr(kvm_host_data)->host_ctxt; |
014c4c77 CD |
211 | guest_ctxt = &vcpu->arch.ctxt; |
212 | host_dbg = &vcpu->arch.host_debug_state.regs; | |
213 | guest_dbg = kern_hyp_va(vcpu->arch.debug_ptr); | |
214 | ||
215 | __debug_save_state(vcpu, guest_dbg, guest_ctxt); | |
216 | __debug_restore_state(vcpu, host_dbg, host_ctxt); | |
8eb99267 | 217 | |
fa89d31c | 218 | vcpu->arch.flags &= ~KVM_ARM64_DEBUG_DIRTY; |
8eb99267 MZ |
219 | } |
220 | ||
cf0ba18a | 221 | u32 __hyp_text __kvm_get_mdcr_el2(void) |
8eb99267 MZ |
222 | { |
223 | return read_sysreg(mdcr_el2); | |
224 | } |