diff options
author | Hollis Blanchard <hollisb@us.ibm.com> | 2008-07-25 14:54:49 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-10-15 04:15:16 -0400 |
commit | 6a0ab738ef42d87951b3980f61b1f4cbb14d4171 (patch) | |
tree | 8650adf6b8c2df9817c7d6dff2a2f8a4b4904abc /arch/powerpc/kvm/powerpc.c | |
parent | b5e2fec0ebc3fcaff954092bb69444a67a904c0a (diff) |
KVM: ppc: guest breakpoint support
Allow host userspace to program hardware debug registers to set breakpoints
inside guests.
Signed-off-by: Jerone Young <jyoung5@us.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/powerpc/kvm/powerpc.c')
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 84 |
1 files changed, 83 insertions, 1 deletions
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 53826a5f6c06..b75607180ddb 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -239,18 +239,100 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) | |||
239 | { | 239 | { |
240 | } | 240 | } |
241 | 241 | ||
242 | /* Note: clearing MSR[DE] just means that the debug interrupt will not be | ||
243 | * delivered *immediately*. Instead, it simply sets the appropriate DBSR bits. | ||
244 | * If those DBSR bits are still set when MSR[DE] is re-enabled, the interrupt | ||
245 | * will be delivered as an "imprecise debug event" (which is indicated by | ||
246 | * DBSR[IDE]. | ||
247 | */ | ||
248 | static void kvmppc_disable_debug_interrupts(void) | ||
249 | { | ||
250 | mtmsr(mfmsr() & ~MSR_DE); | ||
251 | } | ||
252 | |||
253 | static void kvmppc_restore_host_debug_state(struct kvm_vcpu *vcpu) | ||
254 | { | ||
255 | kvmppc_disable_debug_interrupts(); | ||
256 | |||
257 | mtspr(SPRN_IAC1, vcpu->arch.host_iac[0]); | ||
258 | mtspr(SPRN_IAC2, vcpu->arch.host_iac[1]); | ||
259 | mtspr(SPRN_IAC3, vcpu->arch.host_iac[2]); | ||
260 | mtspr(SPRN_IAC4, vcpu->arch.host_iac[3]); | ||
261 | mtspr(SPRN_DBCR1, vcpu->arch.host_dbcr1); | ||
262 | mtspr(SPRN_DBCR2, vcpu->arch.host_dbcr2); | ||
263 | mtspr(SPRN_DBCR0, vcpu->arch.host_dbcr0); | ||
264 | mtmsr(vcpu->arch.host_msr); | ||
265 | } | ||
266 | |||
267 | static void kvmppc_load_guest_debug_registers(struct kvm_vcpu *vcpu) | ||
268 | { | ||
269 | struct kvm_guest_debug *dbg = &vcpu->guest_debug; | ||
270 | u32 dbcr0 = 0; | ||
271 | |||
272 | vcpu->arch.host_msr = mfmsr(); | ||
273 | kvmppc_disable_debug_interrupts(); | ||
274 | |||
275 | /* Save host debug register state. */ | ||
276 | vcpu->arch.host_iac[0] = mfspr(SPRN_IAC1); | ||
277 | vcpu->arch.host_iac[1] = mfspr(SPRN_IAC2); | ||
278 | vcpu->arch.host_iac[2] = mfspr(SPRN_IAC3); | ||
279 | vcpu->arch.host_iac[3] = mfspr(SPRN_IAC4); | ||
280 | vcpu->arch.host_dbcr0 = mfspr(SPRN_DBCR0); | ||
281 | vcpu->arch.host_dbcr1 = mfspr(SPRN_DBCR1); | ||
282 | vcpu->arch.host_dbcr2 = mfspr(SPRN_DBCR2); | ||
283 | |||
284 | /* set registers up for guest */ | ||
285 | |||
286 | if (dbg->bp[0]) { | ||
287 | mtspr(SPRN_IAC1, dbg->bp[0]); | ||
288 | dbcr0 |= DBCR0_IAC1 | DBCR0_IDM; | ||
289 | } | ||
290 | if (dbg->bp[1]) { | ||
291 | mtspr(SPRN_IAC2, dbg->bp[1]); | ||
292 | dbcr0 |= DBCR0_IAC2 | DBCR0_IDM; | ||
293 | } | ||
294 | if (dbg->bp[2]) { | ||
295 | mtspr(SPRN_IAC3, dbg->bp[2]); | ||
296 | dbcr0 |= DBCR0_IAC3 | DBCR0_IDM; | ||
297 | } | ||
298 | if (dbg->bp[3]) { | ||
299 | mtspr(SPRN_IAC4, dbg->bp[3]); | ||
300 | dbcr0 |= DBCR0_IAC4 | DBCR0_IDM; | ||
301 | } | ||
302 | |||
303 | mtspr(SPRN_DBCR0, dbcr0); | ||
304 | mtspr(SPRN_DBCR1, 0); | ||
305 | mtspr(SPRN_DBCR2, 0); | ||
306 | } | ||
307 | |||
242 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 308 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
243 | { | 309 | { |
310 | if (vcpu->guest_debug.enabled) | ||
311 | kvmppc_load_guest_debug_registers(vcpu); | ||
244 | } | 312 | } |
245 | 313 | ||
246 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | 314 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) |
247 | { | 315 | { |
316 | if (vcpu->guest_debug.enabled) | ||
317 | kvmppc_restore_host_debug_state(vcpu); | ||
248 | } | 318 | } |
249 | 319 | ||
250 | int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, | 320 | int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, |
251 | struct kvm_debug_guest *dbg) | 321 | struct kvm_debug_guest *dbg) |
252 | { | 322 | { |
253 | return -ENOTSUPP; | 323 | int i; |
324 | |||
325 | vcpu->guest_debug.enabled = dbg->enabled; | ||
326 | if (vcpu->guest_debug.enabled) { | ||
327 | for (i=0; i < ARRAY_SIZE(vcpu->guest_debug.bp); i++) { | ||
328 | if (dbg->breakpoints[i].enabled) | ||
329 | vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address; | ||
330 | else | ||
331 | vcpu->guest_debug.bp[i] = 0; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | return 0; | ||
254 | } | 336 | } |
255 | 337 | ||
256 | static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, | 338 | static void kvmppc_complete_dcr_load(struct kvm_vcpu *vcpu, |