From patchwork Thu Jul 26 05:22:37 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bharat Bhushan X-Patchwork-Id: 173340 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id BA03A2C0096 for ; Thu, 26 Jul 2012 15:21:32 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751341Ab2GZFVc (ORCPT ); Thu, 26 Jul 2012 01:21:32 -0400 Received: from am1ehsobe004.messaging.microsoft.com ([213.199.154.207]:40309 "EHLO am1outboundpool.messaging.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751238Ab2GZFVb (ORCPT ); Thu, 26 Jul 2012 01:21:31 -0400 Received: from mail52-am1-R.bigfish.com (10.3.201.249) by AM1EHSOBE006.bigfish.com (10.3.204.26) with Microsoft SMTP Server id 14.1.225.23; Thu, 26 Jul 2012 05:21:30 +0000 Received: from mail52-am1 (localhost [127.0.0.1]) by mail52-am1-R.bigfish.com (Postfix) with ESMTP id 297048037D; Thu, 26 Jul 2012 05:21:30 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 6 X-BigFish: VS6(zz853kzz1202h1082kzz8275bhz2dh2a8h668h839he5bhf0ah) Received: from mail52-am1 (localhost.localdomain [127.0.0.1]) by mail52-am1 (MessageSwitch) id 1343280088342850_15416; Thu, 26 Jul 2012 05:21:28 +0000 (UTC) Received: from AM1EHSMHS014.bigfish.com (unknown [10.3.201.242]) by mail52-am1.bigfish.com (Postfix) with ESMTP id 4742F140053; Thu, 26 Jul 2012 05:21:28 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by AM1EHSMHS014.bigfish.com (10.3.207.152) with Microsoft SMTP Server (TLS) id 14.1.225.23; Thu, 26 Jul 2012 05:21:27 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-002.039d.mgd.msft.net (10.84.1.15) with Microsoft SMTP Server (TLS) id 14.2.298.5; Thu, 26 Jul 2012 00:21:25 -0500 Received: from freescale.com ([10.232.15.72]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with SMTP id q6Q5LKdE019450; Wed, 25 Jul 2012 22:21:22 -0700 Received: by freescale.com (sSMTP sendmail emulation); Thu, 26 Jul 2012 10:52:44 +0530 From: Bharat Bhushan To: , , CC: Bharat Bhushan , Bharat Bhushan Subject: [PATCH 2/2] Add guest debug support Date: Thu, 26 Jul 2012 10:52:37 +0530 Message-ID: <1343280157-3077-2-git-send-email-Bharat.Bhushan@freescale.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1343280157-3077-1-git-send-email-Bharat.Bhushan@freescale.com> References: <1343280157-3077-1-git-send-email-Bharat.Bhushan@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com Sender: kvm-ppc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org This patch add support for guest debugging with qemu gdbstub. Now hardware breakpoint and watchpoint can be set/unset. This patch also support for software beakpoint. Signed-off-by: Bharat Bhushan --- hw/ppc/e500.c | 3 + target-ppc/kvm.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 1 + 3 files changed, 246 insertions(+), 0 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index f07be08..83a2972 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -588,5 +588,8 @@ void ppce500_init(PPCE500Params *params) if (kvm_enabled()) { kvmppc_init(); +#ifdef KVM_CAP_SET_GUEST_DEBUG + kvmppc_e500_hw_breakpoint_init(); +#endif } } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index f70e7a6..f980700 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -33,6 +33,7 @@ #include "hw/sysbus.h" #include "hw/spapr.h" #include "hw/watchdog.h" +#include "gdbstub.h" #include "hw/sysbus.h" #include "hw/spapr.h" @@ -805,6 +806,236 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env, uint32_t dcrn, uint32_t dat return 0; } +#ifdef KVM_CAP_SET_GUEST_DEBUG +int kvm_arch_insert_sw_breakpoint(CPUPPCState *env, + struct kvm_sw_breakpoint *bp) +{ + uint32_t sc = tswap32(KVM_INST_GUESTGDB); + + if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || + cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&sc, 4, 1)) { + return -EINVAL; + } + + return 0; +} + +int kvm_arch_remove_sw_breakpoint(CPUPPCState *env, + struct kvm_sw_breakpoint *bp) +{ + uint32_t sc; + + if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&sc, 4, 0) || + sc != tswap32(KVM_INST_GUESTGDB) || + cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { + return -EINVAL; + } + + return 0; +} + +static struct HWBreakpoint { + target_ulong addr; + int type; +} hw_breakpoint[6]; + +static int nb_hw_breakpoint; +static int nb_hw_watchpoint; +static int max_hw_breakpoint = 4; +static int max_hw_watchpoint = 2; + +void kvmppc_e500_hw_breakpoint_init(void) +{ + max_hw_breakpoint = 2; + max_hw_watchpoint = 2; +} + +static int find_hw_breakpoint(target_ulong addr, int type) +{ + int n; + + for (n = 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) { + if (hw_breakpoint[n].addr == addr && hw_breakpoint[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, KVMPPC_DEBUG_WATCH_WRITE); + if (n >= 0) { + *flag = BP_MEM_WRITE; + return n; + } + + n = find_hw_breakpoint(addr, KVMPPC_DEBUG_WATCH_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) +{ + hw_breakpoint[nb_hw_breakpoint + nb_hw_watchpoint].addr = addr; + hw_breakpoint[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_breakpoint[n] = hw_breakpoint[nb_hw_breakpoint + nb_hw_watchpoint]; + + return 0; +} + +void kvm_arch_remove_all_hw_breakpoints(void) +{ + nb_hw_breakpoint = nb_hw_watchpoint = 0; +} + +static CPUWatchpoint hw_watchpoint; + + +static int kvm_handle_debug(struct kvm_debug_exit_arch *arch_info) +{ + int handle = 0; + int n; + int flag = 0; + + if (cpu_single_env->singlestep_enabled) { + handle = 1; + } else if (arch_info->status) { + if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) { + n = find_hw_breakpoint(arch_info->pc, 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->pc, &flag); + if (n >= 0) { + handle = 1; + cpu_single_env->watchpoint_hit = &hw_watchpoint; + hw_watchpoint.vaddr = hw_breakpoint[n].addr; + hw_watchpoint.flags = flag; + } + } + } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) { + handle = 1; + } + + /* XXX inject guest debug exception */ + if (!handle) { + fprintf(stderr, "Unhandled debug exception!\n"); + } + + return handle; +} + +void kvm_arch_update_guest_debug(CPUPPCState *env, struct kvm_guest_debug *dbg) +{ + if (kvm_sw_breakpoints_active(env)) { + dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; + } + + if (nb_hw_breakpoint + nb_hw_watchpoint > 0) { + int n; + + 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_breakpoint[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(env, "Unsupported breakpoint type\n"); + } + dbg->arch.bp[n].addr = hw_breakpoint[n].addr; + } + } +} +#endif /* KVM_CAP_SET_GUEST_DEBUG */ + int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run) { int ret; @@ -838,6 +1069,17 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run) ret = 0; break; #endif +#ifdef KVM_CAP_SET_GUEST_DEBUG + case KVM_EXIT_DEBUG: + dprintf("kvm_exit_debug\n"); + if (kvm_handle_debug(&run->debug.arch)) { + ret = EXCP_DEBUG; + break; + } + /* re-enter, this exception was guest-internal */ + ret = 0; + break; +#endif default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index e2f8703..6e34cf3 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -30,6 +30,7 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); #endif /* !CONFIG_USER_ONLY */ const ppc_def_t *kvmppc_host_cpu_def(void); int kvmppc_fixup_cpu(CPUPPCState *env); +void kvmppc_e500_hw_breakpoint_init(void); #else