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;
+}