|
@@ -725,6 +725,30 @@ static int kvmppc_hcall_impl_hv(unsigned long cmd)
|
|
|
return kvmppc_hcall_impl_hv_realmode(cmd);
|
|
|
}
|
|
|
|
|
|
+static int kvmppc_emulate_debug_inst(struct kvm_run *run,
|
|
|
+ struct kvm_vcpu *vcpu)
|
|
|
+{
|
|
|
+ u32 last_inst;
|
|
|
+
|
|
|
+ if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst) !=
|
|
|
+ EMULATE_DONE) {
|
|
|
+ /*
|
|
|
+ * Fetch failed, so return to guest and
|
|
|
+ * try executing it again.
|
|
|
+ */
|
|
|
+ return RESUME_GUEST;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (last_inst == KVMPPC_INST_SW_BREAKPOINT) {
|
|
|
+ run->exit_reason = KVM_EXIT_DEBUG;
|
|
|
+ run->debug.arch.address = kvmppc_get_pc(vcpu);
|
|
|
+ return RESUME_HOST;
|
|
|
+ } else {
|
|
|
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
|
|
|
+ return RESUME_GUEST;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|
|
struct task_struct *tsk)
|
|
|
{
|
|
@@ -807,12 +831,18 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|
|
break;
|
|
|
/*
|
|
|
* This occurs if the guest executes an illegal instruction.
|
|
|
- * We just generate a program interrupt to the guest, since
|
|
|
- * we don't emulate any guest instructions at this stage.
|
|
|
+ * If the guest debug is disabled, generate a program interrupt
|
|
|
+ * to the guest. If guest debug is enabled, we need to check
|
|
|
+ * whether the instruction is a software breakpoint instruction.
|
|
|
+ * Accordingly return to Guest or Host.
|
|
|
*/
|
|
|
case BOOK3S_INTERRUPT_H_EMUL_ASSIST:
|
|
|
- kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
|
|
|
- r = RESUME_GUEST;
|
|
|
+ if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) {
|
|
|
+ r = kvmppc_emulate_debug_inst(run, vcpu);
|
|
|
+ } else {
|
|
|
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
|
|
|
+ r = RESUME_GUEST;
|
|
|
+ }
|
|
|
break;
|
|
|
/*
|
|
|
* This occurs if the guest (kernel or userspace), does something that
|
|
@@ -924,6 +954,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
|
|
|
long int i;
|
|
|
|
|
|
switch (id) {
|
|
|
+ case KVM_REG_PPC_DEBUG_INST:
|
|
|
+ *val = get_reg_val(id, KVMPPC_INST_SW_BREAKPOINT);
|
|
|
+ break;
|
|
|
case KVM_REG_PPC_HIOR:
|
|
|
*val = get_reg_val(id, 0);
|
|
|
break;
|