[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH 3/5] Add guest debug support for kvmppc
From: |
Jan Kiszka |
Subject: |
[Qemu-devel] Re: [PATCH 3/5] Add guest debug support for kvmppc |
Date: |
Sat, 25 Jul 2009 12:18:56 +0200 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 |
Liu Yu wrote:
> Signed-off-by: Liu Yu <address@hidden>
> ---
> target-ppc/kvm.c | 197
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 197 insertions(+), 0 deletions(-)
>
> diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
> index b53d6e9..d8dbdb4 100644
> --- a/target-ppc/kvm.c
> +++ b/target-ppc/kvm.c
> @@ -8,6 +8,9 @@
> * Christian Ehrhardt <address@hidden>
> * Hollis Blanchard <hollisb-r/address@hidden>
> *
> + * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
> + * Yu Liu <address@hidden>
> + *
> * This work is licensed under the terms of the GNU GPL, version 2 or later.
> * See the COPYING file in the top-level directory.
> *
> @@ -18,6 +21,7 @@
> #include <sys/mman.h>
>
> #include <linux/kvm.h>
> +#include <asm/kvm_asm.h>
>
> #include "qemu-common.h"
> #include "qemu-timer.h"
> @@ -26,6 +30,7 @@
> #include "kvm_ppc.h"
> #include "cpu.h"
> #include "device_tree.h"
> +#include "gdbstub.h"
>
> //#define DEBUG_KVM
>
> @@ -216,3 +221,195 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run
> *run)
> return ret;
> }
>
> +#ifdef KVM_CAP_SET_GUEST_DEBUG
> +int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint
> *bp)
> +{
> + uint32_t sc = tswap32(KVM_INST_GUESTGDB);
> + uint32_t tmp;
> +
> + 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;
> + cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&tmp, 4, 0);
> + return 0;
> +}
> +
> +int kvm_arch_remove_sw_breakpoint(CPUState *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 {
> + target_ulong addr;
> + int type;
> +} hw_breakpoint[6];
> +
> +static int nb_hw_breakpoint;
> +static int nb_hw_watchpoint;
> +static int max_hw_breakpoint;
> +static int max_hw_watchpoint;
> +
> +void kvmppc_debug_init(int max_hw_bp, int max_hw_wp)
> +{
> + max_hw_breakpoint = max_hw_bp > 4? 4 : max_hw_bp;
> + max_hw_watchpoint = max_hw_wp > 2? 2 : max_hw_wp;
> +}
> +
> +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;
> +}
> +
> +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_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_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;
> +
> +int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
> +{
> + int handle = 0;
> + int n;
> +
> + 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_ACCESS) {
> + n = find_hw_breakpoint(arch_info->pc, GDB_WATCHPOINT_ACCESS);
> + if (n >= 0) {
> + handle = 1;
> + cpu_single_env->watchpoint_hit = &hw_watchpoint;
> + hw_watchpoint.vaddr = hw_breakpoint[n].addr;
> + hw_watchpoint.flags = BP_MEM_ACCESS;
> + }
> +
> + } else if (arch_info->status == KVMPPC_DEBUG_WATCH_WRITE) {
> + n = find_hw_breakpoint(arch_info->pc, GDB_WATCHPOINT_WRITE);
> + if (n >= 0) {
> + handle = 1;
> + cpu_single_env->watchpoint_hit = &hw_watchpoint;
> + hw_watchpoint.vaddr = hw_breakpoint[n].addr;
> + hw_watchpoint.flags = BP_MEM_WRITE;
> + }
> + }
> +
> + } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc))
> + handle = 1;
> +
> + /* XXX inject guest debug exception */
> + if (!handle)
> + printf("Unhandled debug exception!\n");
Out of curiosity: Not yet implemented here, or is PPC also lacking some
kernel bits to support it?
> +
> + return handle;
> +}
> +
> +void kvm_arch_update_guest_debug(CPUState *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_ACCESS:
> + dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_ACCESS;
> + break;
> + case GDB_WATCHPOINT_WRITE:
> + dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_WRITE;
> + break;
> + default:
> + printf("Unsupported breakpoint type\n");
> + exit(-1);
> + }
> + dbg->arch.bp[n].addr = hw_breakpoint[n].addr;
> + }
> + }
> +}
> +#endif /* KVM_CAP_SET_GUEST_DEBUG */
Looks fine. Just a style remark: My x86 code does not follow QEMU's
coding style /wrt code block braces, but this should not prevent you
from applying it to yours. :)
Jan
signature.asc
Description: OpenPGP digital signature
[Qemu-devel] Re: [PATCH 0/5], Jan Kiszka, 2009/07/25
[Qemu-devel] Re: [PATCH 0/5], Nathan Froyd, 2009/07/27