Module Name:    src
Committed By:   macallan
Date:           Mon Mar  3 15:36:36 UTC 2014

Modified Files:
        src/sys/arch/powerpc/include: cpu.h trap.h
        src/sys/arch/powerpc/oea: oea_machdep.c ofwoea_machdep.c pmap.c
        src/sys/arch/powerpc/powerpc: clock.c fixup.c trap.c

Log Message:
support ppc601
from scole_mail, ok matt@


To generate a diff of this commit:
cvs rdiff -u -r1.98 -r1.99 src/sys/arch/powerpc/include/cpu.h
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/powerpc/include/trap.h
cvs rdiff -u -r1.69 -r1.70 src/sys/arch/powerpc/oea/oea_machdep.c
cvs rdiff -u -r1.36 -r1.37 src/sys/arch/powerpc/oea/ofwoea_machdep.c
cvs rdiff -u -r1.90 -r1.91 src/sys/arch/powerpc/oea/pmap.c
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/powerpc/powerpc/clock.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/powerpc/powerpc/fixup.c
cvs rdiff -u -r1.148 -r1.149 src/sys/arch/powerpc/powerpc/trap.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/include/cpu.h
diff -u src/sys/arch/powerpc/include/cpu.h:1.98 src/sys/arch/powerpc/include/cpu.h:1.99
--- src/sys/arch/powerpc/include/cpu.h:1.98	Fri Nov  8 03:59:35 2013
+++ src/sys/arch/powerpc/include/cpu.h	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.h,v 1.98 2013/11/08 03:59:35 nisimura Exp $	*/
+/*	$NetBSD: cpu.h,v 1.99 2014/03/03 15:36:36 macallan Exp $	*/
 
 /*
  * Copyright (C) 1999 Wolfgang Solfrank.
@@ -316,6 +316,26 @@ mfrtc(uint32_t *rtcp)
 	    : [rtcu] "=r"(rtcp[0]), [rtcl] "=r"(rtcp[1]), [tmp] "=r"(tmp)
 	    :: "cr0");
 }
+
+static __inline uint64_t
+rtc_nanosecs(void)
+{
+    /* 
+     * 601 RTC/DEC registers share clock of 7.8125 MHz, 128 ns per tick.
+     * DEC has max of 25 bits, FFFFFF => 2.14748352 seconds.
+     * RTCU is seconds, 32 bits.
+     * RTCL is nano-seconds, 23 bit counter from 0 - 999,999,872 (999,999,999 - 128 ns)
+     */
+    uint64_t cycles;
+    uint32_t tmp[2];
+
+    mfrtc(tmp);
+
+    cycles = tmp[0] * 1000000000;
+    cycles += (tmp[1] >> 7);
+
+    return cycles;
+}
 #endif /* !_MODULE */
 
 static __inline uint32_t

Index: src/sys/arch/powerpc/include/trap.h
diff -u src/sys/arch/powerpc/include/trap.h:1.12 src/sys/arch/powerpc/include/trap.h:1.13
--- src/sys/arch/powerpc/include/trap.h:1.12	Wed Jul 18 16:44:52 2012
+++ src/sys/arch/powerpc/include/trap.h	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.h,v 1.12 2012/07/18 16:44:52 matt Exp $	*/
+/*	$NetBSD: trap.h,v 1.13 2014/03/03 15:36:36 macallan Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -47,7 +47,8 @@
 #define	EXC_TRC		0x0d00		/* Trace */
 #define	EXC_FPA		0x0e00		/* Floating-point Assist */
 
-/* The following is only available on the 601: */
+/* The following are only available on the 601: */
+#define EXC_IOC         0x0a00          /* I/O Controller Interface Exception */
 #define	EXC_RUNMODETRC	0x2000		/* Run Mode/Trace Exception */
 
 /* The following are only available on 7400(G4): */
@@ -112,12 +113,78 @@
  */
 
 #define EXC_ALI_OPCODE_INDICATOR(dsisr) ((dsisr >> 10) & 0x7f)
+
+#define EXC_ALI_LWARX_LWZ  0x00
+#define EXC_ALI_LDARX      0x01
+#define EXC_ALI_STW        0x02
+#define EXC_ALI_LHZ        0x04
+#define EXC_ALI_LHA        0x05
+#define EXC_ALI_STH        0x06
+#define EXC_ALI_LMW        0x07
+#define EXC_ALI_LFS        0x08
 #define EXC_ALI_LFD	0x09
+#define EXC_ALI_STFS       0x0a
 #define EXC_ALI_STFD	0x0b
+#define EXC_ALI_LD_LDU_LWA 0x0d
+#define EXC_ALI_STD_STDU   0x0f
+#define EXC_ALI_LWZU       0x10
+#define EXC_ALI_STWU       0x12
+#define EXC_ALI_LHZU       0x14
+#define EXC_ALI_LHAU       0x15
+#define EXC_ALI_STHU       0x16
+#define EXC_ALI_STMW       0x17
+#define EXC_ALI_LFSU       0x18
+#define EXC_ALI_LFDU       0x19
+#define EXC_ALI_STFSU      0x1a
+#define EXC_ALI_STFDU      0x1b
+#define EXC_ALI_LDX        0x20
+#define EXC_ALI_STDX       0x22
+#define EXC_ALI_LWAX       0x25
+#define EXC_ALI_LSWX       0x28
+#define EXC_ALI_LSWI       0x29
+#define EXC_ALI_STSWX      0x2a
+#define EXC_ALI_STSWI      0x2b
+#define EXC_ALI_LDUX       0x30
+#define EXC_ALI_STDUX      0x32
+#define EXC_ALI_LWAUX      0x35
+#define EXC_ALI_STWCX      0x42  /* stwcx. */
+#define EXC_ALI_STDCX      0x43  /* stdcx. */
+#define EXC_ALI_LWBRX      0x48
+#define EXC_ALI_STWBRX     0x4a
+#define EXC_ALI_LHBRX      0x4c
+#define EXC_ALI_STHBRX     0x4e
+#define EXC_ALI_ECIWX      0x54
+#define EXC_ALI_ECOWX      0x56
 #define EXC_ALI_DCBZ	0x5f
+#define EXC_ALI_LWZX       0x60
+#define EXC_ALI_STWX       0x62
+#define EXC_ALI_LHZX       0x64
+#define EXC_ALI_LHAX       0x65
+#define EXC_ALI_STHX       0x66
+#define EXC_ALI_LSFX       0x68
+#define EXC_ALI_LDFX       0x69
+#define EXC_ALI_STFSX      0x6a
+#define EXC_ALI_STFDX      0x6b
+#define EXC_ALI_STFIWX     0x6f
+#define EXC_ALI_LWZUX      0x70
+#define EXC_ALI_STWUX      0x72
+#define EXC_ALI_LHZUX      0x74
+#define EXC_ALI_LHAUX      0x75
+#define EXC_ALI_STHUX      0x76
+#define EXC_ALI_LFSUX      0x78
+#define EXC_ALI_LFDUX      0x79
+#define EXC_ALI_STFSUX     0x7a
+#define EXC_ALI_STFDUX     0x7b
 
 /* Macros to extract register information */
 #define EXC_ALI_RST(dsisr) ((dsisr >> 5) & 0x1f)   /* source or target */
 #define EXC_ALI_RA(dsisr) (dsisr & 0x1f)
 
+/* Helper defines to classify EXC_ALI_ */
+#define DSI_OP_ZERO      0x0001
+#define DSI_OP_UPDATE    0x0002
+#define DSI_OP_INDEXED   0x0004
+#define DSI_OP_ALGEBRAIC 0x0008
+#define DSI_OP_REVERSED  0x0010
+
 #endif	/* _POWERPC_TRAP_H_ */

Index: src/sys/arch/powerpc/oea/oea_machdep.c
diff -u src/sys/arch/powerpc/oea/oea_machdep.c:1.69 src/sys/arch/powerpc/oea/oea_machdep.c:1.70
--- src/sys/arch/powerpc/oea/oea_machdep.c:1.69	Fri Feb 28 05:34:39 2014
+++ src/sys/arch/powerpc/oea/oea_machdep.c	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: oea_machdep.c,v 1.69 2014/02/28 05:34:39 matt Exp $	*/
+/*	$NetBSD: oea_machdep.c,v 1.70 2014/03/03 15:36:36 macallan Exp $	*/
 
 /*
  * Copyright (C) 2002 Matt Thomas
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: oea_machdep.c,v 1.69 2014/02/28 05:34:39 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: oea_machdep.c,v 1.70 2014/03/03 15:36:36 macallan Exp $");
 
 #include "opt_ppcarch.h"
 #include "opt_compat_netbsd.h"
@@ -496,9 +496,16 @@ mpc601_ioseg_add(paddr_t pa, register_t 
 	 * in pmap_bootstrap().
 	 */
 	iosrtable[i] = SR601(SR601_Ks, SR601_BUID_MEMFORCED, 0, i);
+
+	/*
+	 * XXX Setting segment register 0xf on my powermac 7200
+	 * wedges machine so set later in pmap.c
+	 */
+	/*
 	__asm volatile ("mtsrin %0,%1"
 	    ::	"r"(iosrtable[i]),
 		"r"(pa));
+	*/
 }
 #endif /* PPC_OEA601 */
 

Index: src/sys/arch/powerpc/oea/ofwoea_machdep.c
diff -u src/sys/arch/powerpc/oea/ofwoea_machdep.c:1.36 src/sys/arch/powerpc/oea/ofwoea_machdep.c:1.37
--- src/sys/arch/powerpc/oea/ofwoea_machdep.c:1.36	Fri Feb 28 05:35:49 2014
+++ src/sys/arch/powerpc/oea/ofwoea_machdep.c	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: ofwoea_machdep.c,v 1.36 2014/02/28 05:35:49 matt Exp $ */
+/* $NetBSD: ofwoea_machdep.c,v 1.37 2014/03/03 15:36:36 macallan Exp $ */
 
 /*-
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.36 2014/02/28 05:35:49 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ofwoea_machdep.c,v 1.37 2014/03/03 15:36:36 macallan Exp $");
 
 #include "opt_ppcarch.h"
 #include "opt_compat_netbsd.h"
@@ -63,6 +63,7 @@ __KERNEL_RCSID(0, "$NetBSD: ofwoea_machd
 #include <powerpc/oea/bat.h>
 #include <powerpc/oea/ofw_rasconsvar.h>
 #include <powerpc/oea/cpufeat.h>
+#include <powerpc/include/oea/spr.h>
 #include <powerpc/ofw_cons.h>
 #include <powerpc/spr.h>
 #include <powerpc/pic/picvar.h>
@@ -120,6 +121,11 @@ char model_name[64];
 #if NKSYMS || defined(DDB) || defined(MODULAR)
 void *startsym, *endsym;
 #endif
+
+#if PPC_OEA601
+#define TIMEBASE_FREQ (1000000000)  /* RTC register */
+#endif
+
 #ifdef TIMEBASE_FREQ
 u_int timebase_freq = TIMEBASE_FREQ;
 #else
@@ -334,7 +340,14 @@ found:
 	ns_per_tick = 1000000000 / ticks_per_sec;
 	ticks_per_intr = ticks_per_sec / hz;
 	cpu_timebase = ticks_per_sec;
+
+#ifdef PPC_OEA601
+	if ((mfpvr() >> 16) == MPC601)
+	    curcpu()->ci_lasttb = rtc_nanosecs();
+	else
+#endif
 	curcpu()->ci_lasttb = mftbl();
+
 	mtspr(SPR_DEC, ticks_per_intr);
 	mtmsr(msr);
 }
@@ -459,6 +472,24 @@ ofwoea_batinit(void)
 	/*
 	 * cover PCI and register space but not the firmware ROM
 	 */
+#ifdef PPC_OEA601
+
+        /*
+	 * use segment registers for the 601
+	 */
+	if ((mfpvr() >> 16 ) == MPC601)
+	    oea_batinit(
+		0x80000000, BAT_BL_256M,
+		0x90000000, BAT_BL_256M,
+		0xa0000000, BAT_BL_256M,
+		0xb0000000, BAT_BL_256M,
+		0xf0000000, BAT_BL_256M,
+		0);
+	else
+#endif
+	/*
+	 * map to bats
+	 */
 	oea_batinit(0x80000000, BAT_BL_1G,
 		    0xf0000000, BAT_BL_128M,
 		    0xf8000000, BAT_BL_64M,

Index: src/sys/arch/powerpc/oea/pmap.c
diff -u src/sys/arch/powerpc/oea/pmap.c:1.90 src/sys/arch/powerpc/oea/pmap.c:1.91
--- src/sys/arch/powerpc/oea/pmap.c:1.90	Sun Nov  3 22:15:57 2013
+++ src/sys/arch/powerpc/oea/pmap.c	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.90 2013/11/03 22:15:57 mrg Exp $	*/
+/*	$NetBSD: pmap.c,v 1.91 2014/03/03 15:36:36 macallan Exp $	*/
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -63,7 +63,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.90 2013/11/03 22:15:57 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.91 2014/03/03 15:36:36 macallan Exp $");
 
 #define	PMAP_NOOPNAMES
 
@@ -3403,6 +3403,11 @@ pmap_bootstrap(paddr_t kernelstart, padd
 /* PMAP_OEA64_BRIDGE does support these instructions */
 #if defined (PMAP_OEA) || defined (PMAP_OEA64_BRIDGE)
 	for (i = 0; i < 16; i++) {
+#if defined(PPC_OEA601)
+	    /* XXX wedges for segment register 0xf , so set later */
+	    if ((iosrtable[i] & SR601_T) && ((MFPVR() >> 16) == MPC601))
+		    continue;
+#endif
  		pmap_kernel()->pm_sr[i] = KERNELN_SEGMENT(i)|SR_PRKEY;
 		__asm volatile ("mtsrin %0,%1"
  			      :: "r"(KERNELN_SEGMENT(i)|SR_PRKEY), "r"(i << ADDR_SR_SHFT));
@@ -3530,4 +3535,9 @@ pmap_bootstrap(paddr_t kernelstart, padd
  			      :: "r"(sr), "r"(kernelstart));
 	}
 #endif
+
+#if defined(PMAPDEBUG)
+	if ( pmapdebug )
+	    pmap_print_mmuregs();
+#endif
 }

Index: src/sys/arch/powerpc/powerpc/clock.c
diff -u src/sys/arch/powerpc/powerpc/clock.c:1.13 src/sys/arch/powerpc/powerpc/clock.c:1.14
--- src/sys/arch/powerpc/powerpc/clock.c:1.13	Thu Apr 25 00:11:35 2013
+++ src/sys/arch/powerpc/powerpc/clock.c	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: clock.c,v 1.13 2013/04/25 00:11:35 macallan Exp $	*/
+/*	$NetBSD: clock.c,v 1.14 2014/03/03 15:36:36 macallan Exp $	*/
 /*      $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $	*/
 
 /*
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.13 2013/04/25 00:11:35 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.14 2014/03/03 15:36:36 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -68,7 +68,11 @@ static struct timecounter powerpc_timeco
 	0,			/* no poll_pps */
 	0x7fffffff,		/* counter_mask */
 	0,			/* frequency */
+#if PPC_OEA601
+	"rtc",			/* name */
+#else
 	"mftb",			/* name */
+#endif
 	100,			/* quality */
 	NULL,			/* tc_priv */
 	NULL			/* tc_next */
@@ -88,8 +92,7 @@ cpu_initclocks(void)
 	cpu_timebase = ticks_per_sec;
 #ifdef PPC_OEA601
 	if ((mfpvr() >> 16) == MPC601)
-		__asm volatile 
-		    ("mfspr %0,%1" : "=r"(ci->ci_lasttb) : "n"(SPR_RTCL_R));
+		ci->ci_lasttb = rtc_nanosecs();
 	else
 #endif
 		__asm volatile ("mftb %0" : "=r"(ci->ci_lasttb));
@@ -154,8 +157,7 @@ decr_intr(struct clockframe *cfp)
 		 */
 #ifdef PPC_OEA601
 		if ((mfpvr() >> 16) == MPC601)
-			__asm volatile 
-			    ("mfspr %0,%1" : "=r"(tb) : "n"(SPR_RTCL_R));
+			tb = rtc_nanosecs();
 		else
 #endif
 			__asm volatile ("mftb %0" : "=r"(tb));
@@ -241,7 +243,7 @@ get_powerpc_timecount(struct timecounter
 		      : "=r"(msr), "=r"(scratch) : "K"((u_short)~PSL_EE));
 #ifdef PPC_OEA601
 	if ((mfpvr() >> 16) == MPC601)
-		__asm volatile ("mfspr %0,%1" : "=r"(tb) : "n"(SPR_RTCL_R));
+		tb = rtc_nanosecs();
 	else
 #endif
 		__asm volatile ("mftb %0" : "=r"(tb));

Index: src/sys/arch/powerpc/powerpc/fixup.c
diff -u src/sys/arch/powerpc/powerpc/fixup.c:1.7 src/sys/arch/powerpc/powerpc/fixup.c:1.8
--- src/sys/arch/powerpc/powerpc/fixup.c:1.7	Fri Feb 28 05:38:53 2014
+++ src/sys/arch/powerpc/powerpc/fixup.c	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: fixup.c,v 1.7 2014/02/28 05:38:53 matt Exp $	*/
+/*	$NetBSD: fixup.c,v 1.8 2014/03/03 15:36:36 macallan Exp $	*/
 /*-
  * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -36,13 +36,15 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: fixup.c,v 1.7 2014/02/28 05:38:53 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fixup.c,v 1.8 2014/03/03 15:36:36 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
 
 #include <powerpc/instr.h>
 #include <powerpc/spr.h>
+#include <powerpc/include/cpu.h>
+#include <powerpc/include/oea/spr.h>
 
 static inline void
 fixup_jump(uint32_t *insnp, const struct powerpc_jump_fixup_info *jfi)
@@ -71,7 +73,13 @@ powerpc_fixup_stubs(uint32_t *start, uin
 	extern uint32_t __stub_start[], __stub_end[];
 #ifdef DEBUG
 	size_t fixups_done = 0;
-	uint64_t cycles = mftb();
+	uint64_t cycles = 0;
+#ifdef PPC_OEA601
+	if ((mfpvr() >> 16) == MPC601)
+	    cycles = rtc_nanosecs() >> 7;
+	else
+#endif
+	    cycles = mftb();
 #endif
 
 	if (stub_start == NULL) {
@@ -209,7 +217,14 @@ powerpc_fixup_stubs(uint32_t *start, uin
 	}
 
 #ifdef DEBUG
+
+#ifdef PPC_OEA601
+	if ((mfpvr() >> 16) == MPC601)
+	    cycles = (rtc_nanosecs() >> 7) - cycles;
+	else
+#endif
 	cycles = mftb() - cycles;
+
 	printf("%s: %zu fixup%s done in %"PRIu64" cycles\n", __func__,
 	    fixups_done, fixups_done == 1 ? "" : "s",
 	    cycles);

Index: src/sys/arch/powerpc/powerpc/trap.c
diff -u src/sys/arch/powerpc/powerpc/trap.c:1.148 src/sys/arch/powerpc/powerpc/trap.c:1.149
--- src/sys/arch/powerpc/powerpc/trap.c:1.148	Thu Aug  2 14:06:34 2012
+++ src/sys/arch/powerpc/powerpc/trap.c	Mon Mar  3 15:36:36 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.148 2012/08/02 14:06:34 matt Exp $	*/
+/*	$NetBSD: trap.c,v 1.149 2014/03/03 15:36:36 macallan Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.148 2012/08/02 14:06:34 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.149 2014/03/03 15:36:36 macallan Exp $");
 
 #include "opt_altivec.h"
 #include "opt_ddb.h"
@@ -77,6 +77,13 @@ void trap(struct trapframe *);	/* Called
 int badaddr(void *, size_t);
 int badaddr_read(void *, size_t, int *);
 
+struct dsi_info {
+    uint16_t indicator;
+    uint16_t flags;
+};
+
+static const struct dsi_info* get_dsi_info(register_t);
+
 void
 trap(struct trapframe *tf)
 {
@@ -695,9 +702,12 @@ badaddr_read(void *addr, size_t size, in
 static int
 fix_unaligned(struct lwp *l, struct trapframe *tf)
 {
-	int indicator = EXC_ALI_OPCODE_INDICATOR(tf->tf_dsisr);
+	const struct dsi_info* dsi = get_dsi_info(tf->tf_dsisr);
+
+	if ( !dsi )
+	    return -1;
 
-	switch (indicator) {
+	switch (dsi->indicator) {
 	case EXC_ALI_DCBZ:
 		{
 			/*
@@ -716,13 +726,18 @@ fix_unaligned(struct lwp *l, struct trap
 				return -1;
 			return 0;
 		}
+		break;
 
 	case EXC_ALI_LFD:
-	case EXC_ALI_STFD:
+	case EXC_ALI_LFDU:
+	case EXC_ALI_LDFX:
+	case EXC_ALI_LFDUX:
 		{
 			struct pcb * const pcb = lwp_getpcb(l);
 			const int reg = EXC_ALI_RST(tf->tf_dsisr);
+			const int a_reg = EXC_ALI_RA(tf->tf_dsisr);
 			double * const fpreg = &pcb->pcb_fpu.fpreg[reg];
+			register_t* a_reg_addr = &tf->tf_fixreg[a_reg];
 
 			/*
 			 * Juggle the FPU to ensure that we've initialized
@@ -737,19 +752,260 @@ fix_unaligned(struct lwp *l, struct trap
 			} else {
 				fpu_save();
 			}
-			if (indicator == EXC_ALI_LFD) {
+
 				if (copyin((void *)tf->tf_dar, fpreg,
 				    sizeof(double)) != 0)
 					return -1;
+
+			if (dsi->flags & DSI_OP_INDEXED) {
+			    /* do nothing */
+			}
+
+			if (dsi->flags & DSI_OP_UPDATE) {
+			    /* this is valid for 601, but to simplify logic don't pass for any */
+			    if (a_reg == 0)
+				return -1;
+			    else
+				*a_reg_addr = tf->tf_dar;
+			}
+
+			fpu_load();
+			return 0;
+		}
+		break;
+
+	case EXC_ALI_STFD:
+	case EXC_ALI_STFDU:
+	case EXC_ALI_STFDX:
+	case EXC_ALI_STFDUX:
+		{
+			struct pcb * const pcb = lwp_getpcb(l);
+			const int reg = EXC_ALI_RST(tf->tf_dsisr);
+			const int a_reg = EXC_ALI_RA(tf->tf_dsisr);
+			double * const fpreg = &pcb->pcb_fpu.fpreg[reg];
+			register_t* a_reg_addr = &tf->tf_fixreg[a_reg];
+
+			/*
+			 * Juggle the FPU to ensure that we've initialized
+			 * the FPRs, and that their current state is in
+			 * the PCB.
+			 */
+
+			KASSERT(l == curlwp);
+			if (!fpu_used_p(l)) {
+				memset(&pcb->pcb_fpu, 0, sizeof(pcb->pcb_fpu));
+				fpu_mark_used(l);
 			} else {
+				fpu_save();
+			}
+
 				if (copyout(fpreg, (void *)tf->tf_dar,
 				    sizeof(double)) != 0)
 					return -1;
+
+			if (dsi->flags & DSI_OP_INDEXED) {
+			    /* do nothing */
+			}
+
+			if (dsi->flags & DSI_OP_UPDATE) {
+			    /* this is valid for 601, but to simplify logic don't pass for any */
+			    if (a_reg == 0)
+				return -1;
+			    else
+				*a_reg_addr = tf->tf_dar;
 			}
+
 			fpu_load();
 			return 0;
 		}
 		break;
+
+	case EXC_ALI_LHZ:
+	case EXC_ALI_LHZU:
+	case EXC_ALI_LHZX:
+	case EXC_ALI_LHZUX:
+	case EXC_ALI_LHA:
+	case EXC_ALI_LHAU:
+	case EXC_ALI_LHAX:
+	case EXC_ALI_LHAUX:
+	case EXC_ALI_LHBRX:
+		{
+		    const register_t ea_addr = tf->tf_dar;
+		    const unsigned int t_reg = EXC_ALI_RST(tf->tf_dsisr);
+		    const unsigned int a_reg = EXC_ALI_RA(tf->tf_dsisr);
+		    register_t* t_reg_addr = &tf->tf_fixreg[t_reg];
+		    register_t* a_reg_addr = &tf->tf_fixreg[a_reg];
+
+		    /* load into lower 2 bytes of reg */
+		    if (copyin((void *)ea_addr,
+			       t_reg_addr+2,
+			       sizeof(uint16_t)) != 0)
+			return -1;
+
+		    if (dsi->flags & DSI_OP_UPDATE) {
+			/* this is valid for 601, but to simplify logic don't pass for any */
+			if (a_reg == 0)
+			    return -1;
+			else
+			    *a_reg_addr = ea_addr;
+		    }
+
+		    if (dsi->flags & DSI_OP_INDEXED) {
+			/* do nothing , indexed address already in ea */
+		    }
+
+		    if (dsi->flags & DSI_OP_ZERO) {
+			/* clear upper 2 bytes */
+			*t_reg_addr &= 0x0000ffff;
+		    } else if (dsi->flags & DSI_OP_ALGEBRAIC) {
+			/* sign extend upper 2 bytes */
+			if (*t_reg_addr & 0x00008000)
+			    *t_reg_addr |= 0xffff0000;
+			else
+			    *t_reg_addr &= 0x0000ffff;
+		    }
+
+		    if (dsi->flags & DSI_OP_REVERSED) {
+			/* reverse lower 2 bytes */
+			uint32_t temp = *t_reg_addr;
+
+			*t_reg_addr = ((temp & 0x000000ff) << 8 ) |
+			              ((temp & 0x0000ff00) >> 8 );
+		    }
+		    return 0;
+		}
+		break;
+
+	case EXC_ALI_STH:
+	case EXC_ALI_STHU:
+	case EXC_ALI_STHX:
+	case EXC_ALI_STHUX:
+	case EXC_ALI_STHBRX:
+		{
+		    const register_t ea_addr = tf->tf_dar;
+		    const unsigned int s_reg = EXC_ALI_RST(tf->tf_dsisr);
+		    const unsigned int a_reg = EXC_ALI_RA(tf->tf_dsisr);
+		    register_t* s_reg_addr = &tf->tf_fixreg[s_reg];
+		    register_t* a_reg_addr = &tf->tf_fixreg[a_reg];
+
+		    /* byte-reversed write out of lower 2 bytes */
+		    if (dsi->flags & DSI_OP_REVERSED) {
+			uint16_t tmp = *s_reg_addr & 0xffff;
+			tmp = bswap16(tmp);
+
+			if (copyout(&tmp,
+				    (void *)ea_addr,
+				    sizeof(uint16_t)) != 0)
+			    return -1;
+		    }
+		    /* write out lower 2 bytes */
+		    else if (copyout(s_reg_addr+2,
+				     (void *)ea_addr,
+				     sizeof(uint16_t)) != 0) {
+			return -1;
+		    }
+
+		    if (dsi->flags & DSI_OP_INDEXED) {
+			/* do nothing, indexed address already in ea */
+		    }
+
+		    if (dsi->flags & DSI_OP_UPDATE) {
+			/* this is valid for 601, but to simplify logic don't pass for any */
+			if (a_reg == 0)
+			    return -1;
+			else
+			    *a_reg_addr = ea_addr;
+		    }
+
+		    return 0;
+		}
+		break;
+
+	case EXC_ALI_LWARX_LWZ:
+	case EXC_ALI_LWZU:
+	case EXC_ALI_LWZX:
+	case EXC_ALI_LWZUX:
+	case EXC_ALI_LWBRX:
+		{
+		    const register_t ea_addr = tf->tf_dar;
+		    const unsigned int t_reg = EXC_ALI_RST(tf->tf_dsisr);
+		    const unsigned int a_reg = EXC_ALI_RA(tf->tf_dsisr);
+		    register_t* t_reg_addr = &tf->tf_fixreg[t_reg];
+		    register_t* a_reg_addr = &tf->tf_fixreg[a_reg];
+
+		    if (copyin((void *)ea_addr,
+			       t_reg_addr,
+			       sizeof(uint32_t)) != 0)
+			return -1;
+
+		    if (dsi->flags & DSI_OP_UPDATE) {
+			/* this is valid for 601, but to simplify logic don't pass for any */
+			if (a_reg == 0)
+			    return -1;
+			else
+			    *a_reg_addr = ea_addr;
+		    }
+
+		    if (dsi->flags & DSI_OP_INDEXED) {
+			/* do nothing , indexed address already in ea */
+		    }
+
+		    if (dsi->flags & DSI_OP_ZERO) {
+			/* XXX - 64bit clear upper word */
+		    }
+
+		    if (dsi->flags & DSI_OP_REVERSED) {
+			/* reverse  bytes */
+			register_t temp = bswap32(*t_reg_addr);
+			*t_reg_addr = temp;
+		    }
+
+		    return 0;
+		}
+		break;
+
+	case EXC_ALI_STW:
+	case EXC_ALI_STWU:
+	case EXC_ALI_STWX:
+	case EXC_ALI_STWUX:
+	case EXC_ALI_STWBRX:
+		{
+		    const register_t ea_addr = tf->tf_dar;
+		    const unsigned int s_reg = EXC_ALI_RST(tf->tf_dsisr);
+		    const unsigned int a_reg = EXC_ALI_RA(tf->tf_dsisr);
+		    register_t* s_reg_addr = &tf->tf_fixreg[s_reg];
+		    register_t* a_reg_addr = &tf->tf_fixreg[a_reg];
+
+		    if (dsi->flags & DSI_OP_REVERSED) {
+			/* byte-reversed write out */
+			register_t temp = bswap32(*s_reg_addr);
+
+			if (copyout(&temp,
+				    (void *)ea_addr,
+				    sizeof(uint32_t)) != 0)
+			    return -1;
+		    }
+		    /* write out word */
+		    else if (copyout(s_reg_addr,
+				     (void *)ea_addr,
+				     sizeof(uint32_t)) != 0)
+			return -1;
+
+		    if (dsi->flags & DSI_OP_INDEXED) {
+			/* do nothing, indexed address already in ea */
+		    }
+
+		    if (dsi->flags & DSI_OP_UPDATE) {
+			/* this is valid for 601, but to simplify logic don't pass for any */
+			if (a_reg == 0)
+			    return -1;
+			else
+			    *a_reg_addr = ea_addr;
+		    }
+
+		    return 0;
+		}
+		break;
 	}
 
 	return -1;
@@ -892,3 +1148,123 @@ copyoutstr(const void *kaddr, void *udad
 	curpcb->pcb_onfault = 0;
 	return rv;
 }
+
+const struct dsi_info*
+get_dsi_info(register_t dsisr)
+{
+    static const struct dsi_info dsi[] = 
+	{
+	    /* data cache block zero */
+	    {EXC_ALI_DCBZ, 0},
+
+	    /* load halfwords */
+	    {EXC_ALI_LHZ,   DSI_OP_ZERO},
+	    {EXC_ALI_LHZU,  DSI_OP_ZERO|DSI_OP_UPDATE},
+	    {EXC_ALI_LHZX,  DSI_OP_ZERO|DSI_OP_INDEXED},
+	    {EXC_ALI_LHZUX, DSI_OP_ZERO|DSI_OP_UPDATE|DSI_OP_INDEXED},
+	    {EXC_ALI_LHA,   DSI_OP_ALGEBRAIC},
+	    {EXC_ALI_LHAU,  DSI_OP_ALGEBRAIC|DSI_OP_UPDATE},
+	    {EXC_ALI_LHAX,  DSI_OP_ALGEBRAIC|DSI_OP_INDEXED},
+	    {EXC_ALI_LHAUX, DSI_OP_ALGEBRAIC|DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* store halfwords */
+	    {EXC_ALI_STH,   0},
+	    {EXC_ALI_STHU,  DSI_OP_UPDATE},
+	    {EXC_ALI_STHX,  DSI_OP_INDEXED},
+	    {EXC_ALI_STHUX, DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* load words */
+	    {EXC_ALI_LWARX_LWZ, DSI_OP_ZERO},
+	    {EXC_ALI_LWZU,      DSI_OP_ZERO|DSI_OP_UPDATE},
+	    {EXC_ALI_LWZX,      DSI_OP_ZERO|DSI_OP_INDEXED},
+	    {EXC_ALI_LWZUX,     DSI_OP_ZERO|DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* store words */
+	    {EXC_ALI_STW,   0},				  
+	    {EXC_ALI_STWU,  DSI_OP_UPDATE},		  
+	    {EXC_ALI_STWX,  DSI_OP_INDEXED},		  
+	    {EXC_ALI_STWUX, DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* load byte-reversed */
+	    {EXC_ALI_LHBRX, DSI_OP_REVERSED|DSI_OP_INDEXED|DSI_OP_ZERO},
+	    {EXC_ALI_LWBRX, DSI_OP_REVERSED|DSI_OP_INDEXED},
+
+	    /* store byte-reversed */
+	    {EXC_ALI_STHBRX, DSI_OP_REVERSED|DSI_OP_INDEXED},
+	    {EXC_ALI_STWBRX, DSI_OP_REVERSED|DSI_OP_INDEXED},
+
+	    /* load float double-precision */
+	    {EXC_ALI_LFD,   0},
+	    {EXC_ALI_LFDU,  DSI_OP_UPDATE},
+	    {EXC_ALI_LDFX,  DSI_OP_INDEXED},
+	    {EXC_ALI_LFDUX, DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* store float double precision */
+	    {EXC_ALI_STFD,   0},
+	    {EXC_ALI_STFDU,  DSI_OP_UPDATE},
+	    {EXC_ALI_STFDX,  DSI_OP_INDEXED},
+	    {EXC_ALI_STFDUX, DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* XXX - ones below here not yet implemented in fix_unaligned() */
+	    /* load float single precision */
+	    {EXC_ALI_LFS,   0},
+	    {EXC_ALI_LFSU,  DSI_OP_UPDATE},
+	    {EXC_ALI_LSFX,  DSI_OP_INDEXED},
+	    {EXC_ALI_LFSUX, DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* store float single precision */
+	    {EXC_ALI_STFS,   0},
+	    {EXC_ALI_STFSU,  DSI_OP_UPDATE},
+	    {EXC_ALI_STFSX,  DSI_OP_INDEXED},
+	    {EXC_ALI_STFSUX, DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* multiple */
+	    {EXC_ALI_LMW,  0},
+	    {EXC_ALI_STMW, 0},
+
+	    /* load & store string */
+	    {EXC_ALI_LSWI, 0},
+	    {EXC_ALI_LSWX, DSI_OP_INDEXED},
+	    {EXC_ALI_STSWI, 0},
+	    {EXC_ALI_STSWX, DSI_OP_INDEXED},
+
+	    /* get/send word from external */
+	    {EXC_ALI_ECIWX, DSI_OP_INDEXED},
+	    {EXC_ALI_ECOWX, DSI_OP_INDEXED},
+
+	    /* store float as integer word */
+	    {EXC_ALI_STFIWX, 0},
+
+	    /* store conditional */
+	    {EXC_ALI_LDARX, DSI_OP_INDEXED}, /* stdcx */
+	    {EXC_ALI_STDCX, DSI_OP_INDEXED},
+	    {EXC_ALI_STWCX, DSI_OP_INDEXED},  /* lwarx */
+
+#ifdef PPC_OEA64
+	    /* 64 bit, load word algebriac */ 
+	    {EXC_ALI_LWAX,  DSI_OP_ALGEBRAIC|DSI_OP_INDEXED},
+	    {EXC_ALI_LWAUX, DSI_OP_ALGEBRAIC|DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* 64 bit load doubleword */
+	    {EXC_ALI_LD_LDU_LWA, 0},
+	    {EXC_ALI_LDX,        DSI_OP_INDEXED},
+	    {EXC_ALI_LDUX,       DSI_OP_UPDATE|DSI_OP_INDEXED},
+
+	    /* 64 bit store double word */
+	    {EXC_ALI_STD_STDU, 0},
+	    {EXC_ALI_STDX,     DSI_OP_INDEXED},
+	    {EXC_ALI_STDUX,    DSI_OP_UPDATE|DSI_OP_INDEXED},
+#endif
+	};
+
+    int num_elems = sizeof(dsi)/sizeof(dsi[0]);
+    int indicator = EXC_ALI_OPCODE_INDICATOR(dsisr);
+    int i;
+
+    for (i = 0 ; i < num_elems; i++) {
+	if (indicator == dsi[i].indicator){
+	    return &dsi[i];
+	}
+    }
+    return 0;
+}

Reply via email to