Module Name: src Committed By: matt Date: Thu Feb 17 13:53:33 UTC 2011
Modified Files: src/sys/arch/powerpc/booke: booke_machdep.c copyin.c trap.c src/sys/arch/powerpc/include: userret.h src/sys/arch/powerpc/include/booke: cpuvar.h Log Message: add begging of single step support. Since BookE doesn't support PSL_SE, if userret find PSL_SE set in SRR1, it will call booke_sstep to setup the debug registers. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/arch/powerpc/booke/booke_machdep.c cvs rdiff -u -r1.2 -r1.3 src/sys/arch/powerpc/booke/copyin.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/powerpc/booke/trap.c cvs rdiff -u -r1.17 -r1.18 src/sys/arch/powerpc/include/userret.h cvs rdiff -u -r1.4 -r1.5 src/sys/arch/powerpc/include/booke/cpuvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/powerpc/booke/booke_machdep.c diff -u src/sys/arch/powerpc/booke/booke_machdep.c:1.3 src/sys/arch/powerpc/booke/booke_machdep.c:1.4 --- src/sys/arch/powerpc/booke/booke_machdep.c:1.3 Wed Feb 16 18:44:54 2011 +++ src/sys/arch/powerpc/booke/booke_machdep.c Thu Feb 17 13:53:32 2011 @@ -50,7 +50,9 @@ #include <uvm/uvm_extern.h> -#include <powerpc/altivec.h> +#include <powerpc/spr.h> +#include <powerpc/booke/spr.h> +#include <powerpc/booke/cpuvar.h> /* * Global variables used here and there @@ -442,3 +444,37 @@ struct cpu_softc * const cpu = curcpu()->ci_softc; bus_space_write_1(cpu->cpu_bst, cpu->cpu_bsh, a, v); } + +void +booke_sstep(struct trapframe *tf) +{ + KASSERT(tf->tf_srr1 & PSL_DE); + const uint32_t insn = ufetch_32((const void *)tf->tf_srr0); + register_t dbcr0 = DBCR0_IAC1 | DBCR0_IDM; + register_t dbcr1 = DBCR1_IAC1US_USER | DBCR1_IAC1ER_DS1; + if ((insn >> 28) == 4) { + uint32_t iac2 = 0; + if ((insn >> 26) == 0x12) { + const int32_t off = (((int32_t)insn << 6) >> 6) & ~3; + iac2 = ((insn & 2) ? 0 : tf->tf_srr0) + off; + dbcr0 |= DBCR0_IAC2; + } else if ((insn >> 26) == 0x10) { + const int16_t off = insn & ~3; + iac2 = ((insn & 2) ? 0 : tf->tf_srr0) + off; + dbcr0 |= DBCR0_IAC2; + } else if ((insn & 0xfc00ffde) == 0x4c000420) { + iac2 = tf->tf_ctr; + dbcr0 |= DBCR0_IAC2; + } else if ((insn & 0xfc00ffde) == 0x4c000020) { + iac2 = tf->tf_lr; + dbcr0 |= DBCR0_IAC2; + } + if (dbcr0 & DBCR0_IAC2) { + dbcr1 |= DBCR1_IAC2US_USER | DBCR1_IAC2ER_DS1; + mtspr(SPR_IAC2, iac2); + } + } + mtspr(SPR_IAC1, tf->tf_srr0 + 4); + mtspr(SPR_DBCR1, dbcr1); + mtspr(SPR_DBCR0, dbcr0); +} Index: src/sys/arch/powerpc/booke/copyin.c diff -u src/sys/arch/powerpc/booke/copyin.c:1.2 src/sys/arch/powerpc/booke/copyin.c:1.3 --- src/sys/arch/powerpc/booke/copyin.c:1.2 Tue Jan 18 01:02:52 2011 +++ src/sys/arch/powerpc/booke/copyin.c Thu Feb 17 13:53:32 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: copyin.c,v 1.2 2011/01/18 01:02:52 matt Exp $ */ +/* $NetBSD: copyin.c,v 1.3 2011/02/17 13:53:32 matt Exp $ */ /*- * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. @@ -36,13 +36,15 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: copyin.c,v 1.2 2011/01/18 01:02:52 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: copyin.c,v 1.3 2011/02/17 13:53:32 matt Exp $"); #include <sys/param.h> #include <sys/lwp.h> #include <machine/pcb.h> +#include <powerpc/booke/cpuvar.h> + static inline uint8_t copyin_byte(const uint8_t * const usaddr8, register_t ds_msr) { @@ -195,6 +197,24 @@ } } +uint32_t +ufetch_32(const void *vusaddr) +{ + struct pcb * const pcb = lwp_getpcb(curlwp); + struct faultbuf env; + + if (setfault(&env) != 0) { + pcb->pcb_onfault = NULL; + return -1; + } + + uint32_t rv = copyin_word(vusaddr, mfmsr() | PSL_DS); + + pcb->pcb_onfault = NULL; + + return rv; +} + int copyin(const void *vusaddr, void *vkdaddr, size_t len) { Index: src/sys/arch/powerpc/booke/trap.c diff -u src/sys/arch/powerpc/booke/trap.c:1.4 src/sys/arch/powerpc/booke/trap.c:1.5 --- src/sys/arch/powerpc/booke/trap.c:1.4 Tue Feb 8 01:38:48 2011 +++ src/sys/arch/powerpc/booke/trap.c Thu Feb 17 13:53:32 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.4 2011/02/08 01:38:48 matt Exp $ */ +/* $NetBSD: trap.c,v 1.5 2011/02/17 13:53:32 matt Exp $ */ /*- * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -39,7 +39,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.4 2011/02/08 01:38:48 matt Exp $"); +__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.5 2011/02/17 13:53:32 matt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -64,6 +64,7 @@ #include <powerpc/spr.h> #include <powerpc/booke/spr.h> +#include <powerpc/booke/cpuvar.h> #include <powerpc/db_machdep.h> #include <ddb/db_interface.h> @@ -450,7 +451,9 @@ tf->tf_srr0 += 4; return 0; } - } else if (tf->tf_esr & (ESR_PIL|ESR_PPR)) { + } + + if (tf->tf_esr & (ESR_PIL|ESR_PPR)) { if (emulate_opcode(tf, ksi)) { tf->tf_srr0 += 4; return 0; @@ -475,6 +478,41 @@ } static int +debug_exception(struct trapframe *tf, ksiginfo_t *ksi) +{ + struct cpu_info * const ci = curcpu(); + int rv = EPERM; + + if (!usertrap_p(tf)) + return rv; + + ci->ci_ev_debug.ev_count++; + + /* + * Ack the interrupt. + */ + mtspr(SPR_DBSR, tf->tf_esr); + KASSERT(tf->tf_esr & (DBSR_IAC1|DBSR_IAC2)); + KASSERT((tf->tf_srr1 & PSL_SE) == 0); + + /* + * Disable debug events + */ + mtspr(SPR_DBCR1, 0); + mtspr(SPR_DBCR0, 0); + + /* + * Tell the debugger ... + */ + KSI_INIT_TRAP(ksi); + ksi->ksi_signo = SIGTRAP; + ksi->ksi_trap = EXC_TRC; + ksi->ksi_addr = (void *)tf->tf_srr0; + ksi->ksi_code = TRAP_TRACE; + return rv; +} + +static int ali_exception(struct trapframe *tf, ksiginfo_t *ksi) { struct cpu_info * const ci = curcpu(); @@ -578,6 +616,7 @@ } return false; #else +#if 0 struct cpu_info * const ci = curcpu(); struct cpu_softc * const cpu = ci->ci_softc; printf("CPL stack:"); @@ -588,6 +627,7 @@ } printf(" %u\n", ci->ci_cpl); dump_trapframe(tf); +#endif if (kdb_trap(tf->tf_exc, tf)) { tf->tf_srr0 += 4; return true; @@ -713,6 +753,12 @@ rv = itlb_exception(tf, &ksi); break; case T_DEBUG: +#ifdef DDB + if (!usertrap && ddb_exception(tf)) + return; +#endif + rv = debug_exception(tf, &ksi); + break; case T_EMBEDDED_FP_DATA: rv = embedded_fp_data_exception(tf, &ksi); break; Index: src/sys/arch/powerpc/include/userret.h diff -u src/sys/arch/powerpc/include/userret.h:1.17 src/sys/arch/powerpc/include/userret.h:1.18 --- src/sys/arch/powerpc/include/userret.h:1.17 Tue Jan 18 01:02:54 2011 +++ src/sys/arch/powerpc/include/userret.h Thu Feb 17 13:53:32 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: userret.h,v 1.17 2011/01/18 01:02:54 matt Exp $ */ +/* $NetBSD: userret.h,v 1.18 2011/02/17 13:53:32 matt Exp $ */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -31,12 +31,18 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "opt_ppcarch.h" #include "opt_altivec.h" #include <sys/userret.h> #include <powerpc/fpu.h> +#ifdef PPC_BOOKE +#include <powerpc/spr.h> +#include <powerpc/booke/spr.h> +#endif + /* * Define the code needed before returning to user mode, for * trap and syscall. @@ -89,6 +95,18 @@ __asm volatile("dssall;sync"); } #endif +#ifdef PPC_BOOKE + /* + * BookE doesn't PSL_SE but it does have a debug instruction completion + * exception but it needs PSL_DE to fire. Since we don't want it to + * happen in the kernel, we must disable PSL_DE and let it get + * restored by rfi/rfci. + */ + if (__predict_false(tf->tf_srr1 & PSL_SE)) { + extern void booke_sstep(struct trapframe *); /* ugly */ + booke_sstep(tf); + } +#endif #ifdef PPC_HAVE_SPE /* * We need to manually restore PSL_SPV each time we return Index: src/sys/arch/powerpc/include/booke/cpuvar.h diff -u src/sys/arch/powerpc/include/booke/cpuvar.h:1.4 src/sys/arch/powerpc/include/booke/cpuvar.h:1.5 --- src/sys/arch/powerpc/include/booke/cpuvar.h:1.4 Wed Feb 16 18:41:48 2011 +++ src/sys/arch/powerpc/include/booke/cpuvar.h Thu Feb 17 13:53:32 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: cpuvar.h,v 1.4 2011/02/16 18:41:48 matt Exp $ */ +/* $NetBSD: cpuvar.h,v 1.5 2011/02/17 13:53:32 matt Exp $ */ /*- * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -157,6 +157,11 @@ return old_msr; } +uint32_t ufetch_32(const void *); + +struct trapframe; +void booke_sstep(struct trapframe *); + void booke_fixup_stubs(void); void booke_cpu_startup(const char *); /* model name */ struct powerpc_bus_dma_tag booke_bus_dma_tag;