From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Date: Sat, 25 Jul 2009 10:18:56 +0000 Subject: Re: [PATCH 3/5] Add guest debug support for kvmppc Message-Id: <4A6ADC10.2010802@web.de> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------enig1AF7C88054EA0C4E8BE79C7A" List-Id: References: <1248511217-22681-1-git-send-email-yu.liu@freescale.com> <1248511217-22681-2-git-send-email-yu.liu@freescale.com> <1248511217-22681-3-git-send-email-yu.liu@freescale.com> <1248511217-22681-4-git-send-email-yu.liu@freescale.com> In-Reply-To: <1248511217-22681-4-git-send-email-yu.liu@freescale.com> To: Liu Yu-B13201 Cc: kvm-ppc , Nathan Froyd , qemu-devel , Hollis Blanchard This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig1AF7C88054EA0C4E8BE79C7A Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: quoted-printable Liu Yu wrote: > Signed-off-by: Liu Yu > --- > target-ppc/kvm.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++= ++++++++ > 1 files changed, 197 insertions(+), 0 deletions(-) >=20 > 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 > * Hollis Blanchard = > * > + * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserve= d. > + * Yu Liu > + * > * 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 > =20 > #include > +#include > =20 > #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" > =20 > //#define DEBUG_KVM > =20 > @@ -216,3 +221,195 @@ int kvm_arch_handle_exit(CPUState *env, struct kv= m_run *run) > return ret; > } > =20 > +#ifdef KVM_CAP_SET_GUEST_DEBUG > +int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpo= int *bp) > +{ > + uint32_t sc =3D 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_breakpo= int *bp) > +{ > + uint32_t sc; > + > + if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&sc, 4, 0) || > + sc !=3D 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 =3D max_hw_bp > 4? 4 : max_hw_bp; > + max_hw_watchpoint =3D max_hw_wp > 2? 2 : max_hw_wp; > +} > + > +static int find_hw_breakpoint(target_ulong addr, int type) > +{ > + int n; > + > + for (n =3D 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) > + if (hw_breakpoint[n].addr =3D=3D addr && hw_breakpoint[n].type= =3D=3D 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 =3D addr; > + hw_breakpoint[nb_hw_breakpoint + nb_hw_watchpoint].type =3D type; > + > + switch (type) { > + case GDB_BREAKPOINT_HW: > + if (nb_hw_breakpoint >=3D max_hw_breakpoint) > + return -ENOBUFS; > + > + if (find_hw_breakpoint(addr, type) >=3D 0) > + return -EEXIST; > + > + nb_hw_breakpoint++; > + break; > + > + case GDB_WATCHPOINT_WRITE: > + case GDB_WATCHPOINT_ACCESS: > + if (nb_hw_watchpoint >=3D max_hw_watchpoint) > + return -ENOBUFS; > + > + if (find_hw_breakpoint(addr, type) >=3D 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 =3D 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] =3D hw_breakpoint[nb_hw_breakpoint + nb_hw_watchp= oint]; > + > + return 0; > +} > + > +void kvm_arch_remove_all_hw_breakpoints(void) > +{ > + nb_hw_breakpoint =3D nb_hw_watchpoint =3D 0; > +} > + > +static CPUWatchpoint hw_watchpoint; > + > +int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info) > +{ > + int handle =3D 0; > + int n; > + > + if (cpu_single_env->singlestep_enabled) { > + handle =3D 1; > + > + } else if (arch_info->status) { > + if (arch_info->status =3D=3D KVMPPC_DEBUG_BREAKPOINT) { > + n =3D find_hw_breakpoint(arch_info->pc, GDB_BREAKPOINT_HW)= ; > + if (n >=3D 0) > + handle =3D 1; > + > + } else if (arch_info->status =3D=3D KVMPPC_DEBUG_WATCH_ACCESS)= { > + n =3D find_hw_breakpoint(arch_info->pc, GDB_WATCHPOINT_ACC= ESS); > + if (n >=3D 0) { > + handle =3D 1; > + cpu_single_env->watchpoint_hit =3D &hw_watchpoint; > + hw_watchpoint.vaddr =3D hw_breakpoint[n].addr; > + hw_watchpoint.flags =3D BP_MEM_ACCESS; > + } > + > + } else if (arch_info->status =3D=3D KVMPPC_DEBUG_WATCH_WRITE) = { > + n =3D find_hw_breakpoint(arch_info->pc, GDB_WATCHPOINT_WRI= TE); > + if (n >=3D 0) { > + handle =3D 1; > + cpu_single_env->watchpoint_hit =3D &hw_watchpoint; > + hw_watchpoint.vaddr =3D hw_breakpoint[n].addr; > + hw_watchpoint.flags =3D BP_MEM_WRITE; > + } > + } > + > + } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) > + handle =3D 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 |=3D KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP= ; > + > + if (nb_hw_breakpoint + nb_hw_watchpoint > 0) { > + int n; > + > + dbg->control |=3D KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP= ; > + memset(dbg->arch.bp, 0, sizeof(dbg->arch.bp)); > + for (n =3D 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) { > + switch (hw_breakpoint[n].type) { > + case GDB_BREAKPOINT_HW: > + dbg->arch.bp[n].type =3D KVMPPC_DEBUG_BREAKPOINT; > + break; > + case GDB_WATCHPOINT_ACCESS: > + dbg->arch.bp[n].type =3D KVMPPC_DEBUG_WATCH_ACCESS; > + break; > + case GDB_WATCHPOINT_WRITE: > + dbg->arch.bp[n].type =3D KVMPPC_DEBUG_WATCH_WRITE; > + break; > + default: > + printf("Unsupported breakpoint type\n"); > + exit(-1); > + } > + dbg->arch.bp[n].addr =3D 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 --------------enig1AF7C88054EA0C4E8BE79C7A Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkpq3BUACgkQniDOoMHTA+mzmACfVXW7f6A8xftoKzSlE6by9av6 mVwAn3j/xUN02HcEoC2RoC//Wfs7Dvem =36Vg -----END PGP SIGNATURE----- --------------enig1AF7C88054EA0C4E8BE79C7A--