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