Module Name:    src
Committed By:   rin
Date:           Sat Mar  6 08:08:19 UTC 2021

Modified Files:
        src/sys/arch/powerpc/booke: trap.c
        src/sys/arch/powerpc/ibm4xx: ibm4xx_machdep.c trap.c
        src/sys/arch/powerpc/include: proc.h psl.h ptrace.h
        src/sys/arch/powerpc/powerpc: locore_subr.S powerpc_machdep.c
            process_machdep.c

Log Message:
For booke and ibm4xx, switch to software-based single-stepping for PT_STEP
ptrace(2) command from broken hardware-based implementation.

As described in proposal on port-powerpc@,

http://mail-index.netbsd.org/port-powerpc/2021/02/26/msg003597.html

hardware debug facilities of booke and 4xx use critical interrupts, that
are difficult to handle for this purpose; they are not automatically masked
when entering kernel mode via system call trap or hardware interrupt.
See my proposal above for more details.

Now, hardware debug facilities are exclusively usable by kernel itself.
They are much more functional than PSL_SE MSR bit of oea, and should be
useful to, e.g., support byte-granular watchpoint for DDB in the future.


To generate a diff of this commit:
cvs rdiff -u -r1.36 -r1.37 src/sys/arch/powerpc/booke/trap.c
cvs rdiff -u -r1.34 -r1.35 src/sys/arch/powerpc/ibm4xx/ibm4xx_machdep.c
cvs rdiff -u -r1.85 -r1.86 src/sys/arch/powerpc/ibm4xx/trap.c
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/powerpc/include/proc.h
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/powerpc/include/psl.h
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/powerpc/include/ptrace.h
cvs rdiff -u -r1.63 -r1.64 src/sys/arch/powerpc/powerpc/locore_subr.S
cvs rdiff -u -r1.80 -r1.81 src/sys/arch/powerpc/powerpc/powerpc_machdep.c
cvs rdiff -u -r1.41 -r1.42 src/sys/arch/powerpc/powerpc/process_machdep.c

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/trap.c
diff -u src/sys/arch/powerpc/booke/trap.c:1.36 src/sys/arch/powerpc/booke/trap.c:1.37
--- src/sys/arch/powerpc/booke/trap.c:1.36	Wed Jan  6 08:04:57 2021
+++ src/sys/arch/powerpc/booke/trap.c	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.36 2021/01/06 08:04:57 rin Exp $	*/
+/*	$NetBSD: trap.c,v 1.37 2021/03/06 08:08:19 rin Exp $	*/
 /*-
  * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.36 2021/01/06 08:04:57 rin Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.37 2021/03/06 08:08:19 rin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_altivec.h"
@@ -47,6 +47,7 @@ __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.3
 #include <sys/kauth.h>
 #include <sys/lwp.h>
 #include <sys/proc.h>
+#include <sys/ptrace.h>
 #include <sys/ras.h>
 #include <sys/siginfo.h>
 #include <sys/systm.h>
@@ -461,11 +462,31 @@ pgm_exception(struct trapframe *tf, ksig
 
 	ci->ci_ev_pgm.ev_count++;
 
+	KSI_INIT_TRAP(ksi);
+
 	if (tf->tf_esr & ESR_PTR) {
-		struct proc *p = curlwp->l_proc;
-		if (p->p_raslist != NULL
-		    && ras_lookup(p, (void *)tf->tf_srr0) != (void *) -1) {
-			tf->tf_srr0 += 4;
+		struct lwp * const l = curlwp;
+		struct proc * const p = curlwp->l_proc;
+		vaddr_t va = (vaddr_t)tf->tf_srr0;
+		int error;
+
+		/*
+		 * Restore original instruction and clear BP.
+		 */
+		if (p->p_md.md_ss_addr[0] == va ||
+		    p->p_md.md_ss_addr[1] == va) {
+			error = ppc_sstep(l, 0);
+			if (error != 0) {
+				vm_signal(error, EXC_PGM /* XXX */, va, ksi);
+				return error;
+			}
+			ksi->ksi_code = TRAP_TRACE;
+		} else
+			ksi->ksi_code = TRAP_BRKPT;
+
+		if (p->p_raslist != NULL &&
+		    ras_lookup(p, (void *)va) != (void *)-1) {
+			tf->tf_srr0 += (ksi->ksi_code == TRAP_TRACE) ? 0 : 4;
 			return 0;
 		}
 	}
@@ -494,7 +515,6 @@ pgm_exception(struct trapframe *tf, ksig
 		}
 	}
 
-	KSI_INIT_TRAP(ksi);
 	ksi->ksi_signo = SIGILL;
 	ksi->ksi_trap = EXC_PGM;
 	if (tf->tf_esr & ESR_PIL) {
@@ -503,7 +523,6 @@ pgm_exception(struct trapframe *tf, ksig
 		ksi->ksi_code = ILL_PRVOPC;
 	} else if (tf->tf_esr & ESR_PTR) {
 		ksi->ksi_signo = SIGTRAP;
-		ksi->ksi_code = TRAP_BRKPT;
 	} else {
 		ksi->ksi_code = 0;
 	}
@@ -511,6 +530,7 @@ pgm_exception(struct trapframe *tf, ksig
 	return rv;
 }
 
+#if 0
 static int
 debug_exception(struct trapframe *tf, ksiginfo_t *ksi)
 {
@@ -545,6 +565,7 @@ debug_exception(struct trapframe *tf, ks
 	ksi->ksi_code = TRAP_TRACE;
 	return rv;
 }
+#endif
 
 static int
 ali_exception(struct trapframe *tf, ksiginfo_t *ksi)
@@ -752,6 +773,7 @@ trap(enum ppc_booke_exceptions trap_code
 	switch (trap_code) {
 	case T_CRITIAL_INPUT:
 	case T_EXTERNAL_INPUT:
+	case T_DEBUG:
 	case T_DECREMENTER:
 	case T_FIXED_INTERVAL:
 	case T_WATCHDOG:
@@ -791,6 +813,7 @@ trap(enum ppc_booke_exceptions trap_code
 	case T_INSTRUCTION_TLB_ERROR:
 		rv = itlb_exception(tf, &ksi);
 		break;
+#if 0
 	case T_DEBUG:
 #ifdef DDB
 		if (!usertrap && ddb_exception(tf))
@@ -798,6 +821,7 @@ trap(enum ppc_booke_exceptions trap_code
 #endif
 		rv = debug_exception(tf, &ksi);
 		break;
+#endif
 	case T_EMBEDDED_FP_DATA:
 		rv = embedded_fp_data_exception(tf, &ksi);
 		break;

Index: src/sys/arch/powerpc/ibm4xx/ibm4xx_machdep.c
diff -u src/sys/arch/powerpc/ibm4xx/ibm4xx_machdep.c:1.34 src/sys/arch/powerpc/ibm4xx/ibm4xx_machdep.c:1.35
--- src/sys/arch/powerpc/ibm4xx/ibm4xx_machdep.c:1.34	Mon Jan 18 02:43:27 2021
+++ src/sys/arch/powerpc/ibm4xx/ibm4xx_machdep.c	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: ibm4xx_machdep.c,v 1.34 2021/01/18 02:43:27 rin Exp $	*/
+/*	$NetBSD: ibm4xx_machdep.c,v 1.35 2021/03/06 08:08:19 rin Exp $	*/
 /*	Original: ibm40x_machdep.c,v 1.3 2005/01/17 17:19:36 shige Exp $ */
 
 /*
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ibm4xx_machdep.c,v 1.34 2021/01/18 02:43:27 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ibm4xx_machdep.c,v 1.35 2021/03/06 08:08:19 rin Exp $");
 
 #include "ksyms.h"
 
@@ -148,6 +148,8 @@ static const struct exc_info trap_table[
 			errata51handler, (uintptr_t)&errata51size },
 #if defined(DDB)
 	{ EXC_PGM,	ddblow,		(uintptr_t)&ddbsize },
+#else
+	{ EXC_PGM,	accesstrap,	(uintptr_t)&accesssize },
 #endif
 };
 

Index: src/sys/arch/powerpc/ibm4xx/trap.c
diff -u src/sys/arch/powerpc/ibm4xx/trap.c:1.85 src/sys/arch/powerpc/ibm4xx/trap.c:1.86
--- src/sys/arch/powerpc/ibm4xx/trap.c:1.85	Wed Jul 15 09:10:14 2020
+++ src/sys/arch/powerpc/ibm4xx/trap.c	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.85 2020/07/15 09:10:14 rin Exp $	*/
+/*	$NetBSD: trap.c,v 1.86 2021/03/06 08:08:19 rin Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -69,7 +69,7 @@
 #define	__UFETCHSTORE_PRIVATE
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.85 2020/07/15 09:10:14 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.86 2021/03/06 08:08:19 rin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -81,6 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.8
 #include <sys/cpu.h>
 #include <sys/kauth.h>
 #include <sys/proc.h>
+#include <sys/ptrace.h>
 #include <sys/reboot.h>
 #include <sys/syscall.h>
 #include <sys/systm.h>
@@ -157,20 +158,10 @@ trap(struct trapframe *tf)
 
 	switch (type) {
 	case EXC_DEBUG|EXC_USER:
-		{
-			int srr2, srr3;
+		/* We don't use hardware breakpoints for userland. */
+		goto brain_damage;
 
-			__asm volatile("mfspr %0,0x3f0" :
-			    "=r" (rv), "=r" (srr2), "=r" (srr3) :);
-			printf("debug reg is %x srr2 %x srr3 %x\n", rv, srr2,
-			    srr3);
-			/* XXX fall through or break here?! */
-		}
-		/*
-		 * DEBUG intr -- probably single-step.
-		 */
 	case EXC_TRC|EXC_USER:
-		tf->tf_srr1 &= ~PSL_SE;
 		KSI_INIT_TRAP(&ksi);
 		ksi.ksi_signo = SIGTRAP;
 		ksi.ksi_trap = EXC_TRC;
@@ -317,13 +308,26 @@ isi:
 		ksi.ksi_addr = (void *)tf->tf_srr0;
 
 		if (tf->tf_esr & ESR_PTR) {
+			vaddr_t va;
 sigtrap:
+			va = (vaddr_t)tf->tf_srr0;
+			/*
+		 	 * Restore original instruction and clear BP.
+		 	 */
+			if (p->p_md.md_ss_addr[0] == va ||
+			    p->p_md.md_ss_addr[1] == va) {
+				rv = ppc_sstep(l, 0);
+				if (rv != 0)
+					goto vm_signal;
+				ksi.ksi_code = TRAP_TRACE;
+			} else
+				ksi.ksi_code = TRAP_BRKPT;
 			if (p->p_raslist != NULL &&
-			    ras_lookup(p, (void *)tf->tf_srr0) != (void *) -1) {
-				tf->tf_srr1 += 4;
+			    ras_lookup(p, (void *)va) != (void *)-1) {
+				tf->tf_srr0 += (ksi.ksi_code == TRAP_TRACE) ?
+				    0 : 4;
 				break;
 			}
-			ksi.ksi_code = TRAP_BRKPT;
 			ksi.ksi_signo = SIGTRAP;
 		} else if (tf->tf_esr & ESR_PPR) {
 			uint32_t opcode;
@@ -411,20 +415,6 @@ ctx_setup(int ctx, int srr1)
 			ctx_alloc(__UNVOLATILE(pm));
 		}
 		ctx = pm->pm_ctx;
-		if (srr1 & PSL_SE) {
-			int dbreg, mask = 0x48000000;
-				/*
-				 * Set the Internal Debug and
-				 * Instruction Completion bits of
-				 * the DBCR0 register.
-				 *
-				 * XXX this is also used by jtag debuggers...
-				 */
-			__asm volatile("mfspr %0,0x3f2;"
-			    "or %0,%0,%1;"
-			    "mtspr 0x3f2,%0;" :
-			    "=&r" (dbreg) : "r" (mask));
-		}
 	}
 	else if (!ctx) {
 		ctx = KERNEL_PID;

Index: src/sys/arch/powerpc/include/proc.h
diff -u src/sys/arch/powerpc/include/proc.h:1.13 src/sys/arch/powerpc/include/proc.h:1.14
--- src/sys/arch/powerpc/include/proc.h:1.13	Fri Aug 23 06:19:46 2013
+++ src/sys/arch/powerpc/include/proc.h	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: proc.h,v 1.13 2013/08/23 06:19:46 matt Exp $	*/
+/*	$NetBSD: proc.h,v 1.14 2021/03/06 08:08:19 rin Exp $	*/
 
 /*-
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -34,6 +34,11 @@
 #ifndef _POWERPC_PROC_H_
 #define _POWERPC_PROC_H_
 
+#ifdef _KERNEL_OPT
+#include "opt_modular.h"
+#include "opt_ppcarch.h"
+#endif
+
 /*
  * Machine-dependent part of the lwp structure
  */
@@ -47,6 +52,11 @@ struct trapframe;
 
 struct mdproc {
 	void (*md_syscall)(struct trapframe *);
+#if defined(PPC_BOOKE) || defined(PPC_IBM4XX) || \
+    defined(MODULAR) || defined(_MODULE)
+	vaddr_t md_ss_addr[2];
+	uint32_t md_ss_insn[2];
+#endif
 };
 
 #ifdef _KERNEL

Index: src/sys/arch/powerpc/include/psl.h
diff -u src/sys/arch/powerpc/include/psl.h:1.21 src/sys/arch/powerpc/include/psl.h:1.22
--- src/sys/arch/powerpc/include/psl.h:1.21	Mon Jul  6 09:34:17 2020
+++ src/sys/arch/powerpc/include/psl.h	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: psl.h,v 1.21 2020/07/06 09:34:17 rin Exp $	*/
+/*	$NetBSD: psl.h,v 1.22 2021/03/06 08:08:19 rin Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -111,7 +111,7 @@ extern register_t cpu_psluserset, cpu_ps
 #define	PSL_USERMOD		cpu_pslusermod
 #define	PSL_USERMASK		cpu_pslusermask
 #elif defined(PPC_BOOKE)
-#define	PSL_USERSET		(PSL_EE | PSL_PR | PSL_IS | PSL_DS | PSL_ME | PSL_CE | PSL_DE)
+#define	PSL_USERSET		(PSL_EE | PSL_PR | PSL_IS | PSL_DS | PSL_ME | PSL_CE)
 #define	PSL_USERMASK		(PSL_SPV | PSL_CE | 0xFFFF)
 #define	PSL_USERMOD		(0)
 #else /* PPC_IBM4XX */
@@ -122,14 +122,7 @@ extern register_t cpu_psluserset, cpu_ps
 #endif
 #define	PSL_USERMASK		0xFFFF
 #define	PSL_USERMOD		(0)
-/* 
- * We also need to override the PSL_SE bit.  4xx have completely different
- * debug register support.  The SE bit is actually the DWE bit.  We want to
- * set the DE bit to enable the debug regs instead of the DWE bit.
- */
-#undef	PSL_SE
-#define	PSL_SE			PSL_DE
-#endif /* PPC_OEA */
+#endif
 
 #define	PSL_USERSRR1		((PSL_USERSET|PSL_USERMOD) & PSL_USERMASK)
 #define	PSL_USEROK_P(psl)	(((psl) & ~PSL_USERMOD) == PSL_USERSET)

Index: src/sys/arch/powerpc/include/ptrace.h
diff -u src/sys/arch/powerpc/include/ptrace.h:1.18 src/sys/arch/powerpc/include/ptrace.h:1.19
--- src/sys/arch/powerpc/include/ptrace.h:1.18	Thu Oct 15 17:37:35 2020
+++ src/sys/arch/powerpc/include/ptrace.h	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.18 2020/10/15 17:37:35 mgorny Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.19 2021/03/06 08:08:19 rin Exp $	*/
 
 #ifndef _POWERPC_PTRACE_H
 #define	_POWERPC_PTRACE_H
@@ -69,6 +69,10 @@ int procfs_machdep_dovecregs(struct lwp 
 int procfs_machdep_validvecregs(struct lwp *, struct mount *);
 
 #endif /* ALTIVEC || PPC_HAVE_SPE */
+
+#if defined(PPC_BOOKE) || defined(PPC_IBM4XX)
+int ppc_sstep(struct lwp *, int);
+#endif /* PPC_BOOKE || PPC_IBM4XX */
 #endif /* _KERNEL */
 
 #define PTRACE_ILLEGAL_ASM	__asm __volatile (".long 0" : : : "memory")

Index: src/sys/arch/powerpc/powerpc/locore_subr.S
diff -u src/sys/arch/powerpc/powerpc/locore_subr.S:1.63 src/sys/arch/powerpc/powerpc/locore_subr.S:1.64
--- src/sys/arch/powerpc/powerpc/locore_subr.S:1.63	Mon Jul  6 11:06:52 2020
+++ src/sys/arch/powerpc/powerpc/locore_subr.S	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: locore_subr.S,v 1.63 2020/07/06 11:06:52 rin Exp $	*/
+/*	$NetBSD: locore_subr.S,v 1.64 2021/03/06 08:08:19 rin Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -175,9 +175,6 @@ ENTRY(cpu_switchto)
 	mfmsr	%r0
 	andis.	%r0,%r0,PSL_CE@h
 	tweqi	%r0,0	
-	mfmsr	%r0
-	andi.	%r0,%r0,PSL_DE@l
-	tweqi	%r0,0	
 #endif
 
 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
@@ -510,8 +507,6 @@ _ENTRY(cpu_lwp_bootstrap)
 	ori	%r30, %r30, 0xbeeffeed@l
 	andis.	%r0,%r31,PSL_CE@h
 	tweqi	%r0,0
-	andi.	%r0,%r31,PSL_DE@l
-	tweqi	%r0,0
 #endif
 	li	%r4, 1			/* make sure userret gets called */
 	stint	%r4, L_MD_ASTPENDING(%r13)

Index: src/sys/arch/powerpc/powerpc/powerpc_machdep.c
diff -u src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.80 src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.81
--- src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.80	Wed Jul 15 08:58:52 2020
+++ src/sys/arch/powerpc/powerpc/powerpc_machdep.c	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: powerpc_machdep.c,v 1.80 2020/07/15 08:58:52 rin Exp $	*/
+/*	$NetBSD: powerpc_machdep.c,v 1.81 2021/03/06 08:08:19 rin Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.80 2020/07/15 08:58:52 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.81 2021/03/06 08:08:19 rin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_altivec.h"
@@ -160,6 +160,11 @@ setregs(struct lwp *l, struct exec_packa
 	tf->tf_vrsave = 0;
 #endif
 	pcb->pcb_flags = PSL_FE_DFLT;
+
+#if defined(PPC_BOOKE) || defined(PPC_IBM4XX)
+	p->p_md.md_ss_addr[0] = p->p_md.md_ss_addr[1] = 0;
+	p->p_md.md_ss_insn[0] = p->p_md.md_ss_insn[1] = 0;
+#endif
 }
 
 /*

Index: src/sys/arch/powerpc/powerpc/process_machdep.c
diff -u src/sys/arch/powerpc/powerpc/process_machdep.c:1.41 src/sys/arch/powerpc/powerpc/process_machdep.c:1.42
--- src/sys/arch/powerpc/powerpc/process_machdep.c:1.41	Thu Oct 15 18:57:16 2020
+++ src/sys/arch/powerpc/powerpc/process_machdep.c	Sat Mar  6 08:08:19 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: process_machdep.c,v 1.41 2020/10/15 18:57:16 martin Exp $	*/
+/*	$NetBSD: process_machdep.c,v 1.42 2021/03/06 08:08:19 rin Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,10 +32,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.41 2020/10/15 18:57:16 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.42 2021/03/06 08:08:19 rin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_altivec.h"
+#include "opt_ppcarch.h"
 #endif
 
 #include <sys/param.h>
@@ -132,6 +133,7 @@ process_set_pc(struct lwp *l, void *addr
 int
 process_sstep(struct lwp *l, int sstep)
 {
+#if !defined(PPC_BOOKE) && !defined(PPC_IBM4XX)
 	struct trapframe * const tf = l->l_md.md_utf;
 	
 	if (sstep) {
@@ -142,6 +144,12 @@ process_sstep(struct lwp *l, int sstep)
 		l->l_md.md_flags &= ~PSL_SE;
 	}
 	return 0;
+#else
+/*
+ * We use the software single-stepping for booke/ibm4xx.
+ */
+	return ppc_sstep(l, sstep);
+#endif
 }
 
 
@@ -274,3 +282,127 @@ process_machdep_validvecregs(struct proc
 #endif
 }
 #endif /* __HAVE_PTRACE_MACHDEP */
+
+#if defined(PPC_BOOKE) || defined(PPC_IBM4XX)
+/*
+ * ppc_ifetch and ppc_istore:
+ * fetch/store instructions from/to given process (therefore, we cannot use
+ * ufetch/ustore(9) here).
+ */
+
+static int
+ppc_ifetch(struct lwp *l, vaddr_t va, uint32_t *insn)
+{
+	struct uio uio;
+	struct iovec iov;
+
+	iov.iov_base = insn;
+	iov.iov_len = sizeof(*insn);
+	uio.uio_iov = &iov;
+	uio.uio_iovcnt = 1;
+	uio.uio_offset = (off_t)va;
+	uio.uio_resid = sizeof(*insn);
+	uio.uio_rw = UIO_READ;
+	UIO_SETUP_SYSSPACE(&uio);
+
+	return process_domem(curlwp, l, &uio);
+}
+
+static int
+ppc_istore(struct lwp *l, vaddr_t va, uint32_t insn)
+{
+	struct uio uio;
+	struct iovec iov;
+
+	iov.iov_base = &insn;
+	iov.iov_len = sizeof(insn);
+	uio.uio_iov = &iov;
+	uio.uio_iovcnt = 1;
+	uio.uio_offset = (off_t)va;
+	uio.uio_resid = sizeof(insn);
+	uio.uio_rw = UIO_WRITE;
+	UIO_SETUP_SYSSPACE(&uio);
+
+	return process_domem(curlwp, l, &uio);
+}
+
+/*
+ * Insert or remove single-step breakpoints:
+ * We need two breakpoints, in general, at (SRR0 + 4) and the address to
+ * which the process can branch into.
+ */
+
+int
+ppc_sstep(struct lwp *l, int step)
+{
+	struct trapframe * const tf = l->l_md.md_utf;
+	struct proc * const p = l->l_proc;
+	const uint32_t trap = 0x7d821008;	/* twge %r2, %r2 */
+	uint32_t insn;
+	vaddr_t va[2];
+	int i, rv;
+
+	if (step) {
+		if (p->p_md.md_ss_addr[0] != 0)
+			return 0; /* XXX Should we reset breakpoints? */
+
+		va[0] = (vaddr_t)tf->tf_srr0;
+		va[1] = 0;
+
+		/*
+		 * Find the address to which the process can branch into.
+		 */
+		if ((rv = ppc_ifetch(l, va[0], &insn)) != 0)
+			return rv;
+		if ((insn >> 28) == 4) {
+			if ((insn >> 26) == 0x12) {
+				const int32_t off =
+				    ((int32_t)(insn << 6) >> 6) & ~3;
+				va[1] = ((insn & 2) ? 0 : va[0]) + off;
+			} else if ((insn >> 26) == 0x10) {
+				const int16_t off = (int16_t)insn & ~3;
+				va[1] = ((insn & 2) ? 0 : va[0]) + off;
+			} else if ((insn & 0xfc00fffe) == 0x4c000420)
+				va[1] = tf->tf_ctr;
+			  else if ((insn & 0xfc00fffe) == 0x4c000020)
+				va[1] = tf->tf_lr;
+		}
+		va[0] += sizeof(insn);
+		if (va[1] == va[0])
+			va[1] = 0;
+
+		for (i = 0; i < 2; i++) {
+			if (va[i] == 0)
+				return 0;
+			if ((rv = ppc_ifetch(l, va[i], &insn)) != 0)
+				goto error;
+			p->p_md.md_ss_insn[i] = insn;
+			if ((rv = ppc_istore(l, va[i], trap)) != 0) {
+error:				/* Recover as far as possible. */
+				if (i == 1 && ppc_istore(l, va[0],
+				    p->p_md.md_ss_insn[0]) == 0)
+					p->p_md.md_ss_addr[0] = 0;
+				return rv;
+			}
+			p->p_md.md_ss_addr[i] = va[i];
+		}
+	} else {
+		for (i = 0; i < 2; i++) {
+			va[i] = p->p_md.md_ss_addr[i];
+			if (va[i] == 0)
+				return 0;
+			if ((rv = ppc_ifetch(l, va[i], &insn)) != 0)
+				return rv;
+			if (insn != trap) {
+				panic("%s: ss_insn[%d] = 0x%x != trap",
+				    __func__, i, insn);
+			}
+			if ((rv = ppc_istore(l, va[i], p->p_md.md_ss_insn[i]))
+			    != 0)
+				return rv;
+			p->p_md.md_ss_addr[i] = 0;
+		}
+	}
+	return 0;
+}
+#endif /* PPC_BOOKE || PPC_IBM4XX */

Reply via email to