powerpc/kvm: support to handle sw breakpoint
authorMadhavan Srinivasan <maddy@linux.vnet.ibm.com>
Tue, 9 Sep 2014 17:07:35 +0000 (22:37 +0530)
committerAlexander Graf <agraf@suse.de>
Mon, 22 Sep 2014 08:11:35 +0000 (10:11 +0200)
This patch adds kernel side support for software breakpoint.
Design is that, by using an illegal instruction, we trap to hypervisor
via Emulation Assistance interrupt, where we check for the illegal instruction
and accordingly we return to Host or Guest. Patch also adds support for
software breakpoint in PR KVM.

Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/emulate.c

index 73063ef5369432578a26dcb8fbffcf189e85aab2..dbd160f16cb0b6630dc25a0d793fb4bcfa0036a9 100644 (file)
 #include <asm/paca.h>
 #endif
 
+/*
+ * KVMPPC_INST_SW_BREAKPOINT is debug Instruction
+ * for supporting software breakpoint.
+ */
+#define KVMPPC_INST_SW_BREAKPOINT      0x00dddd00
+
 enum emulation_result {
        EMULATE_DONE,         /* no further processing */
        EMULATE_DO_MMIO,      /* kvm_run filled with MMIO request */
index f23b6a5530825703fc6ed8f3097c5a0c7b3d45e0..27d1b7041746433dad4b7053974d32d8c128a933 100644 (file)
@@ -715,7 +715,8 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
                                        struct kvm_guest_debug *dbg)
 {
-       return -EINVAL;
+       vcpu->guest_debug = dbg->control;
+       return 0;
 }
 
 void kvmppc_decrementer_func(struct kvm_vcpu *vcpu)
index 529d10a7a36f025ce59ba1abbc73e9b7ce20e508..e63587d30b70819b15bb215ca858a7b722795a21 100644 (file)
@@ -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;
index faffb27badd9de362465c6a8ea12052cb7ab53ef..6d7370890775c35fab424b1dd9c4441bdceaf619 100644 (file)
@@ -1319,6 +1319,9 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
        int r = 0;
 
        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, to_book3s(vcpu)->hior);
                break;
index e96b50d0bdab1f80f3374b35a7c9462a9fcc8a51..005222b580eaece3fcb1739b7810f04ae9c44a06 100644 (file)
@@ -274,6 +274,21 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                }
                break;
 
+       case 0:
+               /*
+                * Instruction with primary opcode 0. Based on PowerISA
+                * these are illegal instructions.
+                */
+               if (inst == KVMPPC_INST_SW_BREAKPOINT) {
+                       run->exit_reason = KVM_EXIT_DEBUG;
+                       run->debug.arch.address = kvmppc_get_pc(vcpu);
+                       emulated = EMULATE_EXIT_USER;
+                       advance = 0;
+               } else
+                       emulated = EMULATE_FAIL;
+
+               break;
+
        default:
                emulated = EMULATE_FAIL;
        }