qemu-devel
[Top][All Lists]
Advanced

[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

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]