All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4 v7] ppc: Add debug stub support
@ 2014-07-10 14:19 Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 1/4 v7] ppc: debug stub: Get trap instruction opcode from KVM Bharat Bhushan
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Bharat Bhushan @ 2014-07-10 14:19 UTC (permalink / raw)
  To: agraf; +Cc: Bharat Bhushan, maddy, qemu-ppc, qemu-devel

This patchset add support for
 - software breakpoint
 - h/w breakpoint
 - h/w watchpoint
  
Please find description in individual patch.

v6->v7
 - Removed interrupt injection infrastructure
 - Simplified excp_vector initialization based on comment
 - Moved program check exception to software breakpoint patch
 
v5->v6
 - Added a new patch to synchronize excp_vectors.
 - Inject program exception rather than debug exception if
   guest is not able to handle debug exception. why? detail
   in respective patch.

Bharat Bhushan (4):
  ppc: debug stub: Get trap instruction opcode from KVM
  ppc: synchronize excp_vectors for injecting exception
  ppc: Add software breakpoint support
  ppc: Add hw breakpoint watchpoint support

 target-ppc/kvm.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 319 insertions(+), 28 deletions(-)

-- 
1.9.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 1/4 v7] ppc: debug stub: Get trap instruction opcode from KVM
  2014-07-10 14:19 [Qemu-devel] [PATCH 0/4 v7] ppc: Add debug stub support Bharat Bhushan
@ 2014-07-10 14:19 ` Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 2/4 v7] ppc: synchronize excp_vectors for injecting exception Bharat Bhushan
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Bharat Bhushan @ 2014-07-10 14:19 UTC (permalink / raw)
  To: agraf; +Cc: Bharat Bhushan, maddy, qemu-ppc, qemu-devel

Get trap instruction opcode from KVM and this opcode will
be used for setting software breakpoint in following patch

Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
---
v6->v7
 - No change

 target-ppc/kvm.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 2d87108..4df23dd 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -72,6 +72,8 @@ static int cap_papr;
 static int cap_htab_fd;
 static int cap_fixup_hcalls;
 
+static uint32_t debug_inst_opcode;
+
 /* XXX We have a race condition where we actually have a level triggered
  *     interrupt, but the infrastructure can't expose that yet, so the guest
  *     takes but ignores it, goes to sleep and never gets notified that there's
@@ -436,6 +438,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
         break;
     }
 
+    kvm_get_one_reg(cs, KVM_REG_PPC_DEBUG_INST, &debug_inst_opcode);
+
     return ret;
 }
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 2/4 v7] ppc: synchronize excp_vectors for injecting exception
  2014-07-10 14:19 [Qemu-devel] [PATCH 0/4 v7] ppc: Add debug stub support Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 1/4 v7] ppc: debug stub: Get trap instruction opcode from KVM Bharat Bhushan
@ 2014-07-10 14:19 ` Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 4/4 v7] ppc: Add hw breakpoint watchpoint support Bharat Bhushan
  3 siblings, 0 replies; 7+ messages in thread
From: Bharat Bhushan @ 2014-07-10 14:19 UTC (permalink / raw)
  To: agraf; +Cc: Bharat Bhushan, maddy, qemu-ppc, qemu-devel

This patch synchronizes env->excp_vectors[] with env->iovr[].
This is required for using the existing interrupt injection mechanism
for kvm.

Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
---
v1->v2
 - simplified excp initialization based on Alex comment

 target-ppc/kvm.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 4df23dd..e00a20f 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -903,6 +903,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     return ret;
 }
 
+static void kvm_sync_excp(CPUPPCState *env, int vector, int ivor)
+{
+     env->excp_vectors[vector] = env->spr[ivor] + env->spr[SPR_BOOKE_IVPR];
+}
+
 int kvm_arch_get_registers(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -985,35 +990,57 @@ int kvm_arch_get_registers(CPUState *cs)
 
         if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
             env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
+            kvm_sync_excp(env, POWERPC_EXCP_CRITICAL,  SPR_BOOKE_IVOR0);
             env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
+            kvm_sync_excp(env, POWERPC_EXCP_MCHECK,  SPR_BOOKE_IVOR1);
             env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
+            kvm_sync_excp(env, POWERPC_EXCP_DSI,  SPR_BOOKE_IVOR2);
             env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
+            kvm_sync_excp(env, POWERPC_EXCP_ISI,  SPR_BOOKE_IVOR3);
             env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
+            kvm_sync_excp(env, POWERPC_EXCP_EXTERNAL,  SPR_BOOKE_IVOR4);
             env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
+            kvm_sync_excp(env, POWERPC_EXCP_ALIGN,  SPR_BOOKE_IVOR5);
             env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
+            kvm_sync_excp(env, POWERPC_EXCP_PROGRAM,  SPR_BOOKE_IVOR6);
             env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
+            kvm_sync_excp(env, POWERPC_EXCP_FPU,  SPR_BOOKE_IVOR7);
             env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
+            kvm_sync_excp(env, POWERPC_EXCP_SYSCALL,  SPR_BOOKE_IVOR8);
             env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
+            kvm_sync_excp(env, POWERPC_EXCP_APU,  SPR_BOOKE_IVOR9);
             env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
+            kvm_sync_excp(env, POWERPC_EXCP_DECR,  SPR_BOOKE_IVOR10);
             env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
+            kvm_sync_excp(env, POWERPC_EXCP_FIT,  SPR_BOOKE_IVOR11);
             env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
+            kvm_sync_excp(env, POWERPC_EXCP_WDT,  SPR_BOOKE_IVOR12);
             env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
+            kvm_sync_excp(env, POWERPC_EXCP_DTLB,  SPR_BOOKE_IVOR13);
             env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
+            kvm_sync_excp(env, POWERPC_EXCP_ITLB,  SPR_BOOKE_IVOR14);
             env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
+            kvm_sync_excp(env, POWERPC_EXCP_DEBUG,  SPR_BOOKE_IVOR15);
 
             if (sregs.u.e.features & KVM_SREGS_E_SPE) {
                 env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
+                kvm_sync_excp(env, POWERPC_EXCP_SPEU,  SPR_BOOKE_IVOR32);
                 env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
+                kvm_sync_excp(env, POWERPC_EXCP_EFPDI,  SPR_BOOKE_IVOR33);
                 env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
+                kvm_sync_excp(env, POWERPC_EXCP_EFPRI,  SPR_BOOKE_IVOR34);
             }
 
             if (sregs.u.e.features & KVM_SREGS_E_PM) {
                 env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
+                kvm_sync_excp(env, POWERPC_EXCP_EPERFM,  SPR_BOOKE_IVOR35);
             }
 
             if (sregs.u.e.features & KVM_SREGS_E_PC) {
                 env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
+                kvm_sync_excp(env, POWERPC_EXCP_DOORI,  SPR_BOOKE_IVOR36);
                 env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
+                kvm_sync_excp(env, POWERPC_EXCP_DOORCI, SPR_BOOKE_IVOR37);
             }
         }
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support
  2014-07-10 14:19 [Qemu-devel] [PATCH 0/4 v7] ppc: Add debug stub support Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 1/4 v7] ppc: debug stub: Get trap instruction opcode from KVM Bharat Bhushan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 2/4 v7] ppc: synchronize excp_vectors for injecting exception Bharat Bhushan
@ 2014-07-10 14:19 ` Bharat Bhushan
  2014-07-11  5:21   ` Madhavan Srinivasan
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 4/4 v7] ppc: Add hw breakpoint watchpoint support Bharat Bhushan
  3 siblings, 1 reply; 7+ messages in thread
From: Bharat Bhushan @ 2014-07-10 14:19 UTC (permalink / raw)
  To: agraf; +Cc: Bharat Bhushan, maddy, qemu-ppc, qemu-devel

This patch allow insert/remove software breakpoint.

When QEMU is not able to handle debug exception then we inject program
exception to guest because for software breakpoint QEMU uses a ehpriv-1
instruction;
So there cannot be any reason that we are in qemu with exit reason
KVM_EXIT_DEBUG  for guest set debug exception, only possibility is
guest executed ehpriv-1 privilege instruction and that's why we are
injecting program exception.

Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
---
v6->v7
 - Moved exception injection to this patch
 - Inject the fault directly

 target-ppc/kvm.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 73 insertions(+), 14 deletions(-)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index e00a20f..afa2291 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -1275,6 +1275,69 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env, uint32_t dcrn, uint32_t dat
     return 0;
 }
 
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+    /* Mixed endian case is not handled */
+    uint32_t sc = debug_inst_opcode;
+
+    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
+                            sizeof(sc), 0) ||
+        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 1)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+    uint32_t sc;
+
+    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 0) ||
+        sc != debug_inst_opcode ||
+        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
+                            sizeof(sc), 1)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
+{
+    /* Software Breakpoint updates */
+    if (kvm_sw_breakpoints_active(cs)) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+    }
+}
+
+static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
+    int handle = 0;
+
+    if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
+        handle = 1;
+    } else {
+        /* QEMU is not able to handle debug exception, so inject
+         * program exception to guest;
+         * Yes program exception NOT debug exception !!
+         * For software breakpoint QEMU uses a ehpriv-1 instruction;
+         * So there cannot be any reason that we are here for guest
+         * set debug exception, only possibility is guest executed a
+         * privilege instruction and that's why we are injecting
+         * program exception.
+         */
+         cs->exception_index = POWERPC_EXCP_PROGRAM;
+         env->error_code = POWERPC_EXCP_INVAL;
+         ppc_cpu_do_interrupt(cs);
+    }
+
+    return handle;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -1315,6 +1378,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
         ret = 0;
         break;
 
+    case KVM_EXIT_DEBUG:
+        DPRINTF("handle debug exception\n");
+        if (kvm_handle_debug(cpu, run)) {
+            ret = EXCP_DEBUG;
+            break;
+        }
+        /* re-enter, this exception was guest-internal */
+        ret = 0;
+        break;
+
     default:
         fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
         ret = -1;
@@ -2003,16 +2076,6 @@ void kvm_arch_init_irq_routing(KVMState *s)
 {
 }
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp)
-{
-    return -EINVAL;
-}
-
-int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp)
-{
-    return -EINVAL;
-}
-
 int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
 {
     return -EINVAL;
@@ -2027,10 +2090,6 @@ void kvm_arch_remove_all_hw_breakpoints(void)
 {
 }
 
-void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
-{
-}
-
 struct kvm_get_htab_buf {
     struct kvm_get_htab_header header;
     /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [Qemu-devel] [PATCH 4/4 v7] ppc: Add hw breakpoint watchpoint support
  2014-07-10 14:19 [Qemu-devel] [PATCH 0/4 v7] ppc: Add debug stub support Bharat Bhushan
                   ` (2 preceding siblings ...)
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support Bharat Bhushan
@ 2014-07-10 14:19 ` Bharat Bhushan
  3 siblings, 0 replies; 7+ messages in thread
From: Bharat Bhushan @ 2014-07-10 14:19 UTC (permalink / raw)
  To: agraf; +Cc: Bharat Bhushan, maddy, qemu-ppc, qemu-devel

This patch adds hardware breakpoint and hardware watchpoint support
for ppc.

On BOOKE architecture we cannot share debug resources between QEMU
and guest because:
    When QEMU is using debug resources then debug exception must
    be always enabled. To achieve this we set MSR_DE and also set
    MSRP_DEP so guest cannot change MSR_DE.

    When emulating debug resource for guest we want guest
    to control MSR_DE (enable/disable debug interrupt on need).

    So above mentioned two configuration cannot be supported
    at the same time. So the result is that we cannot share
    debug resources between QEMU and Guest on BOOKE architecture.

In the current design QEMU gets priority over guest,
this means that if QEMU is using debug resources then guest
cannot use them and if guest is using debug resource then
qemu can overwrite them.

When QEMU is not able to handle debug exception then we inject program
exception to guest. Yes program exception NOT debug exception and the
reason is:
 1) QEMU and guest not sharing debug resources
 2) For software breakpoint QEMU uses a ehpriv-1 instruction;

 So there cannot be any reason that we are in qemu with exit reason
 KVM_EXIT_DEBUG  for guest set debug exception, only possibility is
 guest executed ehpriv-1 privilege instruction and that's why we are
 injecting program exception.

Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
---
 target-ppc/kvm.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 217 insertions(+), 16 deletions(-)

diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index afa2291..d20962f 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -38,6 +38,7 @@
 #include "hw/ppc/ppc.h"
 #include "sysemu/watchdog.h"
 #include "trace.h"
+#include "exec/gdbstub.h"
 
 //#define DEBUG_KVM
 
@@ -412,6 +413,38 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
     return ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
 }
 
+/* e500 supports 2 h/w breakpoint and 2 watchpoint.
+ * book3s supports only 1 watchpoint, so array size
+ * of 4 is sufficient for now.
+ */
+#define MAX_HW_BKPTS 4
+
+static struct HWBreakpoint {
+    target_ulong addr;
+    int type;
+} hw_debug_points[MAX_HW_BKPTS];
+
+static CPUWatchpoint hw_watchpoint;
+
+/* Default there is no breakpoint and watchpoint supported */
+static int max_hw_breakpoint;
+static int max_hw_watchpoint;
+static int nb_hw_breakpoint;
+static int nb_hw_watchpoint;
+
+static void kvmppc_hw_debug_points_init(CPUPPCState *cenv)
+{
+    if (cenv->excp_model == POWERPC_EXCP_BOOKE) {
+        max_hw_breakpoint = 2;
+        max_hw_watchpoint = 2;
+    }
+
+    if ((max_hw_breakpoint + max_hw_watchpoint) > MAX_HW_BKPTS) {
+        fprintf(stderr, "Error initializing h/w breakpoints\n");
+        return;
+    }
+}
+
 int kvm_arch_init_vcpu(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -439,6 +472,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
     }
 
     kvm_get_one_reg(cs, KVM_REG_PPC_DEBUG_INST, &debug_inst_opcode);
+    kvmppc_hw_debug_points_init(cenv);
 
     return ret;
 }
@@ -1303,12 +1337,161 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
+static int find_hw_breakpoint(target_ulong addr, int type)
+{
+    int n;
+
+    assert((nb_hw_breakpoint + nb_hw_watchpoint)
+           <= ARRAY_SIZE(hw_debug_points));
+
+    for (n = 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) {
+        if (hw_debug_points[n].addr == addr && hw_debug_points[n].type == type) {
+            return n;
+        }
+    }
+
+    return -1;
+}
+
+static int find_hw_watchpoint(target_ulong addr, int *flag)
+{
+    int n;
+
+    n = find_hw_breakpoint(addr, GDB_WATCHPOINT_ACCESS);
+    if (n >= 0) {
+        *flag = BP_MEM_ACCESS;
+        return n;
+    }
+
+    n = find_hw_breakpoint(addr, GDB_WATCHPOINT_WRITE);
+    if (n >= 0) {
+        *flag = BP_MEM_WRITE;
+        return n;
+    }
+
+    n = find_hw_breakpoint(addr, GDB_WATCHPOINT_READ);
+    if (n >= 0) {
+        *flag = BP_MEM_READ;
+        return n;
+    }
+
+    return -1;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    if ((nb_hw_breakpoint + nb_hw_watchpoint) >= ARRAY_SIZE(hw_debug_points))
+	return -ENOBUFS;
+
+    hw_debug_points[nb_hw_breakpoint + nb_hw_watchpoint].addr = addr;
+    hw_debug_points[nb_hw_breakpoint + nb_hw_watchpoint].type = type;
+
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        if (nb_hw_breakpoint >= max_hw_breakpoint) {
+            return -ENOBUFS;
+        }
+
+        if (find_hw_breakpoint(addr, type) >= 0) {
+            return -EEXIST;
+        }
+
+        nb_hw_breakpoint++;
+        break;
+
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        if (nb_hw_watchpoint >= max_hw_watchpoint) {
+            return -ENOBUFS;
+        }
+
+        if (find_hw_breakpoint(addr, type) >= 0) {
+            return -EEXIST;
+        }
+
+        nb_hw_watchpoint++;
+        break;
+
+    default:
+        return -ENOSYS;
+    }
+
+    return 0;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    int n;
+
+    n = find_hw_breakpoint(addr, type);
+    if (n < 0) {
+        return -ENOENT;
+    }
+
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        nb_hw_breakpoint--;
+        break;
+
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case GDB_WATCHPOINT_ACCESS:
+        nb_hw_watchpoint--;
+        break;
+
+    default:
+        return -ENOSYS;
+    }
+    hw_debug_points[n] = hw_debug_points[nb_hw_breakpoint + nb_hw_watchpoint];
+
+    return 0;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    nb_hw_breakpoint = nb_hw_watchpoint = 0;
+}
+
 void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
 {
+    int n;
+
     /* Software Breakpoint updates */
     if (kvm_sw_breakpoints_active(cs)) {
         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
     }
+
+    assert((nb_hw_breakpoint + nb_hw_watchpoint)
+           <= ARRAY_SIZE(hw_debug_points));
+    assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
+
+    if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+        memset(dbg->arch.bp, 0, sizeof(dbg->arch.bp));
+        for (n = 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) {
+            switch (hw_debug_points[n].type) {
+            case GDB_BREAKPOINT_HW:
+                dbg->arch.bp[n].type = KVMPPC_DEBUG_BREAKPOINT;
+                break;
+            case GDB_WATCHPOINT_WRITE:
+                dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_WRITE;
+                break;
+            case GDB_WATCHPOINT_READ:
+                dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_READ;
+                break;
+            case GDB_WATCHPOINT_ACCESS:
+                dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_WRITE |
+                                        KVMPPC_DEBUG_WATCH_READ;
+                break;
+            default:
+                cpu_abort(cs, "Unsupported breakpoint type\n");
+            }
+            dbg->arch.bp[n].addr = hw_debug_points[n].addr;
+        }
+    }
 }
 
 static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
@@ -1317,13 +1500,46 @@ static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
     CPUPPCState *env = &cpu->env;
     struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
     int handle = 0;
+    int n;
+    int flag = 0;
 
-    if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
+    if (cs->singlestep_enabled) {
+        handle = 1;
+    } else if (arch_info->status) {
+        if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
+            if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) {
+                n = find_hw_breakpoint(arch_info->address, GDB_BREAKPOINT_HW);
+                if (n >= 0) {
+                    handle = 1;
+                }
+            } else if (arch_info->status & (KVMPPC_DEBUG_WATCH_READ |
+                                            KVMPPC_DEBUG_WATCH_WRITE)) {
+                n = find_hw_watchpoint(arch_info->address,  &flag);
+                if (n >= 0) {
+                    handle = 1;
+                    cs->watchpoint_hit = &hw_watchpoint;
+                    hw_watchpoint.vaddr = hw_debug_points[n].addr;
+                    hw_watchpoint.flags = flag;
+                }
+            }
+        }
+    } else if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
         handle = 1;
     } else {
         /* QEMU is not able to handle debug exception, so inject
          * program exception to guest;
          * Yes program exception NOT debug exception !!
+         * When QEMU is using debug resources then debug exception must
+         * be always set. To achieve this we set MSR_DE and also set
+         * MSRP_DEP so guest cannot change MSR_DE.
+         * When emulating debug resource for guest we want guest
+         * to control MSR_DE (enable/disable debug interrupt on need).
+         * Supporting both configurations are NOT possible.
+         * So the result is that we cannot share debug resources
+         * between QEMU and Guest on BOOKE architecture.
+         * In the current design QEMU gets the priority over guest,
+         * this means that if QEMU is using debug resources then guest
+         * cannot use them;
          * For software breakpoint QEMU uses a ehpriv-1 instruction;
          * So there cannot be any reason that we are here for guest
          * set debug exception, only possibility is guest executed a
@@ -1334,7 +1550,6 @@ static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
          env->error_code = POWERPC_EXCP_INVAL;
          ppc_cpu_do_interrupt(cs);
     }
-
     return handle;
 }
 
@@ -2076,20 +2291,6 @@ void kvm_arch_init_irq_routing(KVMState *s)
 {
 }
 
-int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
-{
-    return -EINVAL;
-}
-
-int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type)
-{
-    return -EINVAL;
-}
-
-void kvm_arch_remove_all_hw_breakpoints(void)
-{
-}
-
 struct kvm_get_htab_buf {
     struct kvm_get_htab_header header;
     /*
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support
  2014-07-10 14:19 ` [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support Bharat Bhushan
@ 2014-07-11  5:21   ` Madhavan Srinivasan
  2014-07-14  8:55     ` Bharat.Bhushan
  0 siblings, 1 reply; 7+ messages in thread
From: Madhavan Srinivasan @ 2014-07-11  5:21 UTC (permalink / raw)
  To: Bharat Bhushan, agraf; +Cc: qemu-ppc, qemu-devel

On Thursday 10 July 2014 07:49 PM, Bharat Bhushan wrote:
> This patch allow insert/remove software breakpoint.
> 
> When QEMU is not able to handle debug exception then we inject program
> exception to guest because for software breakpoint QEMU uses a ehpriv-1
> instruction;
> So there cannot be any reason that we are in qemu with exit reason
> KVM_EXIT_DEBUG  for guest set debug exception, only possibility is
> guest executed ehpriv-1 privilege instruction and that's why we are
> injecting program exception.
> 
> Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
> ---
> v6->v7
>  - Moved exception injection to this patch
>  - Inject the fault directly
> 
>  target-ppc/kvm.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 73 insertions(+), 14 deletions(-)
> 
> diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
> index e00a20f..afa2291 100644
> --- a/target-ppc/kvm.c
> +++ b/target-ppc/kvm.c
> @@ -1275,6 +1275,69 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env, uint32_t dcrn, uint32_t dat
>      return 0;
>  }
> 
> +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
> +{
> +    /* Mixed endian case is not handled */
> +    uint32_t sc = debug_inst_opcode;
> +
> +    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
> +                            sizeof(sc), 0) ||
> +        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 1)) {
> +        return -EINVAL;
> +    }
> +
> +    return 0;
> +}
> +
> +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
> +{
> +    uint32_t sc;
> +
> +    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 0) ||
> +        sc != debug_inst_opcode ||
> +        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
> +                            sizeof(sc), 1)) {
> +        return -EINVAL;
> +    }
> +
> +    return 0;
> +}
> +
> +void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
> +{
> +    /* Software Breakpoint updates */
> +    if (kvm_sw_breakpoints_active(cs)) {
> +        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
> +    }
> +}
> +
> +static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
> +    int handle = 0;
> +
> +    if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
> +        handle = 1;
> +    } else {
> +        /* QEMU is not able to handle debug exception, so inject
> +         * program exception to guest;
> +         * Yes program exception NOT debug exception !!
> +         * For software breakpoint QEMU uses a ehpriv-1 instruction;
> +         * So there cannot be any reason that we are here for guest
> +         * set debug exception, only possibility is guest executed a
> +         * privilege instruction and that's why we are injecting
> +         * program exception.
> +         */
> +         cs->exception_index = POWERPC_EXCP_PROGRAM;
> +         env->error_code = POWERPC_EXCP_INVAL;
> +         ppc_cpu_do_interrupt(cs);
> +    }
> +

Excellent. This is the change I had as part of server side patch for no
sw breakpoint case. Also have one more addition to this, which I found
in the debug.

Only issue in here (using TCG for injecting) is that, KVM gives us PC,
but incase of TCG, it uses nip. So nip gets decremented in
ppc_cpu_do_interrupt function ending up sending the wrong pc to guest.
So Alex suggested to increment the nip by 4 before calling the
ppc_cpu_do_interrupt function. Also kindly add cpu_synchronize_state
before calling since we are changing the register values.

Regards
Maddy

> +    return handle;
> +}
> +
>  int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
>  {
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
> @@ -1315,6 +1378,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
>          ret = 0;
>          break;
> 
> +    case KVM_EXIT_DEBUG:
> +        DPRINTF("handle debug exception\n");
> +        if (kvm_handle_debug(cpu, run)) {
> +            ret = EXCP_DEBUG;
> +            break;
> +        }
> +        /* re-enter, this exception was guest-internal */
> +        ret = 0;
> +        break;
> +
>      default:
>          fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
>          ret = -1;
> @@ -2003,16 +2076,6 @@ void kvm_arch_init_irq_routing(KVMState *s)
>  {
>  }
> 
> -int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp)
> -{
> -    return -EINVAL;
> -}
> -
> -int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp)
> -{
> -    return -EINVAL;
> -}
> -
>  int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
>  {
>      return -EINVAL;
> @@ -2027,10 +2090,6 @@ void kvm_arch_remove_all_hw_breakpoints(void)
>  {
>  }
> 
> -void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
> -{
> -}
> -
>  struct kvm_get_htab_buf {
>      struct kvm_get_htab_header header;
>      /*
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support
  2014-07-11  5:21   ` Madhavan Srinivasan
@ 2014-07-14  8:55     ` Bharat.Bhushan
  0 siblings, 0 replies; 7+ messages in thread
From: Bharat.Bhushan @ 2014-07-14  8:55 UTC (permalink / raw)
  To: Madhavan Srinivasan, agraf; +Cc: qemu-ppc, qemu-devel



> -----Original Message-----
> From: Madhavan Srinivasan [mailto:maddy@linux.vnet.ibm.com]
> Sent: Friday, July 11, 2014 10:51 AM
> To: Bhushan Bharat-R65777; agraf@suse.de
> Cc: qemu-ppc@nongnu.org; qemu-devel@nongnu.org
> Subject: Re: [PATCH 3/4 v7] ppc: Add software breakpoint support
> 
> On Thursday 10 July 2014 07:49 PM, Bharat Bhushan wrote:
> > This patch allow insert/remove software breakpoint.
> >
> > When QEMU is not able to handle debug exception then we inject program
> > exception to guest because for software breakpoint QEMU uses a
> > ehpriv-1 instruction; So there cannot be any reason that we are in
> > qemu with exit reason KVM_EXIT_DEBUG  for guest set debug exception,
> > only possibility is guest executed ehpriv-1 privilege instruction and
> > that's why we are injecting program exception.
> >
> > Signed-off-by: Bharat Bhushan <Bharat.Bhushan@freescale.com>
> > ---
> > v6->v7
> >  - Moved exception injection to this patch
> >  - Inject the fault directly
> >
> >  target-ppc/kvm.c | 87
> > +++++++++++++++++++++++++++++++++++++++++++++++---------
> >  1 file changed, 73 insertions(+), 14 deletions(-)
> >
> > diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index
> > e00a20f..afa2291 100644
> > --- a/target-ppc/kvm.c
> > +++ b/target-ppc/kvm.c
> > @@ -1275,6 +1275,69 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env,
> uint32_t dcrn, uint32_t dat
> >      return 0;
> >  }
> >
> > +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct
> > +kvm_sw_breakpoint *bp) {
> > +    /* Mixed endian case is not handled */
> > +    uint32_t sc = debug_inst_opcode;
> > +
> > +    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
> > +                            sizeof(sc), 0) ||
> > +        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 1)) {
> > +        return -EINVAL;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct
> > +kvm_sw_breakpoint *bp) {
> > +    uint32_t sc;
> > +
> > +    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 0) ||
> > +        sc != debug_inst_opcode ||
> > +        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
> > +                            sizeof(sc), 1)) {
> > +        return -EINVAL;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug
> > +*dbg) {
> > +    /* Software Breakpoint updates */
> > +    if (kvm_sw_breakpoints_active(cs)) {
> > +        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
> > +    }
> > +}
> > +
> > +static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run) {
> > +    CPUState *cs = CPU(cpu);
> > +    CPUPPCState *env = &cpu->env;
> > +    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
> > +    int handle = 0;
> > +
> > +    if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
> > +        handle = 1;
> > +    } else {
> > +        /* QEMU is not able to handle debug exception, so inject
> > +         * program exception to guest;
> > +         * Yes program exception NOT debug exception !!
> > +         * For software breakpoint QEMU uses a ehpriv-1 instruction;
> > +         * So there cannot be any reason that we are here for guest
> > +         * set debug exception, only possibility is guest executed a
> > +         * privilege instruction and that's why we are injecting
> > +         * program exception.
> > +         */
> > +         cs->exception_index = POWERPC_EXCP_PROGRAM;
> > +         env->error_code = POWERPC_EXCP_INVAL;
> > +         ppc_cpu_do_interrupt(cs);
> > +    }
> > +
> 
> Excellent. This is the change I had as part of server side patch for no sw
> breakpoint case. Also have one more addition to this, which I found in the
> debug.
> 
> Only issue in here (using TCG for injecting) is that, KVM gives us PC, but
> incase of TCG, it uses nip. So nip gets decremented in ppc_cpu_do_interrupt
> function ending up sending the wrong pc to guest.

This is a good catch, I did not hit this because of some other issue (srr0/1 not getting sync properly on Booke-hv.

Thanks
-Bharat


> So Alex suggested to increment the nip by 4 before calling the
> ppc_cpu_do_interrupt function. Also kindly add cpu_synchronize_state before
> calling since we are changing the register values.
> 
> Regards
> Maddy
> 
> > +    return handle;
> > +}
> > +
> >  int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)  {
> >      PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -1315,6 +1378,16 @@ int
> > kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
> >          ret = 0;
> >          break;
> >
> > +    case KVM_EXIT_DEBUG:
> > +        DPRINTF("handle debug exception\n");
> > +        if (kvm_handle_debug(cpu, run)) {
> > +            ret = EXCP_DEBUG;
> > +            break;
> > +        }
> > +        /* re-enter, this exception was guest-internal */
> > +        ret = 0;
> > +        break;
> > +
> >      default:
> >          fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
> >          ret = -1;
> > @@ -2003,16 +2076,6 @@ void kvm_arch_init_irq_routing(KVMState *s)  {
> > }
> >
> > -int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct
> > kvm_sw_breakpoint *bp) -{
> > -    return -EINVAL;
> > -}
> > -
> > -int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct
> > kvm_sw_breakpoint *bp) -{
> > -    return -EINVAL;
> > -}
> > -
> >  int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong
> > len, int type)  {
> >      return -EINVAL;
> > @@ -2027,10 +2090,6 @@ void kvm_arch_remove_all_hw_breakpoints(void)
> >  {
> >  }
> >
> > -void kvm_arch_update_guest_debug(CPUState *cpu, struct
> > kvm_guest_debug *dbg) -{ -}
> > -
> >  struct kvm_get_htab_buf {
> >      struct kvm_get_htab_header header;
> >      /*
> >

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-07-14  8:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-10 14:19 [Qemu-devel] [PATCH 0/4 v7] ppc: Add debug stub support Bharat Bhushan
2014-07-10 14:19 ` [Qemu-devel] [PATCH 1/4 v7] ppc: debug stub: Get trap instruction opcode from KVM Bharat Bhushan
2014-07-10 14:19 ` [Qemu-devel] [PATCH 2/4 v7] ppc: synchronize excp_vectors for injecting exception Bharat Bhushan
2014-07-10 14:19 ` [Qemu-devel] [PATCH 3/4 v7] ppc: Add software breakpoint support Bharat Bhushan
2014-07-11  5:21   ` Madhavan Srinivasan
2014-07-14  8:55     ` Bharat.Bhushan
2014-07-10 14:19 ` [Qemu-devel] [PATCH 4/4 v7] ppc: Add hw breakpoint watchpoint support Bharat Bhushan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.