summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/luna88k/conf/GENERIC46
-rw-r--r--sys/arch/luna88k/conf/Makefile.luna88k206
-rw-r--r--sys/arch/luna88k/conf/files.luna88k101
-rw-r--r--sys/arch/luna88k/ddb/db_disasm.c689
-rw-r--r--sys/arch/luna88k/ddb/db_interface.c827
-rw-r--r--sys/arch/luna88k/ddb/db_sstep.c337
-rw-r--r--sys/arch/luna88k/ddb/db_trace.c1143
-rw-r--r--sys/arch/luna88k/dev/if_le.c204
-rw-r--r--sys/arch/luna88k/dev/lcd.c173
-rw-r--r--sys/arch/luna88k/dev/lunafb.c510
-rw-r--r--sys/arch/luna88k/dev/lunaws.c545
-rw-r--r--sys/arch/luna88k/dev/mb89352.c2184
-rw-r--r--sys/arch/luna88k/dev/mb89352reg.h238
-rw-r--r--sys/arch/luna88k/dev/mb89352var.h214
-rw-r--r--sys/arch/luna88k/dev/omrasops.c475
-rw-r--r--sys/arch/luna88k/dev/sio.c136
-rw-r--r--sys/arch/luna88k/dev/sioreg.h137
-rw-r--r--sys/arch/luna88k/dev/siotty.c664
-rw-r--r--sys/arch/luna88k/dev/siovar.h60
-rw-r--r--sys/arch/luna88k/dev/spc.c111
-rw-r--r--sys/arch/luna88k/dev/timekeeper.c303
-rw-r--r--sys/arch/luna88k/dev/timekeeper.h93
-rw-r--r--sys/arch/luna88k/include/ansi.h83
-rw-r--r--sys/arch/luna88k/include/asm.h310
-rw-r--r--sys/arch/luna88k/include/asm_macro.h123
-rw-r--r--sys/arch/luna88k/include/autoconf.h79
-rw-r--r--sys/arch/luna88k/include/board.h214
-rw-r--r--sys/arch/luna88k/include/bus.h632
-rw-r--r--sys/arch/luna88k/include/cdefs.h40
-rw-r--r--sys/arch/luna88k/include/cmmu.h103
-rw-r--r--sys/arch/luna88k/include/cpu.h198
-rw-r--r--sys/arch/luna88k/include/cpu_number.h47
-rw-r--r--sys/arch/luna88k/include/cpus.h65
-rw-r--r--sys/arch/luna88k/include/db_machdep.h167
-rw-r--r--sys/arch/luna88k/include/disklabel.h52
-rw-r--r--sys/arch/luna88k/include/endian.h36
-rw-r--r--sys/arch/luna88k/include/exec.h32
-rw-r--r--sys/arch/luna88k/include/float.h76
-rw-r--r--sys/arch/luna88k/include/frame.h49
-rw-r--r--sys/arch/luna88k/include/ieee.h142
-rw-r--r--sys/arch/luna88k/include/ieeefp.h56
-rw-r--r--sys/arch/luna88k/include/internal_types.h6
-rw-r--r--sys/arch/luna88k/include/intr.h132
-rw-r--r--sys/arch/luna88k/include/kcore.h39
-rw-r--r--sys/arch/luna88k/include/limits.h53
-rw-r--r--sys/arch/luna88k/include/locore.h84
-rw-r--r--sys/arch/luna88k/include/m88100.h59
-rw-r--r--sys/arch/luna88k/include/m8820x.h169
-rw-r--r--sys/arch/luna88k/include/mmu.h252
-rw-r--r--sys/arch/luna88k/include/param.h183
-rw-r--r--sys/arch/luna88k/include/pcb.h149
-rw-r--r--sys/arch/luna88k/include/pmap.h77
-rw-r--r--sys/arch/luna88k/include/pmap_table.h49
-rw-r--r--sys/arch/luna88k/include/proc.h64
-rw-r--r--sys/arch/luna88k/include/psl.h93
-rw-r--r--sys/arch/luna88k/include/ptrace.h62
-rw-r--r--sys/arch/luna88k/include/reg.h90
-rw-r--r--sys/arch/luna88k/include/setjmp.h9
-rw-r--r--sys/arch/luna88k/include/signal.h56
-rw-r--r--sys/arch/luna88k/include/spinlock.h10
-rw-r--r--sys/arch/luna88k/include/stdarg.h16
-rw-r--r--sys/arch/luna88k/include/trap.h78
-rw-r--r--sys/arch/luna88k/include/types.h80
-rw-r--r--sys/arch/luna88k/include/va-m88k.h82
-rw-r--r--sys/arch/luna88k/include/varargs.h13
-rw-r--r--sys/arch/luna88k/include/vmparam.h133
-rw-r--r--sys/arch/luna88k/luna88k/autoconf.c415
-rw-r--r--sys/arch/luna88k/luna88k/clock.c218
-rw-r--r--sys/arch/luna88k/luna88k/clockvar.h54
-rw-r--r--sys/arch/luna88k/luna88k/cmmu.c78
-rw-r--r--sys/arch/luna88k/luna88k/conf.c274
-rw-r--r--sys/arch/luna88k/luna88k/disksubr.c526
-rw-r--r--sys/arch/luna88k/luna88k/eh.S2709
-rw-r--r--sys/arch/luna88k/luna88k/genassym.cf144
-rw-r--r--sys/arch/luna88k/luna88k/isr.c204
-rw-r--r--sys/arch/luna88k/luna88k/isr.h70
-rw-r--r--sys/arch/luna88k/luna88k/locore.S545
-rw-r--r--sys/arch/luna88k/luna88k/locore_asm_routines.S1621
-rw-r--r--sys/arch/luna88k/luna88k/locore_c_routines.c512
-rw-r--r--sys/arch/luna88k/luna88k/m88100_fp.S2516
-rw-r--r--sys/arch/luna88k/luna88k/m8820x.c1595
-rw-r--r--sys/arch/luna88k/luna88k/machdep.c1840
-rw-r--r--sys/arch/luna88k/luna88k/mainbus.c107
-rw-r--r--sys/arch/luna88k/luna88k/mem.c237
-rw-r--r--sys/arch/luna88k/luna88k/pmap.c2834
-rw-r--r--sys/arch/luna88k/luna88k/pmap_table.c89
-rw-r--r--sys/arch/luna88k/luna88k/process.S332
-rw-r--r--sys/arch/luna88k/luna88k/process_machdep.c149
-rw-r--r--sys/arch/luna88k/luna88k/trap.c1797
-rw-r--r--sys/arch/luna88k/luna88k/vectors_88100.S89
-rw-r--r--sys/arch/luna88k/luna88k/vm_machdep.c502
91 files changed, 33395 insertions, 0 deletions
diff --git a/sys/arch/luna88k/conf/GENERIC b/sys/arch/luna88k/conf/GENERIC
new file mode 100644
index 00000000000..97100bc3e9f
--- /dev/null
+++ b/sys/arch/luna88k/conf/GENERIC
@@ -0,0 +1,46 @@
+# $OpenBSD: GENERIC,v 1.1 2004/04/21 15:23:44 aoyama Exp $
+
+machine luna88k
+
+include "../../../conf/GENERIC"
+
+option "NCPUS=1" # number of CPUs supported (max 4)
+#option DEBUG # print debugging statements
+#option EH_DEBUG # debugging code for exception handlers
+
+# Define this if your processor has the xxx.usr bug (mask C82N)
+option ERRATA__XXX_USR
+
+maxusers 64
+
+config bsd swap generic
+
+#
+# devices
+#
+
+mainbus0 at root
+clock0 at mainbus0
+le0 at mainbus0
+sio0 at mainbus0
+siotty0 at sio0
+ws0 at sio0
+fb0 at mainbus0
+spc0 at mainbus0
+spc1 at mainbus0
+
+# Workstation Console attachments
+wsdisplay* at fb?
+wskbd* at ws? console ?
+wsmouse* at ws?
+
+# SCSI bus support
+scsibus* at spc?
+
+# SCSI devices
+sd* at scsibus? target ? lun ?
+st* at scsibus? target ? lun ?
+cd* at scsibus? target ? lun ?
+ch* at scsibus? target ? lun ?
+ss* at scsibus? target ? lun ?
+uk* at scsibus? target ? lun ?
diff --git a/sys/arch/luna88k/conf/Makefile.luna88k b/sys/arch/luna88k/conf/Makefile.luna88k
new file mode 100644
index 00000000000..9c67c8fca69
--- /dev/null
+++ b/sys/arch/luna88k/conf/Makefile.luna88k
@@ -0,0 +1,206 @@
+# $OpenBSD: Makefile.luna88k,v 1.1 2004/04/21 15:23:47 aoyama Exp $
+#
+# Makefile for OpenBSD
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/arch/luna88k/conf/``machineid''
+# after which you should do
+# config machineid
+# Machine generic makefile changes should be made in
+# /sys/arch/luna88k/conf/Makefile.luna88k
+# after which config should be rerun for all machines of that type.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+
+# DEBUG is set to -g by config if debugging is requested (config -g).
+# PROF is set to -pg by config if profiling is requested (config -p).
+
+.include <bsd.own.mk>
+
+MKDEP?= mkdep
+SIZE?= size
+STRIP?= strip
+
+# source tree is located via $S relative to the compilation directory
+.ifndef S
+S!= cd ../../../..; pwd
+.endif
+LUNA88K= $S/arch/luna88k
+
+INCLUDES= -nostdinc -I. -I$S/arch -I$S
+CPPFLAGS= ${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -Dluna88k -Dm88k
+CWARNFLAGS= -Wall -Werror -Wmissing-prototypes \
+ -Wno-uninitialized -Wno-format -Wno-main -Wstrict-prototypes
+CMACHFLAGS= -mno-check-zero-division -mmemcpy \
+ -fno-builtin-printf -fno-builtin-log
+.if ${IDENT:M-DNO_PROPOLICE}
+CMACHFLAGS+= -fno-stack-protector
+.endif
+COPTS?= -O2
+CFLAGS= ${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE}
+AFLAGS= -x assembler-with-cpp -traditional-cpp -D_LOCORE ${CMACHFLAGS}
+LINKFLAGS= -N -Ttext 0x20000 -e start
+STRIPFLAGS= -d
+
+HOSTCC?= ${CC}
+HOSTED_CPPFLAGS?=${CPPFLAGS:S/^-nostdinc$//}
+HOSTED_CFLAGS?= ${CFLAGS}
+
+### CPU configuration
+
+CPPFLAGS+= -DM88100
+
+### find out what to use for libkern
+.include "$S/lib/libkern/Makefile.inc"
+.ifndef PROF
+LIBKERN= ${KERNLIB}
+.else
+LIBKERN= ${KERNLIB_PROF}
+.endif
+
+### find out what to use for libcompat
+.include "$S/compat/common/Makefile.inc"
+.ifndef PROF
+LIBCOMPAT= ${COMPATLIB}
+.else
+LIBCOMPAT= ${COMPATLIB_PROF}
+.endif
+
+# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP}
+# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix,
+# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file
+# is marked as config-dependent.
+
+NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
+NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
+
+HOSTED_C= ${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $<
+
+PROFILE_C= ${CC} -S -c ${CFLAGS} ${CPPFLAGS} $<; \
+ sed -e s/_mcount/mcount/ -e s/subrmcount/subr_mcount/ <$*.s | \
+ ${AS} -o $@; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%SFILES
+
+# load lines for config "xxx" will be emitted as:
+# xxx: ${SYSTEM_DEP} swapxxx.o
+# ${SYSTEM_LD_HEAD}
+# ${SYSTEM_LD} swapxxx.o
+# ${SYSTEM_LD_TAIL}
+# Kernel is linked as a ZMAGIC executable, with start at 10020
+SYSTEM_OBJ= locore.o \
+ param.o ioconf.o ${OBJS} ${LIBKERN} ${LIBCOMPAT}
+SYSTEM_DEP= Makefile ${SYSTEM_OBJ}
+SYSTEM_LD_HEAD= @rm -f $@
+SYSTEM_LD= @echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_OBJ}' vers.o; \
+ ${LD} ${LINKFLAGS} -o $@ ${SYSTEM_OBJ} vers.o
+SYSTEM_LD_TAIL= @${SIZE} $@; chmod 755 $@;
+
+DEBUG?=
+.if ${DEBUG} == "-g"
+LINKFLAGS+= -X
+SYSTEM_LD_TAIL+= \
+ echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \
+ echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@
+.else
+LINKFLAGS+= -x
+.endif
+
+%LOAD
+
+assym.h: $S/kern/genassym.sh ${LUNA88K}/luna88k/genassym.cf Makefile
+ sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} \
+ ${PARAM} < ${LUNA88K}/luna88k/genassym.cf > assym.h.tmp && \
+ mv -f assym.h.tmp assym.h
+
+param.c: $S/conf/param.c
+ rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${NORMAL_C}
+
+ioconf.o: ioconf.c
+ ${NORMAL_C}
+
+newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
+ sh $S/conf/newvers.sh
+ ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c
+
+clean::
+ rm -f eddep *bsd bsd.gdb tags *.[io] [a-z]*.s \
+ [Ee]rrs linterrs makelinks assym.h
+
+lint:
+ @lint -hbxncez -DGENERIC -Dvolatile= ${CPPFLAGS} ${PARAM} -UKGDB \
+ ${CFILES} ioconf.c param.c | \
+ grep -v 'struct/union .* never defined' | \
+ grep -v 'possible pointer alignment problem'
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+SRCS= param.c ioconf.c ${CFILES} ${SFILES}
+
+depend:: .depend
+.depend: ${SRCS} assym.h param.c
+ ${MKDEP} -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES}
+.if !empty(SFILES)
+ ${MKDEP} -a ${AFLAGS} ${CPPFLAGS} ${SFILES}
+.endif
+ sh $S/kern/genassym.sh ${MKDEP} -f assym.dep ${CFLAGS} \
+ ${CPPFLAGS} < ${LUNA88K}/luna88k/genassym.cf
+ @sed -e 's/.*\.o:.* /assym.h: /' < assym.dep >> .depend
+ @rm -f assym.dep
+
+# depend on root or device configuration
+autoconf.o conf.o: Makefile
+
+# depend on network or filesystem configuration
+uipc_domain.o uipc_proto.o vfs_conf.o: Makefile
+if_tun.o if_loop.o if_ethersubr.o: Makefile
+in_proto.o: Makefile
+
+# depend on maxusers
+assym.h machdep.o: Makefile
+
+# depend on CPU configuration
+locore.o machdep.o: Makefile
+process.o locore_asm_routines.o eh.o: assym.h
+m88100_fp.o : assym.h
+
+locore.o: ${LUNA88K}/luna88k/locore.S assym.h
+ ${NORMAL_S}
+
+# The install target can be redefined by putting a
+# install-kernel-${MACHINE_NAME} target into /etc/mk.conf
+MACHINE_NAME!= uname -n
+install: install-kernel-${MACHINE_NAME}
+.if !target(install-kernel-${MACHINE_NAME}})
+install-kernel-${MACHINE_NAME}:
+ rm -f /obsd
+ ln /bsd /obsd
+ cp bsd /nbsd
+ mv /nbsd /bsd
+.endif
+
+%RULES
diff --git a/sys/arch/luna88k/conf/files.luna88k b/sys/arch/luna88k/conf/files.luna88k
new file mode 100644
index 00000000000..b60d9268090
--- /dev/null
+++ b/sys/arch/luna88k/conf/files.luna88k
@@ -0,0 +1,101 @@
+# $OpenBSD: files.luna88k,v 1.1 2004/04/21 15:23:47 aoyama Exp $
+#
+maxpartitions 16
+
+device mainbus {}
+attach mainbus at root
+file arch/luna88k/luna88k/mainbus.c
+
+device clock
+attach clock at mainbus
+file arch/luna88k/dev/timekeeper.c clock
+
+attach le at mainbus
+file arch/luna88k/dev/if_le.c le
+
+device sio { [channel = -1] }
+attach sio at mainbus
+file arch/luna88k/dev/sio.c sio
+
+# this should be removed after bringup
+#device romtty: tty
+#attach romtty at mainbus
+#file arch/luna88k/dev/romtty.c romtty needs-flag
+
+device siotty: tty
+attach siotty at sio
+file arch/luna88k/dev/siotty.c siotty needs-flag
+
+device ws: wskbddev,wsmousedev
+attach ws at sio
+file arch/luna88k/dev/lunaws.c ws
+
+device fb: wsemuldisplaydev,wsrasteremulops
+attach fb at mainbus
+file arch/luna88k/dev/lunafb.c fb
+file arch/luna88k/dev/omrasops.c fb
+
+# Raster operations
+include "dev/rasops/files.rasops"
+include "dev/wsfont/files.wsfont"
+# "Workstation Console" glue.
+include "dev/wscons/files.wscons"
+
+device cpu
+attach cpu at mainbus
+
+include "../../../scsi/files.scsi"
+
+major { sd = 4 }
+major { st = 5 }
+major { cd = 6 }
+major { rd = 7 }
+major { vnd = 8 }
+
+device spc: scsi
+attach spc at mainbus
+file arch/luna88k/dev/spc.c spc
+file arch/luna88k/dev/mb89352.c spc
+
+# XXX: now testing
+#device pcm: audio, auconv, mulaw
+#attach pcm at mainbus
+#file arch/luna88k/dev/nec86.c pcm needs-flag
+#file arch/luna88k/dev/nec86hw.c pcm needs-flag
+#file arch/luna88k/dev/nec86_luna88k.c pcm needs-flag
+
+# list of standard files
+file dev/cons.c
+file dev/cninit.c
+file dev/clock_subr.c
+
+file netinet/in_cksum.c
+file netns/ns_cksum.c ns
+
+file arch/luna88k/luna88k/clock.c
+
+file arch/luna88k/luna88k/autoconf.c
+file arch/luna88k/luna88k/conf.c
+file arch/luna88k/luna88k/cmmu.c
+file arch/luna88k/luna88k/m8820x.c
+file arch/luna88k/luna88k/disksubr.c
+#file arch/luna88k/luna88k/dkbad.c
+file arch/luna88k/luna88k/eh.S
+file arch/luna88k/luna88k/isr.c
+file arch/luna88k/luna88k/locore_asm_routines.S
+file arch/luna88k/luna88k/locore_c_routines.c
+file arch/luna88k/luna88k/m88100_fp.S
+file arch/luna88k/luna88k/machdep.c
+file arch/luna88k/luna88k/mem.c
+file arch/luna88k/luna88k/pmap.c
+file arch/luna88k/luna88k/pmap_table.c
+file arch/luna88k/luna88k/process.S
+file arch/luna88k/luna88k/process_machdep.c
+file arch/luna88k/luna88k/trap.c
+file arch/luna88k/luna88k/vectors_88100.S
+file arch/luna88k/luna88k/vm_machdep.c
+file arch/luna88k/ddb/db_disasm.c ddb
+file arch/luna88k/ddb/db_interface.c ddb
+file arch/luna88k/ddb/db_sstep.c ddb
+file arch/luna88k/ddb/db_trace.c ddb
+file arch/luna88k/dev/lcd.c
diff --git a/sys/arch/luna88k/ddb/db_disasm.c b/sys/arch/luna88k/ddb/db_disasm.c
new file mode 100644
index 00000000000..feef3d4afe7
--- /dev/null
+++ b/sys/arch/luna88k/ddb/db_disasm.c
@@ -0,0 +1,689 @@
+/* $OpenBSD: db_disasm.c,v 1.1 2004/04/21 15:23:49 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * m88k disassembler for use in ddb
+ */
+
+#include <sys/param.h> /* cputyp and friends */
+#include <sys/types.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_sym.h> /* DB_STGY_PROC, db_printsym() */
+#include <ddb/db_access.h> /* db_get_value() */
+#include <ddb/db_output.h> /* db_printf() */
+#include <ddb/db_interface.h>
+
+static const char *instwidth[4] = {
+ ".d", " ", ".h", ".b"
+};
+
+static const char *condname[6] = {
+ "gt0 ", "eq0 ", "ge0 ", "lt0 ", "ne0 ", "le0 "
+};
+
+static const char *m88100_ctrlreg[64] = {
+ "cr0(PID) ",
+ "cr1(PSR) ",
+ "cr2(EPSR) ",
+ "cr3(SSBR) ",
+ "cr4(SXIP) ",
+ "cr5(SNIP) ",
+ "cr6(SFIP) ",
+ "cr7(VBR) ",
+ "cr8(DMT0) ",
+ "cr9(DMD0) ",
+ "cr10(DMA0) ",
+ "cr11(DMT1) ",
+ "cr12(DMD1) ",
+ "cr13(DMA1) ",
+ "cr14(DMT2) ",
+ "cr15(DMD2) ",
+ "cr16(DMA2) ",
+ "cr17(SR0) ",
+ "cr18(SR1) ",
+ "cr19(SR2) ",
+ "cr20(SR3) ",
+ "fcr0(FPECR)",
+ "fcr1(FPHS1)",
+ "fcr2(FPLS1)",
+ "fcr3(FPHS2)",
+ "fcr4(FPLS2)",
+ "fcr5(FPPT) ",
+ "fcr6(FPRH) ",
+ "fcr7(FPRL) ",
+ "fcr8(FPIT) ",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "fcr62(FPSR)",
+ "fcr63(FPCR)"
+};
+
+static const char *m88110_ctrlreg[64] = {
+ "cr0(PID) ",
+ "cr1(PSR) ",
+ "cr2(EPSR) ",
+ NULL,
+ "cr4(EXIP) ",
+ "cr5(ENIP) ",
+ NULL,
+ "cr7(VBR) ",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "cr14(RES1) ",
+ "cr15(RES2) ",
+ "cr16(SR0) ",
+ "cr17(SR1) ",
+ "cr18(SR2) ",
+ "cr19(SR3) ",
+ "cr20(SR4) ",
+ "fcr0(FPECR)",
+ NULL,
+ NULL,
+ NULL,
+ "cr25(ICMD) ",
+ "cr26(ICTL) ",
+ "cr27(ISAR) ",
+ "cr28(ISAP) ",
+ "cr29(IUAP) ",
+ "cr30(IIR) ",
+ "cr31(IBP) ",
+ "cr32(IPPU) ",
+ "cr33(IPPL) ",
+ "cr34(ISR) ",
+ "cr35(ILAR) ",
+ "cr36(IPAR) ",
+ NULL,
+ NULL,
+ NULL,
+ "cr40(DCMD) ",
+ "cr41(DCTL) ",
+ "cr42(DSAR) ",
+ "cr43(DSAP) ",
+ "cr44(DUAP) ",
+ "cr45(DIR) ",
+ "cr46(DBP) ",
+ "cr47(DPPU) ",
+ "cr48(DPPL) ",
+ "cr49(DSR) ",
+ "cr50(DLAR) ",
+ "cr51(DPAR) ",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ "fcr62(FPSR)",
+ "fcr63(FPCR)"
+};
+
+#define printval(x) \
+ do { \
+ if ((x) < 0) \
+ db_printf("-0x%X", -(x)); \
+ else \
+ db_printf("0x%X", (x)); \
+ } while (0)
+
+/* prototypes */
+void oimmed(int, const char *, long);
+void ctrlregs(int, const char *, long);
+void printsod(int);
+void sindou(int, const char *, long);
+void jump(int, const char *, long);
+void instset(int, const char *, long);
+void symofset(int, int, int);
+void obranch(int, const char *, long);
+void brcond(int, const char *, long);
+void otrap(int, const char *, long);
+void obit(int, const char *, long);
+void bitman(int, const char *, long);
+void immem(int, const char *, long);
+void nimmem(int, const char *, long);
+void lognim(int, const char *, long);
+void onimmed(int, const char *, long);
+
+/* Handlers immediate integer arithmetic instructions */
+void
+oimmed(int inst, const char *opcode, long iadr)
+{
+ int Linst = inst & 0177777;
+ int Hinst = inst >> 16;
+ int H6inst = Hinst >> 10;
+ int rs1 = Hinst & 037;
+ int rd = ( Hinst >> 5 ) & 037;
+
+ if (( H6inst > 017 ) && ( H6inst < 030 ) && ( H6inst & 01) == 1 )
+ db_printf("\t%s.u",opcode);
+ else {
+ db_printf("\t%s",opcode);
+ db_printf(" ");
+ }
+ db_printf("\t\tr%-3d,r%-3d,", rd, rs1);
+ printval(Linst);
+}
+
+
+/* Handles instructions dealing with control registers */
+void
+ctrlregs(int inst, const char *opcode, long iadr)
+{
+ int L6inst = (inst >> 11) & 037;
+ int creg = (inst >> 5) & 077;
+ int rd = (inst >> 21) & 037;
+ int rs1 = (inst >> 16) & 037;
+
+ db_printf("\t%s",opcode);
+
+ if ( L6inst == 010 || L6inst == 011 )
+ db_printf("\t\tr%-3d,%s", rd,
+ cputyp == CPU_88100 ? m88100_ctrlreg[creg] : m88110_ctrlreg[creg]);
+ else if ( L6inst == 020 || L6inst == 021 )
+ db_printf("\t\tr%-3d,%s", rs1,
+ cputyp == CPU_88100 ? m88100_ctrlreg[creg] : m88110_ctrlreg[creg]);
+ else
+ db_printf("\t\tr%-3d,r%-3d,%s", rd, rs1,
+ cputyp == CPU_88100 ? m88100_ctrlreg[creg] : m88110_ctrlreg[creg]);
+}
+
+
+void
+printsod(int t)
+{
+ if ( t == 0 )
+ db_printf("s");
+ else
+ db_printf("d");
+}
+
+/* Handles floating point instructions */
+void
+sindou(int inst, const char *opcode, long iadr)
+{
+ int rs2 = inst & 037;
+ int td = ( inst >> 5 ) & 03;
+ int t2 = ( inst >> 7 ) & 03;
+ int t1 = ( inst >> 9 ) & 03;
+ int rs1 = ( inst >> 16 ) & 037;
+ int rd = ( inst >> 21 ) & 037;
+ int checkbits = ( inst >> 11 ) & 037;
+
+ db_printf("\t%s.",opcode);
+ printsod(td);
+ if (( checkbits > 010 && checkbits < 014 ) || ( checkbits == 04 )) {
+ printsod(t2);
+ db_printf(" ");
+ if ( checkbits == 012 || checkbits == 013 )
+ db_printf("\t\tr%-3d,r%-3d", rd, rs2);
+ else
+ db_printf("\t\tr%-3d,r%-3d", rd, rs2);
+ } else {
+ printsod(t1);printsod(t2);
+ db_printf("\t\tr%-3d,r%-3d,r%-3d", rd, rs1, rs2);
+ }
+}
+
+
+void
+jump(int inst, const char *opcode, long iadr)
+{
+ int rs2 = inst & 037;
+ int Nbit = ( inst >> 10 ) & 01;
+
+ db_printf("\t%s",opcode);
+ if ( Nbit == 1 )
+ db_printf(".n");
+ else
+ db_printf(" ");
+ db_printf("\t\tr%-3d",rs2);
+}
+
+
+/* Handles ff1, ff0, tbnd and rte instructions */
+void
+instset(int inst, const char *opcode, long iadr)
+{
+ int rs2 = inst & 037;
+ int rs1 = ( inst >> 16 ) & 037;
+ int rd = ( inst >> 21 ) & 037;
+ int checkbits = ( inst >> 10 ) & 077;
+ int H6inst = ( inst >> 26 ) & 077;
+
+ db_printf("\t%s",opcode);
+ if ( H6inst == 076 ) {
+ db_printf("\t\tr%-3d,",rs1);
+ printval(inst & 0177777);
+ } else if (( checkbits == 072 ) || ( checkbits == 073 ))
+ db_printf("\t\tr%-3d,r%-3d", rd, rs2);
+ else if ( checkbits == 076 )
+ db_printf("\t\tr%-3d,r%-3d",rs1,rs2);
+}
+
+void
+symofset(int disp, int bit, int iadr)
+{
+ long addr;
+
+ if ( disp & (1 << (bit-1)) ) {
+ /* negative value */
+ addr = iadr + ((disp << 2) | (~0 << bit));
+ } else {
+ addr = iadr + (disp << 2);
+ }
+ db_printsym(addr,DB_STGY_PROC, db_printf);
+ return;
+}
+
+void
+obranch(int inst, const char *opcode, long iadr)
+{
+ int cond = ( inst >> 26 ) & 01;
+ int disp = inst &0377777777;
+
+ if ( cond == 0 ) {
+ db_printf("\t%s\t\t",opcode);
+ symofset(disp, 26, iadr);
+ } else {
+ db_printf("\t%s.n\t\t",opcode);
+ symofset(disp, 26, iadr);
+ }
+}
+
+
+/* Handles branch on conditions instructions */
+void
+brcond(int inst, const char *opcode, long iadr)
+{
+ int cond = ( inst >> 26 ) & 1;
+ int match = ( inst >> 21 ) & 037;
+ int rs = ( inst >> 16 ) & 037;
+ int disp = ( inst & 0177777 );
+
+ if ( cond == 0 )
+ db_printf("\t%s\t\t", opcode);
+ else
+ db_printf("\t%s.n\t\t", opcode);
+ if ( ( ( inst >> 27 ) & 03 ) == 1 )
+ switch (match) {
+ case 1 : db_printf("%s,", condname[0]); break;
+ case 2 : db_printf("%s,", condname[1]); break;
+ case 3 : db_printf("%s,", condname[2]); break;
+ case 12: db_printf("%s,", condname[3]); break;
+ case 13: db_printf("%s,", condname[4]); break;
+ case 14: db_printf("%s,", condname[5]); break;
+ default: printval(match);
+ db_printf(",");
+ } else {
+ printval(match);
+ db_printf(",");
+ }
+
+ db_printf("r%-3d,", rs);
+ symofset(disp, 16, iadr);
+}
+
+
+void
+otrap(int inst, const char *opcode, long iadr)
+{
+ int vecno = inst & 0777;
+ int match = ( inst >> 21 ) & 037;
+ int rs = ( inst >> 16 ) & 037;
+
+ db_printf("\t%s\t",opcode);
+ if ( ( ( inst >> 12 ) & 017 ) == 0xe )
+ switch (match) {
+ case 1 : db_printf("%s,", condname[0]);break;
+ case 2 : db_printf("%s,", condname[1]);break;
+ case 3 : db_printf("%s,", condname[2]);break;
+ case 12: db_printf("%s,", condname[3]);break;
+ case 13: db_printf("%s,", condname[4]);break;
+ case 14: db_printf("%s,", condname[5]);break;
+ default: printval(match);
+ db_printf(",");
+ } else {
+ printval(match);
+ db_printf(",");
+ }
+ db_printf("\tr%-3d,", rs);
+ printval(vecno);
+}
+
+
+/* Handles 10 bit immediate bit field operations */
+void
+obit(int inst, const char *opcode, long iadr)
+{
+ int rs = ( inst >> 16 ) & 037;
+ int rd = ( inst >> 21 ) & 037;
+ int width = ( inst >> 5 ) & 037;
+ int offset = ( inst & 037 );
+
+ db_printf("\t%s\t\tr%-3d,r%-3d,", opcode, rd, rs);
+ if ( ( ( inst >> 10 ) & 077 ) == 052 ) {
+ db_printf("<");
+ printval(offset);
+ db_printf(">");
+ } else {
+ printval(width);
+ db_printf("<");
+ printval(offset);
+ db_printf(">");
+ }
+}
+
+
+/* Handles triadic mode bit field instructions */
+void
+bitman(int inst, const char *opcode, long iadr)
+{
+
+ int rs1 = ( inst >> 16 ) & 037;
+ int rd = ( inst >> 21 ) & 037;
+ int rs2 = inst & 037;
+
+ db_printf("\t%s\t\tr%-3d,r%-3d,r%-3d", opcode, rd, rs1, rs2);
+}
+
+
+/* Handles immediate load/store/exchange instructions */
+void
+immem(int inst, const char *opcode, long iadr)
+{
+ int immed = inst & 0xFFFF;
+ int rd = (inst >> 21) & 037;
+ int rs = (inst >> 16) & 037;
+ int st_lda = (inst >> 28) & 03;
+ int aryno = (inst >> 26) & 03;
+ char c = ' ';
+
+ if (!st_lda) {
+ if ((aryno == 0) || (aryno == 01))
+ opcode = "xmem";
+ else
+ opcode = "ld";
+ if (aryno == 0)
+ aryno = 03;
+ if (!(aryno == 01))
+ c = 'u';
+ } else
+ if (st_lda == 01)
+ opcode = "ld";
+
+ db_printf("\t%s%s%c\t\tr%-3d,r%-3d,", opcode, instwidth[aryno],
+ c, rd, rs);
+ printval(immed);
+}
+
+
+/* Handles triadic mode load/store/exchange instructions */
+void
+nimmem(int inst, const char *opcode, long iadr)
+{
+ int scaled = (inst >> 9) & 01;
+ int rd = (inst >> 21) & 037;
+ int rs1 = (inst >> 16) & 037;
+ int rs2 = inst & 037;
+ int st_lda = (inst >> 12) & 03;
+ int aryno = (inst >> 10) & 03;
+ int user_bit = 0;
+ int signed_fg = 1;
+ char *user = " ";
+ char c = ' ';
+
+ if (!st_lda) {
+ if ((aryno == 0) || (aryno == 01))
+ opcode = "xmem";
+ else
+ opcode = "ld";
+ if (aryno == 0)
+ aryno = 03;
+ if (!(aryno == 01)) {
+ c = 'u';
+ signed_fg = 0;
+ }
+ } else
+ if (st_lda == 01)
+ opcode = "ld";
+
+ if (!(st_lda == 03)) {
+ user_bit = (inst >> 8) & 01;
+ if (user_bit)
+ user = ".usr";
+ }
+
+ if (user_bit && signed_fg && (aryno == 01)) {
+ if (st_lda)
+ db_printf("\t%s%s\tr%-3d,r%-3d", opcode,
+ user, rd, rs1);
+ else
+ db_printf("\t%s%s\tr%-3d,r%-3d", opcode,
+ user, rd, rs1);
+ } else
+ if (user_bit && signed_fg)
+ db_printf("\t%s%s%s\tr%-3d,r%-3d", opcode,
+ instwidth[aryno], user, rd, rs1);
+ else
+ db_printf("\t%s%s%c%s\tr%-3d,r%-3d", opcode,
+ instwidth[aryno], c, user, rd, rs1);
+
+ if (scaled)
+ db_printf("[r%-3d]", rs2);
+ else
+ db_printf(",r%-3d", rs2);
+}
+
+
+/* Handles triadic mode logical instructions */
+void
+lognim(int inst, const char *opcode, long iadr)
+{
+ int rd = (inst >> 21) & 037;
+ int rs1 = (inst >> 16) & 037;
+ int rs2 = inst & 037;
+ int complemt = (inst >> 10) & 01;
+ char *c = " ";
+
+ if (complemt)
+ c = ".c";
+
+ db_printf("\t%s%s\t\tr%-3d,r%-3d,r%-3d", opcode, c, rd, rs1, rs2);
+}
+
+
+/* Handles triadic mode arithmetic instructions */
+void
+onimmed(int inst, const char *opcode, long iadr)
+{
+ int rd = (inst >> 21) & 037;
+ int rs1 = (inst >> 16) & 037;
+ int rs2 = inst & 037;
+ int carry = (inst >> 8) & 03;
+ int nochar = (inst >> 10) & 07;
+ int nodecode = (inst >> 11) & 01;
+ char *tab, *c ;
+
+ if (nochar > 02)
+ tab = "\t\t";
+ else
+ tab = "\t";
+
+ if (!nodecode) {
+ if (carry == 01)
+ c = ".co ";
+ else
+ if (carry == 02)
+ c = ".ci ";
+ else
+ if (carry == 03)
+ c = ".cio";
+ else
+ c = " ";
+ } else
+ c = " ";
+
+ db_printf("\t%s%s%sr%-3d,r%-3d,r%-3d", opcode, c,
+ tab, rd, rs1, rs2);
+}
+
+static const struct opdesc {
+ unsigned mask, match;
+ void (*opfun)(int, const char *, long);
+ const char *farg;
+} opdecode[] = {
+
+ /* ORDER IS IMPORTANT BELOW */
+
+ { 0xF0000000U, 0x00000000U, immem, NULL},
+ { 0xF0000000U, 0x10000000U, immem, NULL},
+ { 0xF0000000U, 0x20000000U, immem, "st"},
+ { 0xF0000000U, 0x30000000U, immem, "lda"},
+
+ { 0xF8000000U, 0x40000000U, oimmed, "and"},
+ { 0xF8000000U, 0x48000000U, oimmed, "mask"},
+ { 0xF8000000U, 0x50000000U, oimmed, "xor"},
+ { 0xF8000000U, 0x58000000U, oimmed, "or"},
+ { 0xFC000000U, 0x60000000U, oimmed, "addu"},
+ { 0xFC000000U, 0x64000000U, oimmed, "subu"},
+ { 0xFC000000U, 0x68000000U, oimmed, "divu"},
+ { 0xFC000000U, 0x6C000000U, oimmed, "mul"},
+ { 0xFC000000U, 0x70000000U, oimmed, "add"},
+ { 0xFC000000U, 0x74000000U, oimmed, "sub"},
+ { 0xFC000000U, 0x78000000U, oimmed, "div"},
+ { 0xFC000000U, 0x7C000000U, oimmed, "cmp"},
+
+ { 0xFC00F800U, 0x80004000U, ctrlregs, "ldcr"},
+ { 0xFC00F800U, 0x80004800U, ctrlregs, "fldcr"},
+ { 0xFC00F800U, 0x80008000U, ctrlregs, "stcr"},
+ { 0xFC00F800U, 0x80008800U, ctrlregs, "fstcr"},
+ { 0xFC00F800U, 0x8000C000U, ctrlregs, "xcr"},
+ { 0xFC00F800U, 0x8000C800U, ctrlregs, "fxcr"},
+
+ { 0xFC00F800U, 0x84000000U, sindou, "fmul"},
+ { 0xFC1FFF80U, 0x84002000U, sindou, "flt"},
+ { 0xFC00F800U, 0x84002800U, sindou, "fadd"},
+ { 0xFC00F800U, 0x84003000U, sindou, "fsub"},
+ { 0xFC00F860U, 0x84003800U, sindou, "fcmp"},
+ { 0xFC1FFE60U, 0x84004800U, sindou, "int"},
+ { 0xFC1FFE60U, 0x84005000U, sindou, "nint"},
+ { 0xFC1FFE60U, 0x84005800U, sindou, "trnc"},
+ { 0xFC00F800U, 0x84007000U, sindou, "fdiv"},
+
+ { 0xF8000000U, 0xC0000000U, obranch, "br"},
+ { 0xF8000000U, 0xC8000000U, obranch, "bsr"},
+
+ { 0xF8000000U, 0xD0000000U, brcond, "bb0"},
+ { 0xF8000000U, 0xD8000000U, brcond, "bb1"},
+ { 0xF8000000U, 0xE8000000U, brcond, "bcnd"},
+
+ { 0xFC00FC00U, 0xF0008000U, obit, "clr"},
+ { 0xFC00FC00U, 0xF0008800U, obit, "set"},
+ { 0xFC00FC00U, 0xF0009000U, obit, "ext"},
+ { 0xFC00FC00U, 0xF0009800U, obit, "extu"},
+ { 0xFC00FC00U, 0xF000A000U, obit, "mak"},
+ { 0xFC00FC00U, 0xF000A800U, obit, "rot"},
+
+ { 0xFC00FE00U, 0xF000D000U, otrap, "tb0"},
+ { 0xFC00FE00U, 0xF000D800U, otrap, "tb1"},
+ { 0xFC00FE00U, 0xF000E800U, otrap, "tcnd"},
+
+ { 0xFC00F2E0U, 0xF4000000U, nimmem, NULL},
+ { 0xFC00F2E0U, 0xF4000200U, nimmem, NULL},
+ { 0xFC00F2E0U, 0xF4001000U, nimmem, NULL},
+ { 0xFC00F2E0U, 0xF4001200U, nimmem, NULL},
+ { 0xFC00F2E0U, 0xF4002000U, nimmem, "st"},
+ { 0xFC00F2E0U, 0xF4002200U, nimmem, "st"},
+ { 0xFC00F2E0U, 0xF4003000U, nimmem, "lda"},
+ { 0xFC00F2E0U, 0xF4003200U, nimmem, "lda"},
+
+ { 0xFC00FBE0U, 0xF4004000U, lognim, "and"},
+ { 0xFC00FBE0U, 0xF4005000U, lognim, "xor"},
+ { 0xFC00FBE0U, 0xF4005800U, lognim, "or"},
+
+ { 0xFC00FCE0U, 0xF4006000U, onimmed, "addu"},
+ { 0xFC00FCE0U, 0xF4006400U, onimmed, "subu"},
+ { 0xFC00FCE0U, 0xF4006800U, onimmed, "divu"},
+ { 0xFC00FCE0U, 0xF4006C00U, onimmed, "mul"},
+ { 0xFC00FCE0U, 0xF4007000U, onimmed, "add"},
+ { 0xFC00FCE0U, 0xF4007400U, onimmed, "sub"},
+ { 0xFC00FCE0U, 0xF4007800U, onimmed, "div"},
+ { 0xFC00FCE0U, 0xF4007C00U, onimmed, "cmp"},
+
+ { 0xFC00FFE0U, 0xF4008000U, bitman, "clr"},
+ { 0xFC00FFE0U, 0xF4008800U, bitman, "set"},
+ { 0xFC00FFE0U, 0xF4009000U, bitman, "ext"},
+ { 0xFC00FFE0U, 0xF4009800U, bitman, "extu"},
+ { 0xFC00FFE0U, 0xF400A000U, bitman, "mak"},
+ { 0xFC00FFE0U, 0xF400A800U, bitman, "rot"},
+
+ { 0xFC00FBE0U, 0xF400C000U, jump, "jmp"},
+ { 0xFC00FBE0U, 0xF400C800U, jump, "jsr"},
+
+ { 0xFC00FFE0U, 0xF400E800U, instset, "ff1"},
+ { 0xFC00FFE0U, 0xF400EC00U, instset, "ff0"},
+ { 0xFC00FFE0U, 0xF400F800U, instset, "tbnd"},
+ { 0xFC00FFE0U, 0xF400FC00U, instset, "rte"},
+ { 0xFC000000U, 0xF8000000U, instset, "tbnd"},
+ { 0, 0, NULL, NULL}
+};
+
+static const char *badop = "\t???";
+
+int
+m88k_print_instruction(unsigned iadr, long inst)
+{
+ const struct opdesc *p;
+
+ /* this messes up "orb" instructions ever so slightly, */
+ /* but keeps us in sync between routines... */
+ if (inst == 0) {
+ db_printf ("\t.word 0");
+ } else {
+ for (p = opdecode; p->mask; p++)
+ if ((inst & p->mask) == p->match) {
+ (*p->opfun) (inst, p->farg, iadr);
+ break;
+ }
+ if (!p->mask)
+ db_printf (badop);
+ }
+
+ return iadr+4;
+}
+
+db_addr_t
+db_disasm(db_addr_t loc, boolean_t altfmt)
+{
+ m88k_print_instruction(loc, db_get_value(loc, 4, FALSE));
+ db_printf ("\n");
+ return loc+4;
+}
diff --git a/sys/arch/luna88k/ddb/db_interface.c b/sys/arch/luna88k/ddb/db_interface.c
new file mode 100644
index 00000000000..f08df609f78
--- /dev/null
+++ b/sys/arch/luna88k/ddb/db_interface.c
@@ -0,0 +1,827 @@
+/* $OpenBSD: db_interface.c,v 1.1 2004/04/21 15:23:50 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * m88k interface to ddb debugger
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/asm_macro.h> /* flush_pipeline() */
+#include <machine/cmmu.h> /* CMMU defs */
+#include <machine/trap.h> /* current_thread() */
+#include <machine/db_machdep.h> /* local ddb stuff */
+#include <machine/locore.h>
+#include <machine/cpu_number.h>
+#ifdef M88100
+#include <machine/m88100.h>
+#include <machine/m8820x.h>
+#endif
+
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_output.h>
+#include <ddb/db_sym.h>
+
+extern label_t *db_recover;
+extern unsigned db_trace_get_val(vaddr_t, unsigned *);
+extern int frame_is_sane(db_regs_t *, int);
+extern void cnpollc(int);
+void kdbprinttrap(int, int);
+
+void m88k_db_trap(int, struct trapframe *);
+int ddb_nmi_trap(int, db_regs_t *);
+void ddb_error_trap(char *, db_regs_t *);
+void db_putc(int);
+int db_getc(void);
+int m88k_dmx_print(unsigned, unsigned, unsigned, unsigned);
+void m88k_db_pause(unsigned);
+void m88k_db_print_frame(db_expr_t, int, db_expr_t, char *);
+void m88k_db_registers(db_expr_t, int, db_expr_t, char *);
+void m88k_db_where(db_expr_t, int, db_expr_t, char *);
+void m88k_db_frame_search(db_expr_t, int, db_expr_t, char *);
+void m88k_db_iflush(db_expr_t, int, db_expr_t, char *);
+void m88k_db_dflush(db_expr_t, int, db_expr_t, char *);
+void m88k_db_peek(db_expr_t, int, db_expr_t, char *);
+void m88k_db_noise(db_expr_t, int, db_expr_t, char *);
+void m88k_db_translate(db_expr_t, int, db_expr_t, char *);
+void m88k_db_cmmucfg(db_expr_t, int, db_expr_t, char *);
+void m88k_db_prom_cmd(db_expr_t, int, db_expr_t, char *);
+
+int db_active;
+int db_noisy;
+
+db_regs_t ddb_regs;
+
+/*
+ *
+ * If you really feel like understanding the following procedure and
+ * macros, see pages 6-22 to 6-30 (Section 6.7.3) of
+ *
+ * MC88100 RISC Microprocessor User's Manual Second Edition
+ * (Motorola Order: MC88100UM/AD REV 1)
+ *
+ * and ERRATA-5 (6-23, 6-24, 6-24) of
+ *
+ * Errata to MC88100 User's Manual Second Edition MC88100UM/AD Rev 1
+ * (Oct 2, 1990)
+ * (Motorola Order: MC88100UMAD/AD)
+ *
+ */
+
+#ifdef M88100
+/* macros for decoding dmt registers */
+
+/*
+ * return 1 if the printing of the next stage should be suppressed
+ */
+int
+m88k_dmx_print(t, d, a, no)
+ unsigned t, d, a, no;
+{
+ static const unsigned addr_mod[16] = {
+ 0, 3, 2, 2, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ static const char *mode[16] = {
+ "?", ".b", ".b", ".h", ".b", "?", "?", "?",
+ ".b", "?", "?" , "?" , ".h" , "?", "?", ""
+ };
+ static const unsigned mask[16] = {
+ 0, 0xff, 0xff00, 0xffff,
+ 0xff0000, 0, 0, 0,
+ 0xff000000, 0, 0, 0,
+ 0xffff0000, 0, 0, 0xffffffff
+ };
+ static const unsigned shift[16] = {
+ 0, 0, 8, 0, 16, 0, 0, 0,
+ 24, 0, 0, 0, 16, 0, 0, 0
+ };
+ int reg = DMT_DREGBITS(t);
+
+ if (ISSET(t, DMT_LOCKBAR)) {
+ db_printf("xmem%s%s r%d(0x%x) <-> mem(0x%x),",
+ DMT_ENBITS(t) == 0x0f ? "" : ".bu", ISSET(t, DMT_DAS) ? "" : ".usr", reg,
+ (((t)>>2 & 0xf) == 0xf) ? d : (d & 0xff), a);
+ return 1;
+ } else {
+ if (DMT_ENBITS(t) == 0xf) {
+ /* full or double word */
+ if (ISSET(t, DMT_WRITE)) {
+ if (ISSET(t, DMT_DOUB1) && no == 2)
+ db_printf("st.d%s -> mem(0x%x) (** restart sxip **)",
+ ISSET(t, DMT_DAS) ? "" : ".usr", a);
+ else
+ db_printf("st%s (0x%x) -> mem(0x%x)",
+ ISSET(t, DMT_DAS) ? "" : ".usr", d, a);
+ } else {
+ /* load */
+ if (ISSET(t, DMT_DOUB1) && no == 2)
+ db_printf("ld.d%s r%d <- mem(0x%x), r%d <- mem(0x%x)",
+ ISSET(t, DMT_DAS) ? "" : ".usr", reg, a, reg+1, a+4);
+ else
+ db_printf("ld%s r%d <- mem(0x%x)",
+ ISSET(t, DMT_DAS) ? "" : ".usr", reg, a);
+ }
+ } else {
+ /* fractional word - check if load or store */
+ a += addr_mod[DMT_ENBITS(t)];
+ if (ISSET(t, DMT_WRITE))
+ db_printf("st%s%s (0x%x) -> mem(0x%x)",
+ mode[DMT_ENBITS(t)], ISSET(t, DMT_DAS) ? "" : ".usr",
+ (d & mask[DMT_ENBITS(t)]) >> shift[DMT_ENBITS(t)], a);
+ else
+ db_printf("ld%s%s%s r%d <- mem(0x%x)",
+ mode[DMT_ENBITS(t)],
+ ISSET(t, DMT_SIGNED) ? "" : "u",
+ ISSET(t, DMT_DAS) ? "" : ".usr", reg, a);
+ }
+ }
+ return 0;
+}
+#endif /* M88100 */
+
+void
+m88k_db_print_frame(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ struct trapframe *s = (struct trapframe *)addr;
+ char *name;
+ db_expr_t offset;
+#ifdef M88100
+ int suppress1 = 0, suppress2 = 0;
+#endif
+ int c, force = 0, help = 0;
+
+ if (!have_addr) {
+ db_printf("requires address of frame\n");
+ help = 1;
+ }
+
+ while (modif && *modif) {
+ switch (c = *modif++, c) {
+ case 'f':
+ force = 1;
+ break;
+ case 'h':
+ help = 1;
+ break;
+ default:
+ db_printf("unknown modifier [%c]\n", c);
+ help = 1;
+ break;
+ }
+ }
+
+ if (help) {
+ db_printf("usage: mach frame/[f] ADDRESS\n");
+ db_printf(" /f force printing of insane frames.\n");
+ return;
+ }
+
+ if (badwordaddr((vaddr_t)s) ||
+ badwordaddr((vaddr_t)(&((db_regs_t*)s)->fpit))) {
+ db_printf("frame at %8p is unreadable\n", s);
+ return;
+ }
+
+ if (frame_is_sane((db_regs_t *)s, 0) == 0) { /* see db_trace.c */
+ if (force == 0)
+ return;
+ }
+
+#define R(i) s->tf_r[i]
+#define IPMASK(x) ((x) & ~(3))
+ db_printf("R00-05: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(0), R(1), R(2), R(3), R(4), R(5));
+ db_printf("R06-11: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(6), R(7), R(8), R(9), R(10), R(11));
+ db_printf("R12-17: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(12), R(13), R(14), R(15), R(16), R(17));
+ db_printf("R18-23: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(18), R(19), R(20), R(21), R(22), R(23));
+ db_printf("R24-29: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(24), R(25), R(26), R(27), R(28), R(29));
+ db_printf("R30-31: 0x%08x 0x%08x\n", R(30), R(31));
+
+ db_printf("%cxip: 0x%08x ",
+ cputyp == CPU_88110 ? 'e' : 's', s->tf_sxip & ~3);
+ db_find_xtrn_sym_and_offset((db_addr_t)IPMASK(s->tf_sxip),
+ &name, &offset);
+ if (name != NULL && (unsigned)offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned)offset);
+ db_printf("\n");
+
+ if (s->tf_snip != s->tf_sxip + 4) {
+ db_printf("%cnip: 0x%08x ",
+ cputyp == CPU_88110 ? 'e' : 's', s->tf_snip);
+ db_find_xtrn_sym_and_offset((db_addr_t)IPMASK(s->tf_snip),
+ &name, &offset);
+ if (name != NULL && (unsigned)offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned)offset);
+ db_printf("\n");
+ }
+
+ if (cputyp != CPU_88110) {
+ if (s->tf_sfip != s->tf_snip + 4) {
+ db_printf("sfip: 0x%08x ", s->tf_sfip);
+ db_find_xtrn_sym_and_offset((db_addr_t)IPMASK(s->tf_sfip),
+ &name, &offset);
+ if (name != NULL && (unsigned)offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned)offset);
+ db_printf("\n");
+ }
+ } else {
+ db_printf("fpsr: 0x%08x fpcr: 0x%08x fpecr: 0x%08x\n",
+ s->tf_fpsr, s->tf_fpcr, s->tf_fpecr);
+ db_printf("dsap 0x%08x duap 0x%08x dsr 0x%08x dlar 0x%08x dpar 0x%08x\n",
+ s->tf_dsap, s->tf_duap, s->tf_dsr, s->tf_dlar, s->tf_dpar);
+ db_printf("isap 0x%08x iuap 0x%08x isr 0x%08x ilar 0x%08x ipar 0x%08x\n",
+ s->tf_isap, s->tf_iuap, s->tf_isr, s->tf_ilar, s->tf_ipar);
+ }
+
+ db_printf("epsr: 0x%08x current process: %p\n",
+ s->tf_epsr, curproc);
+ db_printf("vector: 0x%02x interrupt mask: 0x%08x\n",
+ s->tf_vector, s->tf_mask);
+
+ /*
+ * If the vector indicates trap, instead of an exception or
+ * interrupt, skip the check of dmt and fp regs.
+ *
+ * Interrupt and exceptions are vectored at 0-10 and 114-127.
+ */
+
+ if (!(s->tf_vector <= 10 || (114 <= s->tf_vector && s->tf_vector <= 127))) {
+ db_printf("\n");
+ return;
+ }
+
+#ifdef M88100
+ if (cputyp != CPU_88110) {
+ if (s->tf_vector == /*data*/3 || s->tf_dmt0 & DMT_VALID) {
+ db_printf("dmt,d,a0: 0x%08x 0x%08x 0x%08x ",
+ s->tf_dmt0, s->tf_dmd0, s->tf_dma0);
+ db_find_xtrn_sym_and_offset((db_addr_t)s->tf_dma0, &name, &offset);
+ if (name != NULL && (unsigned)offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned)offset);
+ db_printf("\n ");
+
+ suppress1 = m88k_dmx_print(s->tf_dmt0, s->tf_dmd0, s->tf_dma0, 0);
+ db_printf("\n");
+
+ if ((s->tf_dmt1 & DMT_VALID) && (!suppress1)) {
+ db_printf("dmt,d,a1: 0x%08x 0x%08x 0x%08x ",
+ s->tf_dmt1, s->tf_dmd1, s->tf_dma1);
+ db_find_xtrn_sym_and_offset((db_addr_t)s->tf_dma1,
+ &name, &offset);
+ if (name != NULL &&
+ (unsigned)offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned)offset);
+ db_printf("\n ");
+ suppress2 = m88k_dmx_print(s->tf_dmt1, s->tf_dmd1, s->tf_dma1, 1);
+ db_printf("\n");
+
+ if ((s->tf_dmt2 & DMT_VALID) && (!suppress2)) {
+ db_printf("dmt,d,a2: 0x%08x 0x%08x 0x%08x ",
+ s->tf_dmt2, s->tf_dmd2, s->tf_dma2);
+ db_find_xtrn_sym_and_offset((db_addr_t)s->tf_dma2,
+ &name, &offset);
+ if (name != 0 && (unsigned)offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned)offset);
+ db_printf("\n ");
+ m88k_dmx_print(s->tf_dmt2, s->tf_dmd2, s->tf_dma2, 2);
+ db_printf("\n");
+ }
+ }
+
+ db_printf("fault code %d\n",
+ CMMU_PFSR_FAULT(s->tf_dpfsr));
+ }
+ }
+#endif /* M88100 */
+
+ if (s->tf_fpecr & 255) { /* floating point error occurred */
+ db_printf("fpecr: 0x%08x fpsr: 0x%08x fpcr: 0x%08x\n",
+ s->tf_fpecr, s->tf_fpsr, s->tf_fpcr);
+#ifdef M88100
+ if (cputyp != CPU_88110) {
+ db_printf("fcr1-4: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ s->tf_fphs1, s->tf_fpls1, s->tf_fphs2, s->tf_fpls2);
+ db_printf("fcr5-8: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ s->tf_fppt, s->tf_fprh, s->tf_fprl, s->tf_fpit);
+ }
+#endif
+ }
+ db_printf("\n");
+}
+
+void
+m88k_db_registers(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ m88k_db_print_frame((db_expr_t)DDB_REGS, TRUE, 0, modif);
+}
+
+/*
+ * pause for 2*ticks many cycles
+ */
+void
+m88k_db_pause(ticks)
+ unsigned volatile ticks;
+{
+ while (ticks)
+ ticks -= 1;
+}
+
+/*
+ * m88k_db_trap - field a TRACE or BPT trap
+ * Note that only the tf_regs part of the frame is valid - some ddb routines
+ * invoke this function with a promoted struct reg!
+ */
+void
+m88k_db_trap(type, frame)
+ int type;
+ struct trapframe *frame;
+{
+
+ if (get_psr() & (1 << PSR_INTERRUPT_DISABLE_BIT))
+ db_printf("WARNING: entered debugger with interrupts disabled\n");
+
+ switch(type) {
+ case T_KDB_BREAK:
+ case T_KDB_TRACE:
+ case T_KDB_ENTRY:
+ break;
+ case -1:
+ break;
+ default:
+ kdbprinttrap(type, 0);
+ if (db_recover != 0) {
+ db_error("Caught exception in ddb.\n");
+ /*NOTREACHED*/
+ }
+ }
+
+ ddb_regs = frame->tf_regs;
+
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, 0);
+ cnpollc(FALSE);
+ db_active--;
+
+ frame->tf_regs = ddb_regs;
+}
+
+extern const char *trap_type[];
+extern const int trap_types;
+
+/*
+ * Print trap reason.
+ */
+void
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: ");
+ if (type >= trap_types || type < 0)
+ printf("type %d", type);
+ else
+ printf("%s", trap_type[type]);
+ printf(" trap\n");
+}
+
+void
+Debugger()
+{
+ asm (ENTRY_ASM); /* entry trap */
+ /* ends up at ddb_entry_trap below */
+}
+
+/* fielded a non maskable interrupt */
+int
+ddb_nmi_trap(level, eframe)
+ int level;
+ db_regs_t *eframe;
+{
+ if (db_noisy)
+ db_printf("kernel: nmi interrupt\n");
+ m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)eframe);
+
+ return 0;
+}
+
+/*
+ * When the below routine is entered interrupts should be on
+ * but spl should be high
+ *
+ * The following routine is for breakpoint and watchpoint entry.
+ */
+
+/* breakpoint/watchpoint entry */
+int
+ddb_break_trap(type, eframe)
+ int type;
+ db_regs_t *eframe;
+{
+ m88k_db_trap(type, (struct trapframe *)eframe);
+
+ if (type == T_KDB_BREAK) {
+ /*
+ * back up an instruction and retry the instruction
+ * at the breakpoint address. mc88110's exip reg
+ * already has the address of the exception instruction.
+ */
+ if (cputyp != CPU_88110) {
+ eframe->sfip = eframe->snip;
+ eframe->snip = eframe->sxip;
+ }
+ }
+
+ return 0;
+}
+
+/* enter at splhigh */
+int
+ddb_entry_trap(level, eframe)
+ int level;
+ db_regs_t *eframe;
+{
+ m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)eframe);
+
+ return 0;
+}
+
+/*
+ * When the below routine is entered interrupts should be on
+ * but spl should be high
+ */
+/* error trap - unreturnable */
+void
+ddb_error_trap(error, regs)
+ char *error;
+ db_regs_t *regs;
+{
+ db_printf("KERNEL: terminal error [%s]\n", error);
+ db_printf("KERNEL: Exiting debugger will cause abort to rom\n");
+ db_printf("at 0x%x ", regs->sxip & XIP_ADDR);
+ db_printf("dmt0 0x%x dma0 0x%x", regs->dmt0, regs->dma0);
+ m88k_db_pause(1000000);
+ m88k_db_trap(T_KDB_BREAK, (struct trapframe *)regs);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+void
+db_read_bytes(db_addr_t addr, size_t size, char *data)
+{
+ char *src;
+
+ src = (char *)addr;
+
+ while(size-- > 0) {
+ *data++ = *src++;
+ }
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ * This should make a text page writable to be able
+ * to plant a break point (right now text is mapped with
+ * write access in pmap_bootstrap()). XXX nivas
+ */
+void
+db_write_bytes(db_addr_t addr, size_t size, char *data)
+{
+ char *dst;
+ paddr_t physaddr;
+ psize_t psize = size;
+
+ dst = (char *)addr;
+
+ while (size-- > 0) {
+ *dst++ = *data++;
+ }
+ /* XXX test return value */
+ pmap_extract(pmap_kernel(), (vaddr_t)addr, &physaddr);
+ cmmu_flush_cache(cpu_number(), physaddr, psize);
+}
+
+#define __ROM_FUNC_TABLE ((int **)0x00001100)
+
+/* to print a character to the console */
+void
+db_putc(c)
+ int c;
+{
+ (*(void (*)(int))__ROM_FUNC_TABLE[4])(c & 0xff);
+}
+
+/* to peek at the console; returns -1 if no character is there */
+int
+db_getc()
+{
+ int c;
+ do {
+ c = (*(int (*)(void))__ROM_FUNC_TABLE[3])();
+ } while (c == -1);
+ return c;
+}
+
+/* display where all the cpus are stopped at */
+void
+m88k_db_where(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ char *name;
+ db_expr_t offset;
+ db_addr_t l;
+
+ l = PC_REGS(DDB_REGS); /* clear low bits */
+
+ db_find_xtrn_sym_and_offset(l, &name, &offset);
+ if (name && (unsigned)offset <= db_maxoff)
+ db_printf("stopped at 0x%lx (%s+0x%x)\n", l, name, offset);
+ else
+ db_printf("stopped at 0x%lx\n", l);
+}
+
+/*
+ * Walk back a stack, looking for exception frames.
+ * These frames are recognized by the routine frame_is_sane. Frames
+ * only start with zero, so we only call frame_is_sane if the
+ * current address contains zero.
+ *
+ * If addr is given, it is assumed to an address on the stack to be
+ * searched. Otherwise, r31 of the current cpu is used.
+ */
+void
+m88k_db_frame_search(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ if (have_addr)
+ addr &= ~3; /* round to word */
+ else
+ addr = (DDB_REGS->r[31]);
+
+ /* walk back up stack until 8k boundry, looking for 0 */
+ while (addr & ((8 * 1024) - 1)) {
+ if (frame_is_sane((db_regs_t *)addr, 1) != 0)
+ db_printf("frame found at 0x%x\n", addr);
+ addr += 4;
+ }
+
+ db_printf("(Walked back until 0x%x)\n",addr);
+}
+
+/* flush icache */
+void
+m88k_db_iflush(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ addr = 0;
+#ifdef may_be_removed
+ cmmu_remote_set(addr, CMMU_SCR, 0, CMMU_FLUSH_CACHE_CBI_ALL);
+#endif
+}
+
+/* flush dcache */
+
+void
+m88k_db_dflush(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ addr = 0;
+#ifdef may_be_removed
+ cmmu_remote_set(addr, CMMU_SCR, 1, CMMU_FLUSH_CACHE_CBI_ALL);
+#endif
+}
+
+/* probe my cache */
+void
+m88k_db_peek(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+#ifdef may_be_removed
+ int pa12;
+ int valmask;
+
+ pa12 = addr & ~((1<<12) -1);
+
+ /* probe dcache */
+ cmmu_remote_set(0, CMMU_SAR, 1, addr);
+
+ valmask = cmmu_remote_get(0, CMMU_CSSP, 1);
+ db_printf("dcache valmask 0x%x\n", (unsigned)valmask);
+ db_printf("dcache tag ports 0x%x 0x%x 0x%x 0x%x\n",
+ (unsigned)cmmu_remote_get(0, CMMU_CTP0, 1),
+ (unsigned)cmmu_remote_get(0, CMMU_CTP1, 1),
+ (unsigned)cmmu_remote_get(0, CMMU_CTP2, 1),
+ (unsigned)cmmu_remote_get(0, CMMU_CTP3, 1));
+
+ /* probe icache */
+ cmmu_remote_set(0, CMMU_SAR, 0, addr);
+
+ valmask = cmmu_remote_get(0, CMMU_CSSP, 0);
+ db_printf("icache valmask 0x%x\n", (unsigned)valmask);
+ db_printf("icache tag ports 0x%x 0x%x 0x%x 0x%x\n",
+ (unsigned)cmmu_remote_get(0, CMMU_CTP0, 0),
+ (unsigned)cmmu_remote_get(0, CMMU_CTP1, 0),
+ (unsigned)cmmu_remote_get(0, CMMU_CTP2, 0),
+ (unsigned)cmmu_remote_get(0, CMMU_CTP3, 0));
+#endif
+}
+
+
+/*
+ * control how much info the debugger prints about itself
+ */
+void
+m88k_db_noise(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ if (!have_addr) {
+ /* if off make noisy; if noisy or very noisy turn off */
+ if (db_noisy) {
+ db_printf("changing debugger status from %s to quiet\n",
+ db_noisy == 1 ? "noisy" :
+ db_noisy == 2 ? "very noisy" : "violent");
+ db_noisy = 0;
+ } else {
+ db_printf("changing debugger status from quiet to noisy\n");
+ db_noisy = 1;
+ }
+ } else if (addr < 0 || addr > 3)
+ db_printf("invalid noise level to m88k_db_noisy; should be 0, 1, 2, or 3\n");
+ else {
+ db_noisy = addr;
+ db_printf("debugger noise level set to %s\n",
+ db_noisy == 0 ? "quiet" :
+ (db_noisy == 1 ? "noisy" :
+ db_noisy==2 ? "very noisy" : "violent"));
+ }
+}
+
+/*
+ * See how a virtual address translates.
+ * Must have an address.
+ */
+void
+m88k_db_translate(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ char c;
+ int verbose_flag = 0;
+ int supervisor_flag = 1;
+ int wanthelp = 0;
+
+ if (!have_addr)
+ wanthelp = 1;
+ else {
+ while (c = *modif++, c != 0) {
+ switch (c) {
+ default:
+ db_printf("bad modifier [%c]\n", c);
+ wanthelp = 1;
+ break;
+ case 'h':
+ wanthelp = 1;
+ break;
+ case 'v':
+ verbose_flag++;
+ break;
+ case 's':
+ supervisor_flag = 1;
+ break;
+ case 'u':
+ supervisor_flag = 0;
+ break;
+ }
+ }
+ }
+
+ if (wanthelp) {
+ db_printf("usage: translate[/vvsu] address\n");
+ db_printf("flags: v - be verbose (vv - be very verbose)\n");
+ db_printf(" s - use cmmu's supervisor area pointer (default)\n");
+ db_printf(" u - use cmmu's user area pointer\n");
+ return;
+ }
+ cmmu_show_translation(addr, supervisor_flag, verbose_flag, -1);
+}
+
+void
+m88k_db_cmmucfg(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ if (modif != NULL && *modif != 0) {
+ db_printf("usage: mach cmmucfg\n");
+ return;
+ }
+
+ cmmu_dump_config();
+}
+
+void
+m88k_db_prom_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ db_printf("m88k_db_prom_cmd() is not implemented\n");
+}
+
+/************************/
+/* COMMAND TABLE / INIT */
+/************************/
+
+struct db_command m88k_cache_cmds[] = {
+ { "iflush", m88k_db_iflush, 0, NULL },
+ { "dflush", m88k_db_dflush, 0, NULL },
+ { "peek", m88k_db_peek, 0, NULL },
+ { NULL, NULL, 0, NULL }
+};
+
+struct db_command db_machine_cmds[] = {
+ { "cache", NULL, 0, m88k_cache_cmds },
+ { "frame", m88k_db_print_frame, 0, NULL },
+ { "regs", m88k_db_registers, 0, NULL },
+ { "noise", m88k_db_noise, 0, NULL },
+ { "searchframe",m88k_db_frame_search, 0, NULL },
+ { "translate", m88k_db_translate, 0, NULL },
+ { "cmmucfg", m88k_db_cmmucfg, 0, NULL },
+ { "where", m88k_db_where, 0, NULL },
+ { "prom", m88k_db_prom_cmd, 0, NULL },
+ { NULL, NULL, 0, NULL }
+};
+
+void
+db_machine_init()
+{
+ db_machine_commands_install(db_machine_cmds);
+}
diff --git a/sys/arch/luna88k/ddb/db_sstep.c b/sys/arch/luna88k/ddb/db_sstep.c
new file mode 100644
index 00000000000..7c9a2da3254
--- /dev/null
+++ b/sys/arch/luna88k/ddb/db_sstep.c
@@ -0,0 +1,337 @@
+/* $OpenBSD: db_sstep.c,v 1.1 2004/04/21 15:23:51 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h> /* db_get_value() */
+#include <ddb/db_break.h> /* db_breakpoint_t */
+
+/*
+ * Support routines for software single step.
+ *
+ * Author: Daniel Stodolsky (danner@cs.cmu.edu)
+ *
+ */
+
+boolean_t inst_delayed(unsigned int ins);
+
+#ifdef INTERNAL_SSTEP
+db_breakpoint_t db_not_taken_bkpt = 0;
+db_breakpoint_t db_taken_bkpt = 0;
+#endif
+
+/*
+ * Returns TRUE is the instruction a branch or jump instruction
+ * (br, bb0, bb1, bcnd, jmp) but not a function call (bsr or jsr)
+ */
+boolean_t
+inst_branch(ins)
+ unsigned int ins;
+{
+ /* check high five bits */
+ switch (ins >> (32 - 5)) {
+ case 0x18: /* br */
+ case 0x1a: /* bb0 */
+ case 0x1b: /* bb1 */
+ case 0x1d: /* bcnd */
+ return TRUE;
+ break;
+ case 0x1e: /* could be jmp */
+ if ((ins & 0xfffffbe0U) == 0xf400c000U)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * inst_load(ins)
+ * Returns the number of words the instruction loads. byte,
+ * half and word count as 1; double word as 2
+ */
+unsigned
+inst_load(ins)
+ unsigned int ins;
+{
+ /* look at the top six bits, for starters */
+ switch (ins >> (32 - 6)) {
+ case 0x0: /* xmem byte imm */
+ case 0x1: /* xmem word imm */
+
+ case 0x2: /* unsigned half-word load imm */
+ case 0x3: /* unsigned byte load imm */
+ case 0x5: /* signed word load imm */
+ case 0x6: /* signed half-word load imm */
+ case 0x7: /* signed byte load imm */
+ return 1;
+
+ case 0x4: /* signed double word load imm */
+ return 2;
+
+ case 0x3d: /* load/store/xmem scaled/unscaled instruction */
+ if ((ins & 0xf400c0e0U) == 0xf4000000U) /* is load/xmem */
+ switch ((ins & 0x0000fce0) >> 5) { /* look at bits 15-5, but mask bits 8-9 */
+ case 0x0: /* xmem byte */
+ case 0x1: /* xmem word */
+ case 0x2: /* unsigned half word */
+ case 0x3: /* unsigned byte load */
+ case 0x5: /* signed word load */
+ case 0x6: /* signed half-word load */
+ case 0x7: /* signed byte load */
+ return 1;
+
+ case 0x4: /* signed double word load */
+ return 2;
+ } /* end switch load/xmem */
+ break;
+ } /* end switch 32-6 */
+
+ return 0;
+}
+
+/*
+ * inst_store
+ * Like inst_load, except for store instructions.
+ */
+unsigned
+inst_store(ins)
+ unsigned int ins;
+{
+ /* decode top 6 bits again */
+ switch (ins >> (32 - 6)) {
+ case 0x0: /* xmem byte imm */
+ case 0x1: /* xmem word imm */
+ case 0x9: /* store word imm */
+ case 0xa: /* store half-word imm */
+ case 0xb: /* store byte imm */
+ return 1;
+
+ case 0x8: /* store double word */
+ return 2;
+ case 0x3d: /* load/store/xmem scaled/unscaled instruction */
+ /* check bits 15,14,12,7,6,5 are all 0 */
+ if ((ins & 0x0000d0e0U) == 0)
+ switch ((ins & 0x00003c00U) >> 10) { /* decode bits 10-13 */
+ case 0x0: /* xmem byte imm */
+ case 0x1: /* xmem word imm */
+ case 0x9: /* store word */
+ case 0xa: /* store half-word */
+ case 0xb: /* store byte */
+ return 1;
+
+ case 0x8: /* store double word */
+ return 2;
+ } /* end switch store/xmem */
+ break;
+ } /* end switch 32-6 */
+
+ return 0;
+}
+
+/*
+ * inst_delayed
+ * Returns TRUE if this instruction is followed by a delay slot.
+ * Could be br.n, bsr.n bb0.n, bb1.n, bcnd.n or jmp.n or jsr.n
+ */
+boolean_t
+inst_delayed(ins)
+ unsigned int ins;
+{
+ /* check the br, bsr, bb0, bb1, bcnd cases */
+ switch ((ins & 0xfc000000U) >> (32 - 6)) {
+ case 0x31: /* br */
+ case 0x33: /* bsr */
+ case 0x35: /* bb0 */
+ case 0x37: /* bb1 */
+ case 0x3b: /* bcnd */
+ return TRUE;
+ }
+
+ /* check the jmp, jsr cases */
+ /* mask out bits 0-4, bit 11 */
+ return ((ins & 0xfffff7e0U) == 0xf400c400U) ? TRUE : FALSE;
+}
+
+/*
+ * next_instr_address(pc,delay_slot,task) has the following semantics.
+ * Let inst be the instruction at pc.
+ * If delay_slot = 1, next_instr_address should return
+ * the address of the instruction in the delay slot; if this instruction
+ * does not have a delay slot, it should return pc.
+ * If delay_slot = 0, next_instr_address should return the
+ * address of next sequential instruction, or pc if the instruction is
+ * followed by a delay slot.
+ *
+ * 91-11-28 jfriedl: I think the above is wrong. I think it should be:
+ * if delay_slot true, return address of the delay slot if there is one,
+ * return pc otherwise.
+ * if delay_slot false, return (pc + 4) regardless.
+ *
+ */
+db_addr_t
+next_instr_address(pc, delay_slot)
+ db_addr_t pc;
+ unsigned delay_slot;
+{
+ if (delay_slot == 0)
+ return pc + 4;
+ else {
+ if (inst_delayed(db_get_value(pc, sizeof(int), FALSE)))
+ return pc + 4;
+ else
+ return pc;
+ }
+}
+
+
+/*
+ * branch_taken(instruction, program counter, func, func_data)
+ *
+ * instruction will be a control flow instruction location at address pc.
+ * Branch taken is supposed to return the address to which the instruction
+ * would jump if the branch is taken. Func can be used to get the current
+ * register values when invoked with a register number and func_data as
+ * arguments.
+ *
+ * If the instruction is not a control flow instruction, panic.
+ */
+db_addr_t
+branch_taken(inst, pc, func, func_data)
+ u_int inst;
+ db_addr_t pc;
+ db_expr_t (*func)(db_regs_t *, int);
+ db_regs_t *func_data;
+{
+ /* check if br/bsr */
+ if ((inst & 0xf0000000U) == 0xc0000000U) {
+ /* signed 26 bit pc relative displacement, shift left two bits */
+ inst = (inst & 0x03ffffffU) << 2;
+ /* check if sign extension is needed */
+ if (inst & 0x08000000U)
+ inst |= 0xf0000000U;
+ return pc + inst;
+ }
+
+ /* check if bb0/bb1/bcnd case */
+ switch ((inst & 0xf8000000U)) {
+ case 0xd0000000U: /* bb0 */
+ case 0xd8000000U: /* bb1 */
+ case 0xe8000000U: /* bcnd */
+ /* signed 16 bit pc relative displacement, shift left two bits */
+ inst = (inst & 0x0000ffffU) << 2;
+ /* check if sign extension is needed */
+ if (inst & 0x00020000U)
+ inst |= 0xfffc0000U;
+ return pc + inst;
+ }
+
+ /* check jmp/jsr case */
+ /* check bits 5-31, skipping 10 & 11 */
+ if ((inst & 0xfffff3e0U) == 0xf400c000U) {
+ return (*func)(func_data, (inst & 0x0000001fU)); /* the register value */
+ }
+
+
+ panic("branch_taken");
+ return 0; /* keeps compiler happy */
+}
+
+/*
+ * getreg_val - handed a register number and an exception frame.
+ * Returns the value of the register in the specified
+ * frame. Only makes sense for general registers.
+ */
+
+db_expr_t
+getreg_val(frame, regno)
+ db_regs_t *frame;
+ int regno;
+{
+ if (regno == 0)
+ return 0;
+ else if (regno < 31)
+ return frame->r[regno];
+ else
+ panic("bad register number (%d) to getreg_val.", regno);
+}
+
+#ifdef INTERNAL_SSTEP
+void
+db_set_single_step(regs)
+ db_regs_t *regs;
+{
+ if (cputyp == CPU_88110) {
+ ((regs)->epsr |= (PSR_TRACE | PSR_SER));
+ } else {
+ db_addr_t pc = PC_REGS(regs);
+#ifndef SOFTWARE_SSTEP_EMUL
+ db_addr_t brpc;
+ u_int inst;
+
+ /*
+ * User was stopped at pc, e.g. the instruction
+ * at pc was not executed.
+ */
+ inst = db_get_value(pc, sizeof(int), FALSE);
+ if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
+ brpc = branch_taken(inst, pc, getreg_val, regs);
+ if (brpc != pc) { /* self-branches are hopeless */
+ db_taken_bkpt = db_set_temp_breakpoint(brpc);
+ }
+#if 0
+ /* XXX this seems like a true bug, no? */
+ pc = next_instr_address(pc, 1);
+#endif
+ }
+#endif /*SOFTWARE_SSTEP_EMUL*/
+ pc = next_instr_address(pc, 0);
+ db_not_taken_bkpt = db_set_temp_breakpoint(pc);
+ }
+}
+
+void
+db_clear_single_step(regs)
+ db_regs_t *regs;
+{
+ if (cputyp == CPU_88110) {
+ ((regs)->epsr &= ~(PSR_TRACE | PSR_SER));
+ } else {
+ if (db_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_taken_bkpt);
+ db_taken_bkpt = 0;
+ }
+ if (db_not_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_not_taken_bkpt);
+ db_not_taken_bkpt = 0;
+ }
+ }
+}
+#endif
diff --git a/sys/arch/luna88k/ddb/db_trace.c b/sys/arch/luna88k/ddb/db_trace.c
new file mode 100644
index 00000000000..3c24e6c4105
--- /dev/null
+++ b/sys/arch/luna88k/ddb/db_trace.c
@@ -0,0 +1,1143 @@
+/* $OpenBSD: db_trace.c,v 1.1 2004/04/21 15:23:52 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/db_machdep.h>
+#include <machine/locore.h>
+
+#include <ddb/db_variables.h> /* db_variable, DB_VAR_GET, etc. */
+#include <ddb/db_output.h> /* db_printf */
+#include <ddb/db_sym.h> /* DB_STGY_PROC, etc. */
+#include <ddb/db_command.h> /* db_recover */
+#include <ddb/db_access.h>
+#include <ddb/db_interface.h>
+
+union instruction {
+ unsigned rawbits;
+
+ struct {
+ unsigned int : 5;
+ unsigned int n: 1;
+ signed int d26:26;
+ } br;
+
+ struct {
+ unsigned int : 4;
+ unsigned int isbb1: 1; /* isbb1==0 means bb0, isbb1==1 means bb1 */
+ unsigned int n : 1;
+ unsigned int b5 : 5;
+ unsigned int s1 : 5;
+ signed int d16 :16;
+ } bb; /* bcnd too, except "isbb1" makes no sense for bcnd */
+
+ struct {
+ unsigned int : 6;
+ unsigned int b5 : 5;
+ unsigned int s1 : 5;
+ unsigned int : 7;
+ unsigned int vec9 : 9;
+ } tb; /* tcnd too */
+
+ struct {
+ unsigned int :21;
+ unsigned int n : 1;
+ unsigned int : 5;
+ unsigned int s2 : 5;
+ } jump; /* jmp, jsr */
+
+ struct {
+ unsigned int : 6;
+ unsigned int d : 5;
+ unsigned int s1 : 5;
+ unsigned int i16 :16;
+ } diatic; /* general reg/reg/i16 instructions */
+
+ struct {
+ unsigned int : 6;
+ unsigned int d : 5;
+ unsigned int s1 : 5;
+ unsigned int :11;
+ unsigned int s2 : 5;
+ } triatic; /* general reg/reg/reg instructions */
+
+};
+
+static inline unsigned br_dest(unsigned addr, union instruction inst)
+{
+ return addr + inst.br.d26 * 4;
+}
+
+
+#define TRACE_DEBUG /* undefine to disable debugging */
+
+int frame_is_sane(db_regs_t *regs, int);
+char *m88k_exception_name(unsigned vector);
+unsigned db_trace_get_val(vaddr_t addr, unsigned *ptr);
+
+/*
+ * Some macros to tell if the given text is the instruction.
+ */
+#define JMPN_R1(I) ( (I) == 0xf400c401U) /* jmp.n r1 */
+#define JMP_R1(I) ( (I) == 0xf400c001U) /* jmp r1 */
+
+/* gets the IMM16 value from an instruction */
+#define IMM16VAL(I) (((union instruction)(I)).diatic.i16)
+
+/* subu r31, r31, IMM */
+#define SUBU_R31_R31_IMM(I) (((I) & 0xffff0000U) == 0x67ff0000U)
+
+/* st r1, r31, IMM */
+#define ST_R1_R31_IMM(I) (((I) & 0xffff0000U) == 0x243f0000U)
+
+static int trace_flags;
+#define TRACE_DEBUG_FLAG 0x01
+#define TRACE_SHOWCALLPRESERVED_FLAG 0x02
+#define TRACE_SHOWADDRESS_FLAG 0x04
+#define TRACE_SHOWFRAME_FLAG 0x08
+#define TRACE_USER_FLAG 0x10
+
+#ifdef TRACE_DEBUG
+ #define DEBUGGING_ON (trace_flags & TRACE_DEBUG_FLAG)
+#endif
+
+#ifndef TRACE_DEBUG
+ #define SHOW_INSTRUCTION(Addr, Inst, Note) { /*nothing*/ }
+#else
+ #define SHOW_INSTRUCTION(Addr, Inst, Note) if (DEBUGGING_ON) { \
+ db_printf("%s0x%x: (0x%08x) ", Note, (unsigned)(Addr), (Inst)); \
+ m88k_print_instruction((unsigned)(Addr), (Inst)); \
+ db_printf("\n"); \
+ }
+#endif
+
+extern label_t *db_recover;
+
+/*
+ * m88k trace/register state interface for ddb.
+ */
+
+/* lifted from mips */
+static int
+db_setf_regs(struct db_variable *vp,
+ db_expr_t *valuep,
+ int op) /* read/write */
+{
+ int *regp = (int *) ((char *) DDB_REGS + (int) (vp->valuep));
+
+ if (op == DB_VAR_GET)
+ *valuep = *regp;
+ else if (op == DB_VAR_SET)
+ *regp = *valuep;
+
+ return (0); /* silence warning */
+}
+
+#define N(s, x) {s, (long *)&(((db_regs_t *) 0)->x), db_setf_regs}
+
+struct db_variable db_regs[] = {
+ N("r1", r[1]), N("r2", r[2]), N("r3", r[3]), N("r4", r[4]),
+ N("r5", r[5]), N("r6", r[6]), N("r7", r[7]), N("r8", r[8]),
+ N("r9", r[9]), N("r10", r[10]), N("r11", r[11]), N("r12", r[12]),
+ N("r13", r[13]), N("r14", r[14]), N("r15", r[15]), N("r16", r[16]),
+ N("r17", r[17]), N("r18", r[18]), N("r19", r[19]), N("r20", r[20]),
+ N("r21", r[21]), N("r22", r[22]), N("r23", r[23]), N("r24", r[24]),
+ N("r25", r[25]), N("r26", r[26]), N("r27", r[27]), N("r28", r[28]),
+ N("r29", r[29]), N("r30", r[30]), N("r31", r[31]), N("epsr", epsr),
+ N("sxip", sxip), N("snip", snip), N("sfip", sfip), N("ssbr", ssbr),
+ N("dmt0", dmt0), N("dmd0", dmd0), N("dma0", dma0), N("dmt1", dmt1),
+ N("dmd1", dmd1), N("dma1", dma1), N("dmt2", dmt2), N("dmd2", dmd2),
+ N("dma2", dma2), N("fpecr", fpecr),N("fphs1", fphs1),N("fpls1", fpls1),
+ N("fphs2", fphs2), N("fpls2", fpls2),N("fppt", fppt), N("fprh", fprh),
+ N("fprl", fprl), N("fpit", fpit), N("fpsr", fpsr), N("fpcr", fpcr),
+};
+#undef N
+
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+
+#define TRASHES 0x001 /* clobbers instruction field D */
+#define STORE 0x002 /* does a store to S1+IMM16 */
+#define LOAD 0x004 /* does a load from S1+IMM16 */
+#define DOUBLE 0x008 /* double-register */
+#define FLOW_CTRL 0x010 /* flow-control instruction */
+#define DELAYED 0x020 /* delayed flow control */
+#define JSR 0x040 /* flow-control is a jsr[.n] */
+#define BSR 0x080 /* flow-control is a bsr[.n] */
+
+/*
+ * Given a word of instruction text, return some flags about that
+ * instruction (flags defined above).
+ */
+static unsigned
+m88k_instruction_info(unsigned instruction)
+{
+ static const struct {
+ unsigned mask, value, flags;
+ } *ptr, control[] = {
+ /* runs in the same order as 2nd Ed 88100 manual Table 3-14 */
+ { 0xf0000000U, 0x00000000U, /* xmem */ TRASHES | STORE | LOAD},
+ { 0xec000000U, 0x00000000U, /* ld.d */ TRASHES | LOAD | DOUBLE},
+ { 0xe0000000U, 0x00000000U, /* load */ TRASHES | LOAD},
+ { 0xfc000000U, 0x20000000U, /* st.d */ STORE | DOUBLE},
+ { 0xf0000000U, 0x20000000U, /* store */ STORE},
+ { 0xc0000000U, 0x40000000U, /* arith */ TRASHES},
+ { 0xfc004000U, 0x80004000U, /* ld cr */ TRASHES},
+ { 0xfc004000U, 0x80000000U, /* st cr */ 0},
+ { 0xfc008060U, 0x84000000U, /* f */ TRASHES},
+ { 0xfc008060U, 0x84000020U, /* f.d */ TRASHES | DOUBLE},
+ { 0xfc000000U, 0xcc000000U, /* bsr.n */ FLOW_CTRL | DELAYED | BSR},
+ { 0xfc000000U, 0xc8000000U, /* bsr */ FLOW_CTRL | BSR},
+ { 0xe4000000U, 0xc4000000U, /* br/bb.n */ FLOW_CTRL | DELAYED},
+ { 0xe4000000U, 0xc0000000U, /* br/bb */ FLOW_CTRL},
+ { 0xfc000000U, 0xec000000U, /* bcnd.n */ FLOW_CTRL | DELAYED},
+ { 0xfc000000U, 0xe8000000U, /* bcnd */ FLOW_CTRL},
+ { 0xfc00c000U, 0xf0008000U, /* bits */ TRASHES},
+ { 0xfc00c000U, 0xf000c000U, /* trap */ 0},
+ { 0xfc00f0e0U, 0xf4002000U, /* st */ 0},
+ { 0xfc00cce0U, 0xf4000000U, /* ld.d */ TRASHES | DOUBLE},
+ { 0xfc00c0e0U, 0xf4000000U, /* ld */ TRASHES},
+ { 0xfc00c0e0U, 0xf4004000U, /* arith */ TRASHES},
+ { 0xfc00c3e0U, 0xf4008000U, /* bits */ TRASHES},
+ { 0xfc00ffe0U, 0xf400cc00U, /* jsr.n */ FLOW_CTRL | DELAYED | JSR},
+ { 0xfc00ffe0U, 0xf400c800U, /* jsr */ FLOW_CTRL | JSR},
+ { 0xfc00ffe0U, 0xf400c400U, /* jmp.n */ FLOW_CTRL | DELAYED},
+ { 0xfc00ffe0U, 0xf400c000U, /* jmp */ FLOW_CTRL},
+ { 0xfc00fbe0U, 0xf400e800U, /* ff */ TRASHES},
+ { 0xfc00ffe0U, 0xf400f800U, /* tbnd */ 0},
+ { 0xfc00ffe0U, 0xf400fc00U, /* rte */ FLOW_CTRL},
+ { 0xfc000000U, 0xf8000000U, /* tbnd */ 0},
+ };
+#define ctrl_count (sizeof(control)/sizeof(control[0]))
+ for (ptr = &control[0]; ptr < &control[ctrl_count]; ptr++)
+ if ((instruction & ptr->mask) == ptr->value)
+ return ptr->flags;
+ SHOW_INSTRUCTION(0, instruction, "bad m88k_instruction_info");
+ return 0;
+}
+
+static int
+hex_value_needs_0x(unsigned value)
+{
+ int i;
+ unsigned last = 0;
+ unsigned char c;
+ unsigned have_a_hex_digit = 0;
+
+ if (value <= 9)
+ return 0;
+
+ for (i = 0; i < 8; i++) {
+ c = value & 0xf;
+ value >>= 4;
+ if (c)
+ last = c;
+ if (c > 9)
+ have_a_hex_digit = 1;
+ }
+ if (have_a_hex_digit == 0)
+ return 1;
+ if (last > 9)
+ return 1;
+ return 0;
+}
+
+/*
+ * returns
+ * 1 if regs seems to be a reasonable kernel exception frame.
+ * 2 if regs seems to be a reasonable user exception frame
+ * (in the current task).
+ * 0 if this looks like neither.
+ */
+int
+frame_is_sane(db_regs_t *regs, int quiet)
+{
+ /* no good if we can't read the whole frame */
+ if (badwordaddr((vaddr_t)regs) || badwordaddr((vaddr_t)&regs->fpit)) {
+ if (quiet == 0)
+ db_printf("[WARNING: frame at %p : unreadable]\n", regs);
+ return 0;
+ }
+
+ /* r0 must be 0 (obviously) */
+ if (regs->r[0] != 0) {
+ if (quiet == 0)
+ db_printf("[WARNING: frame at %p : r[0] != 0]\n", regs);
+ return 0;
+ }
+
+ /* stack sanity ... r31 must be nonzero, and must be word aligned */
+ if (regs->r[31] == 0 || (regs->r[31] & 3) != 0) {
+ if (quiet == 0)
+ db_printf("[WARNING: frame at %p : r[31] == 0 or not word aligned]\n", regs);
+ return 0;
+ }
+
+ if (cputyp != CPU_88110) {
+ /* sxip is reasonable */
+#if 0
+ if ((regs->sxip & 1) == 1)
+ return 0;
+#endif
+ /* snip is reasonable */
+ if ((regs->snip & 3) != 2)
+ return 0;
+ /* sfip is reasonable */
+ if ((regs->sfip & 3) != 2)
+ return 0;
+ }
+
+ /* epsr sanity */
+ if ((regs->epsr & PSR_MODE)) { /* kernel mode */
+ if (regs->epsr & PSR_BO)
+ return 0;
+ return 1;
+ }
+ if (!(regs->epsr & PSR_MODE)) { /* user mode */
+ if (regs->epsr & PSR_BO)
+ return 0;
+ return 2;
+ }
+ if (quiet == 0)
+ db_printf("[WARNING: not an exception frame?]\n");
+ return 0;
+}
+
+char *
+m88k_exception_name(unsigned vector)
+{
+ switch (vector) {
+ default:
+ case 0: return "Reset";
+ case 1: return "Interrupt";
+ case 2: return "Instruction Access Exception";
+ case 3: return "Data Access Exception";
+ case 4: return "Misaligned Access Exception";
+ case 5: return "Unimplemented Opcode Exception";
+ case 6: return "Privilege Violation";
+ case 7: return "Bounds Check";
+ case 8: return "Integer Divide Exception";
+ case 9: return "Integer Overflow Exception";
+ case 10: return "Error Exception";
+ case 11: return "Non Maskable Interrupt";
+ case 114: return "FPU precise";
+ case 115: return "FPU imprecise";
+ case DDB_ENTRY_BKPT_NO:
+ return "ddb break";
+ case DDB_ENTRY_TRACE_NO:
+ return "ddb trace";
+ case DDB_ENTRY_TRAP_NO:
+ return "ddb trap";
+ case 451: return "Syscall";
+ }
+}
+
+/*
+ * Read a word at address addr.
+ * Return 1 if was able to read, 0 otherwise.
+ */
+unsigned
+db_trace_get_val(vaddr_t addr, unsigned *ptr)
+{
+ label_t db_jmpbuf;
+ label_t *prev = db_recover;
+
+ if (setjmp((db_recover = &db_jmpbuf)) != 0) {
+ db_recover = prev;
+ return 0;
+ } else {
+ db_read_bytes(addr, 4, (char *)ptr);
+ db_recover = prev;
+ return 1;
+ }
+}
+
+#define FIRST_CALLPRESERVED_REG 14
+#define LAST_CALLPRESERVED_REG 29
+#define FIRST_ARG_REG 2
+#define LAST_ARG_REG 9
+#define RETURN_VAL_REG 1
+
+static unsigned global_saved_list = 0x0; /* one bit per register */
+static unsigned local_saved_list = 0x0; /* one bit per register */
+static unsigned trashed_list = 0x0; /* one bit per register */
+static unsigned saved_reg[32]; /* one value per register */
+
+#define reg_bit(reg) (1<<((reg)%32))
+
+static void
+save_reg(int reg, unsigned value)
+{
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) db_printf("save_reg(%d, %x)\n", reg, value);
+#endif
+ if (trashed_list & reg_bit(reg)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) db_printf("<trashed>\n");
+#endif
+ return; /* don't save trashed registers */
+ }
+ saved_reg[(reg%32)] = value;
+ global_saved_list |= reg_bit(reg);
+ local_saved_list |= reg_bit(reg);
+}
+
+#define mark_reg_trashed(reg) (trashed_list |= reg_bit(reg))
+
+#define have_global_reg(reg) (global_saved_list & (1<<(reg)))
+#define have_local_reg(reg) (local_saved_list & (1<<(reg)))
+
+#define clear_local_saved_regs() { local_saved_list = trashed_list = 0; }
+#define clear_global_saved_regs() { local_saved_list = global_saved_list = 0; }
+
+#define saved_reg_value(reg) (saved_reg[(reg)])
+
+/*
+ * Show any arguments that we might have been able to determine.
+ */
+static void
+print_args(void)
+{
+ int reg, last_arg;
+
+ /* find the highest argument register saved */
+ for (last_arg = LAST_ARG_REG; last_arg >= FIRST_ARG_REG; last_arg--)
+ if (have_local_reg(last_arg))
+ break;
+ if (last_arg < FIRST_ARG_REG)
+ return; /* none were saved */
+
+ db_printf("(");
+
+ /* print each one, up to the highest */
+ for (reg = FIRST_ARG_REG; /*nothing */; reg++) {
+ if (!have_local_reg(reg))
+ db_printf("?");
+ else {
+ unsigned value = saved_reg_value(reg);
+ db_printf("%s%x", hex_value_needs_0x(value) ?
+ "0x" : "", value);
+ }
+ if (reg == last_arg)
+ break;
+ else
+ db_printf(", ");
+ }
+ db_printf(")");
+}
+
+
+#define JUMP_SOURCE_IS_BAD 0
+#define JUMP_SOURCE_IS_OK 1
+#define JUMP_SOURCE_IS_UNLIKELY 2
+
+/*
+ * Give an address to where we return, and an address to where we'd jumped,
+ * Decided if it all makes sense.
+ *
+ * Gcc sometimes optimized something like
+ * if (condition)
+ * func1();
+ * else
+ * OtherStuff...
+ * to
+ * bcnd !condition mark
+ * bsr.n func1
+ * or r1, r0, mark2
+ * mark:
+ * OtherStuff...
+ * mark2:
+ *
+ * So RETURN_TO will be MARK2, even though we really did branch via
+ * 'bsr.n func1', so this makes it difficult to be certaian about being
+ * wrong.
+ */
+static int
+is_jump_source_ok(unsigned return_to, unsigned jump_to)
+{
+ unsigned flags;
+ union instruction instruction;
+
+ /*
+ * Delayed branches are most common... look two instructions before
+ * where we were going to return to to see if it's a delayed branch.
+ */
+ if (!db_trace_get_val(return_to - 8, &instruction.rawbits))
+ return JUMP_SOURCE_IS_BAD;
+ flags = m88k_instruction_info(instruction.rawbits);
+
+ if ((flags & FLOW_CTRL) && (flags & DELAYED) && (flags & (JSR|BSR))) {
+ if (flags & JSR)
+ return JUMP_SOURCE_IS_OK; /* have to assume it's correct */
+ /* calculate the offset */
+ if (br_dest(return_to - 8, instruction) == jump_to)
+ return JUMP_SOURCE_IS_OK; /* exactamundo! */
+ else
+ return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */
+ }
+
+ /*
+ * Try again, looking for a non-delayed jump one back.
+ */
+ if (!db_trace_get_val(return_to - 4, &instruction.rawbits))
+ return JUMP_SOURCE_IS_BAD;
+ flags = m88k_instruction_info(instruction.rawbits);
+
+ if ((flags & FLOW_CTRL) && !(flags & DELAYED) && (flags & (JSR|BSR))) {
+ if (flags & JSR)
+ return JUMP_SOURCE_IS_OK; /* have to assume it's correct */
+ /* calculate the offset */
+ if (br_dest(return_to - 4, instruction) == jump_to)
+ return JUMP_SOURCE_IS_OK; /* exactamundo! */
+ else
+ return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */
+ }
+
+ return JUMP_SOURCE_IS_UNLIKELY;
+}
+
+static char *note = 0;
+static int next_address_likely_wrong = 0;
+
+/* How much slop we expect in the stack trace */
+#define FRAME_PLAY 8
+
+/*
+ * Stack decode -
+ * unsigned addr; program counter
+ * unsigned *stack; IN/OUT stack pointer
+ *
+ * given an address within a function and a stack pointer,
+ * try to find the function from which this one was called
+ * and the stack pointer for that function.
+ *
+ * The return value is zero (if we get confused) or
+ * we determine that the return address has not yet
+ * been saved (early in the function prologue). Otherwise
+ * the return value is the address from which this function
+ * was called.
+ *
+ * Note that even is zero is returned (the second case) the
+ * stack pointer can be adjusted.
+ *
+ */
+static int
+stack_decode(db_addr_t addr, unsigned *stack, int (*pr)(const char *, ...))
+{
+ db_sym_t proc;
+ db_expr_t offset_from_proc;
+ unsigned instructions_to_search;
+ db_addr_t check_addr;
+ db_addr_t function_addr; /* start of function */
+ unsigned r31 = *stack; /* the r31 of the function */
+ unsigned inst; /* text of an instruction */
+ unsigned ret_addr; /* address to which we return */
+ unsigned tried_to_save_r1 = 0;
+
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ (*pr)("\n>>>stack_decode(addr=%x, stack=%x)\n",
+ addr, *stack);
+#endif
+
+ /* get what we hope will be the db_sym_t for the function name */
+ proc = db_search_symbol(addr, DB_STGY_PROC, &offset_from_proc);
+ if (offset_from_proc == addr) /* i.e. no symbol found */
+ proc = DB_SYM_NULL;
+
+ /*
+ * Somehow, find the start of this function.
+ * If we found a symbol above, it'll have the address.
+ * Otherwise, we've got to search for it....
+ */
+ if (proc != DB_SYM_NULL) {
+ char *names;
+ db_symbol_values(proc, &names, &function_addr);
+ if (names == 0)
+ return 0;
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("name %s address 0x%x\n",
+ names, function_addr);
+#endif
+ } else {
+ int instructions_to_check = 400;
+ /*
+ * hmm - unable to find symbol. Search back
+ * looking for a function prolog.
+ */
+ for (check_addr = addr; instructions_to_check-- > 0; check_addr -= 4) {
+ if (!db_trace_get_val(check_addr, &inst))
+ break;
+
+ if (SUBU_R31_R31_IMM(inst)) {
+#if 0
+ /*
+ * If the next instruction is "st r1, r31, ####"
+ * then we can feel safe we have the start of
+ * a function.
+ */
+ if (!db_trace_get_val(check_addr + 4, &inst))
+ continue;
+ if (ST_R1_R31_IMM(instr))
+ break; /* success */
+#else
+ /*
+ * Latest GCC optimizer is just too good... the store
+ * of r1 might come much later... so we'll have to
+ * settle for just the "subr r31, r31, ###" to mark
+ * the start....
+ */
+ break;
+#endif
+ }
+ /*
+ * if we come across a [jmp r1] or [jmp.n r1] assume we have hit
+ * the previous functions epilogue and stop our search.
+ * Since we know we would have hit the "subr r31, r31" if it was
+ * right in front of us, we know this doesn't have one so
+ * we just return failure....
+ */
+ if (JMP_R1(inst) || JMPN_R1(inst)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ (*pr)("ran into a [jmp r1] at %x (addr=%x)\n",
+ check_addr, addr);
+#endif
+ return 0;
+ }
+ }
+ if (instructions_to_check < 0) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ (*pr)("couldn't find func start (addr=%x)\n", addr);
+#endif
+ return 0; /* bummer, couldn't find it */
+ }
+ function_addr = check_addr;
+ }
+
+ /*
+ * We now know the start of the function (function_addr).
+ * If we're stopped right there, or if it's not a
+ * subu r31, r31, ####
+ * then we're done.
+ */
+ if (addr == function_addr) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("at start of func\n");
+#endif
+ return 0;
+ }
+ if (!db_trace_get_val(function_addr, &inst)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("couldn't read %x at line %d\n",
+ function_addr, __LINE__);
+#endif
+ return 0;
+ }
+ SHOW_INSTRUCTION(function_addr, inst, "start of function: ");
+ if (!SUBU_R31_R31_IMM(inst)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("<not subu,r31,r31,imm>\n");
+#endif
+ return 0;
+ }
+
+ /* add the size of this frame to the stack (for the next frame) */
+ *stack += IMM16VAL(inst);
+
+ /*
+ * Search from the beginning of the function (funstart) to where we are
+ * in the function (addr) looking to see what kind of registers have
+ * been saved on the stack.
+ *
+ * We'll stop looking before we get to ADDR if we hit a branch.
+ */
+ clear_local_saved_regs();
+ check_addr = function_addr + 4; /* we know the first inst isn't a store */
+
+ for (instructions_to_search = (addr - check_addr)/sizeof(long);
+ instructions_to_search-- > 0;
+ check_addr += 4) {
+ union instruction instruction;
+ unsigned flags;
+
+ /* read the instruction */
+ if (!db_trace_get_val(check_addr, &instruction.rawbits)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("couldn't read %x at line %d\n",
+ check_addr, __LINE__);
+#endif
+ break;
+ }
+
+ SHOW_INSTRUCTION(check_addr, instruction.rawbits, "prolog: ");
+
+ /* find out the particulars about this instruction */
+ flags = m88k_instruction_info(instruction.rawbits);
+
+ /* if a store to something off the stack pointer, note the value */
+ if ((flags & STORE) && instruction.diatic.s1 == /*stack pointer*/31) {
+ unsigned value;
+ if (!have_local_reg(instruction.diatic.d)) {
+ if (instruction.diatic.d == 1)
+ tried_to_save_r1 = r31 + instruction.diatic.i16 ;
+ if (db_trace_get_val(r31 + instruction.diatic.i16, &value))
+ save_reg(instruction.diatic.d, value);
+ }
+ if ((flags & DOUBLE) && !have_local_reg(instruction.diatic.d + 1)) {
+ if (instruction.diatic.d == 0)
+ tried_to_save_r1 = r31+instruction.diatic.i16 +4;
+ if (db_trace_get_val(r31+instruction.diatic.i16 +4, &value))
+ save_reg(instruction.diatic.d + 1, value);
+ }
+ }
+
+ /* if an inst that kills D (and maybe D+1), note that */
+ if (flags & TRASHES) {
+ mark_reg_trashed(instruction.diatic.d);
+ if (flags & DOUBLE)
+ mark_reg_trashed(instruction.diatic.d + 1);
+ }
+
+ /* if a flow control instruction, stop now (or next if delayed) */
+ if ((flags & FLOW_CTRL) && instructions_to_search != 0)
+ instructions_to_search = (flags & DELAYED) ? 1 : 0;
+ }
+
+ /*
+ * If we didn't save r1 at some point, we're hosed.
+ */
+ if (!have_local_reg(1)) {
+ if (tried_to_save_r1) {
+ (*pr)(" <return value of next fcn unreadable in %08x>\n",
+ tried_to_save_r1);
+ }
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("didn't save r1\n");
+#endif
+ return 0;
+ }
+
+ ret_addr = saved_reg_value(1);
+
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ (*pr)("Return value is = %x, function_addr is %x.\n",
+ ret_addr, function_addr);
+#endif
+
+ /*
+ * In support of this, continuation.s puts the low bit on the
+ * return address for continuations (the return address will never
+ * be used, so it's ok to do anything you want to it).
+ */
+ if (ret_addr & 1) {
+ note = "<<can not trace past a continuation>>";
+ ret_addr = 0;
+ } else if (ret_addr != 0x00) {
+ switch (is_jump_source_ok(ret_addr, function_addr)) {
+ case JUMP_SOURCE_IS_OK:
+ break; /* excellent */
+
+ case JUMP_SOURCE_IS_BAD:
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON) (*pr)("jump is bad\n");
+#endif
+ return 0; /* bummer */
+
+ case JUMP_SOURCE_IS_UNLIKELY:
+ next_address_likely_wrong = 1;
+ break;
+ }
+ }
+
+ return ret_addr;
+}
+
+static void
+db_stack_trace_cmd2(db_regs_t *regs, int (*pr)(const char *, ...))
+{
+ unsigned stack;
+ unsigned depth=1;
+ unsigned where;
+ unsigned ft;
+ unsigned pair[2];
+ int i;
+
+ /*
+ * Frame_is_sane returns:
+ * 1 if regs seems to be a reasonable kernel exception frame.
+ * 2 if regs seems to be a reasonable user exception frame
+ * (in the current task).
+ * 0 if this looks like neither.
+ */
+ if ((ft = frame_is_sane(regs, 1)) == 0) {
+ (*pr)("Register frame 0x%x is suspicious; skipping trace\n", regs);
+ return;
+ }
+
+ /* if user space and no user space trace specified, puke */
+ if (ft == 2 && !(trace_flags & TRACE_USER_FLAG))
+ return;
+
+ /* fetch address */
+ /* use sxip if valid, otherwise try snip or sfip */
+ if (cputyp == CPU_88110) {
+ where = regs->exip & ~3;
+ } else {
+ where = ((regs->sxip & 2) ? regs->sxip :
+ ((regs->snip & 2) ? regs->snip :
+ regs->sfip) ) & ~3;
+ }
+ stack = regs->r[31];
+ (*pr)("stack base = 0x%x\n", stack);
+ (*pr)("(0) "); /*depth of trace */
+ if (trace_flags & TRACE_SHOWADDRESS_FLAG)
+ (*pr)("%08x ", where);
+ db_printsym(where, DB_STGY_PROC, pr);
+ clear_global_saved_regs();
+
+ /* see if this routine had a stack frame */
+ if ((where=stack_decode(where, &stack, pr))==0) {
+ where = regs->r[1];
+ (*pr)("(stackless)");
+ } else {
+ print_args();
+ if (trace_flags & TRACE_SHOWFRAME_FLAG)
+ (*pr)(" [frame 0x%x]", stack);
+ }
+ (*pr)("\n");
+ if (note) {
+ (*pr)(" %s\n", note);
+ note = 0;
+ }
+
+ do {
+ /*
+ * If requested, show preserved registers at the time
+ * the next-shown call was made. Only registers known to have
+ * changed from the last exception frame are shown, as others
+ * can be gotten at by looking at the exception frame.
+ */
+ if (trace_flags & TRACE_SHOWCALLPRESERVED_FLAG) {
+ int r, title_printed = 0;
+
+ for (r = FIRST_CALLPRESERVED_REG; r<=LAST_CALLPRESERVED_REG; r++) {
+ if (have_global_reg(r)) {
+ unsigned value = saved_reg_value(r);
+ if (title_printed == 0) {
+ title_printed = 1;
+ (*pr)("[in next func:");
+ }
+ if (value == 0)
+ (*pr)(" r%d", r);
+ else if (value <= 9)
+ (*pr)(" r%d=%x", r, value);
+ else
+ (*pr)(" r%d=x%x", r, value);
+ }
+ }
+ if (title_printed)
+ (*pr)("]\n");
+ }
+
+ (*pr)("(%d)%c", depth++, next_address_likely_wrong ? '?':' ');
+ next_address_likely_wrong = 0;
+
+ if (trace_flags & TRACE_SHOWADDRESS_FLAG)
+ (*pr)("%08x ", where);
+ db_printsym(where, DB_STGY_PROC, pr);
+ where = stack_decode(where, &stack, pr);
+ print_args();
+ if (trace_flags & TRACE_SHOWFRAME_FLAG)
+ (*pr)(" [frame 0x%x]", stack);
+ (*pr)("\n");
+ if (note) {
+ (*pr)(" %s\n", note);
+ note = 0;
+ }
+ } while (where);
+
+ /* try to trace back over trap/exception */
+
+ stack &= ~7; /* double word aligned */
+ /* take last top of stack, and try to find an exception frame near it */
+
+ i = FRAME_PLAY;
+
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ (*pr)("(searching for exception frame at 0x%x)\n", stack);
+#endif
+
+ while (i) {
+ /*
+ * On the stack, a pointer to the exception frame is written
+ * in two adjacent words. In the case of a fault from the kernel,
+ * this should point to the frame right above them:
+ *
+ * Exception Frame Top
+ * ..
+ * Exception Frame Bottom <-- frame addr
+ * frame addr
+ * frame addr <-- stack pointer
+ *
+ * In the case of a fault from user mode, the top of stack
+ * will just have the address of the frame
+ * replicated twice.
+ *
+ * frame addr <-- top of stack
+ * frame addr
+ *
+ * Here we are just looking for kernel exception frames.
+ */
+
+ if (badwordaddr((vaddr_t)stack) ||
+ badwordaddr((vaddr_t)(stack+4)))
+ break;
+
+ db_read_bytes((vaddr_t)stack, 2*sizeof(int), (char *)pair);
+
+ /* the pairs should match and equal stack+8 */
+ if (pair[0] == pair[1]) {
+ if (pair[0] != stack+8) {
+ /*
+ if (!badwordaddr((vaddr_t)pair[0]) && (pair[0]!=0))
+ (*pr)("stack_trace:found pair 0x%x but != to stack+8\n",
+ pair[0]);
+ */
+ }
+
+ else if (frame_is_sane((db_regs_t*)pair[0], 1) != 0) {
+ struct trapframe *frame =
+ (struct trapframe *)pair[0];
+
+ (*pr)("-------------- %s [EF: 0x%x] -------------\n",
+ m88k_exception_name(frame->tf_vector),
+ frame);
+ db_stack_trace_cmd2(&frame->tf_regs, pr);
+ return;
+ }
+#ifdef TRACE_DEBUG
+ else if (DEBUGGING_ON)
+ (*pr)("pair matched, but frame at 0x%x looks insane\n",
+ stack+8);
+#endif
+ }
+ stack += 8;
+ i--;
+ }
+
+ /*
+ * If we go here, crawling back on the stack failed to find us
+ * a previous exception frame. Look for a user frame pointer
+ * pointed to by a word 8 bytes off of the top of the stack
+ * if the "u" option was specified.
+ */
+ if (trace_flags & TRACE_USER_FLAG) {
+ struct trapframe *user;
+
+ /* Make sure we are back on the right page */
+ stack -= 4*FRAME_PLAY;
+ stack = stack & ~(KERNEL_STACK_SIZE-1); /* point to the bottom */
+ stack += KERNEL_STACK_SIZE - 8;
+
+ if (badwordaddr((vaddr_t)stack) ||
+ badwordaddr((vaddr_t)stack))
+ return;
+
+ db_read_bytes((vaddr_t)stack, 2*sizeof(int), (char *)pair);
+ if (pair[0] != pair[1])
+ return;
+
+ /* have a hit */
+ user = *((struct trapframe **)stack);
+
+ if (frame_is_sane(&user->tf_regs, 1) == 2) {
+ (*pr)("---------------- %s [EF : 0x%x] -------------\n",
+ m88k_exception_name(user->tf_vector), user);
+ db_stack_trace_cmd2(&user->tf_regs, pr);
+ }
+ }
+}
+
+/*
+ * stack trace - needs a pointer to a m88k saved state.
+ *
+ * If argument f is given, the stack pointer of each call frame is
+ * printed.
+ */
+void
+db_stack_trace_print(db_expr_t addr,
+ int have_addr,
+ db_expr_t count,
+ char *modif,
+ int (*pr)(const char *, ...))
+{
+ enum {
+ Default, Stack, Frame
+ } style = Default;
+ db_regs_t frame;
+ db_regs_t *regs;
+ union {
+ db_regs_t *frame;
+ db_expr_t num;
+ } arg;
+
+ arg.num = addr;
+
+ trace_flags = 0; /* flags will be set via modifers */
+
+ while (modif && *modif) {
+ switch (*modif++) {
+ case 'd':
+#ifdef TRACE_DEBUG
+ trace_flags |= TRACE_DEBUG_FLAG;
+#else
+ db_printtf("<debug trace not compiled in, ignoring>\n");
+#endif
+ break;
+
+ case 's': style = Stack ; break;
+ case 'f': style = Frame ; break;
+ case 'p': trace_flags |= TRACE_SHOWCALLPRESERVED_FLAG; break;
+ case 'a': trace_flags |= TRACE_SHOWADDRESS_FLAG; break;
+ case 'F': trace_flags |= TRACE_SHOWFRAME_FLAG; break;
+ case 'u': trace_flags |= TRACE_USER_FLAG; break;
+ default:
+ (*pr)("unknown trace modifier [%c]\n", modif[-1]);
+ /*FALLTHROUGH*/
+ case 'h':
+ (*pr)("usage: trace/[MODIFIER] [ARG]\n");
+ (*pr)(" u = include user trace\n");
+ (*pr)(" F = print stack frames\n");
+ (*pr)(" a = show return addresses\n");
+ (*pr)(" p = show call-preserved registers\n");
+ (*pr)(" s = ARG is a stack pointer\n");
+ (*pr)(" f = ARG is a frame pointer\n");
+#ifdef TRACE_DEBUG
+ (*pr)(" d = trace-debugging output\n");
+#endif
+ return;
+ }
+ }
+
+ if (!have_addr && style != Default) {
+ (*pr)("expecting argument with /s or /f\n");
+ return;
+ }
+ if (have_addr && style == Default)
+ style = Frame;
+
+ switch (style) {
+ case Default:
+ regs = DDB_REGS;
+ break;
+ case Frame:
+ regs = arg.frame;
+ break;
+ case Stack:
+ {
+ unsigned val1, val2, sxip;
+ unsigned ptr;
+ bzero((void *)&frame, sizeof(frame));
+#define REASONABLE_FRAME_DISTANCE 2048
+
+ /*
+ * We've got to find the top of a stack frame so we can get both
+ * a PC and and real SP.
+ */
+ for (ptr = arg.num;/**/; ptr += 4) {
+ /* Read a word from the named stack */
+ if (db_trace_get_val(ptr, &val1) == 0) {
+ (*pr)("can't read from %x, aborting.\n", ptr);
+ return;
+ }
+
+ /*
+ * See if it's a frame pointer.... if so it will be larger than
+ * the address it was taken from (i.e. point back up the stack)
+ * and we'll be able to read where it points.
+ */
+ if (val1 <= ptr ||
+ (val1 & 3) ||
+ val1 > (ptr + REASONABLE_FRAME_DISTANCE))
+ continue;
+
+ /* peek at the next word to see if it could be a return address */
+ if (db_trace_get_val(ptr, &sxip) == 0) {
+ (*pr)("can't read from %x, aborting.\n", ptr);
+ return;
+ }
+ if (sxip == 0 || !db_trace_get_val(sxip, &val2))
+ continue;
+
+ if (db_trace_get_val(val1, &val2) == 0) {
+ (*pr)("can't read from %x, aborting.\n", val1);
+ continue;
+ }
+
+ /*
+ * The value we've just read will be either another frame pointer,
+ * or the start of another exception frame.
+ */
+ if (
+#ifdef JEFF_DEBUG
+ val2 == 0
+#else
+ val2 == 0x12345678
+#endif
+ && db_trace_get_val(val1-4, &val2) && val2 == val1
+ && db_trace_get_val(val1-8, &val2) && val2 == val1) {
+ /* we've found a frame, so the stack must have been good */
+ (*pr)("%x looks like a frame, accepting %x\n",val1,ptr);
+ break;
+ }
+
+ if (val2 > val1 && (val2 & 3) == 0) {
+ /* well, looks close enough to be another frame pointer */
+ (*pr)("*%x = %x looks like a stack frame pointer, accepting %x\n", val1, val2, ptr);
+ break;
+ }
+ }
+ frame.r[31] = ptr;
+ frame.epsr = 0x800003f0U;
+ if (cputyp != CPU_88110) {
+ frame.sxip = sxip | 2;
+ frame.snip = frame.sxip + 4;
+ frame.sfip = frame.snip + 4;
+ }
+ (*pr)("[r31=%x, %sxip=%x]\n", frame.r[31],
+ cputyp == CPU_88110 ? "e" : "s", frame.sxip);
+ regs = &frame;
+ }
+ }
+ db_stack_trace_cmd2(regs, pr);
+}
diff --git a/sys/arch/luna88k/dev/if_le.c b/sys/arch/luna88k/dev/if_le.c
new file mode 100644
index 00000000000..4192bbd21d8
--- /dev/null
+++ b/sys/arch/luna88k/dev/if_le.c
@@ -0,0 +1,204 @@
+/* $OpenBSD: if_le.c,v 1.1 2004/04/21 15:23:52 aoyama Exp $ */
+/* $NetBSD: if_le.c,v 1.33 1996/11/20 18:56:52 gwr Exp $ */
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Adam Glass and Gordon W. Ross.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* based on OpenBSD: sys/arch/sun3/dev/if_le.c */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net/if_media.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+#include <dev/ic/am7990reg.h>
+#include <dev/ic/am7990var.h>
+
+#include <luna88k/luna88k/isr.h>
+
+/*
+ * LANCE registers.
+ * The real stuff is in dev/ic/am7990reg.h
+ */
+struct lereg1 {
+ volatile u_int16_t ler1_rdp; /* data port */
+ volatile unsigned : 16 ; /* LUNA-88K2 has a 16 bit gap */
+ volatile u_int16_t ler1_rap; /* register select port */
+};
+
+/*
+ * Ethernet software status per interface.
+ * The real stuff is in dev/ic/am7990var.h
+ */
+struct le_softc {
+ struct am7990_softc sc_am7990; /* glue to MI code */
+
+ struct lereg1 *sc_r1; /* LANCE registers */
+};
+
+static int le_match(struct device *, void *, void *);
+static void le_attach(struct device *, struct device *, void *);
+
+struct cfattach le_ca = {
+ sizeof(struct le_softc), le_match, le_attach
+};
+
+hide void lewrcsr(struct am7990_softc *, u_int16_t, u_int16_t);
+hide u_int16_t lerdcsr(struct am7990_softc *, u_int16_t);
+hide void myetheraddr(u_int8_t *);
+
+hide void
+lewrcsr(sc, port, val)
+ struct am7990_softc *sc;
+ u_int16_t port, val;
+{
+ register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
+
+ ler1->ler1_rap = port;
+ ler1->ler1_rdp = val;
+}
+
+hide u_int16_t
+lerdcsr(sc, port)
+ struct am7990_softc *sc;
+ u_int16_t port;
+{
+ register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
+ u_int16_t val;
+
+ ler1->ler1_rap = port;
+ val = ler1->ler1_rdp;
+ return (val);
+}
+
+static int
+le_match(parent, cf, aux)
+ struct device *parent;
+ void *cf, *aux;
+{
+ struct mainbus_attach_args *ma = aux;
+
+ if (strcmp(ma->ma_name, le_cd.cd_name))
+ return (0);
+
+ return (1);
+}
+
+void
+le_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct le_softc *lesc = (struct le_softc *)self;
+ struct am7990_softc *sc = &lesc->sc_am7990;
+ struct mainbus_attach_args *ma = aux;
+
+ lesc->sc_r1 = (struct lereg1 *)ma->ma_addr; /* LANCE */
+
+ sc->sc_mem = (void *)0x71000000; /* SRAM */
+ sc->sc_conf3 = LE_C3_BSWP;
+ sc->sc_addr = (u_long)sc->sc_mem & 0xffffff;
+ sc->sc_memsize = 64 * 1024; /* 64KB */
+
+ myetheraddr(sc->sc_arpcom.ac_enaddr);
+
+ sc->sc_copytodesc = am7990_copytobuf_contig;
+ sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
+ sc->sc_copytobuf = am7990_copytobuf_contig;
+ sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
+ sc->sc_zerobuf = am7990_zerobuf_contig;
+
+ sc->sc_rdcsr = lerdcsr;
+ sc->sc_wrcsr = lewrcsr;
+ sc->sc_hwreset = NULL;
+ sc->sc_hwinit = NULL;
+
+ am7990_config(sc);
+
+ isrlink_autovec(am7990_intr, (void *)sc, ma->ma_ilvl, ISRPRI_NET);
+}
+
+/*
+ * Taken from NetBSD/luna68k
+ *
+ * LUNA-88K2 (and LUNA-88K?) has 16Kbit NVSRAM on its ethercard, whose
+ * contents are accessible 4bit-wise by ctl register operation. The
+ * register is mapped at 0xF1000008.
+ */
+
+hide void
+myetheraddr(ether)
+ u_int8_t *ether;
+{
+ unsigned i, loc;
+ volatile struct { u_int32_t ctl; } *ds1220;
+
+ ds1220 = (void *)0xF1000008;
+ loc = 12;
+ for (i = 0; i < 6; i++) {
+ unsigned u, l, hex;
+
+ ds1220->ctl = (loc) << 16;
+ u = 0xf0 & (ds1220->ctl >> 12);
+ ds1220->ctl = (loc + 1) << 16;
+ l = 0x0f & (ds1220->ctl >> 16);
+ hex = (u < '9') ? l : l + 9;
+
+ ds1220->ctl = (loc + 2) << 16;
+ u = 0xf0 & (ds1220->ctl >> 12);
+ ds1220->ctl = (loc + 3) << 16;
+ l = 0x0f & (ds1220->ctl >> 16);
+
+ ether[i] = ((u < '9') ? l : l + 9) | (hex << 4);
+ loc += 4;
+ }
+}
diff --git a/sys/arch/luna88k/dev/lcd.c b/sys/arch/luna88k/dev/lcd.c
new file mode 100644
index 00000000000..cfba031871c
--- /dev/null
+++ b/sys/arch/luna88k/dev/lcd.c
@@ -0,0 +1,173 @@
+/* $OpenBSD: lcd.c,v 1.1 2004/04/21 15:23:52 aoyama Exp $ */
+/* $NetBSD: lcd.c,v 1.2 2000/01/07 05:13:08 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Taken from NetBSD/luna68k */
+
+/*
+ * XXX
+ * Following code segments are subject to change.
+ * XXX
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#define PIO1_MODE_OUTPUT 0x84
+#define PIO1_MODE_INPUT 0x94
+
+#define POWER 0x10
+
+#define ENABLE 0x80
+#define DISABLE 0x00
+
+#define WRITE_CMD (0x00 | 0x00)
+#define WRITE_DATA (0x00 | 0x40)
+#define READ_BUSY (0x20 | 0x00)
+#define READ_DATA (0x20 | 0x40)
+
+#define LCD_INIT 0x38
+#define LCD_ENTRY 0x06
+#define LCD_ON 0x0c
+#define LCD_CLS 0x01
+#define LCD_HOME 0x02
+#define LCD_LOCATE(X, Y) (((Y) & 1 ? 0xc0 : 0x80) | ((X) & 0x0f))
+
+struct pio {
+ volatile u_int8_t portA;
+ volatile unsigned : 24;
+ volatile u_int8_t portB;
+ volatile unsigned : 24;
+ volatile u_int8_t portC;
+ volatile unsigned : 24;
+ volatile u_int8_t cntrl;
+ volatile unsigned : 24;
+};
+
+void lcdbusywait(void);
+void lcdput(int);
+void lcdctrl(int);
+void lcdshow(const char *);
+void greeting(void);
+ /* "1234567890123456" */
+static const char lcd_boot_message1[] = "OpenBSD/luna88k ";
+static const char lcd_boot_message2[] = " SX-9100/DT ";
+
+void
+lcdbusywait()
+{
+ struct pio *p1 = (struct pio *)0x4D000000;
+ int msb, s;
+
+ s = splhigh();
+ p1->cntrl = PIO1_MODE_INPUT;
+ p1->portC = POWER | READ_BUSY | ENABLE;
+ splx(s);
+
+ do {
+ msb = p1->portA & ENABLE;
+ delay(5);
+ } while (msb != 0);
+
+ s = splhigh();
+ p1->portC = POWER | READ_BUSY | DISABLE;
+ splx(s);
+}
+
+void
+lcdput(cc)
+ int cc;
+{
+ struct pio *p1 = (struct pio *)0x4D000000;
+ int s;
+
+ lcdbusywait();
+
+ s = splhigh();
+ p1->cntrl = PIO1_MODE_OUTPUT;
+
+ p1->portC = POWER | WRITE_DATA | ENABLE;
+ p1->portA = cc;
+ p1->portC = POWER | WRITE_DATA | DISABLE;
+ splx(s);
+}
+
+void
+lcdctrl(cc)
+ int cc;
+{
+ struct pio *p1 = (struct pio *)0x4D000000;
+ int s;
+
+ lcdbusywait();
+
+ s = splhigh();
+ p1->cntrl = PIO1_MODE_OUTPUT;
+
+ p1->portC = POWER | WRITE_CMD | ENABLE;
+ p1->portA = cc;
+ p1->portC = POWER | WRITE_CMD | DISABLE;
+ splx(s);
+}
+
+void
+lcdshow(s)
+ const char *s;
+{
+ int cc;
+
+ while ((cc = *s++) != '\0')
+ lcdput(cc);
+}
+
+void
+greeting()
+{
+ lcdctrl(LCD_INIT);
+ lcdctrl(LCD_ENTRY);
+ lcdctrl(LCD_ON);
+
+ lcdctrl(LCD_CLS);
+ lcdctrl(LCD_HOME);
+
+ lcdctrl(LCD_LOCATE(0, 0));
+ lcdshow(lcd_boot_message1);
+ lcdctrl(LCD_LOCATE(0, 1));
+ lcdshow(lcd_boot_message2);
+}
diff --git a/sys/arch/luna88k/dev/lunafb.c b/sys/arch/luna88k/dev/lunafb.c
new file mode 100644
index 00000000000..931c5e7a607
--- /dev/null
+++ b/sys/arch/luna88k/dev/lunafb.c
@@ -0,0 +1,510 @@
+/* $OpenBSD: lunafb.c,v 1.1 2004/04/21 15:23:52 aoyama Exp $ */
+/* $NetBSD: lunafb.c,v 1.7.6.1 2002/08/07 01:48:34 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/errno.h>
+#include <sys/buf.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <dev/rcons/raster.h>
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wscons_raster.h>
+#include <dev/wscons/wsdisplayvar.h>
+
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+
+struct bt454 {
+ u_int8_t bt_addr; /* map address register */
+ u_int8_t bt_cmap; /* colormap data register */
+};
+
+struct bt458 {
+ u_int8_t bt_addr; /* map address register */
+ unsigned :24;
+ u_int8_t bt_cmap; /* colormap data register */
+ unsigned :24;
+ u_int8_t bt_ctrl; /* control register */
+ unsigned :24;
+ u_int8_t bt_omap; /* overlay (cursor) map register */
+ unsigned :24;
+};
+
+#define OMFB_RFCNT 0xB1000000 /* video h-origin/v-origin */
+#define OMFB_PLANEMASK 0xB1040000 /* planemask register */
+#define OMFB_FB_WADDR 0xB1080008 /* common plane */
+#define OMFB_FB_RADDR 0xB10C0008 /* plane #0 */
+#define OMFB_ROPFUNC 0xB12C0000 /* ROP function code */
+#define OMFB_RAMDAC 0xC1100000 /* Bt454/Bt458 RAMDAC */
+#define OMFB_SIZE (0xB1300000 - 0xB1080000 + NBPG)
+
+struct om_hwdevconfig {
+ int dc_wid; /* width of frame buffer */
+ int dc_ht; /* height of frame buffer */
+ int dc_depth; /* depth, bits per pixel */
+ int dc_rowbytes; /* bytes in a FB scan line */
+ int dc_cmsize; /* colormap size */
+ vaddr_t dc_videobase; /* base of flat frame buffer */
+ struct raster dc_raster; /* raster description */
+ struct rcons dc_rcons; /* raster blitter control info */
+};
+
+struct hwcmap {
+#define CMAP_SIZE 256
+ u_int8_t r[CMAP_SIZE];
+ u_int8_t g[CMAP_SIZE];
+ u_int8_t b[CMAP_SIZE];
+};
+
+struct omfb_softc {
+ struct device sc_dev; /* base device */
+ struct om_hwdevconfig *sc_dc; /* device configuration */
+ struct hwcmap sc_cmap; /* software copy of colormap */
+ int nscreens;
+};
+
+int omgetcmap(struct omfb_softc *, struct wsdisplay_cmap *);
+int omsetcmap(struct omfb_softc *, struct wsdisplay_cmap *);
+
+struct om_hwdevconfig omfb_console_dc;
+void omfb_getdevconfig(paddr_t, struct om_hwdevconfig *);
+
+extern struct wsdisplay_emulops omfb_emulops;
+
+struct wsscreen_descr omfb_stdscreen = {
+ "std", 0, 0,
+ &omfb_emulops,
+ 0, 0,
+ 0
+};
+
+const struct wsscreen_descr *_omfb_scrlist[] = {
+ &omfb_stdscreen,
+};
+
+const struct wsscreen_list omfb_screenlist = {
+ sizeof(_omfb_scrlist) / sizeof(struct wsscreen_descr *), _omfb_scrlist
+};
+
+int omfbioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t omfbmmap(void *, off_t, int);
+int omfb_alloc_screen(void *, const struct wsscreen_descr *,
+ void **, int *, int *, long *);
+void omfb_free_screen(void *, void *);
+int omfb_show_screen(void *, void *, int,
+ void (*) (void *, int, int), void *);
+
+const struct wsdisplay_accessops omfb_accessops = {
+ omfbioctl,
+ omfbmmap,
+ omfb_alloc_screen,
+ omfb_free_screen,
+ omfb_show_screen,
+ NULL, /* load_font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ NULL /* burner */
+};
+
+int omfbmatch(struct device *, void *, void *);
+void omfbattach(struct device *, struct device *, void *);
+
+const struct cfattach fb_ca = {
+ sizeof(struct omfb_softc), omfbmatch, omfbattach
+};
+
+const struct cfdriver fb_cd = {
+ NULL, "fb", DV_DULL
+};
+
+extern int hwplanemask; /* hardware planemask; retrieved at boot */
+
+int omfb_console;
+int omfb_cnattach(void);
+
+int
+omfbmatch(parent, cf, aux)
+ struct device *parent;
+ void *cf, *aux;
+{
+ struct mainbus_attach_args *ma = aux;
+
+ if (strcmp(ma->ma_name, fb_cd.cd_name))
+ return (0);
+#if 0 /* XXX badaddr() bombs if no framebuffer is installed */
+ if (badaddr((caddr_t)ma->ma_addr, 4))
+ return (0);
+#else
+ if (hwplanemask == 0)
+ return (0);
+#endif
+ return (1);
+}
+
+void
+omfbattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct omfb_softc *sc = (struct omfb_softc *)self;
+ struct wsemuldisplaydev_attach_args waa;
+
+ if (omfb_console) {
+ sc->sc_dc = &omfb_console_dc;
+ sc->nscreens = 1;
+ }
+ else {
+ sc->sc_dc = (struct om_hwdevconfig *)
+ malloc(sizeof(struct om_hwdevconfig), M_DEVBUF, M_WAITOK);
+ omfb_getdevconfig(OMFB_FB_WADDR, sc->sc_dc);
+ }
+ printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
+ sc->sc_dc->dc_depth);
+
+#if 0 /* WHITE on BLACK */
+ cm = &sc->sc_cmap;
+ memset(cm, 255, sizeof(struct hwcmap));
+ cm->r[0] = cm->g[0] = cm->b[0] = 0;
+#endif
+ waa.console = omfb_console;
+ waa.scrdata = &omfb_screenlist;
+ waa.accessops = &omfb_accessops;
+ waa.accesscookie = sc;
+
+ config_found(self, &waa, wsemuldisplaydevprint);
+}
+
+/* EXPORT */ int
+omfb_cnattach()
+{
+ struct om_hwdevconfig *dc = &omfb_console_dc;
+ long defattr;
+
+ omfb_getdevconfig(OMFB_FB_WADDR, dc);
+ (*omfb_emulops.alloc_attr)(&dc->dc_rcons, 0, 0, 0, &defattr);
+ wsdisplay_cnattach(&omfb_stdscreen, &dc->dc_rcons, 0, 0, defattr);
+ omfb_console = 1;
+ return (0);
+}
+
+int
+omfbioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct omfb_softc *sc = v;
+ struct om_hwdevconfig *dc = sc->sc_dc;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX for now */
+ break;
+
+ case WSDISPLAYIO_GINFO:
+#define wsd_fbip ((struct wsdisplay_fbinfo *)data)
+ wsd_fbip->height = dc->dc_ht;
+ wsd_fbip->width = dc->dc_wid;
+ wsd_fbip->depth = dc->dc_depth;
+ wsd_fbip->cmsize = dc->dc_cmsize;
+#undef fbt
+ break;
+
+ case WSDISPLAYIO_GETCMAP:
+ return omgetcmap(sc, (struct wsdisplay_cmap *)data);
+
+ case WSDISPLAYIO_PUTCMAP:
+ return omsetcmap(sc, (struct wsdisplay_cmap *)data);
+
+ case WSDISPLAYIO_SVIDEO:
+ case WSDISPLAYIO_GVIDEO:
+ case WSDISPLAYIO_GCURPOS:
+ case WSDISPLAYIO_SCURPOS:
+ case WSDISPLAYIO_GCURMAX:
+ case WSDISPLAYIO_GCURSOR:
+ case WSDISPLAYIO_SCURSOR:
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Return the address that would map the given device at the given
+ * offset, allowing for the given protection, or return -1 for error.
+ */
+
+paddr_t
+omfbmmap(v, offset, prot)
+ void *v;
+ off_t offset;
+ int prot;
+{
+ struct omfb_softc *sc = v;
+
+ if (offset & PGOFSET)
+ return (-1);
+ if (offset >= OMFB_SIZE || offset < 0)
+ return (-1);
+
+ return atop(trunc_page(sc->sc_dc->dc_videobase) + offset);
+}
+
+int
+omgetcmap(sc, p)
+ struct omfb_softc *sc;
+ struct wsdisplay_cmap *p;
+{
+ u_int index = p->index, count = p->count;
+ unsigned int cmsize;
+ int error;
+
+ cmsize = sc->sc_dc->dc_cmsize;
+ if (index >= cmsize || count > cmsize - index)
+ return (EINVAL);
+
+ error = copyout(&sc->sc_cmap.r[index], p->red, count);
+ if (error != 0)
+ return (error);
+ error = copyout(&sc->sc_cmap.g[index], p->green, count);
+ if (error != 0)
+ return (error);
+ error = copyout(&sc->sc_cmap.b[index], p->blue, count);
+ if (error != 0)
+ return (error);
+
+ return (0);
+}
+
+int
+omsetcmap(sc, p)
+ struct omfb_softc *sc;
+ struct wsdisplay_cmap *p;
+{
+ u_int index = p->index, count = p->count;
+ unsigned int cmsize, i;
+ int error;
+
+ cmsize = sc->sc_dc->dc_cmsize;
+ if (index >= cmsize || count > cmsize - index)
+ return (EINVAL);
+
+ error = copyin(p->red, &sc->sc_cmap.r[index], count);
+ if (error != 0)
+ return (error);
+ error = copyin(p->green, &sc->sc_cmap.g[index], count);
+ if (error != 0)
+ return (error);
+ error = copyin(p->blue, &sc->sc_cmap.b[index], count);
+ if (error != 0)
+ return (error);
+
+ if (hwplanemask == 0x0f) {
+ struct bt454 *odac = (struct bt454 *)OMFB_RAMDAC;
+ odac->bt_addr = index;
+ for (i = index; i < count; i++) {
+ odac->bt_cmap = sc->sc_cmap.r[i];
+ odac->bt_cmap = sc->sc_cmap.g[i];
+ odac->bt_cmap = sc->sc_cmap.b[i];
+ }
+ }
+ else if (hwplanemask == 0xff) {
+ struct bt458 *ndac = (struct bt458 *)OMFB_RAMDAC;
+ ndac->bt_addr = index;
+ for (i = index; i < count; i++) {
+ ndac->bt_cmap = sc->sc_cmap.r[i];
+ ndac->bt_cmap = sc->sc_cmap.g[i];
+ ndac->bt_cmap = sc->sc_cmap.b[i];
+ }
+ }
+ return (0);
+}
+
+void
+omfb_getdevconfig(paddr, dc)
+ paddr_t paddr;
+ struct om_hwdevconfig *dc;
+{
+ int bpp, i;
+ struct raster *rap;
+ struct rcons *rcp;
+ union {
+ struct { short h, v; } p;
+ u_int32_t u;
+ } rfcnt;
+
+ switch (hwplanemask) {
+ case 0xff:
+ bpp = 8; /* XXX check monochrome bit in DIPSW */
+ break;
+ default:
+ case 0x0f:
+ bpp = 4; /* XXX check monochrome bit in DIPSW */
+ break;
+ case 1:
+ bpp = 1;
+ break;
+ }
+ dc->dc_wid = 1280;
+ dc->dc_ht = 1024;
+ dc->dc_depth = bpp;
+ dc->dc_rowbytes = 2048 / 8;
+ dc->dc_cmsize = (bpp == 1) ? 0 : 1 << bpp;
+ dc->dc_videobase = paddr;
+
+#if 0 /* WHITE on BLACK XXX experiment resulted in WHITE on SKYBLUE... */
+ if (hwplanemask == 0x0f) {
+ /* XXX Need Bt454 initialization */
+ struct bt454 *odac = (struct bt454 *)OMFB_RAMDAC;
+ odac->bt_addr = 0;
+ odac->bt_cmap = 0;
+ odac->bt_cmap = 0;
+ odac->bt_cmap = 0;
+ for (i = 1; i < 16; i++) {
+ odac->bt_cmap = 255;
+ odac->bt_cmap = 255;
+ odac->bt_cmap = 255;
+ }
+ }
+ else if (hwplanemask == 0xff) {
+ struct bt458 *ndac = (struct bt458 *)OMFB_RAMDAC;
+
+ ndac->bt_addr = 0x04;
+ ndac->bt_ctrl = 0xff; /* all planes will be read */
+ ndac->bt_ctrl = 0x00; /* all planes have non-blink */
+ ndac->bt_ctrl = 0x43; /* pallete enabled, ovly plane */
+ ndac->bt_ctrl = 0x00; /* no test mode */
+ ndac->bt_addr = 0;
+ ndac->bt_cmap = 0;
+ ndac->bt_cmap = 0;
+ ndac->bt_cmap = 0;
+ for (i = 1; i < 256; i++) {
+ ndac->bt_cmap = 255;
+ ndac->bt_cmap = 255;
+ ndac->bt_cmap = 255;
+ }
+ }
+#endif
+
+ /* adjust h/v orgin on screen */
+ rfcnt.p.h = 7;
+ rfcnt.p.v = -27;
+ *(u_int32_t *)OMFB_RFCNT = rfcnt.u; /* single write of 0x007ffe6 */
+
+ /* clear the screen */
+ *(u_int32_t *)OMFB_PLANEMASK = 0xff;
+ ((u_int32_t *)OMFB_ROPFUNC)[5] = ~0; /* ROP copy */
+ for (i = 0; i < dc->dc_ht * dc->dc_rowbytes/sizeof(u_int32_t); i++)
+ *((u_int32_t *)dc->dc_videobase + i) = 0;
+ *(u_int32_t *)OMFB_PLANEMASK = 0x01;
+
+ /* initialize the raster */
+ rap = &dc->dc_raster;
+ rap->width = dc->dc_wid;
+ rap->height = dc->dc_ht;
+ rap->depth = dc->dc_depth;
+ rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
+ rap->pixels = (u_int32_t *)dc->dc_videobase;
+
+ /* initialize the raster console blitter */
+ rcp = &dc->dc_rcons;
+ rcp->rc_sp = rap;
+ rcp->rc_crow = rcp->rc_ccol = -1;
+ rcp->rc_crowp = &rcp->rc_crow;
+ rcp->rc_ccolp = &rcp->rc_ccol;
+ rcons_init(rcp, 34, 80);
+
+ omfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
+ omfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
+}
+
+int
+omfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
+ void *v;
+ const struct wsscreen_descr *type;
+ void **cookiep;
+ int *curxp, *curyp;
+ long *attrp;
+{
+ struct omfb_softc *sc = v;
+ long defattr;
+
+ if (sc->nscreens > 0)
+ return (ENOMEM);
+
+ *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
+ *curxp = 0;
+ *curyp = 0;
+ (*omfb_emulops.alloc_attr)(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
+ *attrp = defattr;
+ sc->nscreens++;
+ return (0);
+}
+
+void
+omfb_free_screen(v, cookie)
+ void *v;
+ void *cookie;
+{
+ struct omfb_softc *sc = v;
+
+ sc->nscreens--;
+}
+
+int
+omfb_show_screen(v, cookie, waitok, cb, cbarg)
+ void *v;
+ void *cookie;
+ int waitok;
+ void (*cb)(void *, int, int);
+ void *cbarg;
+{
+ return 0;
+}
diff --git a/sys/arch/luna88k/dev/lunaws.c b/sys/arch/luna88k/dev/lunaws.c
new file mode 100644
index 00000000000..e76ab8df98c
--- /dev/null
+++ b/sys/arch/luna88k/dev/lunaws.c
@@ -0,0 +1,545 @@
+/* $NetBSD: lunaws.c,v 1.6 2002/03/17 19:40:42 atatat Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "wsmouse.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+#include <dev/wscons/wsmousevar.h>
+
+#include <luna88k/dev/sioreg.h>
+#include <luna88k/dev/siovar.h>
+
+static const u_int8_t ch1_regs[6] = {
+ WR0_RSTINT, /* Reset E/S Interrupt */
+ WR1_RXALLS, /* Rx per char, No Tx */
+ 0, /* */
+ WR3_RX8BIT | WR3_RXENBL, /* Rx */
+ WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY, /* Tx/Rx */
+ WR5_TX8BIT | WR5_TXENBL, /* Tx */
+};
+
+struct ws_softc {
+ struct device sc_dv;
+ struct sioreg *sc_ctl;
+ u_int8_t sc_wr[6];
+ struct device *sc_wskbddev;
+#if NWSMOUSE > 0
+ struct device *sc_wsmousedev;
+ int sc_msreport;
+ int buttons, dx, dy;
+#endif
+};
+
+void omkbd_input(void *, int);
+void omkbd_decode(void *, int, u_int *, int *);
+int omkbd_enable(void *, int);
+void omkbd_set_leds(void *, int);
+int omkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+struct wscons_keydesc omkbd_keydesctab[];
+
+const struct wskbd_mapdata omkbd_keymapdata = {
+ omkbd_keydesctab,
+#ifdef OMKBD_LAYOUT
+ OMKBD_LAYOUT,
+#else
+ KB_JP,
+#endif
+};
+
+const struct wskbd_accessops omkbd_accessops = {
+ omkbd_enable,
+ omkbd_set_leds,
+ omkbd_ioctl,
+};
+
+void ws_cnattach(void);
+void ws_cngetc(void *, u_int *, int *);
+void ws_cnpollc(void *, int);
+const struct wskbd_consops ws_consops = {
+ ws_cngetc,
+ ws_cnpollc,
+ NULL /* bell */
+};
+
+#if NWSMOUSE > 0
+int omms_enable(void *);
+int omms_ioctl(void *, u_long, caddr_t, int, struct proc *);
+void omms_disable(void *);
+
+const struct wsmouse_accessops omms_accessops = {
+ omms_enable,
+ omms_ioctl,
+ omms_disable,
+};
+#endif
+
+void wsintr(int);
+
+int wsmatch(struct device *, void *, void *);
+void wsattach(struct device *, struct device *, void *);
+int ws_submatch_kbd(struct device *, void *, void *);
+#if NWSMOUSE > 0
+int ws_submatch_mouse(struct device *, void *, void *);
+#endif
+
+const struct cfattach ws_ca = {
+ sizeof(struct ws_softc), wsmatch, wsattach
+};
+
+const struct cfdriver ws_cd = {
+ NULL, "ws", DV_TTY
+};
+
+extern int syscngetc(dev_t);
+extern void syscnputc(dev_t, int);
+
+int
+wsmatch(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct sio_attach_args *args = aux;
+
+ if (args->channel != 1)
+ return 0;
+ return 1;
+}
+
+void
+wsattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct ws_softc *sc = (struct ws_softc *)self;
+ struct sio_softc *scp = (struct sio_softc *)parent;
+ struct sio_attach_args *args = aux;
+ struct wskbddev_attach_args a;
+
+ sc->sc_ctl = (struct sioreg *)scp->scp_ctl + 1;
+ bcopy(ch1_regs, sc->sc_wr, sizeof(ch1_regs));
+ scp->scp_intr[1] = wsintr;
+
+ setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
+ setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
+ setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
+ setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
+ setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
+ setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]);
+
+ syscnputc((dev_t)1, 0x20); /* keep quiet mouse */
+
+ printf("\n");
+
+ a.console = (args->hwflags == 1);
+ a.keymap = &omkbd_keymapdata;
+ a.accessops = &omkbd_accessops;
+ a.accesscookie = (void *)sc;
+ sc->sc_wskbddev = config_found_sm(self, &a, wskbddevprint,
+ ws_submatch_kbd);
+
+#if NWSMOUSE > 0
+ {
+ struct wsmousedev_attach_args b;
+ b.accessops = &omms_accessops;
+ b.accesscookie = (void *)sc;
+ sc->sc_wsmousedev = config_found_sm(self, &b, wsmousedevprint,
+ ws_submatch_mouse);
+ sc->sc_msreport = 0;
+ }
+#endif
+}
+
+int
+ws_submatch_kbd(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct cfdata *cf = match;
+
+ if (strcmp(cf->cf_driver->cd_name, "wskbd"))
+ return (0);
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+#if NWSMOUSE > 0
+
+int
+ws_submatch_mouse(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct cfdata *cf = match;
+
+ if (strcmp(cf->cf_driver->cd_name, "wsmouse"))
+ return (0);
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+}
+
+#endif
+
+/*ARGSUSED*/
+void
+wsintr(chan)
+ int chan;
+{
+ struct ws_softc *sc = ws_cd.cd_devs[0];
+ struct sioreg *sio = sc->sc_ctl;
+ u_int code;
+ int rr;
+
+ rr = getsiocsr(sio);
+ if (rr & RR_RXRDY) {
+ do {
+ code = sio->sio_data;
+ if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
+ sio->sio_cmd = WR0_ERRRST;
+ continue;
+ }
+#if NWSMOUSE > 0
+ /*
+ * if (code >= 0x80 && code <= 0x87), then
+ * it's the first byte of 3 byte long mouse report
+ * code[0] & 07 -> LMR button condition
+ * code[1], [2] -> x,y delta
+ * otherwise, key press or release event.
+ */
+ if (sc->sc_msreport == 0) {
+ if (code < 0x80 || code > 0x87) {
+ omkbd_input(sc, code);
+ continue;
+ }
+ code = (code & 07) ^ 07;
+ /* LMR->RML: wsevent counts 0 for leftmost */
+ sc->buttons = (code & 02);
+ if (code & 01)
+ sc->buttons |= 04;
+ if (code & 04)
+ sc->buttons |= 01;
+ sc->sc_msreport = 1;
+ }
+ else if (sc->sc_msreport == 1) {
+ sc->dx = (signed char)code;
+ sc->sc_msreport = 2;
+ }
+ else if (sc->sc_msreport == 2) {
+ sc->dy = (signed char)code;
+ if (sc->sc_wsmousedev != NULL)
+ wsmouse_input(sc->sc_wsmousedev,
+ sc->buttons, sc->dx, sc->dy, 0, 0);
+ sc->sc_msreport = 0;
+ }
+#else
+ omkbd_input(sc, code);
+#endif
+ } while ((rr = getsiocsr(sio)) & RR_RXRDY);
+ }
+ if (rr && RR_TXRDY)
+ sio->sio_cmd = WR0_RSTPEND;
+ /* not capable of transmit, yet */
+}
+
+void
+omkbd_input(v, data)
+ void *v;
+ int data;
+{
+ struct ws_softc *sc = v;
+ u_int type;
+ int key;
+
+ omkbd_decode(v, data, &type, &key);
+ if (sc->sc_wskbddev != NULL)
+ wskbd_input(sc->sc_wskbddev, type, key);
+}
+
+void
+omkbd_decode(v, datain, type, dataout)
+ void *v;
+ int datain;
+ u_int *type;
+ int *dataout;
+{
+ *type = (datain & 0x80) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
+ *dataout = datain & 0x7f;
+}
+
+#define KC(n) KS_KEYCODE(n)
+
+static const keysym_t omkbd_keydesc_1[] = {
+/* pos command normal shifted */
+ KC(0x9), KS_Tab,
+ KC(0xa), KS_Control_L,
+ KC(0xb), KS_Mode_switch, /* Kana */
+ KC(0xc), KS_Shift_R,
+ KC(0xd), KS_Shift_L,
+ KC(0xe), KS_Caps_Lock,
+ KC(0xf), KS_Meta_L, /* Zenmen */
+ KC(0x10), KS_Escape,
+ KC(0x11), KS_BackSpace,
+ KC(0x12), KS_Return,
+ KC(0x14), KS_space,
+ KC(0x15), KS_Delete,
+ KC(0x16), KS_Alt_L, /* Henkan */
+ KC(0x17), KS_Alt_R, /* Kakutei */
+ KC(0x18), KS_f11, /* Shokyo */
+ KC(0x19), KS_f12, /* Yobidashi */
+ KC(0x1a), KS_f13, /* Bunsetsu L */
+ KC(0x1b), KS_f14, /* Bunsetsu R */
+ KC(0x1c), KS_KP_Up,
+ KC(0x1d), KS_KP_Left,
+ KC(0x1e), KS_KP_Right,
+ KC(0x1f), KS_KP_Down,
+ /* KC(0x20), KS_f11, */
+ /* KC(0x21), KS_f12, */
+ KC(0x22), KS_1, KS_exclam,
+ KC(0x23), KS_2, KS_quotedbl,
+ KC(0x24), KS_3, KS_numbersign,
+ KC(0x25), KS_4, KS_dollar,
+ KC(0x26), KS_5, KS_percent,
+ KC(0x27), KS_6, KS_ampersand,
+ KC(0x28), KS_7, KS_apostrophe,
+ KC(0x29), KS_8, KS_parenleft,
+ KC(0x2a), KS_9, KS_parenright,
+ KC(0x2b), KS_0,
+ KC(0x2c), KS_minus, KS_equal,
+ KC(0x2d), KS_asciicircum, KS_asciitilde,
+ KC(0x2e), KS_backslash, KS_bar,
+ /* KC(0x30), KS_f13, */
+ /* KC(0x31), KS_f14, */
+ KC(0x32), KS_q,
+ KC(0x33), KS_w,
+ KC(0x34), KS_e,
+ KC(0x35), KS_r,
+ KC(0x36), KS_t,
+ KC(0x37), KS_y,
+ KC(0x38), KS_u,
+ KC(0x39), KS_i,
+ KC(0x3a), KS_o,
+ KC(0x3b), KS_p,
+ KC(0x3c), KS_at, KS_grave,
+ KC(0x3d), KS_bracketleft, KS_braceleft,
+ KC(0x42), KS_a,
+ KC(0x43), KS_s,
+ KC(0x44), KS_d,
+ KC(0x45), KS_f,
+ KC(0x46), KS_g,
+ KC(0x47), KS_h,
+ KC(0x48), KS_j,
+ KC(0x49), KS_k,
+ KC(0x4a), KS_l,
+ KC(0x4b), KS_semicolon, KS_plus,
+ KC(0x4c), KS_colon, KS_asterisk,
+ KC(0x4d), KS_bracketright, KS_braceright,
+ KC(0x52), KS_z,
+ KC(0x53), KS_x,
+ KC(0x54), KS_c,
+ KC(0x55), KS_v,
+ KC(0x56), KS_b,
+ KC(0x57), KS_n,
+ KC(0x58), KS_m,
+ KC(0x59), KS_comma, KS_less,
+ KC(0x5a), KS_period, KS_greater,
+ KC(0x5b), KS_slash, KS_question,
+ KC(0x5c), KS_underscore,
+ KC(0x60), KS_KP_Delete,
+ KC(0x61), KS_KP_Add,
+ KC(0x62), KS_KP_Subtract,
+ KC(0x63), KS_KP_7,
+ KC(0x64), KS_KP_8,
+ KC(0x65), KS_KP_9,
+ KC(0x66), KS_KP_4,
+ KC(0x67), KS_KP_5,
+ KC(0x68), KS_KP_6,
+ KC(0x69), KS_KP_1,
+ KC(0x6a), KS_KP_2,
+ KC(0x6b), KS_KP_3,
+ KC(0x6c), KS_KP_0,
+ KC(0x6d), KS_KP_Decimal,
+ KC(0x6e), KS_KP_Enter,
+ KC(0x72), KS_f1,
+ KC(0x73), KS_f2,
+ KC(0x74), KS_f3,
+ KC(0x75), KS_f4,
+ KC(0x76), KS_f5,
+ KC(0x77), KS_f6,
+ KC(0x78), KS_f7,
+ KC(0x79), KS_f8,
+ KC(0x7a), KS_f9,
+ KC(0x7b), KS_f10,
+ KC(0x7c), KS_KP_Multiply,
+ KC(0x7d), KS_KP_Divide,
+ KC(0x7e), KS_KP_Equal,
+ KC(0x7f), KS_KP_Separator,
+};
+
+#define SIZE(map) (sizeof(map)/sizeof(keysym_t))
+
+struct wscons_keydesc omkbd_keydesctab[] = {
+ { KB_JP, 0, SIZE(omkbd_keydesc_1), omkbd_keydesc_1, },
+ { 0, 0, 0, 0 },
+};
+
+void
+ws_cngetc(v, type, data)
+ void *v;
+ u_int *type;
+ int *data;
+{
+ int code;
+
+ code = syscngetc((dev_t)1);
+ omkbd_decode(v, code, type, data);
+}
+
+void
+ws_cnpollc(v, on)
+ void *v;
+ int on;
+{
+}
+
+/* EXPORT */ void
+ws_cnattach()
+{
+ static int voidfill;
+
+ /* XXX need CH.B initialization XXX */
+
+ wskbd_cnattach(&ws_consops, &voidfill, &omkbd_keymapdata);
+}
+
+int
+omkbd_enable(v, on)
+ void *v;
+ int on;
+{
+ return 0;
+}
+
+void
+omkbd_set_leds(v, leds)
+ void *v;
+ int leds;
+{
+#if 0
+ syscnputc((dev_t)1, 0x10); /* kana LED on */
+ syscnputc((dev_t)1, 0x00); /* kana LED off */
+ syscnputc((dev_t)1, 0x11); /* caps LED on */
+ syscnputc((dev_t)1, 0x01); /* caps LED off */
+#endif
+}
+
+int
+omkbd_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+#if 0
+ struct ws_softc *sc = v;
+#endif
+
+ switch (cmd) {
+ case WSKBDIO_GTYPE:
+ *(int *)data = 0; /* XXX for now */
+ return 0;
+ case WSKBDIO_SETLEDS:
+ case WSKBDIO_GETLEDS:
+ case WSKBDIO_COMPLEXBELL: /* XXX capable of complex bell */
+ return -1;
+ }
+ return -1;
+}
+
+#if NWSMOUSE > 0
+
+int
+omms_enable(v)
+ void *v;
+{
+ struct ws_softc *sc = v;
+
+ syscnputc((dev_t)1, 0x60); /* enable 3 byte long mouse reporting */
+ sc->sc_msreport = 0;
+ return 0;
+}
+
+/*ARGUSED*/
+int
+omms_ioctl(v, cmd, data, flag, p)
+ void *v;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+#if 0
+ struct ws_softc *sc = v;
+#endif
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = 0; /* XXX for now*/
+ return 0;
+ }
+
+ return -1;
+}
+
+void
+omms_disable(v)
+ void *v;
+{
+ struct ws_softc *sc = v;
+
+ syscnputc((dev_t)1, 0x20); /* quiet mouse */
+ sc->sc_msreport = 0;
+}
+#endif
diff --git a/sys/arch/luna88k/dev/mb89352.c b/sys/arch/luna88k/dev/mb89352.c
new file mode 100644
index 00000000000..6ed3d6adceb
--- /dev/null
+++ b/sys/arch/luna88k/dev/mb89352.c
@@ -0,0 +1,2184 @@
+/* $OpenBSD: mb89352.c,v 1.1 2004/04/21 15:23:54 aoyama Exp $ */
+/* $NetBSD: mb89352.c,v 1.5 2000/03/23 07:01:31 thorpej Exp $ */
+/* NecBSD: mb89352.c,v 1.4 1998/03/14 07:31:20 kmatsuda Exp */
+
+#ifdef DDB
+#define integrate
+#else
+#define integrate __inline static
+#endif
+
+/*-
+ * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Charles M. Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Copyright (c) 1994 Jarle Greipsland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. All rights reserved.
+ * Copyright (c) 1996, 1997, 1998
+ * Kouichi Matsuda. All rights reserved.
+ */
+
+/*
+ * Acknowledgements: Many of the algorithms used in this driver are
+ * inspired by the work of Julian Elischer (julian@tfs.com) and
+ * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
+ */
+
+/* TODO list:
+ * 1) Get the DMA stuff working.
+ * 2) Get the iov/uio stuff working. Is this a good thing ???
+ * 3) Get the synch stuff working.
+ * 4) Rewrite it to use malloc for the acb structs instead of static alloc.?
+ */
+
+/*
+ * A few customizable items:
+ */
+
+/* Use doubleword transfers to/from SCSI chip. Note: This requires
+ * motherboard support. Basicly, some motherboard chipsets are able to
+ * split a 32 bit I/O operation into two 16 bit I/O operations,
+ * transparently to the processor. This speeds up some things, notably long
+ * data transfers.
+ */
+#define SPC_USE_DWORDS 0
+
+/* Synchronous data transfers? */
+#define SPC_USE_SYNCHRONOUS 0
+#define SPC_SYNC_REQ_ACK_OFS 8
+
+/* Wide data transfers? */
+#define SPC_USE_WIDE 0
+#define SPC_MAX_WIDTH 0
+
+/* Max attempts made to transmit a message */
+#define SPC_MSG_MAX_ATTEMPT 3 /* Not used now XXX */
+
+/*
+ * Some spin loop parameters (essentially how long to wait some places)
+ * The problem(?) is that sometimes we expect either to be able to transmit a
+ * byte or to get a new one from the SCSI bus pretty soon. In order to avoid
+ * returning from the interrupt just to get yanked back for the next byte we
+ * may spin in the interrupt routine waiting for this byte to come. How long?
+ * This is really (SCSI) device and processor dependent. Tuneable, I guess.
+ */
+#define SPC_MSGIN_SPIN 1 /* Will spinwait upto ?ms for a new msg byte */
+#define SPC_MSGOUT_SPIN 1
+
+/* Include debug functions? At the end of this file there are a bunch of
+ * functions that will print out various information regarding queued SCSI
+ * commands, driver state and chip contents. You can call them from the
+ * kernel debugger. If you set SPC_DEBUG to 0 they are not included (the
+ * kernel uses less memory) but you lose the debugging facilities.
+ */
+#define SPC_DEBUG 1
+
+#define SPC_ABORT_TIMEOUT 2000 /* time to wait for abort */
+
+/* End of customizable parameters */
+
+/*
+ * MB89352 SCSI Protocol Controller (SPC) routines.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/queue.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_message.h>
+#include <scsi/scsiconf.h>
+
+#include <luna88k/dev/mb89352reg.h>
+#include <luna88k/dev/mb89352var.h>
+
+#ifndef DDB
+#define Debugger() panic("should call debugger here (mb89352.c)")
+#endif /* ! DDB */
+
+#if SPC_DEBUG
+int spc_debug = 0x00; /* SPC_SHOWSTART|SPC_SHOWMISC|SPC_SHOWTRACE; */
+#endif
+
+void spc_minphys (struct buf *);
+void spc_done (struct spc_softc *, struct spc_acb *);
+void spc_dequeue (struct spc_softc *, struct spc_acb *);
+int spc_scsi_cmd (struct scsi_xfer *);
+int spc_poll (struct spc_softc *, struct scsi_xfer *, int);
+integrate void spc_sched_msgout(struct spc_softc *, u_char);
+integrate void spc_setsync(struct spc_softc *, struct spc_tinfo *);
+void spc_select (struct spc_softc *, struct spc_acb *);
+void spc_timeout (void *);
+void spc_scsi_reset (struct spc_softc *);
+void spc_reset (struct spc_softc *);
+void spc_free_acb (struct spc_softc *, struct spc_acb *, int);
+struct spc_acb* spc_get_acb(struct spc_softc *, int);
+int spc_reselect (struct spc_softc *, int);
+void spc_sense (struct spc_softc *, struct spc_acb *);
+void spc_msgin (struct spc_softc *);
+void spc_abort (struct spc_softc *, struct spc_acb *);
+void spc_msgout (struct spc_softc *);
+int spc_dataout_pio (struct spc_softc *, u_char *, int);
+int spc_datain_pio (struct spc_softc *, u_char *, int);
+#if SPC_DEBUG
+void spc_print_acb (struct spc_acb *);
+void spc_dump_driver (struct spc_softc *);
+void spc_dump89352 (struct spc_softc *);
+void spc_show_scsi_cmd(struct spc_acb *);
+void spc_print_active_acb(void);
+#endif
+
+extern struct cfdriver spc_cd;
+
+struct scsi_device spc_dev = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+/*
+ * INITIALIZATION ROUTINES (probe, attach ++)
+ */
+
+/*
+ * Do the real search-for-device.
+ * Prerequisite: sc->sc_iobase should be set to the proper value
+ */
+int
+spc_find(iot, ioh, bdid)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int bdid;
+{
+ long timeout = SPC_ABORT_TIMEOUT;
+
+ SPC_TRACE(("spc: probing for spc-chip\n"));
+ /*
+ * Disable interrupts then reset the FUJITSU chip.
+ */
+ bus_space_write_1(iot, ioh, SCTL, SCTL_DISABLE | SCTL_CTRLRST);
+ bus_space_write_1(iot, ioh, SCMD, 0);
+ bus_space_write_1(iot, ioh, PCTL, 0);
+ bus_space_write_1(iot, ioh, TEMP, 0);
+ bus_space_write_1(iot, ioh, TCH, 0);
+ bus_space_write_1(iot, ioh, TCM, 0);
+ bus_space_write_1(iot, ioh, TCL, 0);
+ bus_space_write_1(iot, ioh, INTS, 0);
+ bus_space_write_1(iot, ioh, SCTL, SCTL_DISABLE | SCTL_ABRT_ENAB | SCTL_PARITY_ENAB | SCTL_RESEL_ENAB);
+ bus_space_write_1(iot, ioh, BDID, bdid);
+ delay(400);
+ bus_space_write_1(iot, ioh, SCTL, bus_space_read_1(iot, ioh, SCTL) & ~SCTL_DISABLE);
+
+ /* The following detection is derived from spc.c
+ * (by Takahide Matsutsuka) in FreeBSD/pccard-test.
+ */
+ while (bus_space_read_1(iot, ioh, PSNS) && timeout)
+ timeout--;
+ if (!timeout) {
+ printf("spc: find failed\n");
+ return 0;
+ }
+
+ SPC_START(("SPC found"));
+ return 1;
+}
+
+void
+/* spc_attach(sc) */
+spc_attach(sc, adapter)
+ struct spc_softc *sc;
+ struct scsi_adapter *adapter;
+{
+
+ SPC_TRACE(("spc_attach "));
+ sc->sc_state = SPC_INIT;
+
+ sc->sc_freq = 20; /* XXXX Assume 20 MHz. */
+
+#if SPC_USE_SYNCHRONOUS
+ /*
+ * These are the bounds of the sync period, based on the frequency of
+ * the chip's clock input and the size and offset of the sync period
+ * register.
+ *
+ * For a 20Mhz clock, this gives us 25, or 100nS, or 10MB/s, as a
+ * maximum transfer rate, and 112.5, or 450nS, or 2.22MB/s, as a
+ * minimum transfer rate.
+ */
+ sc->sc_minsync = (2 * 250) / sc->sc_freq;
+ sc->sc_maxsync = (9 * 250) / sc->sc_freq;
+#endif
+
+ spc_init(sc); /* Init chip and driver */
+
+ /*
+ * Fill in the adapter.
+ */
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->sc_initiator;
+ sc->sc_link.adapter = adapter;
+ sc->sc_link.device = &spc_dev;
+ sc->sc_link.openings = 2;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
+}
+
+/*
+ * Initialize MB89352 chip itself
+ * The following conditions should hold:
+ * spc_isa_probe should have succeeded, i.e. the iobase address in spc_softc
+ * must be valid.
+ */
+void
+spc_reset(sc)
+ struct spc_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ SPC_TRACE(("spc_reset "));
+ /*
+ * Disable interrupts then reset the FUJITSU chip.
+ */
+ bus_space_write_1(iot, ioh, SCTL, SCTL_DISABLE | SCTL_CTRLRST);
+ bus_space_write_1(iot, ioh, SCMD, 0);
+ bus_space_write_1(iot, ioh, PCTL, 0);
+ bus_space_write_1(iot, ioh, TEMP, 0);
+ bus_space_write_1(iot, ioh, TCH, 0);
+ bus_space_write_1(iot, ioh, TCM, 0);
+ bus_space_write_1(iot, ioh, TCL, 0);
+ bus_space_write_1(iot, ioh, INTS, 0);
+ bus_space_write_1(iot, ioh, SCTL, SCTL_DISABLE | SCTL_ABRT_ENAB | SCTL_PARITY_ENAB | SCTL_RESEL_ENAB);
+ bus_space_write_1(iot, ioh, BDID, sc->sc_initiator);
+ delay(400);
+ bus_space_write_1(iot, ioh, SCTL, bus_space_read_1(iot, ioh, SCTL) & ~SCTL_DISABLE);
+}
+
+
+/*
+ * Pull the SCSI RST line for 500us.
+ */
+void
+spc_scsi_reset(sc)
+ struct spc_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ SPC_TRACE(("spc_scsi_reset "));
+ bus_space_write_1(iot, ioh, SCMD, bus_space_read_1(iot, ioh, SCMD) | SCMD_RST);
+ delay(500);
+ bus_space_write_1(iot, ioh, SCMD, bus_space_read_1(iot, ioh, SCMD) & ~SCMD_RST);
+ delay(50);
+}
+
+/*
+ * Initialize spc SCSI driver.
+ */
+void
+spc_init(sc)
+ struct spc_softc *sc;
+{
+ struct spc_acb *acb;
+ int r;
+
+ SPC_TRACE(("spc_init "));
+ spc_reset(sc);
+ spc_scsi_reset(sc);
+ spc_reset(sc);
+
+ if (sc->sc_state == SPC_INIT) {
+ /* First time through; initialize. */
+ TAILQ_INIT(&sc->ready_list);
+ TAILQ_INIT(&sc->nexus_list);
+ TAILQ_INIT(&sc->free_list);
+ sc->sc_nexus = NULL;
+ acb = sc->sc_acb;
+ bzero(acb, sizeof(sc->sc_acb));
+ for (r = 0; r < sizeof(sc->sc_acb) / sizeof(*acb); r++) {
+ TAILQ_INSERT_TAIL(&sc->free_list, acb, chain);
+ acb++;
+ }
+ bzero(&sc->sc_tinfo, sizeof(sc->sc_tinfo));
+ } else {
+ /* Cancel any active commands. */
+ sc->sc_state = SPC_CLEANING;
+ if ((acb = sc->sc_nexus) != NULL) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ timeout_del(&acb->xs->stimeout);
+ spc_done(sc, acb);
+ }
+ while ((acb = sc->nexus_list.tqh_first) != NULL) {
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ timeout_del(&acb->xs->stimeout);
+ spc_done(sc, acb);
+ }
+ }
+
+ sc->sc_prevphase = PH_INVALID;
+ for (r = 0; r < 8; r++) {
+ struct spc_tinfo *ti = &sc->sc_tinfo[r];
+
+ ti->flags = 0;
+#if SPC_USE_SYNCHRONOUS
+ ti->flags |= DO_SYNC;
+ ti->period = sc->sc_minsync;
+ ti->offset = SPC_SYNC_REQ_ACK_OFS;
+#else
+ ti->period = ti->offset = 0;
+#endif
+#if SPC_USE_WIDE
+ ti->flags |= DO_WIDE;
+ ti->width = SPC_MAX_WIDTH;
+#else
+ ti->width = 0;
+#endif
+ }
+
+ sc->sc_state = SPC_IDLE;
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, SCTL,
+ bus_space_read_1(sc->sc_iot, sc->sc_ioh, SCTL) | SCTL_INTR_ENAB);
+}
+
+void
+spc_free_acb(sc, acb, flags)
+ struct spc_softc *sc;
+ struct spc_acb *acb;
+ int flags;
+{
+ int s;
+
+ SPC_TRACE(("spc_free_acb "));
+ s = splbio();
+
+ acb->flags = 0;
+ TAILQ_INSERT_HEAD(&sc->free_list, acb, chain);
+
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if (acb->chain.tqe_next == 0)
+ wakeup(&sc->free_list);
+
+ splx(s);
+}
+
+struct spc_acb *
+spc_get_acb(sc, flags)
+ struct spc_softc *sc;
+ int flags;
+{
+ struct spc_acb *acb;
+ int s;
+
+ SPC_TRACE(("spc_get_acb "));
+ s = splbio();
+
+ while ((acb = sc->free_list.tqh_first) == NULL &&
+ (flags & SCSI_NOSLEEP) == 0)
+ tsleep(&sc->free_list, PRIBIO, "spcacb", 0);
+ if (acb) {
+ TAILQ_REMOVE(&sc->free_list, acb, chain);
+ acb->flags |= ACB_ALLOC;
+ }
+
+ splx(s);
+ return acb;
+}
+
+/*
+ * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
+ */
+
+/*
+ * Expected sequence:
+ * 1) Command inserted into ready list
+ * 2) Command selected for execution
+ * 3) Command won arbitration and has selected target device
+ * 4) Send message out (identify message, eventually also sync.negotiations)
+ * 5) Send command
+ * 5a) Receive disconnect message, disconnect.
+ * 5b) Reselected by target
+ * 5c) Receive identify message from target.
+ * 6) Send or receive data
+ * 7) Receive status
+ * 8) Receive message (command complete etc.)
+ * 9) If status == SCSI_CHECK construct a synthetic request sense SCSI cmd.
+ * Repeat 2-8 (no disconnects please...)
+ */
+
+/*
+ * Start a SCSI-command
+ * This function is called by the higher level SCSI-driver to queue/run
+ * SCSI-commands.
+ */
+int
+spc_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct spc_softc *sc = sc_link->adapter_softc;
+ struct spc_acb *acb;
+ int s, flags;
+
+ SPC_TRACE(("spc_scsi_cmd "));
+ SPC_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
+ sc_link->target));
+
+ flags = xs->flags;
+ if ((acb = spc_get_acb(sc, flags)) == NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return TRY_AGAIN_LATER;
+ }
+
+ /* Initialize acb */
+ acb->xs = xs;
+ acb->timeout = xs->timeout;
+
+ if (xs->flags & SCSI_RESET) {
+ acb->flags |= ACB_RESET;
+ acb->scsi_cmd_length = 0;
+ acb->data_length = 0;
+ } else {
+ bcopy(xs->cmd, &acb->scsi_cmd, xs->cmdlen);
+ acb->scsi_cmd_length = xs->cmdlen;
+ acb->data_addr = xs->data;
+ acb->data_length = xs->datalen;
+ }
+ acb->target_stat = 0;
+
+ s = splbio();
+
+ TAILQ_INSERT_TAIL(&sc->ready_list, acb, chain);
+ /*
+ * Start scheduling unless a queue process is in progress.
+ */
+ if (sc->sc_state == SPC_IDLE)
+ spc_sched(sc);
+ /*
+ * After successful sending, check if we should return just now.
+ * If so, return SUCCESSFULLY_QUEUED.
+ */
+
+ splx(s);
+
+ if ((flags & SCSI_POLL) == 0)
+ return SUCCESSFULLY_QUEUED;
+
+ /* Not allowed to use interrupts, use polling instead */
+ s = splbio();
+ if (spc_poll(sc, xs, acb->timeout)) {
+ spc_timeout(acb);
+ if (spc_poll(sc, xs, acb->timeout))
+ spc_timeout(acb);
+ }
+ splx(s);
+ return COMPLETE;
+}
+
+/*
+ * Adjust transfer size in buffer structure
+ */
+void
+spc_minphys(bp)
+ struct buf *bp;
+{
+
+ SPC_TRACE(("spc_minphys "));
+ minphys(bp);
+}
+
+/*
+ * Used when interrupt driven I/O isn't allowed, e.g. during boot.
+ */
+int
+spc_poll(sc, xs, count)
+ struct spc_softc *sc;
+ struct scsi_xfer *xs;
+ int count;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ SPC_TRACE(("spc_poll "));
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ spc_intr(sc);
+ if ((xs->flags & ITSDONE) != 0)
+ return 0;
+ delay(1000);
+ count--;
+ }
+ return 1;
+}
+
+/*
+ * LOW LEVEL SCSI UTILITIES
+ */
+
+integrate void
+spc_sched_msgout(sc, m)
+ struct spc_softc *sc;
+ u_char m;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ SPC_TRACE(("spc_sched_msgout "));
+ if (sc->sc_msgpriq == 0)
+ bus_space_write_1(iot, ioh, SCMD, SCMD_SET_ATN);
+ sc->sc_msgpriq |= m;
+}
+
+/*
+ * Set synchronous transfer offset and period.
+ */
+integrate void
+spc_setsync(sc, ti)
+ struct spc_softc *sc;
+ struct spc_tinfo *ti;
+{
+#if SPC_USE_SYNCHRONOUS
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ SPC_TRACE(("spc_setsync "));
+ if (ti->offset != 0)
+ bus_space_write_1(iot, ioh, TMOD,
+ ((ti->period * sc->sc_freq) / 250 - 2) << 4 | ti->offset);
+ else
+ bus_space_write_1(iot, ioh, TMOD, 0);
+#endif
+}
+
+/*
+ * Start a selection. This is used by spc_sched() to select an idle target,
+ * and by spc_done() to immediately reselect a target to get sense information.
+ */
+void
+spc_select(sc, acb)
+ struct spc_softc *sc;
+ struct spc_acb *acb;
+{
+ struct scsi_link *sc_link = acb->xs->sc_link;
+ int target = sc_link->target;
+ struct spc_tinfo *ti = &sc->sc_tinfo[target];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ SPC_TRACE(("spc_select "));
+ spc_setsync(sc, ti);
+
+#if 0
+ bus_space_write_1(iot, ioh, SCMD, SCMD_SET_ATN);
+#endif
+
+ bus_space_write_1(iot, ioh, PCTL, 0);
+ bus_space_write_1(iot, ioh, TEMP, (1 << sc->sc_initiator) | (1 << target));
+ /*
+ * Setup BSY timeout (selection timeout).
+ * 250ms according to the SCSI specification.
+ * T = (X * 256 + 15) * Tclf * 2 (Tclf = 200ns on x68k)
+ * To setup 256ms timeout,
+ * 128000ns/200ns = X * 256 + 15
+ * 640 - 15 = X * 256
+ * X = 625 / 256
+ * X = 2 + 113 / 256
+ * ==> tch = 2, tcm = 113 (correct?)
+ */
+ bus_space_write_1(iot, ioh, TCH, 2);
+ bus_space_write_1(iot, ioh, TCM, 113);
+ /* Time to the information transfer phase start. */
+ bus_space_write_1(iot, ioh, TCL, 3);
+ bus_space_write_1(iot, ioh, SCMD, SCMD_SELECT);
+
+ sc->sc_state = SPC_SELECTING;
+}
+
+int
+spc_reselect(sc, message)
+ struct spc_softc *sc;
+ int message;
+{
+ u_char selid, target, lun;
+ struct spc_acb *acb;
+ struct scsi_link *sc_link;
+ struct spc_tinfo *ti;
+
+ SPC_TRACE(("spc_reselect "));
+ /*
+ * The SCSI chip made a snapshot of the data bus while the reselection
+ * was being negotiated. This enables us to determine which target did
+ * the reselect.
+ */
+ selid = sc->sc_selid & ~(1 << sc->sc_initiator);
+ if (selid & (selid - 1)) {
+ printf("%s: reselect with invalid selid %02x; sending DEVICE RESET\n",
+ sc->sc_dev.dv_xname, selid);
+ SPC_BREAK();
+ goto reset;
+ }
+
+ /*
+ * Search wait queue for disconnected cmd
+ * The list should be short, so I haven't bothered with
+ * any more sophisticated structures than a simple
+ * singly linked list.
+ */
+ target = ffs(selid) - 1;
+ lun = message & 0x07;
+ for (acb = sc->nexus_list.tqh_first; acb != NULL;
+ acb = acb->chain.tqe_next) {
+ sc_link = acb->xs->sc_link;
+ if (sc_link->target == target &&
+ sc_link->lun == lun)
+ break;
+ }
+ if (acb == NULL) {
+ printf("%s: reselect from target %d lun %d with no nexus; sending ABORT\n",
+ sc->sc_dev.dv_xname, target, lun);
+ SPC_BREAK();
+ goto abort;
+ }
+
+ /* Make this nexus active again. */
+ TAILQ_REMOVE(&sc->nexus_list, acb, chain);
+ sc->sc_state = SPC_CONNECTED;
+ sc->sc_nexus = acb;
+ ti = &sc->sc_tinfo[target];
+ ti->lubusy |= (1 << lun);
+ spc_setsync(sc, ti);
+
+ if (acb->flags & ACB_RESET)
+ spc_sched_msgout(sc, SEND_DEV_RESET);
+ else if (acb->flags & ACB_ABORT)
+ spc_sched_msgout(sc, SEND_ABORT);
+
+ /* Do an implicit RESTORE POINTERS. */
+ sc->sc_dp = acb->data_addr;
+ sc->sc_dleft = acb->data_length;
+ sc->sc_cp = (u_char *)&acb->scsi_cmd;
+ sc->sc_cleft = acb->scsi_cmd_length;
+
+ return (0);
+
+reset:
+ spc_sched_msgout(sc, SEND_DEV_RESET);
+ return (1);
+
+abort:
+ spc_sched_msgout(sc, SEND_ABORT);
+ return (1);
+}
+
+/*
+ * Schedule a SCSI operation. This has now been pulled out of the interrupt
+ * handler so that we may call it from spc_scsi_cmd and spc_done. This may
+ * save us an unecessary interrupt just to get things going. Should only be
+ * called when state == SPC_IDLE and at bio pl.
+ */
+void
+spc_sched(sc)
+ struct spc_softc *sc;
+{
+ struct spc_acb *acb;
+ struct scsi_link *sc_link;
+ struct spc_tinfo *ti;
+
+ /* missing the hw, just return and wait for our hw */
+ if (sc->sc_flags & SPC_INACTIVE)
+ return;
+ SPC_TRACE(("spc_sched "));
+ /*
+ * Find first acb in ready queue that is for a target/lunit pair that
+ * is not busy.
+ */
+ for (acb = sc->ready_list.tqh_first; acb != NULL;
+ acb = acb->chain.tqe_next) {
+ sc_link = acb->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+ if ((ti->lubusy & (1 << sc_link->lun)) == 0) {
+ SPC_MISC(("selecting %d:%d ",
+ sc_link->target, sc_link->lun));
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ sc->sc_nexus = acb;
+ spc_select(sc, acb);
+ return;
+ } else
+ SPC_MISC(("%d:%d busy\n",
+ sc_link->target, sc_link->lun));
+ }
+ SPC_MISC(("idle "));
+ /* Nothing to start; just enable reselections and wait. */
+}
+
+void
+spc_sense(sc, acb)
+ struct spc_softc *sc;
+ struct spc_acb *acb;
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct spc_tinfo *ti = &sc->sc_tinfo[sc_link->target];
+ struct scsi_sense *ss = (void *)&acb->scsi_cmd;
+
+ SPC_MISC(("requesting sense "));
+ /* Next, setup a request sense command block */
+ bzero(ss, sizeof(*ss));
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = sc_link->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+ acb->scsi_cmd_length = sizeof(*ss);
+ acb->data_addr = (char *)&xs->sense;
+ acb->data_length = sizeof(struct scsi_sense_data);
+ acb->flags |= ACB_SENSE;
+ ti->senses++;
+ if (acb->flags & ACB_NEXUS)
+ ti->lubusy &= ~(1 << sc_link->lun);
+ if (acb == sc->sc_nexus) {
+ spc_select(sc, acb);
+ } else {
+ spc_dequeue(sc, acb);
+ TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
+ if (sc->sc_state == SPC_IDLE)
+ spc_sched(sc);
+ }
+}
+
+/*
+ * POST PROCESSING OF SCSI_CMD (usually current)
+ */
+void
+spc_done(sc, acb)
+ struct spc_softc *sc;
+ struct spc_acb *acb;
+{
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct spc_tinfo *ti = &sc->sc_tinfo[sc_link->target];
+
+ SPC_TRACE(("spc_done "));
+
+ /*
+ * Now, if we've come here with no error code, i.e. we've kept the
+ * initial XS_NOERROR, and the status code signals that we should
+ * check sense, we'll need to set up a request sense cmd block and
+ * push the command back into the ready queue *before* any other
+ * commands for this target/lunit, else we lose the sense info.
+ * We don't support chk sense conditions for the request sense cmd.
+ */
+ if (xs->error == XS_NOERROR) {
+ if (acb->flags & ACB_ABORT) {
+ xs->error = XS_DRIVER_STUFFUP;
+ } else if (acb->flags & ACB_SENSE) {
+ xs->error = XS_SENSE;
+ } else {
+ switch (acb->target_stat) {
+ case SCSI_CHECK:
+ /* First, save the return values */
+ xs->resid = acb->data_length;
+ xs->status = acb->target_stat;
+ spc_sense(sc, acb);
+ return;
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ case SCSI_OK:
+ xs->resid = acb->data_length;
+ break;
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+#if SPC_DEBUG
+ printf("%s: spc_done: bad stat 0x%x\n",
+ sc->sc_dev.dv_xname, acb->target_stat);
+#endif
+ break;
+ }
+ }
+ }
+
+ xs->flags |= ITSDONE;
+
+#if SPC_DEBUG
+ if ((spc_debug & SPC_SHOWMISC) != 0) {
+ if (xs->resid != 0)
+ printf("resid=%d ", xs->resid);
+ if (xs->error == XS_SENSE)
+ printf("sense=0x%02x\n", xs->sense.error_code);
+ else
+ printf("error=%d\n", xs->error);
+ }
+#endif
+
+ /*
+ * Remove the ACB from whatever queue it happens to be on.
+ */
+ if (acb->flags & ACB_NEXUS)
+ ti->lubusy &= ~(1 << sc_link->lun);
+ if (acb == sc->sc_nexus) {
+ sc->sc_nexus = NULL;
+ sc->sc_state = SPC_IDLE;
+ spc_sched(sc);
+ } else
+ spc_dequeue(sc, acb);
+
+ spc_free_acb(sc, acb, xs->flags);
+ ti->cmds++;
+ scsi_done(xs);
+}
+
+void
+spc_dequeue(sc, acb)
+ struct spc_softc *sc;
+ struct spc_acb *acb;
+{
+
+ SPC_TRACE(("spc_dequeue "));
+ if (acb->flags & ACB_NEXUS) {
+ TAILQ_REMOVE(&sc->nexus_list, acb, chain);
+ } else {
+ TAILQ_REMOVE(&sc->ready_list, acb, chain);
+ }
+}
+
+/*
+ * INTERRUPT/PROTOCOL ENGINE
+ */
+
+#define IS1BYTEMSG(m) (((m) != 0x01 && (m) < 0x20) || (m) >= 0x80)
+#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
+#define ISEXTMSG(m) ((m) == 0x01)
+
+/*
+ * Precondition:
+ * The SCSI bus is already in the MSGI phase and there is a message byte
+ * on the bus, along with an asserted REQ signal.
+ */
+void
+spc_msgin(sc)
+ struct spc_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int n;
+
+ SPC_TRACE(("spc_msgin "));
+
+ if (sc->sc_prevphase == PH_MSGIN) {
+ /* This is a continuation of the previous message. */
+ n = sc->sc_imp - sc->sc_imess;
+ goto nextbyte;
+ }
+
+ /* This is a new MESSAGE IN phase. Clean up our state. */
+ sc->sc_flags &= ~SPC_DROP_MSGIN;
+
+nextmsg:
+ n = 0;
+ sc->sc_imp = &sc->sc_imess[n];
+
+nextbyte:
+ /*
+ * Read a whole message, but don't ack the last byte. If we reject the
+ * message, we have to assert ATN during the message transfer phase
+ * itself.
+ */
+ for (;;) {
+#if 0
+ for (;;) {
+ if ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) != 0)
+ break;
+ /* Wait for REQINIT. XXX Need timeout. */
+ }
+#endif
+ if (bus_space_read_1(iot, ioh, INTS) != 0) {
+ /*
+ * Target left MESSAGE IN, probably because it
+ * a) noticed our ATN signal, or
+ * b) ran out of messages.
+ */
+ goto out;
+ }
+
+ /* If parity error, just dump everything on the floor. */
+ if ((bus_space_read_1(iot, ioh, SERR) &
+ (SERR_SCSI_PAR|SERR_SPC_PAR)) != 0) {
+ sc->sc_flags |= SPC_DROP_MSGIN;
+ spc_sched_msgout(sc, SEND_PARITY_ERROR);
+ }
+
+ /* send TRANSFER command. */
+ bus_space_write_1(iot, ioh, TCH, 0);
+ bus_space_write_1(iot, ioh, TCM, 0);
+ bus_space_write_1(iot, ioh, TCL, 1);
+ bus_space_write_1(iot, ioh, PCTL,
+ sc->sc_phase | PCTL_BFINT_ENAB);
+#ifdef x68k
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* | SCMD_PROG_XFR */
+#else
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR | SCMD_PROG_XFR); /* XXX */
+#endif
+ for (;;) {
+ /*if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0
+ && (bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_EMPTY) != 0)*/
+ if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_EMPTY) == 0)
+ break;
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ goto out;
+ }
+
+ /* Gather incoming message bytes if needed. */
+ if ((sc->sc_flags & SPC_DROP_MSGIN) == 0) {
+ if (n >= SPC_MAX_MSG_LEN) {
+ (void) bus_space_read_1(iot, ioh, DREG);
+ sc->sc_flags |= SPC_DROP_MSGIN;
+ spc_sched_msgout(sc, SEND_REJECT);
+ } else {
+ *sc->sc_imp++ = bus_space_read_1(iot, ioh, DREG);
+ n++;
+ /*
+ * This testing is suboptimal, but most
+ * messages will be of the one byte variety, so
+ * it should not affect performance
+ * significantly.
+ */
+ if (n == 1 && IS1BYTEMSG(sc->sc_imess[0]))
+ break;
+ if (n == 2 && IS2BYTEMSG(sc->sc_imess[0]))
+ break;
+ if (n >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
+ n == sc->sc_imess[1] + 2)
+ break;
+ }
+ } else
+ (void) bus_space_read_1(iot, ioh, DREG);
+
+ /*
+ * If we reach this spot we're either:
+ * a) in the middle of a multi-byte message, or
+ * b) dropping bytes.
+ */
+#if 0
+ /* Ack the last byte read. */
+ /*(void) bus_space_read_1(iot, ioh, DREG);*/
+ while ((bus_space_read_1(iot, ioh, PSNS) & ACKI) != 0)
+ ;
+#endif
+ }
+
+ SPC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0]));
+
+ /* We now have a complete message. Parse it. */
+ switch (sc->sc_state) {
+ struct spc_acb *acb;
+ struct scsi_link *sc_link;
+ struct spc_tinfo *ti;
+
+ case SPC_CONNECTED:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ ti = &sc->sc_tinfo[acb->xs->sc_link->target];
+
+ switch (sc->sc_imess[0]) {
+ case MSG_CMDCOMPLETE:
+ if (sc->sc_dleft < 0) {
+ sc_link = acb->xs->sc_link;
+ printf("%s: %d extra bytes from %d:%d\n",
+ sc->sc_dev.dv_xname, -sc->sc_dleft,
+ sc_link->target, sc_link->lun);
+ acb->data_length = 0;
+ }
+ acb->xs->resid = acb->data_length = sc->sc_dleft;
+ sc->sc_state = SPC_CMDCOMPLETE;
+ break;
+
+ case MSG_PARITY_ERROR:
+ /* Resend the last message. */
+ spc_sched_msgout(sc, sc->sc_lastmsg);
+ break;
+
+ case MSG_MESSAGE_REJECT:
+ SPC_MISC(("message rejected %02x ", sc->sc_lastmsg));
+ switch (sc->sc_lastmsg) {
+#if SPC_USE_SYNCHRONOUS + SPC_USE_WIDE
+ case SEND_IDENTIFY:
+ ti->flags &= ~(DO_SYNC | DO_WIDE);
+ ti->period = ti->offset = 0;
+ spc_setsync(sc, ti);
+ ti->width = 0;
+ break;
+#endif
+#if SPC_USE_SYNCHRONOUS
+ case SEND_SDTR:
+ ti->flags &= ~DO_SYNC;
+ ti->period = ti->offset = 0;
+ spc_setsync(sc, ti);
+ break;
+#endif
+#if SPC_USE_WIDE
+ case SEND_WDTR:
+ ti->flags &= ~DO_WIDE;
+ ti->width = 0;
+ break;
+#endif
+ case SEND_INIT_DET_ERR:
+ spc_sched_msgout(sc, SEND_ABORT);
+ break;
+ }
+ break;
+
+ case MSG_NOOP:
+ break;
+
+ case MSG_DISCONNECT:
+ ti->dconns++;
+ sc->sc_state = SPC_DISCONNECT;
+ break;
+
+ case MSG_SAVEDATAPOINTER:
+ acb->data_addr = sc->sc_dp;
+ acb->data_length = sc->sc_dleft;
+ break;
+
+ case MSG_RESTOREPOINTERS:
+ sc->sc_dp = acb->data_addr;
+ sc->sc_dleft = acb->data_length;
+ sc->sc_cp = (u_char *)&acb->scsi_cmd;
+ sc->sc_cleft = acb->scsi_cmd_length;
+ break;
+
+ case MSG_EXTENDED:
+ switch (sc->sc_imess[2]) {
+#if SPC_USE_SYNCHRONOUS
+ case MSG_EXT_SDTR:
+ if (sc->sc_imess[1] != 3)
+ goto reject;
+ ti->period = sc->sc_imess[3];
+ ti->offset = sc->sc_imess[4];
+ ti->flags &= ~DO_SYNC;
+ if (ti->offset == 0) {
+ } else if (ti->period < sc->sc_minsync ||
+ ti->period > sc->sc_maxsync ||
+ ti->offset > 8) {
+ ti->period = ti->offset = 0;
+ spc_sched_msgout(sc, SEND_SDTR);
+ } else {
+ sc_print_addr(acb->xs->sc_link);
+ printf("sync, offset %d, period %dnsec\n",
+ ti->offset, ti->period * 4);
+ }
+ spc_setsync(sc, ti);
+ break;
+#endif
+
+#if SPC_USE_WIDE
+ case MSG_EXT_WDTR:
+ if (sc->sc_imess[1] != 2)
+ goto reject;
+ ti->width = sc->sc_imess[3];
+ ti->flags &= ~DO_WIDE;
+ if (ti->width == 0) {
+ } else if (ti->width > SPC_MAX_WIDTH) {
+ ti->width = 0;
+ spc_sched_msgout(sc, SEND_WDTR);
+ } else {
+ sc_print_addr(acb->xs->sc_link);
+ printf("wide, width %d\n",
+ 1 << (3 + ti->width));
+ }
+ break;
+#endif
+
+ default:
+ printf("%s: unrecognized MESSAGE EXTENDED; sending REJECT\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ goto reject;
+ }
+ break;
+
+ default:
+ printf("%s: unrecognized MESSAGE; sending REJECT\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ reject:
+ spc_sched_msgout(sc, SEND_REJECT);
+ break;
+ }
+ break;
+
+ case SPC_RESELECTED:
+ if (!MSG_ISIDENTIFY(sc->sc_imess[0])) {
+ printf("%s: reselect without IDENTIFY; sending DEVICE RESET\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ goto reset;
+ }
+
+ (void) spc_reselect(sc, sc->sc_imess[0]);
+ break;
+
+ default:
+ printf("%s: unexpected MESSAGE IN; sending DEVICE RESET\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ reset:
+ spc_sched_msgout(sc, SEND_DEV_RESET);
+ break;
+
+#ifdef notdef
+ abort:
+ spc_sched_msgout(sc, SEND_ABORT);
+ break;
+#endif
+ }
+
+ /* Ack the last message byte. */
+#if 0 /* XXX? */
+ (void) bus_space_read_1(iot, ioh, DREG);
+ while ((bus_space_read_1(iot, ioh, PSNS) & ACKI) != 0)
+ ;
+#endif
+
+ /* Go get the next message, if any. */
+ goto nextmsg;
+
+out:
+ bus_space_write_1(iot, ioh, SCMD, SCMD_RST_ACK);
+ SPC_MISC(("n=%d imess=0x%02x ", n, sc->sc_imess[0]));
+}
+
+/*
+ * Send the highest priority, scheduled message.
+ */
+void
+spc_msgout(sc)
+ struct spc_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+#if SPC_USE_SYNCHRONOUS
+ struct spc_tinfo *ti;
+#endif
+ int n;
+
+ SPC_TRACE(("spc_msgout "));
+
+ if (sc->sc_prevphase == PH_MSGOUT) {
+ if (sc->sc_omp == sc->sc_omess) {
+ /*
+ * This is a retransmission.
+ *
+ * We get here if the target stayed in MESSAGE OUT
+ * phase. Section 5.1.9.2 of the SCSI 2 spec indicates
+ * that all of the previously transmitted messages must
+ * be sent again, in the same order. Therefore, we
+ * requeue all the previously transmitted messages, and
+ * start again from the top. Our simple priority
+ * scheme keeps the messages in the right order.
+ */
+ SPC_MISC(("retransmitting "));
+ sc->sc_msgpriq |= sc->sc_msgoutq;
+ /*
+ * Set ATN. If we're just sending a trivial 1-byte
+ * message, we'll clear ATN later on anyway.
+ */
+ bus_space_write_1(iot, ioh, SCMD, SCMD_SET_ATN); /* XXX? */
+ } else {
+ /* This is a continuation of the previous message. */
+ n = sc->sc_omp - sc->sc_omess;
+ goto nextbyte;
+ }
+ }
+
+ /* No messages transmitted so far. */
+ sc->sc_msgoutq = 0;
+ sc->sc_lastmsg = 0;
+
+nextmsg:
+ /* Pick up highest priority message. */
+ sc->sc_currmsg = sc->sc_msgpriq & -sc->sc_msgpriq;
+ sc->sc_msgpriq &= ~sc->sc_currmsg;
+ sc->sc_msgoutq |= sc->sc_currmsg;
+
+ /* Build the outgoing message data. */
+ switch (sc->sc_currmsg) {
+ case SEND_IDENTIFY:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ sc->sc_omess[0] =
+ MSG_IDENTIFY(sc->sc_nexus->xs->sc_link->lun, 1);
+ n = 1;
+ break;
+
+#if SPC_USE_SYNCHRONOUS
+ case SEND_SDTR:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target];
+ sc->sc_omess[4] = MSG_EXTENDED;
+ sc->sc_omess[3] = 3;
+ sc->sc_omess[2] = MSG_EXT_SDTR;
+ sc->sc_omess[1] = ti->period >> 2;
+ sc->sc_omess[0] = ti->offset;
+ n = 5;
+ break;
+#endif
+
+#if SPC_USE_WIDE
+ case SEND_WDTR:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ ti = &sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target];
+ sc->sc_omess[3] = MSG_EXTENDED;
+ sc->sc_omess[2] = 2;
+ sc->sc_omess[1] = MSG_EXT_WDTR;
+ sc->sc_omess[0] = ti->width;
+ n = 4;
+ break;
+#endif
+
+ case SEND_DEV_RESET:
+ sc->sc_flags |= SPC_ABORTING;
+ sc->sc_omess[0] = MSG_BUS_DEV_RESET;
+ n = 1;
+ break;
+
+ case SEND_REJECT:
+ sc->sc_omess[0] = MSG_MESSAGE_REJECT;
+ n = 1;
+ break;
+
+ case SEND_PARITY_ERROR:
+ sc->sc_omess[0] = MSG_PARITY_ERROR;
+ n = 1;
+ break;
+
+ case SEND_INIT_DET_ERR:
+ sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
+ n = 1;
+ break;
+
+ case SEND_ABORT:
+ sc->sc_flags |= SPC_ABORTING;
+ sc->sc_omess[0] = MSG_ABORT;
+ n = 1;
+ break;
+
+ default:
+ printf("%s: unexpected MESSAGE OUT; sending NOOP\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ sc->sc_omess[0] = MSG_NOOP;
+ n = 1;
+ break;
+ }
+ sc->sc_omp = &sc->sc_omess[n];
+
+nextbyte:
+ /* Send message bytes. */
+ /* send TRANSFER command. */
+ bus_space_write_1(iot, ioh, TCH, n >> 16);
+ bus_space_write_1(iot, ioh, TCM, n >> 8);
+ bus_space_write_1(iot, ioh, TCL, n);
+ bus_space_write_1(iot, ioh, PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
+#ifdef x68k
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* XXX */
+#else
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR | SCMD_PROG_XFR | SCMD_ICPT_XFR);
+#endif
+ for (;;) {
+ if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0)
+ break;
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ goto out;
+ }
+ for (;;) {
+#if 0
+ for (;;) {
+ if ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) != 0)
+ break;
+ /* Wait for REQINIT. XXX Need timeout. */
+ }
+#endif
+ if (bus_space_read_1(iot, ioh, INTS) != 0) {
+ /*
+ * Target left MESSAGE OUT, possibly to reject
+ * our message.
+ *
+ * If this is the last message being sent, then we
+ * deassert ATN, since either the target is going to
+ * ignore this message, or it's going to ask for a
+ * retransmission via MESSAGE PARITY ERROR (in which
+ * case we reassert ATN anyway).
+ */
+#if 0
+ if (sc->sc_msgpriq == 0)
+ bus_space_write_1(iot, ioh, SCMD, SCMD_RST_ATN);
+#endif
+ goto out;
+ }
+
+#if 0
+ /* Clear ATN before last byte if this is the last message. */
+ if (n == 1 && sc->sc_msgpriq == 0)
+ bus_space_write_1(iot, ioh, SCMD, SCMD_RST_ATN);
+#endif
+
+ while ((bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_FULL) != 0)
+ ;
+ /* Send message byte. */
+ bus_space_write_1(iot, ioh, DREG, *--sc->sc_omp);
+ --n;
+ /* Keep track of the last message we've sent any bytes of. */
+ sc->sc_lastmsg = sc->sc_currmsg;
+#if 0
+ /* Wait for ACK to be negated. XXX Need timeout. */
+ while ((bus_space_read_1(iot, ioh, PSNS) & ACKI) != 0)
+ ;
+#endif
+
+ if (n == 0)
+ break;
+ }
+
+ /* We get here only if the entire message has been transmitted. */
+ if (sc->sc_msgpriq != 0) {
+ /* There are more outgoing messages. */
+ goto nextmsg;
+ }
+
+ /*
+ * The last message has been transmitted. We need to remember the last
+ * message transmitted (in case the target switches to MESSAGE IN phase
+ * and sends a MESSAGE REJECT), and the list of messages transmitted
+ * this time around (in case the target stays in MESSAGE OUT phase to
+ * request a retransmit).
+ */
+
+out:
+ /* Disable REQ/ACK protocol. */
+}
+
+/*
+ * spc_dataout_pio: perform a data transfer using the FIFO datapath in the spc
+ * Precondition: The SCSI bus should be in the DOUT phase, with REQ asserted
+ * and ACK deasserted (i.e. waiting for a data byte)
+ *
+ * This new revision has been optimized (I tried) to make the common case fast,
+ * and the rarer cases (as a result) somewhat more comlex
+ */
+int
+spc_dataout_pio(sc, p, n)
+ struct spc_softc *sc;
+ u_char *p;
+ int n;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_char intstat = 0;
+ int out = 0;
+#define DOUTAMOUNT 8 /* Full FIFO */
+
+ SPC_TRACE(("spc_dataout_pio "));
+ /* send TRANSFER command. */
+ bus_space_write_1(iot, ioh, TCH, n >> 16);
+ bus_space_write_1(iot, ioh, TCM, n >> 8);
+ bus_space_write_1(iot, ioh, TCL, n);
+ bus_space_write_1(iot, ioh, PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
+#ifdef x68k
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* XXX */
+#else
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR | SCMD_PROG_XFR | SCMD_ICPT_XFR); /* XXX */
+#endif
+ for (;;) {
+ if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0)
+ break;
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ break;
+ }
+
+ /*
+ * I have tried to make the main loop as tight as possible. This
+ * means that some of the code following the loop is a bit more
+ * complex than otherwise.
+ */
+ while (n > 0) {
+ int xfer;
+
+ for (;;) {
+ intstat = bus_space_read_1(iot, ioh, INTS);
+ /* Wait till buffer is empty. */
+ if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_EMPTY) != 0)
+ break;
+ /* Break on interrupt. */
+ if (intstat != 0)
+ goto phasechange;
+ }
+
+ xfer = min(DOUTAMOUNT, n);
+
+ SPC_MISC(("%d> ", xfer));
+
+ n -= xfer;
+ out += xfer;
+
+ while (xfer-- > 0) {
+ bus_space_write_1(iot, ioh, DREG, *p++);
+ }
+ }
+
+ if (out == 0) {
+ for (;;) {
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ break;
+ }
+ SPC_MISC(("extra data "));
+ } else {
+ /* See the bytes off chip */
+ for (;;) {
+ /* Wait till buffer is empty. */
+ if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_DREG_EMPTY) != 0)
+ break;
+ intstat = bus_space_read_1(iot, ioh, INTS);
+ /* Break on interrupt. */
+ if (intstat != 0)
+ goto phasechange;
+ }
+ }
+
+phasechange:
+ /* Stop the FIFO data path. */
+
+ if (intstat != 0) {
+ /* Some sort of phase change. */
+ int amount;
+
+ amount = ((bus_space_read_1(iot, ioh, TCH) << 16) |
+ (bus_space_read_1(iot, ioh, TCM) << 8) |
+ bus_space_read_1(iot, ioh, TCL));
+ if (amount > 0) {
+ out -= amount;
+ SPC_MISC(("+%d ", amount));
+ }
+ }
+
+ /* Turn on ENREQINIT again. */
+
+ return out;
+}
+
+/*
+ * spc_datain_pio: perform data transfers using the FIFO datapath in the spc
+ * Precondition: The SCSI bus should be in the DIN phase, with REQ asserted
+ * and ACK deasserted (i.e. at least one byte is ready).
+ *
+ * For now, uses a pretty dumb algorithm, hangs around until all data has been
+ * transferred. This, is OK for fast targets, but not so smart for slow
+ * targets which don't disconnect or for huge transfers.
+ */
+int
+spc_datain_pio(sc, p, n)
+ struct spc_softc *sc;
+ u_char *p;
+ int n;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_short intstat;
+ int in = 0;
+#define DINAMOUNT 8 /* Full FIFO */
+
+ SPC_TRACE(("spc_datain_pio "));
+ /* send TRANSFER command. */
+ bus_space_write_1(iot, ioh, TCH, n >> 16);
+ bus_space_write_1(iot, ioh, TCM, n >> 8);
+ bus_space_write_1(iot, ioh, TCL, n);
+ bus_space_write_1(iot, ioh, PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
+#ifdef x68k
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR); /* XXX */
+#else
+ bus_space_write_1(iot, ioh, SCMD, SCMD_XFR | SCMD_PROG_XFR); /* XXX */
+#endif
+ for (;;) {
+ if ((bus_space_read_1(iot, ioh, SSTS) & SSTS_BUSY) != 0)
+ break;
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ goto phasechange;
+ }
+
+ /*
+ * We leave this loop if one or more of the following is true:
+ * a) phase != PH_DATAIN && FIFOs are empty
+ * b) reset has occurred or busfree is detected.
+ */
+ while (n > 0) {
+ int xfer;
+
+#define INTSMASK 0xff
+ /* Wait for fifo half full or phase mismatch */
+ for (;;) {
+ intstat = ((bus_space_read_1(iot, ioh, SSTS) << 8) |
+ bus_space_read_1(iot, ioh, INTS));
+ if ((intstat & (INTSMASK | (SSTS_DREG_FULL << 8))) !=
+ 0)
+ break;
+ if ((intstat & (SSTS_DREG_EMPTY << 8)) == 0)
+ break;
+ }
+
+#if 1
+ if ((intstat & INTSMASK) != 0)
+ goto phasechange;
+#else
+ if ((intstat & INTSMASK) != 0 &&
+ (intstat & (SSTS_DREG_EMPTY << 8)))
+ goto phasechange;
+#endif
+ if ((intstat & (SSTS_DREG_FULL << 8)) != 0)
+ xfer = min(DINAMOUNT, n);
+ else
+ xfer = min(1, n);
+
+ SPC_MISC((">%d ", xfer));
+
+ n -= xfer;
+ in += xfer;
+
+ while (xfer-- > 0) {
+ *p++ = bus_space_read_1(iot, ioh, DREG);
+ }
+
+ if ((intstat & INTSMASK) != 0)
+ goto phasechange;
+ }
+
+ /*
+ * Some SCSI-devices are rude enough to transfer more data than what
+ * was requested, e.g. 2048 bytes from a CD-ROM instead of the
+ * requested 512. Test for progress, i.e. real transfers. If no real
+ * transfers have been performed (n is probably already zero) and the
+ * FIFO is not empty, waste some bytes....
+ */
+ if (in == 0) {
+ for (;;) {
+ if (bus_space_read_1(iot, ioh, INTS) != 0)
+ break;
+ }
+ SPC_MISC(("extra data "));
+ }
+
+phasechange:
+ /* Stop the FIFO data path. */
+
+ /* Turn on ENREQINIT again. */
+
+ return in;
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+/*
+ * This is the workhorse routine of the driver.
+ * Deficiencies (for now):
+ * 1) always uses programmed I/O
+ */
+int
+spc_intr(arg)
+ void *arg;
+{
+ struct spc_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_char ints;
+ struct spc_acb *acb;
+ struct scsi_link *sc_link;
+ struct spc_tinfo *ti;
+ int n;
+
+ /*
+ * Disable interrupt.
+ */
+ bus_space_write_1(iot, ioh, SCTL, bus_space_read_1(iot, ioh, SCTL) & ~SCTL_INTR_ENAB);
+
+ SPC_TRACE(("spc_intr "));
+
+loop:
+ /*
+ * Loop until transfer completion.
+ */
+ /*
+ * First check for abnormal conditions, such as reset.
+ */
+#ifdef x68k /* XXX? */
+ while ((ints = bus_space_read_1(iot, ioh, INTS)) == 0)
+ delay(1);
+ SPC_MISC(("ints = 0x%x ", ints));
+#else
+ ints = bus_space_read_1(iot, ioh, INTS);
+ SPC_MISC(("ints = 0x%x ", ints));
+#endif
+
+ if ((ints & INTS_RST) != 0) {
+ printf("%s: SCSI bus reset\n", sc->sc_dev.dv_xname);
+ goto reset;
+ }
+
+ /*
+ * Check for less serious errors.
+ */
+ if ((bus_space_read_1(iot, ioh, SERR) & (SERR_SCSI_PAR|SERR_SPC_PAR)) != 0) {
+ printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname);
+ if (sc->sc_prevphase == PH_MSGIN) {
+ sc->sc_flags |= SPC_DROP_MSGIN;
+ spc_sched_msgout(sc, SEND_PARITY_ERROR);
+ } else
+ spc_sched_msgout(sc, SEND_INIT_DET_ERR);
+ }
+
+ /*
+ * If we're not already busy doing something test for the following
+ * conditions:
+ * 1) We have been reselected by something
+ * 2) We have selected something successfully
+ * 3) Our selection process has timed out
+ * 4) This is really a bus free interrupt just to get a new command
+ * going?
+ * 5) Spurious interrupt?
+ */
+ switch (sc->sc_state) {
+ case SPC_IDLE:
+ case SPC_SELECTING:
+ SPC_MISC(("ints:0x%02x ", ints));
+
+ if ((ints & INTS_SEL) != 0) {
+ /*
+ * We don't currently support target mode.
+ */
+ printf("%s: target mode selected; going to BUS FREE\n",
+ sc->sc_dev.dv_xname);
+
+ goto sched;
+ } else if ((ints & INTS_RESEL) != 0) {
+ SPC_MISC(("reselected "));
+
+ /*
+ * If we're trying to select a target ourselves,
+ * push our command back into the ready list.
+ */
+ if (sc->sc_state == SPC_SELECTING) {
+ SPC_MISC(("backoff selector "));
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ sc->sc_nexus = NULL;
+ TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
+ }
+
+ /* Save reselection ID. */
+ sc->sc_selid = bus_space_read_1(iot, ioh, TEMP);
+
+ sc->sc_state = SPC_RESELECTED;
+ } else if ((ints & INTS_CMD_DONE) != 0) {
+ SPC_MISC(("selected "));
+
+ /*
+ * We have selected a target. Things to do:
+ * a) Determine what message(s) to send.
+ * b) Verify that we're still selecting the target.
+ * c) Mark device as busy.
+ */
+ if (sc->sc_state != SPC_SELECTING) {
+ printf("%s: selection out while idle; resetting\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ goto reset;
+ }
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ sc_link = acb->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+
+ sc->sc_msgpriq = SEND_IDENTIFY;
+ if (acb->flags & ACB_RESET)
+ sc->sc_msgpriq |= SEND_DEV_RESET;
+ else if (acb->flags & ACB_ABORT)
+ sc->sc_msgpriq |= SEND_ABORT;
+ else {
+#if SPC_USE_SYNCHRONOUS
+ if ((ti->flags & DO_SYNC) != 0)
+ sc->sc_msgpriq |= SEND_SDTR;
+#endif
+#if SPC_USE_WIDE
+ if ((ti->flags & DO_WIDE) != 0)
+ sc->sc_msgpriq |= SEND_WDTR;
+#endif
+ }
+
+ acb->flags |= ACB_NEXUS;
+ ti->lubusy |= (1 << sc_link->lun);
+
+ /* Do an implicit RESTORE POINTERS. */
+ sc->sc_dp = acb->data_addr;
+ sc->sc_dleft = acb->data_length;
+ sc->sc_cp = (u_char *)&acb->scsi_cmd;
+ sc->sc_cleft = acb->scsi_cmd_length;
+
+ /* On our first connection, schedule a timeout. */
+ if ((acb->xs->flags & SCSI_POLL) == 0) {
+ timeout_set(&acb->xs->stimeout, spc_timeout, acb);
+ timeout_add(&acb->xs->stimeout,
+ (acb->timeout * hz) / 1000);
+ }
+ sc->sc_state = SPC_CONNECTED;
+ } else if ((ints & INTS_TIMEOUT) != 0) {
+ SPC_MISC(("selection timeout "));
+
+ if (sc->sc_state != SPC_SELECTING) {
+ printf("%s: selection timeout while idle; resetting\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ goto reset;
+ }
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+
+ delay(250);
+
+ acb->xs->error = XS_SELTIMEOUT;
+ goto finish;
+ } else {
+ if (sc->sc_state != SPC_IDLE) {
+ printf("%s: BUS FREE while not idle; state=%d\n",
+ sc->sc_dev.dv_xname, sc->sc_state);
+ SPC_BREAK();
+ goto out;
+ }
+
+ goto sched;
+ }
+
+ /*
+ * Turn off selection stuff, and prepare to catch bus free
+ * interrupts, parity errors, and phase changes.
+ */
+
+ sc->sc_flags = 0;
+ sc->sc_prevphase = PH_INVALID;
+ goto dophase;
+ }
+
+ if ((ints & INTS_DISCON) != 0) {
+ /* We've gone to BUS FREE phase. */
+ bus_space_write_1(iot, ioh, PCTL,
+ bus_space_read_1(iot, ioh, PCTL) & ~PCTL_BFINT_ENAB);
+ /* disable disconnect interrupt */
+ bus_space_write_1(iot, ioh, INTS, ints);
+ /* XXX reset interrput */
+
+ switch (sc->sc_state) {
+ case SPC_RESELECTED:
+ goto sched;
+
+ case SPC_CONNECTED:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+
+#if SPC_USE_SYNCHRONOUS + SPC_USE_WIDE
+ if (sc->sc_prevphase == PH_MSGOUT) {
+ /*
+ * If the target went to BUS FREE phase during
+ * or immediately after sending a SDTR or WDTR
+ * message, disable negotiation.
+ */
+ sc_link = acb->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+ switch (sc->sc_lastmsg) {
+#if SPC_USE_SYNCHRONOUS
+ case SEND_SDTR:
+ ti->flags &= ~DO_SYNC;
+ ti->period = ti->offset = 0;
+ break;
+#endif
+#if SPC_USE_WIDE
+ case SEND_WDTR:
+ ti->flags &= ~DO_WIDE;
+ ti->width = 0;
+ break;
+#endif
+ }
+ }
+#endif
+
+ if ((sc->sc_flags & SPC_ABORTING) == 0) {
+ /*
+ * Section 5.1.1 of the SCSI 2 spec suggests
+ * issuing a REQUEST SENSE following an
+ * unexpected disconnect. Some devices go into
+ * a contingent allegiance condition when
+ * disconnecting, and this is necessary to
+ * clean up their state.
+ */
+ printf("%s: unexpected disconnect; sending REQUEST SENSE\n",
+ sc->sc_dev.dv_xname);
+ SPC_BREAK();
+ spc_sense(sc, acb);
+ goto out;
+ }
+
+ acb->xs->error = XS_DRIVER_STUFFUP;
+ goto finish;
+
+ case SPC_DISCONNECT:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ TAILQ_INSERT_HEAD(&sc->nexus_list, acb, chain);
+ sc->sc_nexus = NULL;
+ goto sched;
+
+ case SPC_CMDCOMPLETE:
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ goto finish;
+ }
+ }
+ else if ((ints & INTS_CMD_DONE) != 0 &&
+ sc->sc_prevphase == PH_MSGIN && sc->sc_state != SPC_CONNECTED)
+ goto out;
+
+dophase:
+#if 0
+ if ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) == 0) {
+ /* Wait for REQINIT. */
+ goto out;
+ }
+#else
+ bus_space_write_1(iot, ioh, INTS, ints);
+ ints = 0;
+ while ((bus_space_read_1(iot, ioh, PSNS) & PSNS_REQ) == 0)
+ delay(1); /* need timeout XXX */
+#endif
+
+ /*
+ * State transition.
+ */
+ sc->sc_phase = bus_space_read_1(iot, ioh, PSNS) & PH_MASK;
+/* bus_space_write_1(iot, ioh, PCTL, sc->sc_phase);*/
+
+ SPC_MISC(("phase=%d\n", sc->sc_phase));
+ switch (sc->sc_phase) {
+ case PH_MSGOUT:
+ if (sc->sc_state != SPC_CONNECTED &&
+ sc->sc_state != SPC_RESELECTED)
+ break;
+ spc_msgout(sc);
+ sc->sc_prevphase = PH_MSGOUT;
+ goto loop;
+
+ case PH_MSGIN:
+ if (sc->sc_state != SPC_CONNECTED &&
+ sc->sc_state != SPC_RESELECTED)
+ break;
+ spc_msgin(sc);
+ sc->sc_prevphase = PH_MSGIN;
+ goto loop;
+
+ case PH_CMD:
+ if (sc->sc_state != SPC_CONNECTED)
+ break;
+#if SPC_DEBUG
+ if ((spc_debug & SPC_SHOWMISC) != 0) {
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ printf("cmd=0x%02x+%d ",
+ acb->scsi_cmd.opcode, acb->scsi_cmd_length-1);
+ }
+#endif
+ n = spc_dataout_pio(sc, sc->sc_cp, sc->sc_cleft);
+ sc->sc_cp += n;
+ sc->sc_cleft -= n;
+ sc->sc_prevphase = PH_CMD;
+ goto loop;
+
+ case PH_DATAOUT:
+ if (sc->sc_state != SPC_CONNECTED)
+ break;
+ SPC_MISC(("dataout dleft=%d ", sc->sc_dleft));
+ n = spc_dataout_pio(sc, sc->sc_dp, sc->sc_dleft);
+ sc->sc_dp += n;
+ sc->sc_dleft -= n;
+ sc->sc_prevphase = PH_DATAOUT;
+ goto loop;
+
+ case PH_DATAIN:
+ if (sc->sc_state != SPC_CONNECTED)
+ break;
+ SPC_MISC(("datain "));
+ n = spc_datain_pio(sc, sc->sc_dp, sc->sc_dleft);
+ sc->sc_dp += n;
+ sc->sc_dleft -= n;
+ sc->sc_prevphase = PH_DATAIN;
+ goto loop;
+
+ case PH_STAT:
+ if (sc->sc_state != SPC_CONNECTED)
+ break;
+ SPC_ASSERT(sc->sc_nexus != NULL);
+ acb = sc->sc_nexus;
+ /*acb->target_stat = bus_space_read_1(iot, ioh, DREG);*/
+ spc_datain_pio(sc, &acb->target_stat, 1);
+ SPC_MISC(("target_stat=0x%02x ", acb->target_stat));
+ sc->sc_prevphase = PH_STAT;
+ goto loop;
+ }
+
+ printf("%s: unexpected bus phase; resetting\n", sc->sc_dev.dv_xname);
+ SPC_BREAK();
+reset:
+ spc_init(sc);
+ return 1;
+
+finish:
+ timeout_del(&acb->xs->stimeout);
+ bus_space_write_1(iot, ioh, INTS, ints);
+ ints = 0;
+ spc_done(sc, acb);
+ goto out;
+
+sched:
+ sc->sc_state = SPC_IDLE;
+ spc_sched(sc);
+ goto out;
+
+out:
+ if (ints)
+ bus_space_write_1(iot, ioh, INTS, ints);
+ bus_space_write_1(iot, ioh, SCTL,
+ bus_space_read_1(iot, ioh, SCTL) | SCTL_INTR_ENAB);
+ return 1;
+}
+
+void
+spc_abort(sc, acb)
+ struct spc_softc *sc;
+ struct spc_acb *acb;
+{
+
+ /* 2 secs for the abort */
+ acb->timeout = SPC_ABORT_TIMEOUT;
+ acb->flags |= ACB_ABORT;
+
+ if (acb == sc->sc_nexus) {
+ /*
+ * If we're still selecting, the message will be scheduled
+ * after selection is complete.
+ */
+ if (sc->sc_state == SPC_CONNECTED)
+ spc_sched_msgout(sc, SEND_ABORT);
+ } else {
+ spc_dequeue(sc, acb);
+ TAILQ_INSERT_HEAD(&sc->ready_list, acb, chain);
+ if (sc->sc_state == SPC_IDLE)
+ spc_sched(sc);
+ }
+}
+
+void
+spc_timeout(arg)
+ void *arg;
+{
+ struct spc_acb *acb = arg;
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *sc_link = xs->sc_link;
+ struct spc_softc *sc = sc_link->adapter_softc;
+ int s;
+
+ sc_print_addr(sc_link);
+ printf("timed out");
+
+ s = splbio();
+
+ if (acb->flags & ACB_ABORT) {
+ /* abort timed out */
+ printf(" AGAIN\n");
+ /* XXX Must reset! */
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ acb->xs->error = XS_TIMEOUT;
+ spc_abort(sc, acb);
+ }
+
+ splx(s);
+}
+
+#ifdef SPC_DEBUG
+/*
+ * The following functions are mostly used for debugging purposes, either
+ * directly called from the driver or from the kernel debugger.
+ */
+
+void
+spc_show_scsi_cmd(acb)
+ struct spc_acb *acb;
+{
+ u_char *b = (u_char *)&acb->scsi_cmd;
+ struct scsi_link *sc_link = acb->xs->sc_link;
+ int i;
+
+ sc_print_addr(sc_link);
+ if ((acb->xs->flags & SCSI_RESET) == 0) {
+ for (i = 0; i < acb->scsi_cmd_length; i++) {
+ if (i)
+ printf(",");
+ printf("%x", b[i]);
+ }
+ printf("\n");
+ } else
+ printf("RESET\n");
+}
+
+void
+spc_print_acb(acb)
+ struct spc_acb *acb;
+{
+
+ printf("acb@%p xs=%p flags=%x", acb, acb->xs, acb->flags);
+ printf(" dp=%p dleft=%d target_stat=%x\n",
+ acb->data_addr, acb->data_length, acb->target_stat);
+ spc_show_scsi_cmd(acb);
+}
+
+void
+spc_print_active_acb()
+{
+ struct spc_acb *acb;
+ struct spc_softc *sc = spc_cd.cd_devs[0]; /* XXX */
+
+ printf("ready list:\n");
+ for (acb = sc->ready_list.tqh_first; acb != NULL;
+ acb = acb->chain.tqe_next)
+ spc_print_acb(acb);
+ printf("nexus:\n");
+ if (sc->sc_nexus != NULL)
+ spc_print_acb(sc->sc_nexus);
+ printf("nexus list:\n");
+ for (acb = sc->nexus_list.tqh_first; acb != NULL;
+ acb = acb->chain.tqe_next)
+ spc_print_acb(acb);
+}
+
+void
+spc_dump89352(sc)
+ struct spc_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ printf("mb89352: BDID=%x SCTL=%x SCMD=%x TMOD=%x\n",
+ bus_space_read_1(iot, ioh, BDID),
+ bus_space_read_1(iot, ioh, SCTL),
+ bus_space_read_1(iot, ioh, SCMD),
+ bus_space_read_1(iot, ioh, TMOD));
+ printf(" INTS=%x PSNS=%x SSTS=%x SERR=%x PCTL=%x\n",
+ bus_space_read_1(iot, ioh, INTS),
+ bus_space_read_1(iot, ioh, PSNS),
+ bus_space_read_1(iot, ioh, SSTS),
+ bus_space_read_1(iot, ioh, SERR),
+ bus_space_read_1(iot, ioh, PCTL));
+ printf(" MBC=%x DREG=%x TEMP=%x TCH=%x TCM=%x\n",
+ bus_space_read_1(iot, ioh, MBC),
+#if 0
+ bus_space_read_1(iot, ioh, DREG),
+#else
+ 0,
+#endif
+ bus_space_read_1(iot, ioh, TEMP),
+ bus_space_read_1(iot, ioh, TCH),
+ bus_space_read_1(iot, ioh, TCM));
+ printf(" TCL=%x EXBF=%x\n",
+ bus_space_read_1(iot, ioh, TCL),
+ bus_space_read_1(iot, ioh, EXBF));
+}
+
+void
+spc_dump_driver(sc)
+ struct spc_softc *sc;
+{
+ struct spc_tinfo *ti;
+ int i;
+
+ printf("nexus=%p prevphase=%x\n", sc->sc_nexus, sc->sc_prevphase);
+ printf("state=%x msgin=%x msgpriq=%x msgoutq=%x lastmsg=%x currmsg=%x\n",
+ sc->sc_state, sc->sc_imess[0],
+ sc->sc_msgpriq, sc->sc_msgoutq, sc->sc_lastmsg, sc->sc_currmsg);
+ for (i = 0; i < 7; i++) {
+ ti = &sc->sc_tinfo[i];
+ printf("tinfo%d: %d cmds %d disconnects %d timeouts",
+ i, ti->cmds, ti->dconns, ti->touts);
+ printf(" %d senses flags=%x\n", ti->senses, ti->flags);
+ }
+}
+#endif
diff --git a/sys/arch/luna88k/dev/mb89352reg.h b/sys/arch/luna88k/dev/mb89352reg.h
new file mode 100644
index 00000000000..5a30b391173
--- /dev/null
+++ b/sys/arch/luna88k/dev/mb89352reg.h
@@ -0,0 +1,238 @@
+/* $OpenBSD: mb89352reg.h,v 1.1 2004/04/21 15:23:54 aoyama Exp $ */
+/* $NetBSD: mb89352reg.h,v 1.3 2003/08/07 16:31:02 agc Exp $ */
+/* NecBSD: mb89352reg.h,v 1.3 1998/03/14 07:04:34 kmatsuda Exp */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsireg.h 8.1 (Berkeley) 6/10/93
+ */
+
+/*-
+ * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson of Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)scsireg.h 8.1 (Berkeley) 6/10/93
+ */
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. All rights reserved.
+ * Copyright (c) 1996, 1997, 1998
+ * Kouichi Matsuda. All rights reserved.
+ */
+
+/*
+ * FUJITSU MB89352A SCSI Protocol Controler Hardware Description.
+ */
+
+/* Definitions, most of them has turned out to be unneccesary, but here they
+ * are anyway.
+ */
+
+#define BDID 0x00 /* Bus Device ID (R/W) */
+#define SCTL 0x01 /* SPC Control register (R/W) */
+#define SCMD 0x02 /* Command Register (R/W) */
+#define TMOD 0x03 /* Transmit Mode Register (synch models) */
+#define INTS 0x04 /* Interrupt sense (R); Interrupt Reset (W) */
+#define PSNS 0x05 /* Phase Sence (R); SPC Diagnostic Control (W) */
+#define SSTS 0x06 /* SPC status (R/O) */
+#define SERR 0x07 /* SPC error status (R/O) */
+#define PCTL 0x08 /* Phase Control (R/W) */
+#define MBC 0x09 /* Modified Byte Counter (R/O) */
+#define DREG 0x0a /* Data Register (R/W) */
+#define TEMP 0x0b /* Temporary Register (R/W) */
+#define TCH 0x0c /* Transfer Counter High (R/W) */
+#define TCM 0x0d /* Transfer Counter Middle (R/W) */
+#define TCL 0x0e /* Transfer Counter Low (R/W) */
+#define EXBF 0x0f /* External Buffer (synch models) */
+
+/* What all the bits do */
+
+/* SCSI_BDID */
+/* SCSI selection/reselection ID (both target *and* initiator) */
+#define SELID7 0x80
+#define SELID6 0x40
+#define SELID5 0x20
+#define SELID4 0x10
+#define SELID3 0x08
+#define SELID2 0x04
+#define SELID1 0x02
+#define SELID0 0x01
+
+/* SCSI_SCTL */
+#define SCTL_DISABLE 0x80
+#define SCTL_CTRLRST 0x40
+#define SCTL_DIAG 0x20
+#define SCTL_ABRT_ENAB 0x10
+#define SCTL_PARITY_ENAB 0x08
+#define SCTL_SEL_ENAB 0x04
+#define SCTL_RESEL_ENAB 0x02
+#define SCTL_INTR_ENAB 0x01
+
+/* SCSI_SCMD */
+#define SCMD_RST 0x10
+#define SCMD_ICPT_XFR 0x08
+#define SCMD_PROG_XFR 0x04
+#define SCMD_PAD 0x01 /* if initiator */
+#define SCMD_PERR_STOP 0x01 /* if target */
+ /* command codes */
+#define SCMD_BUS_REL 0x00
+#define SCMD_SELECT 0x20
+#define SCMD_RST_ATN 0x40
+#define SCMD_SET_ATN 0x60
+#define SCMD_XFR 0x80
+#define SCMD_XFR_PAUSE 0xa0
+#define SCMD_RST_ACK 0xc0
+#define SCMD_SET_ACK 0xe0
+
+/* SCSI_TMOD */
+#define TMOD_SYNC 0x80
+
+/* SCSI_INTS */
+#define INTS_SEL 0x80
+#define INTS_RESEL 0x40
+#define INTS_DISCON 0x20
+#define INTS_CMD_DONE 0x10
+#define INTS_SRV_REQ 0x08
+#define INTS_TIMEOUT 0x04
+#define INTS_HARD_ERR 0x02
+#define INTS_RST 0x01
+
+/* SCSI_PSNS */
+#define PSNS_REQ 0x80
+#define PSNS_ACK 0x40
+#define PSNS_ATN 0x20
+#define PSNS_SEL 0x10
+#define PSNS_BSY 0x08
+
+/* PSNS */
+#define REQI 0x80
+#define ACKI 0x40
+#define ATNI 0x20
+#define SELI 0x10
+#define BSYI 0x08
+#define MSGI 0x04
+#define CDI 0x02
+#define IOI 0x01
+
+/* Important! The 3 most significant bits of this register, in initiator mode,
+ * represents the "expected" SCSI bus phase and can be used to trigger phase
+ * mismatch and phase change interrupts. But more important: If there is a
+ * phase mismatch the chip will not transfer any data! This is actually a nice
+ * feature as it gives us a bit more control over what is happening when we are
+ * bursting data (in) through the FIFOs and the phase suddenly changes from
+ * DATA IN to STATUS or MESSAGE IN. The transfer will stop and wait for the
+ * proper phase to be set in this register instead of dumping the bits into the
+ * FIFOs.
+ */
+#if 0
+#define REQO 0x80
+#define ACKO 0x40
+#define ATNO 0x20
+#define SELO 0x10
+#define BSYO 0x08
+#endif
+/* PCTL */
+#define MSGO 0x04
+#define CDO 0x02
+#define IOO 0x01
+
+/* Information transfer phases */
+#define PH_DATAOUT (0)
+#define PH_DATAIN (IOI)
+#define PH_CMD (CDI)
+#define PH_STAT (CDI | IOI)
+#define PH_MSGOUT (MSGI | CDI)
+#define PH_MSGIN (MSGI | CDI | IOI)
+
+#define PH_MASK (MSGI | CDI | IOI)
+
+#define PH_INVALID 0xff
+
+/* SCSI_SSTS */
+#define SSTS_INITIATOR 0x80
+#define SSTS_TARGET 0x40
+#define SSTS_BUSY 0x20
+#define SSTS_XFR 0x10
+#define SSTS_ACTIVE (SSTS_INITIATOR|SSTS_XFR)
+#define SSTS_RST 0x08
+#define SSTS_TCZERO 0x04
+#define SSTS_DREG_FULL 0x02
+#define SSTS_DREG_EMPTY 0x01
+
+/* SCSI_SERR */
+#define SERR_SCSI_PAR 0x80
+#define SERR_SPC_PAR 0x40
+#define SERR_TC_PAR 0x08
+#define SERR_PHASE_ERR 0x04
+#define SERR_SHORT_XFR 0x02
+#define SERR_OFFSET 0x01
+
+/* SCSI_PCTL */
+#define PCTL_BFINT_ENAB 0x80
diff --git a/sys/arch/luna88k/dev/mb89352var.h b/sys/arch/luna88k/dev/mb89352var.h
new file mode 100644
index 00000000000..e77f0649a05
--- /dev/null
+++ b/sys/arch/luna88k/dev/mb89352var.h
@@ -0,0 +1,214 @@
+/* $OpenBSD: mb89352var.h,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: mb89352var.h,v 1.6 2003/08/02 12:48:09 tsutsui Exp $ */
+/* NecBSD: mb89352var.h,v 1.4 1998/03/14 07:31:22 kmatsuda Exp */
+
+/*-
+ * Copyright (c) 1996,97,98,99 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum, Masaru Oki and Kouichi Matsuda.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Charles M. Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Copyright (c) 1994 Jarle Greipsland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. All rights reserved.
+ * Copyright (c) 1996, 1997, 1998
+ * Kouich Matsuda. All rights reserved.
+ */
+
+#ifndef _MB89352VAR_H_
+#define _MB89352VAR_H_
+
+/*
+ * ACB. Holds additional information for each SCSI command Comments: We
+ * need a separate scsi command block because we may need to overwrite it
+ * with a request sense command. Basicly, we refrain from fiddling with
+ * the scsi_xfer struct (except do the expected updating of return values).
+ * We'll generally update: xs->{flags,resid,error,sense,status} and
+ * occasionally xs->retries.
+ */
+struct spc_acb {
+ struct scsi_generic scsi_cmd;
+ int scsi_cmd_length;
+ u_char *data_addr; /* Saved data pointer */
+ int data_length; /* Residue */
+
+ u_char target_stat; /* SCSI status byte */
+
+#ifdef notdef
+ struct spc_dma_seg dma[SPC_NSEG]; /* Physical addresses+len */
+#endif
+
+ TAILQ_ENTRY(spc_acb) chain;
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags;
+#define ACB_ALLOC 0x01
+#define ACB_NEXUS 0x02
+#define ACB_SENSE 0x04
+#define ACB_ABORT 0x40
+#define ACB_RESET 0x80
+ int timeout;
+};
+
+/*
+ * Some info about each (possible) target on the SCSI bus. This should
+ * probably have been a "per target+lunit" structure, but we'll leave it at
+ * this for now.
+ */
+struct spc_tinfo {
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ ushort lubusy; /* What local units/subr. are busy? */
+ u_char flags;
+#define DO_SYNC 0x01 /* (Re)Negotiate synchronous options */
+#define DO_WIDE 0x02 /* (Re)Negotiate wide options */
+ u_char period; /* Period suggestion */
+ u_char offset; /* Offset suggestion */
+ u_char width; /* Width suggestion */
+};
+
+struct spc_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ struct scsi_link sc_link; /* prototype for subdevs */
+
+ TAILQ_HEAD(, spc_acb) free_list, ready_list, nexus_list;
+ struct spc_acb *sc_nexus; /* current command */
+ struct spc_acb sc_acb[8];
+ struct spc_tinfo sc_tinfo[8];
+
+ /* Data about the current nexus (updated for every cmd switch) */
+ u_char *sc_dp; /* Current data pointer */
+ size_t sc_dleft; /* Data bytes left to transfer */
+ u_char *sc_cp; /* Current command pointer */
+ size_t sc_cleft; /* Command bytes left to transfer */
+
+ /* Adapter state */
+ u_char sc_phase; /* Current bus phase */
+ u_char sc_prevphase; /* Previous bus phase */
+ u_char sc_state; /* State applicable to the adapter */
+#define SPC_INIT 0
+#define SPC_IDLE 1
+#define SPC_SELECTING 2 /* SCSI command is arbiting */
+#define SPC_RESELECTED 3 /* Has been reselected */
+#define SPC_CONNECTED 4 /* Actively using the SCSI bus */
+#define SPC_DISCONNECT 5 /* MSG_DISCONNECT received */
+#define SPC_CMDCOMPLETE 6 /* MSG_CMDCOMPLETE received */
+#define SPC_CLEANING 7
+ u_char sc_flags;
+#define SPC_DROP_MSGIN 0x01 /* Discard all msgs (parity err detected) */
+#define SPC_ABORTING 0x02 /* Bailing out */
+#define SPC_DOINGDMA 0x04 /* doing DMA */
+#define SPC_INACTIVE 0x80 /* The FIFO data path is active! */
+ u_char sc_selid; /* Reselection ID */
+
+ /* Message stuff */
+ u_char sc_msgpriq; /* Messages we want to send */
+ u_char sc_msgoutq; /* Messages sent during last MESSAGE OUT */
+ u_char sc_lastmsg; /* Message last transmitted */
+ u_char sc_currmsg; /* Message currently ready to transmit */
+#define SEND_DEV_RESET 0x01
+#define SEND_PARITY_ERROR 0x02
+#define SEND_INIT_DET_ERR 0x04
+#define SEND_REJECT 0x08
+#define SEND_IDENTIFY 0x10
+#define SEND_ABORT 0x20
+#define SEND_SDTR 0x40
+#define SEND_WDTR 0x80
+#define SPC_MAX_MSG_LEN 8
+ u_char sc_omess[SPC_MAX_MSG_LEN];
+ u_char *sc_omp; /* Outgoing message pointer */
+ u_char sc_imess[SPC_MAX_MSG_LEN];
+ u_char *sc_imp; /* Incoming message pointer */
+
+ /* Hardware stuff */
+ int sc_initiator; /* Our scsi id */
+ int sc_freq; /* Clock frequency in MHz */
+ int sc_minsync; /* Minimum sync period / 4 */
+ int sc_maxsync; /* Maximum sync period / 4 */
+
+ /* DMA function set from MD code */
+ void (*sc_dma_start)(struct spc_softc *, void *, size_t, int);
+ void (*sc_dma_done)(struct spc_softc *);
+};
+
+#if SPC_DEBUG
+#define SPC_SHOWACBS 0x01
+#define SPC_SHOWINTS 0x02
+#define SPC_SHOWCMDS 0x04
+#define SPC_SHOWMISC 0x08
+#define SPC_SHOWTRACE 0x10
+#define SPC_SHOWSTART 0x20
+#define SPC_DOBREAK 0x40
+extern int spc_debug; /* SPC_SHOWSTART|SPC_SHOWMISC|SPC_SHOWTRACE; */
+#define SPC_PRINT(b, s) do {if ((spc_debug & (b)) != 0) printf s;} while (0)
+#define SPC_BREAK() do {if ((spc_debug & SPC_DOBREAK) != 0) Debugger();} while (0)
+#define SPC_ASSERT(x) do {if (x) {} else {printf("%s at line %d: assertion failed\n", sc->sc_dev.dv_xname, __LINE__); Debugger();}} while (0)
+#else
+#define SPC_PRINT(b, s)
+#define SPC_BREAK()
+#define SPC_ASSERT(x)
+#endif
+
+#define SPC_ACBS(s) SPC_PRINT(SPC_SHOWACBS, s)
+#define SPC_INTS(s) SPC_PRINT(SPC_SHOWINTS, s)
+#define SPC_CMDS(s) SPC_PRINT(SPC_SHOWCMDS, s)
+#define SPC_MISC(s) SPC_PRINT(SPC_SHOWMISC, s)
+#define SPC_TRACE(s) SPC_PRINT(SPC_SHOWTRACE, s)
+#define SPC_START(s) SPC_PRINT(SPC_SHOWSTART, s)
+
+void spc_attach(struct spc_softc *, struct scsi_adapter *);
+int spc_intr(void *);
+int spc_find(bus_space_tag_t, bus_space_handle_t, int);
+void spc_init(struct spc_softc *);
+void spc_sched(struct spc_softc *);
+int spc_scsi_cmd(struct scsi_xfer *);
+void spc_minphys(struct buf *);
+#endif /* _MB89352VAR_H_ */
diff --git a/sys/arch/luna88k/dev/omrasops.c b/sys/arch/luna88k/dev/omrasops.c
new file mode 100644
index 00000000000..f9777c933dc
--- /dev/null
+++ b/sys/arch/luna88k/dev/omrasops.c
@@ -0,0 +1,475 @@
+/* $OpenBSD: omrasops.c,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: omrasops.c,v 1.1 2000/01/05 08:48:56 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Designed speficically for 'm68k bitorder';
+ * - most significant byte is stored at lower address,
+ * - most significant bit is displayed at left most on screen.
+ * Implementation relys on;
+ * - every memory references is done in aligned 32bit chunk,
+ * - font glyphs are stored in 32bit padded.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <dev/rcons/raster.h>
+#include <dev/wscons/wscons_raster.h>
+#include <dev/wscons/wscons_rfont.h>
+#include <dev/wscons/wsdisplayvar.h>
+
+/* wscons emulator operations */
+void om_cursor(void *, int, int, int);
+int om_mapchar(void *, int, unsigned int *);
+void om_putchar(void *, int, int, u_int, long);
+void om_copycols(void *, int, int, int, int);
+void om_copyrows(void *, int, int, int num);
+void om_erasecols(void *, int, int, int, long);
+void om_eraserows(void *, int, int, long);
+int om_alloc_attr(void *, int, int, int, long *);
+
+struct wsdisplay_emulops omfb_emulops = {
+ om_cursor,
+ om_mapchar,
+ om_putchar,
+ om_copycols,
+ om_erasecols,
+ om_copyrows,
+ om_eraserows,
+ om_alloc_attr
+};
+
+#define ALL1BITS (~0U)
+#define ALL0BITS (0U)
+#define BLITWIDTH (32)
+#define ALIGNMASK (0x1f)
+#define BYTESDONE (4)
+
+#define W(p) (*(u_int32_t *)(p))
+#define R(p) (*(u_int32_t *)((caddr_t)(p) + 0x40000))
+
+/*
+ * Blit a character at the specified co-ordinates.
+ */
+void
+om_putchar(cookie, row, startcol, uc, attr)
+ void *cookie;
+ int row, startcol;
+ u_int uc;
+ long attr;
+{
+ struct rcons *rc = cookie;
+ struct raster *rap = rc->rc_sp;
+ caddr_t p;
+ int scanspan, startx, height, width, align, y;
+ u_int32_t lmask, rmask, glyph, inverse;
+ u_int32_t *g;
+
+ scanspan = rap->linelongs * 4;
+ y = rc->rc_yorigin + rc->rc_font->height * row;
+ startx = rc->rc_xorigin + rc->rc_font->width * startcol;
+ height = rc->rc_font->height;
+ g = rc->rc_font->chars[uc].r->pixels;
+ inverse = (attr != 0) ? ALL1BITS : ALL0BITS;
+
+ p = (caddr_t)rap->pixels + y * scanspan + ((startx / 32) * 4);
+ align = startx & ALIGNMASK;
+ width = rc->rc_font->width + align;
+ lmask = ALL1BITS >> align;
+ rmask = ALL1BITS << (-width & ALIGNMASK);
+ if (width <= BLITWIDTH) {
+ lmask &= rmask;
+ while (height > 0) {
+ glyph = *g;
+ glyph = (glyph >> align) ^ inverse;
+ W(p) = (R(p) & ~lmask) | (glyph & lmask);
+ p += scanspan;
+ g += 1;
+ height--;
+ }
+ }
+ else {
+ caddr_t q = p;
+ u_int32_t lhalf, rhalf;
+
+ while (height > 0) {
+ glyph = *g;
+ lhalf = (glyph >> align) ^ inverse;
+ W(p) = (R(p) & ~lmask) | (lhalf & lmask);
+ p += BYTESDONE;
+ rhalf = (glyph << (BLITWIDTH - align)) ^ inverse;
+ W(p) = (rhalf & rmask) | (R(p) & ~rmask);
+
+ p = (q += scanspan);
+ g += 1;
+ height--;
+ }
+ }
+}
+
+void
+om_erasecols(cookie, row, startcol, ncols, attr)
+ void *cookie;
+ int row, startcol, ncols;
+ long attr;
+{
+ struct rcons *rc = cookie;
+ struct raster *rap = rc->rc_sp;
+ caddr_t p;
+ int scanspan, startx, height, width, align, w, y;
+ u_int32_t lmask, rmask, fill;
+
+ scanspan = rap->linelongs * 4;
+ y = rc->rc_yorigin + rc->rc_font->height * row;
+ startx = rc->rc_xorigin + rc->rc_font->width * startcol;
+ height = rc->rc_font->height;
+ w = rc->rc_font->width * ncols;
+ fill = (attr != 0) ? ALL1BITS : ALL0BITS;
+
+ p = (caddr_t)rap->pixels + y * scanspan + ((startx / 32) * 4);
+ align = startx & ALIGNMASK;
+ width = w + align;
+ lmask = ALL1BITS >> align;
+ rmask = ALL1BITS << (-width & ALIGNMASK);
+ if (width <= BLITWIDTH) {
+ lmask &= rmask;
+ fill &= lmask;
+ while (height > 0) {
+ W(p) = (R(p) & ~lmask) | fill;
+ p += scanspan;
+ height--;
+ }
+ }
+ else {
+ caddr_t q = p;
+ while (height > 0) {
+ W(p) = (R(p) & ~lmask) | (fill & lmask);
+ width -= 2 * BLITWIDTH;
+ while (width > 0) {
+ p += BYTESDONE;
+ W(p) = fill;
+ width -= BLITWIDTH;
+ }
+ p += BYTESDONE;
+ W(p) = (fill & rmask) | (R(p) & ~rmask);
+
+ p = (q += scanspan);
+ width = w + align;
+ height--;
+ }
+ }
+}
+
+void
+om_eraserows(cookie, startrow, nrows, attr)
+ void *cookie;
+ int startrow, nrows;
+ long attr;
+{
+ struct rcons *rc = cookie;
+ struct raster *rap = rc->rc_sp;
+ caddr_t p, q;
+ int scanspan, starty, height, width, w;
+ u_int32_t rmask, fill;
+
+ scanspan = rap->linelongs * 4;
+ starty = rc->rc_yorigin + rc->rc_font->height * startrow;
+ height = rc->rc_font->height * nrows;
+ w = rc->rc_font->width * rc->rc_maxcol;
+ fill = (attr == 1) ? ALL1BITS : ALL0BITS;
+
+ p = (caddr_t)rap->pixels + starty * scanspan;
+ p += (rc->rc_xorigin / 32) * 4;
+ width = w;
+ rmask = ALL1BITS << (-width & ALIGNMASK);
+ q = p;
+ while (height > 0) {
+ W(p) = fill; /* always aligned */
+ width -= 2 * BLITWIDTH;
+ while (width > 0) {
+ p += BYTESDONE;
+ W(p) = fill;
+ width -= BLITWIDTH;
+ }
+ p += BYTESDONE;
+ W(p) = (fill & rmask) | (R(p) & ~rmask);
+ p = (q += scanspan);
+ width = w;
+ height--;
+ }
+}
+
+void
+om_copyrows(cookie, srcrow, dstrow, nrows)
+ void *cookie;
+ int srcrow, dstrow, nrows;
+{
+ struct rcons *rc = cookie;
+ struct raster *rap = rc->rc_sp;
+ caddr_t p, q;
+ int scanspan, offset, srcy, height, width, w;
+ u_int32_t rmask;
+
+ scanspan = rap->linelongs * 4;
+ height = rc->rc_font->height * nrows;
+ offset = (dstrow - srcrow) * scanspan * rc->rc_font->height;
+ srcy = rc->rc_yorigin + rc->rc_font->height * srcrow;
+ if (srcrow < dstrow && srcrow + nrows > dstrow) {
+ scanspan = -scanspan;
+ srcy += height;
+ }
+
+ p = (caddr_t)rap->pixels + srcy * (rap->linelongs * 4);
+ p += (rc->rc_xorigin / 32) * 4;
+ w = rc->rc_font->width * rc->rc_maxcol;
+ width = w;
+ rmask = ALL1BITS << (-width & ALIGNMASK);
+ q = p;
+ while (height > 0) {
+ W(p + offset) = R(p); /* always aligned */
+ width -= 2 * BLITWIDTH;
+ while (width > 0) {
+ p += BYTESDONE;
+ W(p + offset) = R(p);
+ width -= BLITWIDTH;
+ }
+ p += BYTESDONE;
+ W(p + offset) = (R(p) & rmask) | (R(p + offset) & ~rmask);
+
+ p = (q += scanspan);
+ width = w;
+ height--;
+ }
+}
+
+void
+om_copycols(cookie, startrow, srccol, dstcol, ncols)
+ void *cookie;
+ int startrow, srccol, dstcol, ncols;
+{
+ struct rcons *rc = cookie;
+ struct raster *rap = rc->rc_sp;
+ caddr_t sp, dp, basep;
+ int scanspan, height, width, align, shift, w, y, srcx, dstx;
+ u_int32_t lmask, rmask;
+
+ scanspan = rap->linelongs * 4;
+ y = rc->rc_yorigin + rc->rc_font->height * startrow;
+ srcx = rc->rc_xorigin + rc->rc_font->width * srccol;
+ dstx = rc->rc_xorigin + rc->rc_font->width * dstcol;
+ height = rc->rc_font->height;
+ w = rc->rc_font->width * ncols;
+ basep = (caddr_t)rap->pixels + y * scanspan;
+
+ align = shift = srcx & ALIGNMASK;
+ width = w + align;
+ align = dstx & ALIGNMASK;
+ lmask = ALL1BITS >> align;
+ rmask = ALL1BITS << (-(w + align) & ALIGNMASK);
+ shift = align - shift;
+ sp = basep + (srcx / 32) * 4;
+ dp = basep + (dstx / 32) * 4;
+
+ if (shift != 0)
+ goto hardluckalignment;
+
+ /* alignments comfortably match */
+ if (width <= BLITWIDTH) {
+ lmask &= rmask;
+ while (height > 0) {
+ W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask);
+ dp += scanspan;
+ sp += scanspan;
+ height--;
+ }
+ }
+ /* copy forward (left-to-right) */
+ else if (dstcol < srccol || srccol + ncols < dstcol) {
+ caddr_t sq = sp, dq = dp;
+
+ w = width;
+ while (height > 0) {
+ W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask);
+ width -= 2 * BLITWIDTH;
+ while (width > 0) {
+ sp += BYTESDONE;
+ dp += BYTESDONE;
+ W(dp) = R(sp);
+ width -= BLITWIDTH;
+ }
+ sp += BYTESDONE;
+ dp += BYTESDONE;
+ W(dp) = (R(sp) & rmask) | (R(dp) & ~rmask);
+ sp = (sq += scanspan);
+ dp = (dq += scanspan);
+ width = w;
+ height--;
+ }
+ }
+ /* copy backward (right-to-left) */
+ else {
+ caddr_t sq, dq;
+
+ sq = (sp += width / 32 * 4);
+ dq = (dp += width / 32 * 4);
+ w = width;
+ while (height > 0) {
+ W(dp) = (R(sp) & rmask) | (R(dp) & ~rmask);
+ width -= 2 * BLITWIDTH;
+ while (width > 0) {
+ sp -= BYTESDONE;
+ dp -= BYTESDONE;
+ W(dp) = R(sp);
+ width -= BLITWIDTH;
+ }
+ sp -= BYTESDONE;
+ dp -= BYTESDONE;
+ W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask);
+
+ sp = (sq += scanspan);
+ dp = (dq += scanspan);
+ width = w;
+ height--;
+ }
+ }
+ return;
+
+ hardluckalignment:
+ /* alignments painfully disagree */
+}
+
+/*
+ * Map a character.
+ */
+int
+om_mapchar(cookie, c, cp)
+ void *cookie;
+ int c;
+ u_int *cp;
+{
+ if (c < 128) {
+ *cp = c;
+ return (5);
+ }
+ *cp = ' ';
+ return (0);
+}
+
+/*
+ * Position|{enable|disable} the cursor at the specified location.
+ */
+void
+om_cursor(cookie, on, row, col)
+ void *cookie;
+ int on, row, col;
+{
+ struct rcons *rc = cookie;
+ struct raster *rap = rc->rc_sp;
+ caddr_t p;
+ int scanspan, startx, height, width, align, y;
+ u_int32_t lmask, rmask, image;
+
+ if (!on) {
+ /* make sure it's on */
+ if ((rc->rc_bits & RC_CURSOR) == 0)
+ return;
+
+ row = *rc->rc_crowp;
+ col = *rc->rc_ccolp;
+ } else {
+ /* unpaint the old copy. */
+ *rc->rc_crowp = row;
+ *rc->rc_ccolp = col;
+ }
+
+ scanspan = rap->linelongs * 4;
+ y = rc->rc_yorigin + rc->rc_font->height * row;
+ startx = rc->rc_xorigin + rc->rc_font->width * col;
+ height = rc->rc_font->height;
+
+ p = (caddr_t)rap->pixels + y * scanspan + ((startx / 32) * 4);
+ align = startx & ALIGNMASK;
+ width = rc->rc_font->width + align;
+ lmask = ALL1BITS >> align;
+ rmask = ALL1BITS << (-width & ALIGNMASK);
+ if (width <= BLITWIDTH) {
+ lmask &= rmask;
+ while (height > 0) {
+ image = R(p);
+ W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
+ p += scanspan;
+ height--;
+ }
+ }
+ else {
+ caddr_t q = p;
+
+ while (height > 0) {
+ image = R(p);
+ W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
+ p += BYTESDONE;
+ image = R(p);
+ W(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
+
+ p = (q += scanspan);
+ height--;
+ }
+ }
+ rc->rc_bits ^= RC_CURSOR;
+}
+
+/*
+ * Allocate attribute. We just pack these into an integer.
+ */
+int
+om_alloc_attr(id, fg, bg, flags, attrp)
+ void *id;
+ int fg, bg, flags;
+ long *attrp;
+{
+ if (flags & (WSATTR_HILIT | WSATTR_BLINK |
+ WSATTR_UNDERLINE | WSATTR_WSCOLORS))
+ return (EINVAL);
+ if (flags & WSATTR_REVERSE)
+ *attrp = 1;
+ else
+ *attrp = 0;
+ return (0);
+}
diff --git a/sys/arch/luna88k/dev/sio.c b/sys/arch/luna88k/dev/sio.c
new file mode 100644
index 00000000000..f593dc8e95c
--- /dev/null
+++ b/sys/arch/luna88k/dev/sio.c
@@ -0,0 +1,136 @@
+/* $OpenBSD: sio.c,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: sio.c,v 1.1 2000/01/05 08:48:55 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* from NetBSD/luna68k dev/sio.c */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+#include <machine/locore.h> /* badaddr() */
+
+#include <luna88k/luna88k/isr.h>
+#include <luna88k/dev/siovar.h>
+
+int sio_match(struct device *, void *, void *);
+void sio_attach(struct device *, struct device *, void *);
+int sio_print(void *, const char *);
+
+const struct cfattach sio_ca = {
+ sizeof(struct sio_softc), sio_match, sio_attach
+};
+
+struct cfdriver sio_cd = {
+ NULL, "sio", DV_DULL, 0
+};
+
+void nullintr(int);
+int xsiointr(void *);
+
+int
+sio_match(parent, cf, aux)
+ struct device *parent;
+ void *cf, *aux;
+{
+ struct mainbus_attach_args *ma = aux;
+
+ if (strcmp(ma->ma_name, sio_cd.cd_name))
+ return 0;
+ if (badaddr((vaddr_t)ma->ma_addr, 4))
+ return 0;
+ return 1;
+}
+
+void
+sio_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct sio_softc *sc = (void *)self;
+ struct mainbus_attach_args *ma = aux;
+ struct sio_attach_args sio_args;
+ int channel;
+ extern int sysconsole; /* console: 0 for ttya, 1 for desktop */
+
+ printf(": 7201a\n");
+
+ sc->scp_ctl = (caddr_t)ma->ma_addr;
+ sc->scp_intr[0] = sc->scp_intr[1] = nullintr;
+ for (channel = 0; channel < 2; channel++) {
+ sio_args.channel = channel;
+ sio_args.hwflags = (channel == sysconsole);
+ config_found(self, (void *)&sio_args, sio_print);
+ }
+
+ isrlink_autovec(xsiointr, sc, ma->ma_ilvl, ISRPRI_TTYNOBUF);
+}
+
+int
+sio_print(aux, name)
+ void *aux;
+ const char *name;
+{
+ struct sio_attach_args *args = aux;
+
+ if (name != NULL)
+ printf("%s: ", name);
+
+ if (args->channel != -1)
+ printf(" channel %d", args->channel);
+
+ return UNCONF;
+}
+
+int
+xsiointr(arg)
+ void *arg;
+{
+ struct sio_softc *sc = arg;
+
+ (*sc->scp_intr[0])(0); /* 0: ttya system serial port */
+ (*sc->scp_intr[1])(1); /* 1: keyboard and mouse */
+ return 1;
+}
+
+void nullintr(v)
+ int v;
+{
+}
diff --git a/sys/arch/luna88k/dev/sioreg.h b/sys/arch/luna88k/dev/sioreg.h
new file mode 100644
index 00000000000..7ec6b04b6a4
--- /dev/null
+++ b/sys/arch/luna88k/dev/sioreg.h
@@ -0,0 +1,137 @@
+/* $OpenBSD: sioreg.h,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: sioreg.h,v 1.1 2000/01/05 08:48:55 nisimura Exp $ */
+/*
+ * Copyright (c) 1992 OMRON Corporation.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * OMRON Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sioreg.h 8.1 (Berkeley) 6/10/93
+ */
+
+#define WR0 0x00
+#define WR1 0x01
+#define WR2 0x02
+#define WR3 0x03
+#define WR4 0x04
+#define WR5 0x05
+#define WR6 0x06
+#define WR7 0x07
+
+#define WR2A WR2
+#define WR2B (WR2|0x10)
+
+#define RR0 0x08
+#define RR1 0x09
+#define RR2 0x0A
+#define RR3 0x0B
+#define RR4 0x0C
+
+#define RR2A RR2
+#define RR2B (RR2|0x10)
+
+#define WR0_NOP 0x00 /* No Operation */
+#define WR0_SNDABRT 0x08 /* Send Abort (HDLC) */
+#define WR0_RSTINT 0x10 /* Reset External/Status Interrupt */
+#define WR0_CHANRST 0x18 /* Channel Reset */
+#define WR0_INTNXT 0x20 /* Enable Interrupt on Next Receive Character */
+#define WR0_RSTPEND 0x28 /* Reset Transmitter Interrput/DMA Pending */
+#define WR0_ERRRST 0x30 /* Error Reset */
+#define WR0_ENDINTR 0x38 /* End of Interrupt */
+
+#define WR1_ESENBL 0x01 /* External/Status Interrupt Enable */
+#define WR1_TXENBL 0x02 /* Tx Interrupt/DMA Enable */
+#define WR1_STATVEC 0x04 /* Status Affects Vector (Only Chan-B) */
+#define WR1_RXDSEBL 0x00 /* Rx Interrupt/DMA Disable */
+#define WR1_RXFIRST 0x08 /* Interrupt only First Character Received */
+#define WR1_RXALLS 0x10 /* Interrupt Every Characters Received (with Special Char.) */
+#define WR1_RXALL 0x18 /* Interrupt Every Characters Received (without Special Char.) */
+
+#define WR2_INTR_0 0x00 /* Interrupt Priority: RxA TxA RxB TxB E/SA E/SA */
+#define WR2_INTR_1 0x04 /* Interrupt Priority: RxA RxB TxA TxB E/SA E/SA */
+#define WR2_VEC85_1 0x00 /* 8085 Vectored Mode - 1 */
+#define WR2_VEC85_2 0x08 /* 8085 Vectored Mode - 2 */
+#define WR2_VEC86 0x10 /* 8086 Vectored */
+#define WR2_VEC85_3 0x18 /* 8085 Vectored Mode - 3 */
+
+#define WR3_RXENBL 0x01 /* Rx Enable */
+#define WR3_RXCRC 0x08 /* Rx CRC Check */
+#define WR3_AUTOEBL 0x20 /* Auto Enable (flow control for MODEM) */
+#define WR3_RX5BIT 0x00 /* Rx Bits/Character: 5 Bits */
+#define WR3_RX7BIT 0x40 /* Rx Bits/Character: 7 Bits */
+#define WR3_RX6BIT 0x80 /* Rx Bits/Character: 6 Bits */
+#define WR3_RX8BIT 0xc0 /* Rx Bits/Character: 8 Bits */
+
+#define WR4_NPARITY 0x00 /* No Parity */
+#define WR4_PARENAB 0x01 /* Parity Enable */
+#define WR4_OPARITY 0x01 /* Parity Odd */
+#define WR4_EPARITY 0x02 /* Parity Even */
+#define WR4_STOP1 0x04 /* Stop Bits (1bit) */
+#define WR4_STOP15 0x08 /* Stop Bits (1.5bit) */
+#define WR4_STOP2 0x0c /* Stop Bits (2bit) */
+#define WR4_BAUD96 0x40 /* Clock Rate (9600 BAUD) */
+#define WR4_BAUD48 0x80 /* Clock Rate (4800 BAUD) */
+#define WR4_BAUD24 0xc0 /* Clock Rate (2400 BAUD) */
+
+#define WR5_TXCRC 0x01 /* Tx CRC Check */
+#define WR5_RTS 0x02 /* Request To Send [RTS] */
+#define WR5_TXENBL 0x08 /* Transmit Enable */
+#define WR5_BREAK 0x10 /* Send Break [BRK] */
+#define WR5_TX5BIT 0x00 /* Tx Bits/Character: 5 Bits */
+#define WR5_TX7BIT 0x20 /* Tx Bits/Character: 7 Bits */
+#define WR5_TX6BIT 0x40 /* Tx Bits/Character: 6 Bits */
+#define WR5_TX8BIT 0x60 /* Tx Bits/Character: 8 Bits */
+#define WR5_DTR 0x80 /* Data Terminal Ready [DTR] */
+
+#define RR0_RXAVAIL 0x01 /* Rx Character Available */
+#define RR0_INTRPEND 0x02 /* Interrupt Pending (Channel-A Only) */
+#define RR0_TXEMPTY 0x04 /* Tx Buffer Empty */
+#define RR0_DCD 0x08 /* Data Carrier Detect [DCD] */
+#define RR0_SYNC 0x10 /* Synchronization */
+#define RR0_CTS 0x20 /* Clear To Send [CTS] */
+#define RR0_BREAK 0x80 /* Break Detected [BRK] */
+
+#define RR1_PARITY 0x10 /* Parity Error */
+#define RR1_OVERRUN 0x20 /* Data Over Run */
+#define RR1_FRAMING 0x40 /* Framing Error */
+
+#define RR_RXRDY 0x0100 /* Rx Character Available */
+#define RR_INTRPEND 0x0200 /* Interrupt Pending (Channel-A Only) */
+#define RR_TXRDY 0x0400 /* Tx Buffer Empty */
+#define RR_DCD 0x0800 /* Data Carrier Detect [DCD] */
+#define RR_SYNC 0x1000 /* Synchronization */
+#define RR_CTS 0x2000 /* Clear To Send [CTS] */
+#define RR_BREAK 0x8000 /* Break Detected */
+#define RR_PARITY 0x0010 /* Parity Error */
+#define RR_OVERRUN 0x0020 /* Data Over Run */
+#define RR_FRAMING 0x0040 /* Framing Error */
diff --git a/sys/arch/luna88k/dev/siotty.c b/sys/arch/luna88k/dev/siotty.c
new file mode 100644
index 00000000000..bb8f5fabeea
--- /dev/null
+++ b/sys/arch/luna88k/dev/siotty.c
@@ -0,0 +1,664 @@
+/* $OpenBSD: siotty.c,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: siotty.c,v 1.9 2002/03/17 19:40:43 atatat Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/fcntl.h>
+#include <dev/cons.h>
+
+#include <machine/cpu.h>
+
+#include <luna88k/dev/sioreg.h>
+#include <luna88k/dev/siovar.h>
+
+#define TIOCM_BREAK 01000 /* non standard use */
+
+static const u_int8_t ch0_regs[6] = {
+ WR0_RSTINT, /* reset E/S interrupt */
+ WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
+ 0, /* */
+ WR3_RX8BIT | WR3_RXENBL, /* Rx */
+ WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
+ WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
+};
+
+static struct speedtab siospeedtab[] = {
+ { 2400, WR4_BAUD24, },
+ { 4800, WR4_BAUD48, },
+ { 9600, WR4_BAUD96, },
+ { -1, 0, },
+};
+
+struct siotty_softc {
+ struct device sc_dev;
+ struct tty *sc_tty;
+ struct sioreg *sc_ctl;
+ u_int sc_flags;
+ u_int8_t sc_wr[6];
+};
+
+cdev_decl(sio);
+void siostart(struct tty *);
+int sioparam(struct tty *, struct termios *);
+void siottyintr(int);
+int siomctl(struct siotty_softc *, int, int);
+
+int siotty_match(struct device *, void *, void *);
+void siotty_attach(struct device *, struct device *, void *);
+
+const struct cfattach siotty_ca = {
+ sizeof(struct siotty_softc), siotty_match, siotty_attach
+};
+
+const struct cfdriver siotty_cd = {
+ NULL, "siotty", DV_TTY
+};
+
+int
+siotty_match(parent, cf, aux)
+ struct device *parent;
+ void *cf, *aux;
+{
+ struct sio_attach_args *args = aux;
+
+ if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
+ return 0;
+ return 1;
+}
+
+void
+siotty_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct sio_softc *scp = (void *)parent;
+ struct siotty_softc *sc = (void *)self;
+ struct sio_attach_args *args = aux;
+
+ sc->sc_ctl = (struct sioreg *)scp->scp_ctl + args->channel;
+ bcopy(ch0_regs, sc->sc_wr, sizeof(ch0_regs));
+ scp->scp_intr[args->channel] = siottyintr;
+
+ if (args->hwflags == 1) {
+ printf(" (console)");
+ sc->sc_flags = TIOCFLAG_SOFTCAR;
+ }
+ else {
+ setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
+ setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
+ setsioreg(sc->sc_ctl, WR2B, 0);
+ setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
+ setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
+ setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
+ setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
+ setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
+ }
+ setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
+
+ printf("\n");
+}
+
+/*-------------------- low level routine --------------------*/
+
+void
+siottyintr(chan)
+ int chan;
+{
+ struct siotty_softc *sc;
+ struct sioreg *sio;
+ struct tty *tp;
+ unsigned int code;
+ int rr;
+
+ if (chan >= siotty_cd.cd_ndevs)
+ return;
+ sc = siotty_cd.cd_devs[chan];
+ tp = sc->sc_tty;
+ sio = sc->sc_ctl;
+ rr = getsiocsr(sio);
+ if (rr & RR_RXRDY) {
+ do {
+ code = sio->sio_data;
+ if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
+ sio->sio_cmd = WR0_ERRRST;
+ if (sio->sio_stat & RR_FRAMING)
+ code |= TTY_FE;
+ else if (sio->sio_stat & RR_PARITY)
+ code |= TTY_PE;
+ }
+ if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
+ continue;
+#if 0 && defined(DDB) /* ?!?! fails to resume ?!?! */
+ if ((rr & RR_BREAK) && tp->t_dev == cn_tab->cn_dev) {
+ if (db_console)
+ Debugger();
+ return;
+ }
+#endif
+/*
+ (*tp->t_linesw->l_rint)(code, tp);
+*/
+ (*linesw[tp->t_line].l_rint)(code, tp);
+ } while ((rr = getsiocsr(sio)) & RR_RXRDY);
+ }
+ if (rr & RR_TXRDY) {
+ sio->sio_cmd = WR0_RSTPEND;
+ if (tp != NULL) {
+ tp->t_state &= ~(TS_BUSY|TS_FLUSH);
+/*
+ (*tp->t_linesw->l_start)(tp);
+*/
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+ }
+}
+
+void
+siostart(tp)
+ struct tty *tp;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
+ int s, c;
+
+ s = spltty();
+ if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP))
+ goto out;
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_outq);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+
+ tp->t_state |= TS_BUSY;
+ while (getsiocsr(sc->sc_ctl) & RR_TXRDY) {
+ if ((c = getc(&tp->t_outq)) == -1)
+ break;
+ sc->sc_ctl->sio_data = c;
+ }
+out:
+ splx(s);
+}
+
+int
+siostop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
+ /*
+ * Device is transmitting; must stop it.
+ */
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+int
+sioparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
+ int wr4, s;
+
+ if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
+ return EINVAL;
+ wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
+ if (wr4 < 0)
+ return EINVAL;
+
+ if (sc->sc_flags & TIOCFLAG_SOFTCAR) {
+ t->c_cflag |= CLOCAL;
+ t->c_cflag &= ~HUPCL;
+ }
+ if (sc->sc_flags & TIOCFLAG_CLOCAL)
+ t->c_cflag |= CLOCAL;
+
+ /*
+ * If there were no changes, don't do anything. This avoids dropping
+ * input and improves performance when all we did was frob things like
+ * VMIN and VTIME.
+ */
+ if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
+ return 0;
+
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+
+ sc->sc_wr[WR3] &= 0x3f;
+ sc->sc_wr[WR5] &= 0x9f;
+ switch (tp->t_cflag & CSIZE) {
+ case CS7:
+ sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
+ break;
+ case CS8:
+ sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
+ break;
+ }
+ if (tp->t_cflag & PARENB) {
+ wr4 |= WR4_PARENAB;
+ if ((tp->t_cflag & PARODD) == 0)
+ wr4 |= WR4_EPARITY;
+ }
+ wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
+ sc->sc_wr[WR4] = wr4;
+
+ s = spltty();
+ setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
+ setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
+ setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
+ splx(s);
+
+ return 0;
+}
+
+int
+siomctl(sc, control, op)
+ struct siotty_softc *sc;
+ int control, op;
+{
+ int val, s, wr5, rr;
+
+ val = 0;
+ if (control & TIOCM_BREAK)
+ val |= WR5_BREAK;
+ if (control & TIOCM_DTR)
+ val |= WR5_DTR;
+ if (control & TIOCM_RTS)
+ val |= WR5_RTS;
+ s = spltty();
+ wr5 = sc->sc_wr[WR5];
+ switch (op) {
+ case DMSET:
+ wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
+ /* FALLTHRU */
+ case DMBIS:
+ wr5 |= val;
+ break;
+ case DMBIC:
+ wr5 &= ~val;
+ break;
+ case DMGET:
+ val = 0;
+ rr = getsiocsr(sc->sc_ctl);
+ if (wr5 & WR5_DTR)
+ val |= TIOCM_DTR;
+ if (wr5 & WR5_RTS)
+ val |= TIOCM_RTS;
+ if (rr & RR_CTS)
+ val |= TIOCM_CTS;
+ if (rr & RR_DCD)
+ val |= TIOCM_CD;
+ goto done;
+ }
+ sc->sc_wr[WR5] = wr5;
+ setsioreg(sc->sc_ctl, WR5, wr5);
+ val = 0;
+ done:
+ splx(s);
+ return val;
+}
+
+/*-------------------- cdevsw[] interface --------------------*/
+
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct siotty_softc *sc;
+ struct tty *tp;
+ int error;
+
+ if ((sc = siotty_cd.cd_devs[minor(dev)]) == NULL)
+ return ENXIO;
+ if ((tp = sc->sc_tty) == NULL) {
+ tp = sc->sc_tty = ttymalloc();
+ }
+ else if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE)
+ && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+
+ tp->t_oproc = siostart;
+ tp->t_param = sioparam;
+ tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
+ tp->t_dev = dev;
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ struct termios t;
+
+ t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
+ t.c_cflag = TTYDEF_CFLAG;
+ tp->t_ospeed = 0; /* force register update */
+ (void)sioparam(tp, &t);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ ttychars(tp);
+ ttsetwater(tp);
+ /* raise RTS and DTR here; but, DTR lead is not wired */
+ /* then check DCD condition; but, DCD lead is not wired */
+ tp->t_state |= TS_CARR_ON; /* assume detected all the time */
+#if 0
+ if ((sc->sc_flags & TIOCFLAG_SOFTCAR)
+ || (tp->t_cflag & MDMBUF)
+ || (getsiocsr(sc->sc_ctl) & RR_DCD))
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+#endif
+ }
+
+ error = ttyopen(dev, tp);
+ if (error > 0)
+ return error;
+/*
+ return (*tp->t_linesw->l_open)(dev, tp);
+*/
+ return (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+ int s;
+
+/*
+ (*tp->t_linesw->l_close)(tp, flag);
+*/
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ s = spltty();
+ siomctl(sc, TIOCM_BREAK, DMBIC);
+#if 0 /* because unable to feed DTR signal */
+ if ((tp->t_cflag & HUPCL)
+ || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
+ siomctl(sc, TIOCM_DTR, DMBIC);
+ /* Yield CPU time to others for 1 second, then ... */
+ siomctl(sc, TIOCM_DTR, DMBIS);
+ }
+#endif
+ splx(s);
+ return ttyclose(tp);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+
+/*
+ return (*tp->t_linesw->l_read)(tp, uio, flag);
+*/
+ return (*linesw[tp->t_line].l_read)(tp, uio, flag);
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+
+/*
+ return (*tp->t_linesw->l_write)(tp, uio, flag);
+*/
+ return (*linesw[tp->t_line].l_write)(tp, uio, flag);
+}
+
+#if 0
+int
+sioselect(dev, events, p)
+ dev_t dev;
+ int events;
+ struct proc *p;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+
+/*
+ return ((*tp->t_linesw->l_poll)(tp, events, p));
+*/
+ return ((*linesw[tp->t_line].l_select)(tp, events, p));
+
+}
+#endif
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+ int error;
+
+/*
+ error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
+*/
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ /* the last resort for TIOC ioctl tranversing */
+ switch (cmd) {
+ case TIOCSBRK: /* Set the hardware into BREAK condition */
+ siomctl(sc, TIOCM_BREAK, DMBIS);
+ break;
+ case TIOCCBRK: /* Clear the hardware BREAK condition */
+ siomctl(sc, TIOCM_BREAK, DMBIC);
+ break;
+ case TIOCSDTR: /* Assert DTR signal */
+ siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
+ break;
+ case TIOCCDTR: /* Clear DTR signal */
+ siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
+ break;
+ case TIOCMSET: /* Set modem state replacing current one */
+ siomctl(sc, *(int *)data, DMSET);
+ break;
+ case TIOCMGET: /* Return current modem state */
+ *(int *)data = siomctl(sc, 0, DMGET);
+ break;
+ case TIOCMBIS: /* Set individual bits of modem state */
+ siomctl(sc, *(int *)data, DMBIS);
+ break;
+ case TIOCMBIC: /* Clear individual bits of modem state */
+ siomctl(sc, *(int *)data, DMBIC);
+ break;
+ case TIOCSFLAGS: /* Instruct how serial port behaves */
+ sc->sc_flags = *(int *)data;
+ break;
+ case TIOCGFLAGS: /* Return current serial port state */
+ *(int *)data = sc->sc_flags;
+ break;
+ default:
+/*
+ return EPASSTHROUGH;
+*/
+ return ENOTTY;
+ }
+ return 0;
+}
+
+/* ARSGUSED */
+struct tty *
+siotty(dev)
+ dev_t dev;
+{
+ struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
+
+ return sc->sc_tty;
+}
+
+/*-------------------- miscellaneous routines --------------------*/
+
+/* EXPORT */ void
+setsioreg(sio, regno, val)
+ struct sioreg *sio;
+ int regno, val;
+{
+ if (regno != 0)
+ sio->sio_cmd = regno; /* DELAY(); */
+ sio->sio_cmd = val; /* DELAY(); */
+}
+
+/* EXPORT */ int
+getsiocsr(sio)
+ struct sioreg *sio;
+{
+ int val;
+
+ val = sio->sio_stat << 8; /* DELAY(); */
+ sio->sio_cmd = 1; /* DELAY(); */
+ val |= sio->sio_stat; /* DELAY(); */
+ return val;
+}
+
+/*--------------------- console interface ----------------------*/
+
+void syscnattach(int);
+int syscngetc(dev_t);
+void syscnputc(dev_t, int);
+
+struct consdev syscons = {
+ NULL,
+ NULL,
+ syscngetc,
+ syscnputc,
+ nullcnpollc,
+ NULL,
+ NODEV,
+ CN_REMOTE,
+};
+
+/* EXPORT */ void
+syscnattach(channel)
+ int channel;
+{
+/*
+ * Channel A is immediately initialized with 9600N1 right after cold
+ * boot/reset/poweron. ROM monitor emits one line message on CH.A.
+ */
+ struct sioreg *sio;
+ sio = (struct sioreg *)0x51000000 + channel;
+
+/* syscons.cn_dev = makedev(7, channel); */
+ syscons.cn_dev = makedev(12, channel);
+ cn_tab = &syscons;
+
+#if 0
+ setsioreg(sio, WR0, WR0_CHANRST);
+ setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
+ setsioreg(sio, WR2B, 0);
+ setsioreg(sio, WR0, ch0_regs[WR0]);
+ setsioreg(sio, WR4, ch0_regs[WR4]);
+ setsioreg(sio, WR3, ch0_regs[WR3]);
+ setsioreg(sio, WR5, ch0_regs[WR5]);
+ setsioreg(sio, WR0, ch0_regs[WR0]);
+#endif
+}
+
+/* EXPORT */ int
+syscngetc(dev)
+ dev_t dev;
+{
+ struct sioreg *sio;
+ int s, c;
+
+ sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
+ s = splhigh();
+ while ((getsiocsr(sio) & RR_RXRDY) == 0)
+ ;
+ c = sio->sio_data;
+ splx(s);
+
+ return c;
+}
+
+/* EXPORT */ void
+syscnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ struct sioreg *sio;
+ int s;
+
+ sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
+ s = splhigh();
+ while ((getsiocsr(sio) & RR_TXRDY) == 0)
+ ;
+ sio->sio_cmd = WR0_RSTPEND;
+ sio->sio_data = c;
+ splx(s);
+}
diff --git a/sys/arch/luna88k/dev/siovar.h b/sys/arch/luna88k/dev/siovar.h
new file mode 100644
index 00000000000..442b295a243
--- /dev/null
+++ b/sys/arch/luna88k/dev/siovar.h
@@ -0,0 +1,60 @@
+/* $OpenBSD: siovar.h,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: siovar.h,v 1.1 2000/01/05 08:48:55 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct sio_softc {
+ struct device scp_dev;
+ caddr_t scp_ctl;
+ void (*scp_intr[2])(int);
+};
+
+struct sio_attach_args {
+ int channel;
+ int hwflags;
+};
+
+struct sioreg {
+ volatile u_int8_t sio_data;
+ volatile unsigned : 24;
+ volatile u_int8_t sio_cmd;
+ volatile unsigned : 24;
+#define sio_stat sio_cmd
+};
+
+int getsiocsr(struct sioreg *);
+void setsioreg(struct sioreg *, int, int);
diff --git a/sys/arch/luna88k/dev/spc.c b/sys/arch/luna88k/dev/spc.c
new file mode 100644
index 00000000000..bbf1044de9d
--- /dev/null
+++ b/sys/arch/luna88k/dev/spc.c
@@ -0,0 +1,111 @@
+/* $OpenBSD: spc.c,v 1.1 2004/04/21 15:23:55 aoyama Exp $ */
+/* $NetBSD: spc.c,v 1.4 2003/07/05 19:00:17 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_message.h>
+#include <scsi/scsiconf.h>
+
+#include <luna88k/dev/mb89352reg.h>
+#include <luna88k/dev/mb89352var.h>
+
+#include <luna88k/luna88k/isr.h>
+
+int spc_mainbus_match(struct device *, void *, void *);
+void spc_mainbus_attach(struct device *, struct device *, void *);
+
+struct cfattach spc_ca = {
+ sizeof(struct spc_softc), spc_mainbus_match, spc_mainbus_attach
+};
+
+struct cfdriver spc_cd = {
+ NULL, "spc", DV_DULL
+};
+
+struct scsi_adapter spc_switch = {
+ spc_scsi_cmd,
+ spc_minphys, /* no max at this level; handled by DMA code */
+ NULL,
+ NULL,
+};
+
+int
+spc_mainbus_match(parent, cf, aux)
+ struct device *parent;
+ void *cf, *aux;
+{
+ struct mainbus_attach_args *ma = aux;
+
+ if (strcmp(ma->ma_name, spc_cd.cd_name))
+ return 0;
+#if 0
+ if (badaddr((caddr_t)ma->ma_addr, 4))
+ return 0;
+ /* Experiments proved 2nd SPC address does NOT make a buserror. */
+#endif
+ return 1;
+}
+
+void
+spc_mainbus_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct spc_softc *sc = (void *)self;
+ struct mainbus_attach_args *ma = aux;
+
+ printf ("\n");
+
+ sc->sc_iot = LUNA88K_BUS_SPACE_MEM;
+ sc->sc_ioh = ma->ma_addr;
+ sc->sc_initiator = 7;
+ sc->sc_dma_start = NULL;
+ sc->sc_dma_done = NULL;
+
+ isrlink_autovec(spc_intr, (void *)sc, ma->ma_ilvl, ISRPRI_BIO);
+
+ spc_attach(sc, &spc_switch);
+}
diff --git a/sys/arch/luna88k/dev/timekeeper.c b/sys/arch/luna88k/dev/timekeeper.c
new file mode 100644
index 00000000000..b154c1fd104
--- /dev/null
+++ b/sys/arch/luna88k/dev/timekeeper.c
@@ -0,0 +1,303 @@
+/* $OpenBSD: timekeeper.c,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/* $NetBSD: timekeeper.c,v 1.1 2000/01/05 08:48:56 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+
+#include <machine/board.h> /* machtype value */
+#include <machine/cpu.h>
+
+#include <dev/clock_subr.h>
+#include <luna88k/luna88k/clockvar.h>
+#include <luna88k/dev/timekeeper.h>
+#include <machine/autoconf.h>
+
+#define MK_YEAR0 1970 /* year offset of MK*/
+#define DS_YEAR0 1990 /* year offset of DS*/
+
+struct timekeeper_softc {
+ struct device sc_dev;
+ void *sc_clock, *sc_nvram;
+ int sc_nvramsize;
+ u_int8_t sc_image[2040];
+};
+
+/*
+ * BCD to decimal and decimal to BCD.
+ */
+#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
+#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
+
+int clock_match(struct device *, void *, void *);
+void clock_attach(struct device *, struct device *, void *);
+
+struct cfattach clock_ca = {
+ sizeof (struct timekeeper_softc), clock_match, clock_attach
+};
+
+struct cfdriver clock_cd = {
+ NULL, "clock", DV_DULL
+};
+
+void mkclock_get(struct device *, time_t, struct clock_ymdhms *);
+void mkclock_set(struct device *, struct clock_ymdhms *);
+void dsclock_get(struct device *, time_t, struct clock_ymdhms *);
+void dsclock_set(struct device *, struct clock_ymdhms *);
+
+const struct clockfns mkclock_clockfns = {
+ NULL /* never used */, mkclock_get, mkclock_set,
+};
+
+const struct clockfns dsclock_clockfns = {
+ NULL /* never used */, dsclock_get, dsclock_set,
+};
+
+int
+clock_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct mainbus_attach_args *ma = aux;
+
+ if (strcmp(ma->ma_name, clock_cd.cd_name))
+ return 0;
+ return 1;
+}
+
+extern int machtype; /* in machdep.c */
+
+void
+clock_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct timekeeper_softc *sc = (void *)self;
+ struct mainbus_attach_args *ma = aux;
+ const struct clockfns *clockwork;
+
+ switch (machtype) {
+ default:
+ case LUNA_88K: /* Mostek MK48T02 */
+ sc->sc_clock = (void *)(ma->ma_addr + 2040);
+ sc->sc_nvram = (void *)ma->ma_addr;
+ sc->sc_nvramsize = 2040;
+ clockwork = &mkclock_clockfns;
+ printf(": MK48T02\n");
+ break;
+ case LUNA_88K2: /* Dallas DS1397 */
+ sc->sc_clock = (void *)ma->ma_addr;
+ sc->sc_nvram = (void *)(ma->ma_addr + 50);
+ sc->sc_nvramsize = 50;
+ clockwork = &dsclock_clockfns;
+ printf(": DS1397\n");
+ break;
+ }
+ clockattach(&sc->sc_dev, clockwork);
+ memcpy(sc->sc_image, sc->sc_nvram, sc->sc_nvramsize);
+}
+
+/*
+ * Get the time of day, based on the clock's value and/or the base value.
+ */
+void
+mkclock_get(dev, base, dt)
+ struct device *dev;
+ time_t base;
+ struct clock_ymdhms *dt;
+{
+ struct timekeeper_softc *sc = (void *)dev;
+ volatile u_int8_t *chiptime = (void *)sc->sc_clock;
+ int s;
+
+ s = splclock();
+ chiptime[MK_CSR] |= MK_CSR_READ; /* enable read (stop time) */
+ dt->dt_sec = FROMBCD(chiptime[MK_SEC]);
+ dt->dt_min = FROMBCD(chiptime[MK_MIN]);
+ dt->dt_hour = FROMBCD(chiptime[MK_HOUR]);
+ dt->dt_wday = FROMBCD(chiptime[MK_DOW]);
+ dt->dt_day = FROMBCD(chiptime[MK_DOM]);
+ dt->dt_mon = FROMBCD(chiptime[MK_MONTH]);
+ dt->dt_year = FROMBCD(chiptime[MK_YEAR]) + MK_YEAR0;
+ chiptime[MK_CSR] &= ~MK_CSR_READ; /* time wears on */
+ splx(s);
+#ifdef TIMEKEEPER_DEBUG
+ printf("get %d/%d/%d %d:%d:%d\n",
+ dt->dt_year, dt->dt_mon, dt->dt_day,
+ dt->dt_hour, dt->dt_min, dt->dt_sec);
+#endif
+}
+
+/*
+ * Reset the TODR based on the time value.
+ */
+void
+mkclock_set(dev, dt)
+ struct device *dev;
+ struct clock_ymdhms *dt;
+{
+ struct timekeeper_softc *sc = (void *)dev;
+ volatile u_int8_t *chiptime = (void *)sc->sc_clock;
+ volatile u_int8_t *stamp = (u_int8_t *)sc->sc_nvram + 0x10;
+ int s;
+
+ s = splclock();
+ chiptime[MK_CSR] |= MK_CSR_WRITE; /* enable write */
+ chiptime[MK_SEC] = TOBCD(dt->dt_sec);
+ chiptime[MK_MIN] = TOBCD(dt->dt_min);
+ chiptime[MK_HOUR] = TOBCD(dt->dt_hour);
+ chiptime[MK_DOW] = TOBCD(dt->dt_wday);
+ chiptime[MK_DOM] = TOBCD(dt->dt_day);
+ chiptime[MK_MONTH] = TOBCD(dt->dt_mon);
+ chiptime[MK_YEAR] = TOBCD(dt->dt_year - MK_YEAR0);
+ chiptime[MK_CSR] &= ~MK_CSR_WRITE; /* load them up */
+ splx(s);
+#ifdef TIMEKEEPER_DEBUG
+ printf("set %d/%d/%d %d:%d:%d\n",
+ dt->dt_year, dt->dt_mon, dt->dt_day,
+ dt->dt_hour, dt->dt_min, dt->dt_sec);
+#endif
+
+ stamp[0] = 'R'; stamp[1] = 'T'; stamp[2] = 'C'; stamp[3] = '\0';
+}
+
+#define _DS_GET(off, data) \
+ do { *chiptime = (off); (u_int8_t)(data) = (*chipdata); } while (0)
+#define _DS_SET(off, data) \
+ do { *chiptime = (off); *chipdata = (u_int8_t)(data); } while (0)
+#define _DS_GET_BCD(off, data) \
+ do { \
+ u_int8_t c; \
+ *chiptime = (off); \
+ c = *chipdata; (u_int8_t)(data) = FROMBCD(c); \
+ } while (0)
+#define _DS_SET_BCD(off, data) \
+ do { \
+ *chiptime = (off); \
+ *chipdata = TOBCD((u_int8_t)(data)); \
+ } while (0)
+
+/*
+ * Get the time of day, based on the clock's value and/or the base value.
+ */
+void
+dsclock_get(dev, base, dt)
+ struct device *dev;
+ time_t base;
+ struct clock_ymdhms *dt;
+{
+ struct timekeeper_softc *sc = (void *)dev;
+ volatile u_int8_t *chiptime = (void *)sc->sc_clock;
+ volatile u_int8_t *chipdata = (void *)(sc->sc_clock + 1);
+ int s;
+ u_int8_t c;
+
+ s = splclock();
+
+ /* specify 24hr and BCD mode */
+ _DS_GET(DS_REGB, c);
+ c |= DS_REGB_24HR;
+ c &= ~DS_REGB_BINARY;
+ _DS_SET(DS_REGB, c);
+
+ /* update in progress; spin loop */
+ *chiptime = DS_REGA;
+ while (*chipdata & DS_REGA_UIP)
+ ;
+
+ _DS_GET_BCD(DS_SEC, dt->dt_sec);
+ _DS_GET_BCD(DS_MIN, dt->dt_min);
+ _DS_GET_BCD(DS_HOUR, dt->dt_hour);
+ _DS_GET_BCD(DS_DOW, dt->dt_wday);
+ _DS_GET_BCD(DS_DOM, dt->dt_day);
+ _DS_GET_BCD(DS_MONTH, dt->dt_mon);
+ _DS_GET_BCD(DS_YEAR, dt->dt_year);
+ dt->dt_year += DS_YEAR0;
+
+ splx(s);
+
+#ifdef TIMEKEEPER_DEBUG
+ printf("get %d/%d/%d %d:%d:%d\n",
+ dt->dt_year, dt->dt_mon, dt->dt_day,
+ dt->dt_hour, dt->dt_min, dt->dt_sec);
+#endif
+}
+
+/*
+ * Reset the TODR based on the time value.
+ */
+void
+dsclock_set(dev, dt)
+ struct device *dev;
+ struct clock_ymdhms *dt;
+{
+ struct timekeeper_softc *sc = (void *)dev;
+ volatile u_int8_t *chiptime = (void *)sc->sc_clock;
+ volatile u_int8_t *chipdata = (void *)(sc->sc_clock + 1);
+ int s;
+ u_int8_t c;
+
+ s = splclock();
+
+ /* enable write */
+ _DS_GET(DS_REGB, c);
+ c |= DS_REGB_SET;
+ _DS_SET(DS_REGB, c);
+
+ _DS_SET_BCD(DS_SEC, dt->dt_sec);
+ _DS_SET_BCD(DS_MIN, dt->dt_min);
+ _DS_SET_BCD(DS_HOUR, dt->dt_hour);
+ _DS_SET_BCD(DS_DOW, dt->dt_wday);
+ _DS_SET_BCD(DS_DOM, dt->dt_day);
+ _DS_SET_BCD(DS_MONTH, dt->dt_mon);
+ _DS_SET_BCD(DS_YEAR, dt->dt_year - DS_YEAR0);
+
+ _DS_GET(DS_REGB, c);
+ c &= ~DS_REGB_SET;
+ _DS_SET(DS_REGB, c);
+
+ splx(s);
+
+#ifdef TIMEKEEPER_DEBUG
+ printf("set %d/%d/%d %d:%d:%d\n",
+ dt->dt_year, dt->dt_mon, dt->dt_day,
+ dt->dt_hour, dt->dt_min, dt->dt_sec);
+#endif
+}
diff --git a/sys/arch/luna88k/dev/timekeeper.h b/sys/arch/luna88k/dev/timekeeper.h
new file mode 100644
index 00000000000..d25f15edd0b
--- /dev/null
+++ b/sys/arch/luna88k/dev/timekeeper.h
@@ -0,0 +1,93 @@
+/* $OpenBSD: timekeeper.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/* $NetBSD: timekeeper.h,v 1.1 2000/01/05 08:48:56 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Mostek MK48T02 for LUNA-88K
+ */
+#define MK_CSR 0 /* control register */
+#define MK_SEC 1 /* seconds (0..59; BCD) */
+#define MK_MIN 2 /* minutes (0..59; BCD) */
+#define MK_HOUR 3 /* hour (0..23; BCD) */
+#define MK_DOW 4 /* weekday (1..7) */
+#define MK_DOM 5 /* day in month (1..31; BCD) */
+#define MK_MONTH 6 /* month (1..12; BCD) */
+#define MK_YEAR 7 /* year (0..99; BCD) */
+/* bits in cl_csr */
+#define MK_CSR_WRITE 0x80 /* want to write */
+#define MK_CSR_READ 0x40 /* want to read (freeze clock) */
+
+/*
+ * Dallas Semiconductor DS1397 for LUNA-88K2
+ */
+#define DS_SEC 0x0 /* Time of year: seconds (0-59) */
+#define DS_MIN 0x2 /* Time of year: minutes (0-59) */
+#define DS_HOUR 0x4 /* Time of year: hour (see above) */
+#define DS_DOW 0x6 /* Time of year: day of week (1-7) */
+#define DS_DOM 0x7 /* Time of year: day of month (1-31) */
+#define DS_MONTH 0x8 /* Time of year: month (1-12) */
+#define DS_YEAR 0x9 /* Time of year: year in century (0-99) */
+
+#define DS_REGA 0xa /* Control register A */
+#define DS_REGA_RSMASK 0x0f /* Interrupt rate select mask (see below) */
+#define DS_REGA_DVMASK 0x70 /* Divisor select mask (see below) */
+#define DS_REGA_UIP 0x80 /* Update in progress; read only. */
+
+#define DS_REGB 0xb /* Control register B */
+#define DS_REGB_DSE 0x01 /* Daylight Savings Enable */
+#define DS_REGB_24HR 0x02 /* 24-hour mode (AM/PM mode when clear) */
+#define DS_REGB_BINARY 0x04 /* Binary mode (BCD mode when clear) */
+#define DS_REGB_SQWE 0x08 /* Square Wave Enable */
+#define DS_REGB_UIE 0x10 /* Update End interrupt enable */
+#define DS_REGB_AIE 0x20 /* Alarm interrupt enable */
+#define DS_REGB_PIE 0x40 /* Periodic interrupt enable */
+#define DS_REGB_SET 0x80 /* Allow time to be set; stops updates */
+
+#define DS_REGC 0xc /* Control register C */
+/* DS_REGC_UNUSED 0x0f UNUSED */
+#define DS_REGC_UF 0x10 /* Update End interrupt flag */
+#define DS_REGC_AF 0x20 /* Alarm interrupt flag */
+#define DS_REGC_PF 0x40 /* Periodic interrupt flag */
+#define DS_REGC_IRQF 0x80 /* Interrupt request pending flag */
+
+#define DS_REGD 0xd /* Control register D */
+/* DS_REGD_UNUSED 0x7f UNUSED */
+#define DS_REGD_VRT 0x80 /* Valid RAM and Time bit */
+
+#define DS_NREGS 0xe /* 14 registers; CMOS follows */
+#define DS_NTODREGS 0xa /* 10 of those regs are for TOD and alarm */
diff --git a/sys/arch/luna88k/include/ansi.h b/sys/arch/luna88k/include/ansi.h
new file mode 100644
index 00000000000..f720f0420e4
--- /dev/null
+++ b/sys/arch/luna88k/include/ansi.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: ansi.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ansi.h 8.2 (Berkeley) 1/4/94
+ */
+
+#ifndef __MACHINE_ANSI_H__
+#define __MACHINE_ANSI_H__
+
+/*
+ * Types which are fundamental to the implementation and may appear in
+ * more than one standard header are defined here. Standard headers
+ * then use:
+ * #ifdef _BSD_SIZE_T_
+ * typedef _BSD_SIZE_T_ size_t;
+ * #undef _BSD_SIZE_T_
+ * #endif
+ */
+#define _BSD_CLOCK_T_ unsigned long /* clock() */
+#define _BSD_PTRDIFF_T_ int /* ptr1 - ptr2 */
+#define _BSD_SIZE_T_ unsigned int /* sizeof() */
+#define _BSD_SSIZE_T_ int /* byte count or error */
+#define _BSD_TIME_T_ int /* time() */
+struct __va_list_tag;
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define _BSD_VA_LIST_ __builtin_va_list
+#else
+#define _BSD_VA_LIST_ struct __va_list_tag * /* va_list */
+#endif
+#define _BSD_CLOCKID_T_ int
+#define _BSD_TIMER_T_ int
+
+/*
+ * Runes (wchar_t) is declared to be an ``int'' instead of the more natural
+ * ``unsigned long'' or ``long''. Two things are happening here. It is not
+ * unsigned so that EOF (-1) can be naturally assigned to it and used. Also,
+ * it looks like 10646 will be a 31 bit standard. This means that if your
+ * ints cannot hold 32 bits, you will be in trouble. The reason an int was
+ * chosen over a long is that the is*() and to*() routines take ints (says
+ * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you
+ * lose a bit of ANSI conformance, but your programs will still work.
+ *
+ * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t
+ * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains
+ * defined for ctype.h.
+ */
+#define _BSD_WCHAR_T_ int /* wchar_t */
+#define _BSD_WINT_T_ int /* wint_t */
+#define _BSD_RUNE_T_ int /* rune_t */
+
+/*
+ * We describe off_t here so its declaration can be visible to
+ * stdio without pulling in all of <sys/type.h>, thus appeasing ANSI.
+ */
+#define _BSD_OFF_T_ long long /* file offset */
+
+#endif /* __MACHINE_ANSI_H__ */
diff --git a/sys/arch/luna88k/include/asm.h b/sys/arch/luna88k/include/asm.h
new file mode 100644
index 00000000000..37e414359c7
--- /dev/null
+++ b/sys/arch/luna88k/include/asm.h
@@ -0,0 +1,310 @@
+/* $OpenBSD: asm.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef __MACHINE_M88K_ASM_H__
+#define __MACHINE_M88K_ASM_H__
+
+#ifdef __STDC__
+#define _C_LABEL(name) _ ## name
+#else
+#define _C_LABEL(name) _/**/name
+#endif
+
+#define _ASM_LABEL(name) name
+
+#define _ENTRY(name) \
+ .text; .align 8; .globl name; name:
+
+#define ENTRY(name) _ENTRY(_C_LABEL(name))
+#define ASENTRY(name) _ENTRY(_ASM_LABEL(name))
+
+#define GLOBAL(name) \
+ .globl _C_LABEL(name); _C_LABEL(name):
+
+#define ASGLOBAL(name) \
+ .globl _ASM_LABEL(name); _ASM_LABEL(name):
+
+#define LOCAL(name) \
+ _C_LABEL(name):
+
+#define ASLOCAL(name) \
+ _ASM_LABEL(name):
+
+#define BSS(name, size) \
+ .comm _C_LABEL(name), size
+
+#define ASBSS(name, size) \
+ .comm _ASM_LABEL(name), size
+
+#ifdef __ELF__
+#define WEAK_ALIAS(alias,sym) \
+ .weak alias; \
+ alias = sym
+#else
+#ifdef __STDC__
+#define WEAK_ALIAS(alias,sym) \
+ .weak _##alias; \
+ _##alias = _##sym
+#else
+#define WEAK_ALIAS(alias,sym) \
+ .weak _/**/alias; \
+ _/**/alias = _/**/sym
+#endif
+#endif
+
+#ifdef _KERNEL
+
+/*
+ * Control register symbolic names
+ */
+
+#define PID cr0
+#define PSR cr1
+#define EPSR cr2
+#define SSBR cr3
+#define SXIP cr4
+#define SNIP cr5
+#define SFIP cr6
+#define VBR cr7
+#define DMT0 cr8
+#define DMD0 cr9
+#define DMA0 cr10
+#define DMT1 cr11
+#define DMD1 cr12
+#define DMA1 cr13
+#define DMT2 cr14
+#define DMD2 cr15
+#define DMA2 cr16
+#define SR0 cr17
+#define SR1 cr18
+#define SR2 cr19
+#define SR3 cr20
+
+/* MVME197 only */
+#define SRX cr16
+#define EXIP cr4
+#define ENIP cr5
+#define ICMD cr25
+#define ICTL cr26
+#define ISAR cr27
+#define ISAP cr28
+#define IUAP cr29
+#define IIR cr30
+#define IBP cr31
+#define IPPU cr32
+#define IPPL cr33
+#define ISR cr34
+#define ILAR cr35
+#define IPAR cr36
+#define DCMD cr40
+#define DCTL cr41
+#define DSAR cr42
+#define DSAP cr43
+#define DUAP cr44
+#define DIR cr45
+#define DBP cr46
+#define DPPU cr47
+#define DPPL cr48
+#define DSR cr49
+#define DLAR cr50
+#define DPAR cr51
+/* end MVME197 only */
+
+#define FPECR fcr0
+#define FPHS1 fcr1
+#define FPLS1 fcr2
+#define FPHS2 fcr3
+#define FPLS2 fcr4
+#define FPPT fcr5
+#define FPRH fcr6
+#define FPRL fcr7
+#define FPIT fcr8
+#define FPSR fcr62
+#define FPCR fcr63
+
+/*
+ * At various times, there is the need to clear the pipeline (i.e.
+ * synchronize). A "tb1 0, r0, foo" will do that (because a trap
+ * instruction always synchronizes, and this particular instruction
+ * will never actually take the trap).
+ */
+#if 0
+#define FLUSH_PIPELINE tcnd ne0, r0, 0
+#define FLUSH_PIPELINE_STRING "tcnd ne0, r0, 0"
+#else
+#define FLUSH_PIPELINE tb1 0, r0, 0
+#define FLUSH_PIPELINE_STRING "tb1 0, r0, 0"
+#endif
+#define NOP or r0, r0, r0
+#define NOP_STRING "or r0, r0, r0"
+
+#define RTE NOP ; rte
+
+/*
+ * Useful in some situations.
+ */
+#define CALL(NAME, ARG1, ARG2) \
+ subu r31, r31, 32; \
+ or r2, r0, ARG1; \
+ bsr.n NAME; \
+ or r3, r0, ARG2; \
+ addu r31, r31, 32
+
+/* This define is similar to CALL, but accepts a function pointer XXX smurph */
+#define CALLP(NAME, ARG1, ARG2) \
+ subu r31, r31, 32; \
+ or.u r5, r0, hi16(NAME); \
+ ld r4, r5, lo16(NAME); \
+ or r2, r0, ARG1; \
+ jsr.n r4; \
+ or r3, r0, ARG2; \
+ addu r31, r31, 32
+
+/*
+ * SR1 - CPU FLAGS REGISTER
+ * XXX clean this when the trap handler is reworked. Among the things
+ * I like to see is having the trap frame on the kernel stack instead
+ * of putting in the PCB. If done properly, we don't need SR1 for doing
+ * anything special. nivas
+ *
+ * SR1 contains flags about the current CPU status.
+ *
+ * The bit FLAG_IGNORE_DATA_EXCEPTION indicates that any data exceptions
+ * should be ignored (well, at least treated in a special way).
+ * The bit FLAG_ENABLING_FPU indicates that the exception handler is
+ * in the process of enabling the FPU (so that an exception can
+ * be serviced). This is needed because enabling the FPU can
+ * cause other exceptions to happen, and the whole system is
+ * in a rather precarious state and so special cautions must
+ * be taken.
+ */
+#define FLAG_CPU_FIELD_WIDTH 2 /* must be <= 12 */
+#define FLAG_IGNORE_DATA_EXCEPTION 5
+#define FLAG_ENABLING_FPU 7
+#define FLAG_FROM_KERNEL 8
+
+/* REGister OFFset into the E.F. (exception frame) */
+#define REG_OFF(reg_num) ((reg_num) * 4) /* (num * sizeof(register_t)) */
+#define GENREG_OFF(num) (REG_OFF(EF_R0 + (num))) /* GENeral REGister OFFset */
+
+/*
+ * Some registers used during the setting up of the new exception frame.
+ * Don't choose r1, r30, or r31 for any of them.
+ *
+ * Also, if any are 'r2' or 'r3', be careful using with CALL above!
+ */
+#define FLAGS r2
+#define TMP r3
+#define TMP2 r10
+#define TMP3 r11
+#define SAVE_TMP2 st r10, r31, GENREG_OFF(10)
+#define SAVE_TMP3 st r11, r31, GENREG_OFF(11)
+#define RESTORE_TMP2 ld r10, r31, GENREG_OFF(10)
+#define RESTORE_TMP3 ld r11, r31, GENREG_OFF(11)
+
+/*
+ * Info about the PSR
+ */
+#define PSR_SHADOW_FREEZE_BIT 0
+#define PSR_INTERRUPT_DISABLE_BIT 1
+#define PSR_FPU_DISABLE_BIT 3
+#define PSR_BIG_ENDIAN_MODE 30
+#define PSR_SUPERVISOR_MODE_BIT 31
+/*
+ * mc88110 PSR bit definitions (MVME197)
+ */
+#define PSR_GRAPHICS_DISABLE_BIT 4
+#define PSR_SERIAL_MODE_BIT 29
+#define PSR_CARRY_BIT 28
+#define PSR_SERIALIZE_BIT 25
+
+/*
+ * Status bits for an SXIP/SNIP/SFIP address.
+ */
+#define RTE_VALID_BIT 1
+#define RTE_ERROR_BIT 0
+
+/*
+ * Info about DMT0/DMT1/DMT2
+ */
+#define DMT_VALID_BIT 0
+#define DMT_WRITE_BIT 1
+#define DMT_LOCK_BIT 12
+#define DMT_DOUBLE_BIT 13
+#define DMT_DAS_BIT 14
+#define DMT_DREG_OFFSET 7
+#define DMT_DREG_WIDTH 5
+
+/*
+ * Bits for eh_debug.
+ */
+#define DEBUG_INTERRUPT_BIT 0
+#define DEBUG_DATA_BIT 1
+#define DEBUG_INSTRUCTION_BIT 2
+#define DEBUG_MISALIGN_BIT 3
+#define DEBUG_UNIMP_BIT 4
+#define DEBUG_DIVIDE_BIT 5
+#define DEBUG_OF_BIT 6
+#define DEBUG_FPp_BIT 7
+#define DEBUG_FPi_BIT 8
+#define DEBUG_SYSCALL_BIT 9
+#define DEBUG_MACHSYSCALL_BIT 10
+#define DEBUG_UNIMPLEMENTED_BIT 11
+#define DEBUG_PRIVILEGE_BIT 12
+#define DEBUG_BOUNDS_BIT 13
+#define DEBUG_OVERFLOW_BIT 14
+#define DEBUG_ERROR_BIT 15
+#define DEBUG_SIGSYS_BIT 16
+#define DEBUG_SIGTRAP_BIT 17
+#define DEBUG_BREAK_BIT 18
+#define DEBUG_TRACE_BIT 19
+#define DEBUG_KDB_BIT 20
+#define DEBUG_JKDB_BIT 21
+#define DEBUG_BUGCALL_BIT 22
+/* MVME197 Non-Maskable Interrupt */
+#define DEBUG_NON_MASK_BIT 23
+/* MVME197 Data Read Miss (Software Table Searches) */
+#define DEBUG_197_READ_BIT 25
+/* MVME197 Data Write Miss (Software Table Searches) */
+#define DEBUG_197_WRITE_BIT 26
+/* MVME197 Inst ATC Miss (Software Table Searches) */
+#define DEBUG_197_INST_BIT 27
+
+#define DEBUG_UNKNOWN_BIT 31
+
+/* exception vector marker */
+#define UNKNOWN_HANDLER 0xffffffff
+#define END_OF_VECTOR_LIST 0xfffffffe
+
+#define VECTOR(x) \
+ word _C_LABEL(x)
+
+#endif /* _KERNEL */
+
+#endif /* __MACHINE_M88K_ASM_H__ */
diff --git a/sys/arch/luna88k/include/asm_macro.h b/sys/arch/luna88k/include/asm_macro.h
new file mode 100644
index 00000000000..62e5b2465c9
--- /dev/null
+++ b/sys/arch/luna88k/include/asm_macro.h
@@ -0,0 +1,123 @@
+/* $OpenBSD: asm_macro.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef __MACHINE_M88K_ASM_MACRO_H__
+#define __MACHINE_M88K_ASM_MACRO_H__
+
+#include <machine/asm.h>
+/*
+ * Various compiler macros used for speed and efficiency.
+ * Anyone can include.
+ */
+
+/*
+ * Flushes the data pipeline.
+ */
+#define flush_pipeline() \
+ __asm__ __volatile__ (FLUSH_PIPELINE_STRING)
+
+/*
+ * PSR_TYPE is the type of the Process Status Register.
+ */
+typedef unsigned long m88k_psr_type;
+
+/*
+ * disable_interrupts_return_psr()
+ *
+ * The INTERRUPT_DISABLE bit is set in the PSR and the *PREVIOUS*
+ * PSR is returned. Intended to be used with set_psr() [below] as in:
+ *
+ * {
+ * m88k_psr_type psr;
+ * .
+ * .
+ * psr = disable_interrupts_return_psr();
+ * .
+ * SHORT [time-wise] CRITICAL SECTION HERE
+ * .
+ * set_psr(psr);
+ * .
+ * .
+ */
+static __inline__ m88k_psr_type disable_interrupts_return_psr(void)
+{
+ m88k_psr_type temp, oldpsr;
+ __asm__ __volatile__ ("ldcr %0, cr1" : "=r" (oldpsr));
+ __asm__ __volatile__ ("set %1, %0, 1<1>" : "=r" (oldpsr), "=r" (temp));
+ __asm__ __volatile__ ("stcr %0, cr1" : "=r" (temp));
+ __asm__ __volatile__ (FLUSH_PIPELINE_STRING);
+ return oldpsr;
+}
+#define disable_interrupt() (void)disable_interrupts_return_psr()
+
+/*
+ * Sets the PSR. See comments above.
+ */
+static __inline__ void set_psr(m88k_psr_type psr)
+{
+ __asm__ __volatile__ ("stcr %0, cr1" :: "r" (psr));
+ __asm__ __volatile__ (FLUSH_PIPELINE_STRING);
+}
+
+/*
+ * Gets the PSR. See comments above.
+ */
+static __inline__ m88k_psr_type get_psr(void)
+{
+ m88k_psr_type psr;
+ __asm__ __volatile__ ("ldcr %0, cr1" : "=r" (psr));
+ return psr;
+}
+
+/*
+ * Enables interrupts.
+ */
+static __inline__ m88k_psr_type enable_interrupts_return_psr(void)
+{
+ m88k_psr_type temp, oldpsr; /* need a temporary register */
+ __asm__ __volatile__ ("ldcr %0, cr1" : "=r" (oldpsr));
+ __asm__ __volatile__ ("clr %1, %0, 1<1>" : "=r" (oldpsr), "=r" (temp));
+ __asm__ __volatile__ ("stcr %0, cr1" : "=r" (temp));
+ __asm__ __volatile__ (FLUSH_PIPELINE_STRING);
+ return oldpsr;
+}
+#define enable_interrupt() (void)enable_interrupts_return_psr()
+
+#define db_enable_interrupt enable_interrupt
+#define db_disable_interrupt disable_interrupt
+
+/*
+ * Provide access from C code to the assembly instruction ff1
+ */
+static __inline__ unsigned ff1(unsigned val)
+{
+ __asm__ __volatile__ ("ff1 %0, %0" : "=r" (val) : "0" (val));
+ return val;
+}
+
+#endif /* __MACHINE_M88K_ASM_MACRO_H__ */
diff --git a/sys/arch/luna88k/include/autoconf.h b/sys/arch/luna88k/include/autoconf.h
new file mode 100644
index 00000000000..c5844f078ac
--- /dev/null
+++ b/sys/arch/luna88k/include/autoconf.h
@@ -0,0 +1,79 @@
+/* $OpenBSD: autoconf.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/*
+ * Copyright (c) 1999, Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Autoconfiguration information.
+ */
+
+#ifndef _MVME88K_AUTOCONF_H_
+#define _MVME88K_AUTOCONF_H_
+
+struct confargs {
+ int ca_bustype;
+ void *ca_vaddr;
+ void *ca_paddr;
+ int ca_offset;
+ int ca_len;
+ int ca_ipl;
+ int ca_vec;
+ char *ca_name;
+ void *ca_master; /* points to bus-dependent data */
+};
+
+#define BUS_MAIN 0
+#define BUS_MC 1
+#define BUS_PCC 2
+#define BUS_PCCTWO 3
+#define BUS_VMES 4
+#define BUS_VMEL 5
+#define BUS_SYSCON 6
+#define BUS_BUSSWITCH 7
+
+/* the following are from the prom/bootblocks */
+extern void *bootaddr; /* PA of boot device */
+extern int bootpart; /* boot partition (disk) */
+
+extern struct device *bootdv; /* boot device */
+
+void *mapiodev(void *pa, int size);
+void unmapiodev(void *kva, int size);
+
+struct device *getdevunit(char *name, int unit);
+
+/* taken from NetBSD/luna68k */
+
+struct mainbus_attach_args {
+ const char *ma_name;
+ paddr_t ma_addr;
+ int ma_ilvl;
+};
+#endif
diff --git a/sys/arch/luna88k/include/board.h b/sys/arch/luna88k/include/board.h
new file mode 100644
index 00000000000..7ed3f905fdc
--- /dev/null
+++ b/sys/arch/luna88k/include/board.h
@@ -0,0 +1,214 @@
+/* $OpenBSD: board.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef __LUNA88K_BOARD_H__
+#define __LUNA88K_BOARD_H__
+
+/*
+ * OMRON SX9100DT CPU board constants
+ */
+
+/*
+ * Something to put append a 'U' to a long constant if it's C so that
+ * it'll be unsigned in both ANSI and traditional.
+ */
+#if defined(_LOCORE)
+#define U(num) num
+#elif defined(__STDC__)
+#define U(num) num ## U
+#else
+#define U(num) num/**/U
+#endif
+#define UDEFINED
+
+#define MAX_CPUS 4 /* maximum cpus on the board */
+#define MAX_CMMUS 8 /* maximum cmmus on the board */
+
+/* machtype values */
+#define LUNA_88K 1
+#define LUNA_88K2 2
+
+#define SYSV_BASE U(0x00000000) /* system virtual base */
+#define VEQR_ADDR U(0x00000000)
+
+#define OBIO_START U(0x41000000)
+#define OBIO_SIZE U(0xBf000000)
+
+#define OBIO1_BASE U(0x41000000) /* on board i/o 1 base */
+#define OBIO1_SPACE U(0x1f000000) /* on board i/o 1 space */
+#define OBIO2_BASE U(0x61000000) /* on board i/o 2 base */
+#define OBIO2_SPACE U(0x1f000000) /* on board i/o 2 space */
+#define OBIO3_BASE U(0x80000000) /* on board i/o 3 base */
+#define OBIO3_SPACE U(0x80000000) /* on board i/o 3 space */
+
+#define MAXU_ADDR U(0x40000000) /* size of user virtual space */
+#define MAXPHYSMEM U(0x10000000) /* max physical memory */
+
+/* #define ILLADDRESS U(0x0F000000) */ /* any faulty address */
+/* #define ILLADDRESS U(0x3FFFFFF0) */ /* any faulty address for LUNA-88K2 */
+
+#define PROM_ADDR U(0x41000000) /* PROM */
+#define PROM_SPACE U(0x00040000)
+#define NVRAM_ADDR U(0x45000000) /* Non Volatile */
+#define NVRAM_SPACE U(0x00001FDC)
+#define FUSE_ROM_ADDR U(0x43000000) /* FUSE_ROM */
+#define FUSE_ROM_SPACE 1024
+#define OBIO_CAL_CTL U(0x45001FE0) /* calendar control register */
+#define OBIO_CAL_SEC U(0x45001FE4) /* seconds */
+#define OBIO_CAL_MIN U(0x45001FE8) /* minutes */
+#define OBIO_CAL_HOUR U(0x45001FEC) /* hours */
+#define OBIO_CAL_DOW U(0x45001FF0) /* Day Of the Week */
+#define OBIO_CAL_DAY U(0x45001FF4) /* days */
+#define OBIO_CAL_MON U(0x45001FF8) /* months */
+#define OBIO_CAL_YEAR U(0x45001FFC) /* years */
+#define OBIO_PIO0_BASE U(0x49000000) /* PIO-0 */
+#define OBIO_PIO0_SPACE U(0x0000000C)
+#define OBIO_PIO0A U(0x49000000) /* PIO-0 port A */
+#define OBIO_PIO0B U(0x49000004) /* PIO-0 port B */
+#define OBIO_PIO0C U(0x49000008) /* PIO-0 port C*/
+#define OBIO_PIO0 U(0x4900000C) /* PIO-0 control */
+#define OBIO_PIO1_BASE U(0x4D000000) /* PIO-1 */
+#define OBIO_PIO1_SPACE U(0x0000000C)
+#define OBIO_PIO1A U(0x4D000000) /* PIO-1 port A */
+#define OBIO_PIO1B U(0x4D000004) /* PIO-1 port B */
+#define OBIO_PIO1C U(0x4D000008) /* PIO-1 port C*/
+#define OBIO_PIO1 U(0x4D00000C) /* PIO-1 control */
+#define OBIO_SIO U(0x51000000) /* SIO */
+#define OBIO_TAS U(0x61000000) /* TAS register */
+#define OBIO_CLOCK0 U(0x63000000) /* system clock CPU 0 */
+#define OBIO_CLOCK1 U(0x63000004) /* system clock CPU 1 */
+#define OBIO_CLOCK2 U(0x63000008) /* system clock CPU 2 */
+#define OBIO_CLOCK3 U(0x6300000C) /* system clock CPU 3 */
+#define OBIO_CLK_INTR 31 /* system clock interrupt flag */
+#define INT_ST_MASK0 U(0x65000000) /* interrupt status register CPU 0 */
+#define INT_ST_MASK1 U(0x65000004) /* interrupt status register CPU 1 */
+#define INT_ST_MASK2 U(0x65000008) /* interrupt status register CPU 2 */
+#define INT_ST_MASK3 U(0x6500000C) /* interrupt status register CPU 3 */
+#define INT_LEVEL 8 /* # of intrrupt level + 1 */
+#define INT_SET_LV7 U(0x00000000) /* disable interrupts */
+#define INT_SET_LV6 U(0x00000000) /* enable level 7 */
+#define INT_SET_LV5 U(0x80000000) /* enable level 7-6 */
+#define INT_SET_LV4 U(0xC0000000) /* enable level 7-5 */
+#define INT_SET_LV3 U(0xE0000000) /* enable level 7-4 */
+#define INT_SET_LV2 U(0xF0000000) /* enable level 7-3 */
+#define INT_SET_LV1 U(0xF8000000) /* enable level 7-2 */
+#define INT_SET_LV0 U(0xFC000000) /* enable interrupts */
+#define INT_SLAVE_MASK U(0x84000000) /* slave can only enable 6 and 1 */
+#define INT_CLOCK_MASK 0xBFFFFFFF /* mask clock */
+#define INT_LV6 U(0x00800000) /* level 6 enebled */
+#define INT_LV5 U(0x00400000) /* level 5 enebled */
+#define INT_LV4 U(0x00200000) /* level 4 enebled */
+#define INT_LV3 U(0x00100000) /* level 3 enebled */
+#define INT_LV2 U(0x00080000) /* level 2 enebled */
+#define INT_LV1 U(0x00040000) /* level 1 enebled */
+#define INT_ST U(0xE0000000) /* interrupt status */
+#define INT_MASK_LV0 INT_LV6 | INT_LV5 | INT_LV4 | INT_LV3 | INT_LV2 | INT_LV1
+#define INT_MASK_LV1 INT_LV6 | INT_LV5 | INT_LV4 | INT_LV3 | INT_LV2
+#define INT_MASK_LV2 INT_LV6 | INT_LV5 | INT_LV4 | INT_LV3
+#define INT_MASK_LV3 INT_LV6 | INT_LV5 | INT_LV4
+#define INT_MASK_LV4 INT_LV6 | INT_LV5
+#define INT_MASK_LV5 INT_LV6
+#define INT_MASK_LV6 0
+#define INT_MASK_LV7 0
+#define SLAVE_MASK INT_LV6 | INT_LV1
+
+#define NON_MASKABLE_LEVEL 7 /* non-maskable-interrupt (abort) */
+#define CLOCK_INT_LEVEL 6 /* clock interrupt level */
+#define SOFT_INT_LEVEL 1 /* software interrupt level */
+#define SOFT_INT0 U(0x69000000) /* software interrupt CPU 0 */
+#define SOFT_INT1 U(0x69000004) /* software interrupt CPU 1 */
+#define SOFT_INT2 U(0x69000008) /* software interrupt CPU 2 */
+#define SOFT_INT3 U(0x6900000C) /* software interrupt CPU 3 */
+#define SOFT_INT_FLAG0 U(0x6B000000) /* sfotware interrupt flag CPU 0 */
+#define SOFT_INT_FLAG1 U(0x6B000000) /* sfotware interrupt flag CPU 1 */
+#define SOFT_INT_FLAG2 U(0x6B000000) /* sfotware interrupt flag CPU 2 */
+#define SOFT_INT_FLAG3 U(0x6B000000) /* sfotware interrupt flag CPU 3 */
+#define SOFT_INT_BIT 31 /* software interrupt flag bit */
+#define RESET_CPU0 U(0x6D000000) /* reset CPU 0 */
+#define RESET_CPU1 U(0x6D000004) /* reset CPU 1 */
+#define RESET_CPU2 U(0x6D000008) /* reset CPU 2 */
+#define RESET_CPU3 U(0x6D00000C) /* reset CPU 3 */
+#define RESET_CPU_ALL U(0x6D000010) /* reset ALL CPUs */
+#define TRI_PORT_RAM U(0x71000000) /* 3 port RAM */
+#define TRI_PORT_RAM_SPACE 0x20000
+#define EXT_A_ADDR U(0x81000000) /* extension board A */
+#define EXT_A_SPACE U(0x02000000)
+#define EU_BASE U(0x81fe0000) /* VME expand board */
+#define EXT_B_ADDR U(0x83000000) /* extension board B */
+#define EXT_B_SPACE U(0x01000000)
+#define PC_BASE U(0x90000000) /* pc-98 extension board */
+#define PC_SPACE U(0x02000000)
+
+#define MROM_ADDR U(0xA1000000) /* Mask ROM address */
+#define MROM_SPACE 0x400000
+#define BMAP_START U(0xB1000000) /* Bitmap start address */
+#define BMAP_SPACE (BMAP_END - BMAP_START)
+#define BMAP_RFCNT U(0xB1000000) /* RFCNT register */
+#define BMAP_BMSEL U(0xB1040000) /* BMSEL register */
+#define BMAP_BMP U(0xB1080000) /* common bitmap plane */
+#define BMAP_BMAP0 U(0xB10C0000) /* bitmap plane 0 */
+#define BMAP_BMAP1 U(0xB1100000) /* bitmap plane 1 */
+#define BMAP_BMAP2 U(0xB1140000) /* bitmap plane 2 */
+#define BMAP_BMAP3 U(0xB1180000) /* bitmap plane 3 */
+#define BMAP_BMAP4 U(0xB11C0000) /* bitmap plane 4 */
+#define BMAP_BMAP5 U(0xB1200000) /* bitmap plane 5 */
+#define BMAP_BMAP6 U(0xB1240000) /* bitmap plane 6 */
+#define BMAP_BMAP7 U(0xB1280000) /* bitmap plane 7 */
+#define BMAP_FN U(0xB12C0000) /* common bitmap function */
+#define BMAP_FN0 U(0xB1300000) /* bitmap function 0 */
+#define BMAP_FN1 U(0xB1340000) /* bitmap function 1 */
+#define BMAP_FN2 U(0xB1380000) /* bitmap function 2 */
+#define BMAP_FN3 U(0xB13C0000) /* bitmap function 3 */
+#define BMAP_FN4 U(0xB1400000) /* bitmap function 4 */
+#define BMAP_FN5 U(0xB1440000) /* bitmap function 5 */
+#define BMAP_FN6 U(0xB1480000) /* bitmap function 6 */
+#define BMAP_FN7 U(0xB14C0000) /* bitmap function 7 */
+#define BMAP_END U(0xB1500000)
+#define BMAP_END24P U(0xB1800000) /* end of 24p framemem */
+#define BMAP_PALLET0 U(0xC0000000) /* color pallet */
+#define BMAP_PALLET1 U(0xC1000000) /* color pallet */
+#define BMAP_PALLET2 U(0xC1100000) /* color pallet */
+#define BOARD_CHECK_REG U(0xD0000000) /* board check register */
+#define BMAP_CRTC U(0xD1000000) /* CTRC-II */
+#define BMAP_IDENTROM U(0xD1800000) /* bitmap-boad identify ROM */
+#define SCSI_ADDR U(0xE1000000) /* SCSI address */
+#define LANCE_ADDR U(0xF1000000) /* LANCE */
+#define EXT_IACK_ADDR 0xFFFFFFF7 /* IACK Space for Extended Board */
+
+#define VDMA_STD(x) ((int)(x))
+
+#define CMMU_I0 U(0xFFF07000) /* CMMU instruction cpu 0 */
+#define CMMU_D0 U(0xFFF06000) /* CMMU data cpu 0 */
+#define CMMU_I1 U(0xFFF05000) /* CMMU instruction cpu 1 */
+#define CMMU_D1 U(0xFFF04000) /* CMMU data cpu 1 */
+#define CMMU_I2 U(0xFFF03000) /* CMMU instruction cpu 2 */
+#define CMMU_D2 U(0xFFF02000) /* CMMU data cpu 2 */
+#define CMMU_I3 U(0xFFF01000) /* CMMU instruction cpu 3 */
+#define CMMU_D3 U(0xFFF00000) /* CMMU data cpu 3 */
+
+#endif /* __LUNA88K_BOARD_H__ */
diff --git a/sys/arch/luna88k/include/bus.h b/sys/arch/luna88k/include/bus.h
new file mode 100644
index 00000000000..a0debb18345
--- /dev/null
+++ b/sys/arch/luna88k/include/bus.h
@@ -0,0 +1,632 @@
+/* $OpenBSD: bus.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/* $NetBSD: bus.h,v 1.9 1998/01/13 18:32:15 scottr Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1997 Scott Reynolds. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* almost same as OpenBSD/mac68k */
+
+#ifndef _LUNA88K_BUS_H_
+#define _LUNA88K_BUS_H_
+
+/*
+ * Value for the luna88k bus space tag, not to be used directly by MI code.
+ */
+#define LUNA88K_BUS_SPACE_MEM 0 /* space is mem space */
+
+/*
+ * Bus address and size types
+ */
+typedef u_long bus_addr_t;
+typedef u_long bus_size_t;
+
+/*
+ * Access methods for bus resources and address space.
+ */
+typedef int bus_space_tag_t;
+typedef u_long bus_space_handle_t;
+
+/*
+ * int bus_space_map(bus_space_tag_t t, bus_addr_t addr,
+ * bus_size_t size, int flags, bus_space_handle_t *bshp);
+ *
+ * Map a region of bus space.
+ */
+
+#define BUS_SPACE_MAP_CACHEABLE 0x01
+#define BUS_SPACE_MAP_LINEAR 0x02
+
+int bus_space_map(bus_space_tag_t, bus_addr_t, bus_size_t,
+ int, bus_space_handle_t *);
+
+/*
+ * void bus_space_unmap(bus_space_tag_t t,
+ * bus_space_handle_t bsh, bus_size_t size);
+ *
+ * Unmap a region of bus space.
+ */
+
+void bus_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+
+/*
+ * int bus_space_subregion(bus_space_tag_t t,
+ * bus_space_handle_t bsh, bus_size_t offset, bus_size_t size,
+ * bus_space_handle_t *nbshp);
+ *
+ * Get a new handle for a subregion of an already-mapped area of bus space.
+ */
+
+int bus_space_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp);
+
+/*
+ * int bus_space_alloc(bus_space_tag_t t, bus_addr_t, rstart,
+ * bus_addr_t rend, bus_size_t size, bus_size_t align,
+ * bus_size_t boundary, int flags, bus_addr_t *addrp,
+ * bus_space_handle_t *bshp);
+ *
+ * Allocate a region of bus space.
+ */
+
+int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart,
+ bus_addr_t rend, bus_size_t size, bus_size_t align,
+ bus_size_t boundary, int cacheable, bus_addr_t *addrp,
+ bus_space_handle_t *bshp);
+
+/*
+ * int bus_space_free(bus_space_tag_t t,
+ * bus_space_handle_t bsh, bus_size_t size);
+ *
+ * Free a region of bus space.
+ */
+
+void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t size);
+
+/*
+ * int luna88k_bus_space_probe(bus_space_tag_t t,
+ * bus_space_handle_t bsh, bus_size_t offset, int sz);
+ *
+ * Probe the bus at t/bsh/offset, using sz as the size of the load.
+ *
+ * This is a machine-dependent extension, and is not to be used by
+ * machine-independent code.
+ */
+
+int luna88k_bus_space_probe(bus_space_tag_t t,
+ bus_space_handle_t bsh, bus_size_t offset, int sz);
+
+/*
+ * u_intN_t bus_space_read_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset);
+ *
+ * Read a 1, 2, 4, or 8 byte quantity from bus space
+ * described by tag/handle/offset.
+ */
+
+#define bus_space_read_1(t, h, o) \
+ ((void) t, (*(volatile u_int8_t *)((h) + 4 * (o))))
+
+#define bus_space_read_2(t, h, o) \
+ ((void) t, (*(volatile u_int16_t *)((h) + 4 * (o))))
+
+#define bus_space_read_4(t, h, o) \
+ ((void) t, (*(volatile u_int32_t *)((h) + 4 * (o))))
+
+#if 0 /* Cause a link error for bus_space_read_8 */
+#define bus_space_read_8(t, h, o) !!! bus_space_read_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_read_multi_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * u_intN_t *addr, size_t count);
+ *
+ * Read `count' 1, 2, 4, or 8 byte quantities from bus space
+ * described by tag/handle/offset and copy into buffer provided.
+ */
+
+#define bus_space_read_multi_1(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.bu r13, r10, 0 ; \
+ st.b r13, r11, 0 ; \
+ add r11, r11, 1 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_read_multi_2(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.hu r13, r10, 0 ; \
+ st.hu r13, r11, 0 ; \
+ add r11, r11, 2 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_read_multi_4(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld r13, r10, 0 ; \
+ st r13, r11, 0 ; \
+ add r11, r11, 4 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#if 0 /* Cause a link error for bus_space_read_multi_8 */
+#define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_read_region_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * u_intN_t *addr, size_t count);
+ *
+ * Read `count' 1, 2, 4, or 8 byte quantities from bus space
+ * described by tag/handle and starting at `offset' and copy into
+ * buffer provided.
+ */
+
+#define bus_space_read_region_1(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.bu r13, r10, 0 ; \
+ st.b r13, r11, 0 ; \
+ add r10, r10, 4 ; \
+ add r11, r11, 1 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_read_region_2(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.hu r13, r10, 0 ; \
+ st.hu r13, r11, 0 ; \
+ add r10, r10, 4 ; \
+ add r11, r11, 2 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_read_region_4(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld r13, r10, 0 ; \
+ st r13, r11, 0 ; \
+ add r10, r10, 4 ; \
+ add r11, r11, 4 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#if 0 /* Cause a link error for bus_space_read_region_8 */
+#define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_write_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * u_intN_t value);
+ *
+ * Write the 1, 2, 4, or 8 byte value `value' to bus space
+ * described by tag/handle/offset.
+ */
+
+#define bus_space_write_1(t, h, o, v) \
+ ((void) t, ((void)(*(volatile u_int8_t *)((h) + 4 * (o)) = (v))))
+
+#define bus_space_write_2(t, h, o, v) \
+ ((void) t, ((void)(*(volatile u_int16_t *)((h) + 4 * (o)) = (v))))
+
+#define bus_space_write_4(t, h, o, v) \
+ ((void) t, ((void)(*(volatile u_int32_t *)((h) + 4 * (o)) = (v))))
+
+#if 0 /* Cause a link error for bus_space_write_8 */
+#define bus_space_write_8 !!! bus_space_write_8 not implemented !!!
+#endif
+
+/*
+ * void bus_space_write_multi_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * const u_intN_t *addr, size_t count);
+ *
+ * Write `count' 1, 2, 4, or 8 byte quantities from the buffer
+ * provided to bus space described by tag/handle/offset.
+ */
+
+#define bus_space_write_multi_1(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.bu r13, r11, 0 ; \
+ st.b r13, r10, 0 ; \
+ add r11, r11, 1 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_write_multi_2(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.hu r13, r11, 0 ; \
+ st.hu r13, r10, 0 ; \
+ add r11, r11, 2 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_write_multi_4(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld r13, r11, 0 ; \
+ st r13, r10, 0 ; \
+ add r11, r11, 4 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#if 0 /* Cause a link error for bus_space_write_8 */
+#define bus_space_write_multi_8(t, h, o, a, c) \
+ !!! bus_space_write_multi_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_write_region_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * const u_intN_t *addr, size_t count);
+ *
+ * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided
+ * to bus space described by tag/handle starting at `offset'.
+ */
+
+#define bus_space_write_region_1(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.bu r13, r11, 0 ; \
+ st.b r13, r10, 0 ; \
+ add r10, r10, 4 ; \
+ add r11, r11, 1 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_write_region_2(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld.hu r13, r11, 0 ; \
+ st.hu r13, r10, 0 ; \
+ add r10, r10, 4 ; \
+ add r11, r11, 2 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#define bus_space_write_region_4(t, h, o, a, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: ld r13, r11, 0 ; \
+ st r13, r10, 0 ; \
+ add r10, r10, 4 ; \
+ add r11, r11, 4 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (a), "r" (c) : \
+ "r10", "r11", "r12", "r13"); \
+} while (0);
+
+#if 0 /* Cause a link error for bus_space_write_region_8 */
+#define bus_space_write_region_8 \
+ !!! bus_space_write_region_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_set_multi_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset, u_intN_t val,
+ * size_t count);
+ *
+ * Write the 1, 2, 4, or 8 byte value `val' to bus space described
+ * by tag/handle/offset `count' times.
+ */
+
+#define bus_space_set_multi_1(t, h, o, val, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: st.b r11, r10, 0 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (val), "r" (c) : \
+ "r10", "r11", "r12"); \
+} while (0);
+
+#define bus_space_set_multi_2(t, h, o, val, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: st.hu r11, r10, 0 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (val), "r" (c) : \
+ "r10", "r11", "r12"); \
+} while (0);
+
+#define bus_space_set_multi_4(t, h, o, val, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: st r11, r10, 0 ; \
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (val), "r" (c) : \
+ "r10", "r11", "r12"); \
+} while (0);
+
+#if 0 /* Cause a link error for bus_space_set_multi_8 */
+#define bus_space_set_multi_8 \
+ !!! bus_space_set_multi_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_set_region_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset, u_intN_t val,
+ * size_t count);
+ *
+ * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described
+ * by tag/handle starting at `offset'.
+ */
+
+#define bus_space_set_region_1(t, h, o, val, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: st.b r11, r10, 0 ; \
+ add r10, r10, 4
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (val), "r" (c) : \
+ "r10", "r11", "r12"); \
+} while (0);
+
+#define bus_space_set_region_2(t, h, o, val, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: st.hu r11, r10, 0 ; \
+ add r10, r10, 4
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (val), "r" (c) : \
+ "r10", "r11", "r12"); \
+} while (0);
+
+#define bus_space_set_region_4(t, h, o, val, c) do { \
+ (void) t; \
+ __asm __volatile (" \
+ or r10, r0, %0 ; \
+ or r11, r0, %1 ; \
+ or r12, r0, %2 ; \
+ 1: st r11, r10, 0 ; \
+ add r10, r10, 4
+ bcnd.n ne0, r12, 1b ; \
+ sub r12, r12, 1" : \
+ : \
+ "r" ((h) + 4 * (o)), "r" (val), "r" (c) : \
+ "r10", "r11", "r12"); \
+} while (0);
+
+#if 0 /* Cause a link error for bus_space_set_region_8 */
+#define bus_space_set_region_8 \
+ !!! bus_space_set_region_8 unimplemented !!!
+#endif
+
+/*
+ * void bus_space_copy_N(bus_space_tag_t tag,
+ * bus_space_handle_t bsh1, bus_size_t off1,
+ * bus_space_handle_t bsh2, bus_size_t off2,
+ * size_t count);
+ *
+ * Copy `count' 1, 2, 4, or 8 byte values from bus space starting
+ * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2.
+ */
+
+#define __LUNA88K_copy_region_N(BYTES) \
+static __inline void __CONCAT(bus_space_copy_region_,BYTES) \
+ (bus_space_tag_t, \
+ bus_space_handle_t bsh1, bus_size_t off1, \
+ bus_space_handle_t bsh2, bus_size_t off2, \
+ bus_size_t count); \
+ \
+static __inline void \
+__CONCAT(bus_space_copy_region_,BYTES)(t, h1, o1, h2, o2, c) \
+ bus_space_tag_t t; \
+ bus_space_handle_t h1, h2; \
+ bus_size_t o1, o2, c; \
+{ \
+ bus_size_t o; \
+ \
+ if ((h1 + o1) >= (h2 + o2)) { \
+ /* src after dest: copy forward */ \
+ for (o = 0; c != 0; c--, o += BYTES) \
+ __CONCAT(bus_space_write_,BYTES)(t, h2, o2 + o, \
+ __CONCAT(bus_space_read_,BYTES)(t, h1, o1 + o)); \
+ } else { \
+ /* dest after src: copy backwards */ \
+ for (o = (c - 1) * BYTES; c != 0; c--, o -= BYTES) \
+ __CONCAT(bus_space_write_,BYTES)(t, h2, o2 + o, \
+ __CONCAT(bus_space_read_,BYTES)(t, h1, o1 + o)); \
+ } \
+}
+__LUNA88K_copy_region_N(1)
+__LUNA88K_copy_region_N(2)
+__LUNA88K_copy_region_N(4)
+#if 0 /* Cause a link error for bus_space_copy_8 */
+#define bus_space_copy_8 \
+ !!! bus_space_copy_8 unimplemented !!!
+#endif
+
+#undef __LUNA88K_copy_region_N
+
+/*
+ * Bus read/write barrier methods.
+ *
+ * void bus_space_barrier(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * bus_size_t len, int flags);
+ *
+ * Note: the 680x0 does not currently require barriers, but we must
+ * provide the flags to MI code.
+ */
+#define bus_space_barrier(t, h, o, l, f) \
+ ((void)((void)(t), (void)(h), (void)(o), (void)(l), (void)(f)))
+#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */
+#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */
+
+#endif /* _LUNA88K_BUS_H_ */
diff --git a/sys/arch/luna88k/include/cdefs.h b/sys/arch/luna88k/include/cdefs.h
new file mode 100644
index 00000000000..3eb37b6b943
--- /dev/null
+++ b/sys/arch/luna88k/include/cdefs.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: cdefs.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/* $NetBSD: cdefs.h,v 1.2 1995/03/23 20:10:48 jtc Exp $ */
+
+/*
+ * Written by J.T. Conklin <jtc@wimsey.com> 01/17/95.
+ * Public domain.
+ */
+
+#ifndef __MACHINE_CDEFS_H__
+#define __MACHINE_CDEFS_H__
+
+#ifdef __STDC__
+#define _C_LABEL(name) _ ## name
+#else
+#define _C_LABEL(name) _/**/name
+#endif
+
+#ifdef __GNUC__
+#ifdef __STDC__
+#define __indr_reference(sym,alias) \
+ __asm__(".stabs \"_" #alias "\",11,0,0,0"); \
+ __asm__(".stabs \"_" #sym "\",1,0,0,0")
+#define __warn_references(sym,msg) \
+ __asm__(".stabs \"" msg "\",30,0,0,0"); \
+ __asm__(".stabs \"_" #sym "\",1,0,0,0")
+#define __weak_alias(alias,sym) \
+ __asm__(".weak _" #alias "; _" #alias "= _" __STRING(sym))
+#else
+#define __indr_reference(sym,alias) \
+ __asm__(".stabs \"_/**/alias\",11,0,0,0"); \
+ __asm__(".stabs \"_/**/sym\",1,0,0,0")
+#define __warn_references(sym,msg) \
+ __asm__(".stabs msg,30,0,0,0"); \
+ __asm__(".stabs \"_/**/sym\",1,0,0,0")
+#define __weak_alias(alias,sym) \
+ __asm__(".weak _/**/alias; _/**/alias = _/**/sym")
+#endif
+#endif
+
+#endif /* __MACHINE_CDEFS_H__ */
diff --git a/sys/arch/luna88k/include/cmmu.h b/sys/arch/luna88k/include/cmmu.h
new file mode 100644
index 00000000000..95cc42031a2
--- /dev/null
+++ b/sys/arch/luna88k/include/cmmu.h
@@ -0,0 +1,103 @@
+/* $OpenBSD: cmmu.h,v 1.1 2004/04/21 15:23:56 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _MACHINE_CMMU_H_
+#define _MACHINE_CMMU_H_
+
+#include <machine/mmu.h>
+
+#ifndef _LOCORE
+/*
+ * Prototypes and stuff for cmmu.c.
+ */
+extern unsigned cpu_sets[MAX_CPUS];
+extern unsigned master_cpu;
+extern int max_cpus, max_cmmus;
+
+/*
+ * This lock protects the cmmu SAR and SCR's; other ports
+ * can be accessed without locking it
+ *
+ * May be used from "db_interface.c".
+ */
+extern struct simplelock cmmu_cpu_lock;
+
+#define CMMU_LOCK simple_lock(&cmmu_cpu_lock)
+#define CMMU_UNLOCK simple_unlock(&cmmu_cpu_lock)
+
+/* machine dependent cmmu function pointer structure */
+struct cmmu_p {
+ void (*cmmu_init_func)(void);
+ void (*setup_board_config_func)(void);
+ void (*cpu_configuration_print_func)(int);
+ void (*cmmu_shutdown_now_func)(void);
+ void (*cmmu_parity_enable_func)(void);
+ unsigned (*cmmu_cpu_number_func)(void);
+ void (*cmmu_set_sapr_func)(unsigned, unsigned);
+ void (*cmmu_set_uapr_func)(unsigned);
+ void (*cmmu_set_pair_batc_entry_func)(unsigned, unsigned, unsigned);
+ void (*cmmu_flush_tlb_func)(unsigned, unsigned, vaddr_t, vsize_t);
+ void (*cmmu_pmap_activate_func)(unsigned, unsigned,
+ u_int32_t i_batc[BATC_MAX], u_int32_t d_batc[BATC_MAX]);
+ void (*cmmu_flush_cache_func)(int, paddr_t, psize_t);
+ void (*cmmu_flush_inst_cache_func)(int, paddr_t, psize_t);
+ void (*cmmu_flush_data_cache_func)(int, paddr_t, psize_t);
+ void (*dma_cachectl_func)(vaddr_t, vsize_t, int);
+ /* DDB only */
+ void (*cmmu_dump_config_func)(void);
+ void (*cmmu_show_translation_func)(unsigned, unsigned, unsigned, int);
+ /* DEBUG only */
+ void (*show_apr_func)(unsigned);
+};
+
+/* THE pointer! */
+extern struct cmmu_p *cmmu;
+
+/* The macros... */
+#define cmmu_init (cmmu->cmmu_init_func)
+#define setup_board_config (cmmu->setup_board_config_func)
+#define cpu_configuration_print(a) (cmmu->cpu_configuration_print_func)(a)
+#define cmmu_shutdown_now (cmmu->cmmu_shutdown_now_func)
+#define cmmu_parity_enable (cmmu->cmmu_parity_enable_func)
+#define cmmu_cpu_number (cmmu->cmmu_cpu_number_func)
+#define cmmu_set_sapr(a, b) (cmmu->cmmu_set_sapr_func)(a, b)
+#define cmmu_set_uapr(a) (cmmu->cmmu_set_uapr_func)(a)
+#define cmmu_set_pair_batc_entry(a, b, c) (cmmu->cmmu_set_pair_batc_entry_func)(a, b, c)
+#define cmmu_flush_tlb(a, b, c, d) (cmmu->cmmu_flush_tlb_func)(a, b, c, d)
+#define cmmu_pmap_activate(a, b, c, d) (cmmu->cmmu_pmap_activate_func)(a, b, c, d)
+#define cmmu_flush_cache(a, b, c) (cmmu->cmmu_flush_cache_func)(a, b, c)
+#define cmmu_flush_inst_cache(a, b, c) (cmmu->cmmu_flush_inst_cache_func)(a, b, c)
+#define cmmu_flush_data_cache(a, b, c) (cmmu->cmmu_flush_data_cache_func)(a, b, c)
+#define dma_cachectl(a, b, c) (cmmu->dma_cachectl_func)(a, b, c)
+#define cmmu_dump_config (cmmu->cmmu_dump_config_func)
+#define cmmu_show_translation(a, b, c, d) (cmmu->cmmu_show_translation_func)(a, b, c, d)
+#define show_apr(ap) (cmmu->show_apr_func)(ap)
+
+#endif /* _LOCORE */
+
+#endif /* _MACHINE_CMMU_H_ */
+
diff --git a/sys/arch/luna88k/include/cpu.h b/sys/arch/luna88k/include/cpu.h
new file mode 100644
index 00000000000..ef11194964a
--- /dev/null
+++ b/sys/arch/luna88k/include/cpu.h
@@ -0,0 +1,198 @@
+/* $OpenBSD: cpu.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 1996 Nivas Madhur
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __MACHINE_CPU_H__
+#define __MACHINE_CPU_H__
+
+/*
+ * CTL_MACHDEP definitinos.
+ */
+#define CPU_CONSDEV 1 /* dev_t: console terminal device */
+#define CPU_MAXID 2 /* number of valid machdep ids */
+
+#define CTL_MACHDEP_NAMES { \
+ { 0, 0 }, \
+ { "console_device", CTLTYPE_STRUCT }, \
+}
+
+#ifdef _KERNEL
+
+#include <machine/psl.h>
+#include <machine/pcb.h>
+#include <machine/board.h>
+
+/*
+ * definitions of cpu-dependent requirements
+ * referenced in generic code
+ */
+#define cpu_exec(p) /* nothing */
+#define cpu_wait(p) /* nothing */
+#define cpu_swapout(p) /* nothing */
+
+/*
+ * Arguments to hardclock and gatherstats encapsulate the previous
+ * machine state in an opaque clockframe. CLKF_INTR is only valid
+ * if the process is in kernel mode. Clockframe is really trapframe,
+ * so pointer to clockframe can be safely cast into a pointer to
+ * trapframe.
+ */
+struct clockframe {
+ struct trapframe tf;
+};
+
+#define CLKF_USERMODE(framep) ((((struct trapframe *)(framep))->tf_epsr & PSR_MODE) == 0)
+#define CLKF_PC(framep) (((struct trapframe *)(framep))->tf_sxip & XIP_ADDR)
+#define CLKF_INTR(framep) (((struct trapframe *)(framep))->tf_r[31] >= UADDR)
+
+/*
+ * Get interrupt glue.
+ */
+#include <machine/intr.h>
+
+/*
+ * Internal IO space (iiomapsize).
+ *
+ * Internal IO space is mapped in the kernel from ``OBIO_START'' to
+ * ``intiolimit'' (defined in locore.s). Since it is always mapped,
+ * conversion between physical and kernel virtual addresses is easy.
+ */
+
+#ifdef VIRTMAP
+/* This will do non 1:1 phys/virt memory mapping in the future - SPM */
+#define ISIIOVA(va) \
+ ((char *)(va) >= intiobase && (char *)(va) < intiolimit)
+#define IIOV(pa) ((int)(pa)-(int)iiomapbase+(int)intiobase)
+#define IIOP(va) ((int)(va)-(int)intiobase+(int)iiomapbase)
+#define IIOPOFF(pa) ((int)(pa)-(int)iiomapbase)
+
+#else
+
+#define ISIIOVA(va) 1
+#define IIOV(pa) ((pa))
+#define IIOP(va) ((va))
+#define IIOPOFF(pa) ((int)(pa)-(int)OBIO_START)
+#endif
+
+#define SIR_NET 1
+#define SIR_CLOCK 2
+
+#define setsoftint(x) (ssir |= (x))
+#define setsoftnet() (ssir |= SIR_NET)
+#define setsoftclock() (ssir |= SIR_CLOCK)
+
+#define siroff(x) (ssir &= ~x)
+
+extern int ssir;
+extern int want_ast;
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+extern int want_resched; /* resched() was called */
+#define need_resched() (want_resched = 1, want_ast = 1)
+
+/*
+ * Give a profiling tick to the current process when the user profiling
+ * buffer pages are invalid. On the sparc, request an ast to send us
+ * through trap(), marking the proc as needing a profiling tick.
+ */
+#define need_proftick(p) ((p)->p_flag |= P_OWEUPC, want_ast = 1)
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+#define signotify(p) (want_ast = 1)
+
+struct intrhand {
+ int (*ih_fn)(void *);
+ void *ih_arg;
+ int ih_ipl;
+ int ih_wantframe;
+ struct intrhand *ih_next;
+};
+
+int intr_establish(int vec, struct intrhand *);
+
+/*
+ * return values for intr_establish()
+ */
+
+#define INTR_EST_SUCC 0
+#define INTR_EST_BADVEC 1
+#define INTR_EST_BADIPL 2
+
+
+/*
+ * There are 256 possible vectors on a MVME1x7 platform (including
+ * onboard and VME vectors. Use intr_establish() to register a
+ * handler for the given vector. vector number is used to index
+ * into the intr_handlers[] table.
+ */
+extern struct intrhand *intr_handlers[256];
+
+/*
+ * switchframe - should be double word aligned.
+ */
+struct switchframe {
+ u_int sf_pc; /* pc */
+ void *sf_proc; /* proc pointer */
+};
+
+/* This struct defines the machine dependent pointers */
+struct md_p {
+ void (*clock_init_func)(void); /* interval clock init function */
+ void (*statclock_init_func)(void); /* statistics clock init function */
+ void (*delayclock_init_func)(void); /* delay clock init function */
+ void (*delay_func)(void); /* delay clock function */
+ void (*interrupt_func)(u_int, struct trapframe *); /* interrupt func */
+ u_char *volatile intr_mask;
+ u_char *volatile intr_ipl;
+ u_char *volatile intr_src;
+};
+
+extern struct md_p md;
+
+int badvaddr(vaddr_t, int);
+void nmihand(void *);
+
+#endif /* _KERNEL */
+#endif /* __MACHINE_CPU_H__ */
diff --git a/sys/arch/luna88k/include/cpu_number.h b/sys/arch/luna88k/include/cpu_number.h
new file mode 100644
index 00000000000..c8d50b3ab6b
--- /dev/null
+++ b/sys/arch/luna88k/include/cpu_number.h
@@ -0,0 +1,47 @@
+/* $OpenBSD: cpu_number.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _M88K_CPU_NUMBER_
+#define _M88K_CPU_NUMBER_
+
+#ifdef _KERNEL
+#ifndef _LOCORE
+#include <machine/param.h>
+
+static unsigned cpu_number(void);
+
+static __inline__ unsigned cpu_number(void)
+{
+ unsigned cpu;
+
+ __asm__ ("ldcr %0, cr18" : "=r" (cpu));
+ return (cpu & 3);
+}
+#endif /* _LOCORE */
+#endif /* _KERNEL */
+#endif /* _M88K_CPU_NUMBER_ */
diff --git a/sys/arch/luna88k/include/cpus.h b/sys/arch/luna88k/include/cpus.h
new file mode 100644
index 00000000000..6270f10b20a
--- /dev/null
+++ b/sys/arch/luna88k/include/cpus.h
@@ -0,0 +1,65 @@
+/* $OpenBSD: cpus.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *
+ * HISTORY
+ */
+/*
+ Versions Idents for 88k family chips
+ */
+
+#ifndef __MACHINE_CPUS_H__
+#define __MACHINE_CPUS_H__
+
+/*
+ * cpu Processor Identification Register (PID).
+ */
+#ifndef _LOCORE
+union cpupid {
+ unsigned cpupid;
+ struct {
+ unsigned
+ /*empty*/:16,
+ arc:8,
+ version:7,
+ master:1;
+ } m88100;
+ struct {
+ unsigned
+ id:8,
+ type:3,
+ version:5,
+ /*empty*/:16;
+ } m88200;
+};
+#endif /* _LOCORE */
+
+#define M88100_ID 0
+#define M88200_ID 5
+#define M88204_ID 6
+
+#endif /* __MACHINE_CPUS_H__ */
diff --git a/sys/arch/luna88k/include/db_machdep.h b/sys/arch/luna88k/include/db_machdep.h
new file mode 100644
index 00000000000..ab6e904a394
--- /dev/null
+++ b/sys/arch/luna88k/include/db_machdep.h
@@ -0,0 +1,167 @@
+/* $OpenBSD: db_machdep.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Machine-dependent defined for the new kernel debugger
+ */
+
+#ifndef _M88K_DB_MACHDEP_H_
+#define _M88K_DB_MACHDEP_H_
+
+/* trap numbers used by ddb */
+#define DDB_ENTRY_BKPT_NO 130
+#define DDB_ENTRY_TRACE_NO 131
+#define DDB_ENTRY_TRAP_NO 132
+
+#ifndef _LOCORE
+
+#include <machine/pcb.h>
+#include <machine/trap.h>
+
+#include <uvm/uvm_param.h>
+
+/*
+ * The low two bits of sxip, snip, sfip have valid bits
+ * in them that need to masked to get the correct addresses
+ */
+#define PC_REGS(regs) \
+ cputyp == CPU_88110 ? ((regs)->exip & ~3) : \
+ (((regs)->sxip & 2) ? (regs)->sxip & ~3 : \
+ ((regs)->snip & 2 ? (regs)->snip & ~3 : (regs)->sfip & ~3))
+
+/* inst_return(ins) - is the instruction a function call return.
+ * Not mutually exclusive with inst_branch. Should be a jmp r1. */
+#define inst_return(I) (((I)&0xfffffbffU) == 0xf400c001U ? TRUE : FALSE)
+
+/*
+ * inst_call - function call predicate: is the instruction a function call.
+ * Could be either bsr or jsr
+ */
+#define inst_call(I) ({ unsigned i = (I); \
+ ((((i) & 0xf8000000U) == 0xc8000000U || /*bsr*/ \
+ ((i) & 0xfffffbe0U) == 0xf400c800U) /*jsr*/ \
+ ? TRUE : FALSE) \
+;})
+
+#ifdef DDB
+
+/*
+ * This is a hack so that mc88100 can use software single step
+ * and mc88110 can use the wonderful hardware single step
+ * feature. XXX smurph
+ */
+#define INTERNAL_SSTEP /* Use local Single Step routines */
+
+#define BKPT_SIZE (4) /* number of bytes in bkpt inst. */
+#define BKPT_INST (0xF000D000 | DDB_ENTRY_BKPT_NO) /* tb0, 0,r0, vector 130 */
+#define BKPT_SET(inst) (BKPT_INST)
+
+/* Entry trap for the debugger - used for inline assembly breaks*/
+#define ENTRY_ASM "tb0 0, r0, 132"
+
+typedef vaddr_t db_addr_t;
+typedef long db_expr_t;
+typedef struct reg db_regs_t;
+extern db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+extern int db_noisy;
+
+unsigned inst_load(unsigned);
+unsigned inst_store(unsigned);
+boolean_t inst_branch(unsigned);
+db_addr_t next_instr_address(db_addr_t, unsigned);
+db_addr_t branch_taken(u_int, db_addr_t, db_expr_t (*)(db_regs_t *, int),
+ db_regs_t *);
+int ddb_break_trap(int type, db_regs_t *eframe);
+int ddb_entry_trap(int level, db_regs_t *eframe);
+
+/* breakpoint/watchpoint foo */
+#define IS_BREAKPOINT_TRAP(type,code) ((type)==T_KDB_BREAK)
+#if defined(T_WATCHPOINT)
+#define IS_WATCHPOINT_TRAP(type,code) ((type)==T_KDB_WATCH)
+#else
+#define IS_WATCHPOINT_TRAP(type,code) 0
+#endif /* T_WATCHPOINT */
+
+/* we don't want coff support */
+#define DB_NO_COFF 1
+
+#ifdef INTERNAL_SSTEP
+db_expr_t getreg_val(db_regs_t *, int);
+void db_set_single_step(db_regs_t *);
+void db_clear_single_step(db_regs_t *);
+#else
+/* need software single step */
+#define SOFTWARE_SSTEP 1 /* we need this for mc88100 */
+#endif
+
+/*
+ * Debugger can get to any address space
+ */
+
+#define DB_ACCESS_LEVEL DB_ACCESS_ANY
+
+#define DB_VALID_KERN_ADDR(addr) (!badaddr((void *)(addr), 1))
+#define DB_VALID_ADDRESS(addr,user) \
+ (user ? db_check_user_addr(addr) : DB_VALID_KERN_ADDR(addr))
+
+/* instruction type checking - others are implemented in db_sstep.c */
+
+#define inst_trap_return(ins) ((ins) == 0xf400fc00U)
+
+/* don't need to load symbols */
+#define DB_SYMBOLS_PRELOADED 1
+
+/* machine specific commands have been added to ddb */
+#define DB_MACHINE_COMMANDS 1
+
+/*
+ * This routine should return true for instructions that result in unconditonal
+ * transfers of the flow of control. (Unconditional Jumps, subroutine calls,
+ * subroutine returns, etc).
+ *
+ * Trap and return from trap should not be listed here.
+ */
+#define inst_unconditional_flow_transfer(I) ({ unsigned i = (I); \
+ ((((i) & 0xf0000000U) == 0xc0000000U || /* br, bsr */ \
+ ((i) & 0xfffff3e0U) == 0xf400c000U) /* jmp, jsr */ \
+ ? TRUE: FALSE) \
+;})
+
+/* Return true if the instruction has a delay slot. */
+#define db_branch_is_delayed(I) inst_delayed(I)
+
+#define db_printf_enter db_printing
+
+int m88k_print_instruction(unsigned iadr, long inst);
+
+#endif /* DDB */
+#endif /* _LOCORE */
+
+#endif /* _M88K_DB_MACHDEP_H_ */
diff --git a/sys/arch/luna88k/include/disklabel.h b/sys/arch/luna88k/include/disklabel.h
new file mode 100644
index 00000000000..4ca457a73cd
--- /dev/null
+++ b/sys/arch/luna88k/include/disklabel.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: disklabel.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/* $NetBSD: disklabel.h,v 1.2 2000/01/28 02:25:24 nisimura Exp $ */
+
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MACHINE_DISKLABEL_H_
+#define _MACHINE_DISKLABEL_H_
+
+#define LABELSECTOR 0 /* sector containing label */
+#define LABELOFFSET 64 /* offset of label in sector */
+#define MAXPARTITIONS 16 /* number of partitions */
+#define RAW_PART 2 /* raw partition: xx?c */
+
+/*
+ * This holds a copy of the whole label block, saved in here by
+ * readdisklabel() so that writedisklabel() can preserve the
+ * parts of the label block outside of the actual label.
+ * (i.e. Sun label info, bad block table, etc.)
+ */
+struct cpu_disklabel {
+ char cd_block[512];
+};
+
+#endif /* _MACHINE_DISKLABEL_H_ */
diff --git a/sys/arch/luna88k/include/endian.h b/sys/arch/luna88k/include/endian.h
new file mode 100644
index 00000000000..a42313b07e3
--- /dev/null
+++ b/sys/arch/luna88k/include/endian.h
@@ -0,0 +1,36 @@
+/* $OpenBSD: endian.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+
+/*-
+ * Copyright (c) 1997 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MVME88K_ENDIAN_H__
+#define __MVME88K_ENDIAN_H__
+
+#define BYTE_ORDER BIG_ENDIAN
+#include <sys/endian.h>
+
+#define __STRICT_ALIGNMENT
+
+#endif /* __MVME88K_ENDIAN_H__ */
+
diff --git a/sys/arch/luna88k/include/exec.h b/sys/arch/luna88k/include/exec.h
new file mode 100644
index 00000000000..0ad476ff297
--- /dev/null
+++ b/sys/arch/luna88k/include/exec.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: exec.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+#ifndef __MACHINE_EXEC_H__
+#define __MACHINE_EXEC_H__
+
+#define __LDPGSZ 4096
+
+struct relocation_info_m88k {
+ unsigned int r_address; /* offset in text or data segment */
+ unsigned int r_symbolnum : 24, /* ordinal number of add symbol */
+ r_extern : 1, /* 1 if need to add symbol to value */
+ r_baserel : 1,
+ r_pcrel : 1,
+ r_jmptable : 1,
+ r_type : 4;
+
+ int r_addend;
+};
+#define relocation_info relocation_info_m88k
+
+#define ARCH_ELFSIZE 32
+
+#define ELF_TARG_CLASS ELFCLASS32
+#define ELF_TARG_DATA ELFDATA2MSB
+#define ELF_TARG_MACH EM_88K
+
+#define _NLIST_DO_AOUT
+#define _NLIST_DO_ELF
+
+#define _KERN_DO_AOUT
+#define _KERN_DO_ELF
+
+#endif /* __MACHINE_EXEC_H__ */
diff --git a/sys/arch/luna88k/include/float.h b/sys/arch/luna88k/include/float.h
new file mode 100644
index 00000000000..8abc3de9f17
--- /dev/null
+++ b/sys/arch/luna88k/include/float.h
@@ -0,0 +1,76 @@
+/* $OpenBSD: float.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)float.h 7.1 (Berkeley) 5/8/90
+ */
+
+#ifndef __M88K_FLOAT_H__
+#define __M88K_FLOAT_H__
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int __flt_rounds(void);
+__END_DECLS
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS __flt_rounds()
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP -125 /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP -37 /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP -1021
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP -307
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
+
+#endif /* __M88K_FLOAT_H__ */
diff --git a/sys/arch/luna88k/include/frame.h b/sys/arch/luna88k/include/frame.h
new file mode 100644
index 00000000000..ab28bb5cf49
--- /dev/null
+++ b/sys/arch/luna88k/include/frame.h
@@ -0,0 +1,49 @@
+/* $OpenBSD: frame.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/* $NetBSD: frame.h,v 1.15 1997/05/03 12:49:05 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: frame.h 1.8 92/12/20$
+ *
+ * @(#)frame.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _M88K_FRAME_H_
+#define _M88K_FRAME_H_
+
+struct frame {
+ struct trapframe __packed F_t;
+};
+
+#endif /* _M88K_FRAME_H_ */
diff --git a/sys/arch/luna88k/include/ieee.h b/sys/arch/luna88k/include/ieee.h
new file mode 100644
index 00000000000..2d769d2a8a3
--- /dev/null
+++ b/sys/arch/luna88k/include/ieee.h
@@ -0,0 +1,142 @@
+/* $OpenBSD: ieee.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ieee.h 8.1 (Berkeley) 6/11/93
+ */
+/*
+ * Stolen from sparc port
+ */
+
+/*
+ * ieee.h defines the machine-dependent layout of the machine's IEEE
+ * floating point. It does *not* define (yet?) any of the rounding
+ * mode bits, exceptions, and so forth.
+ */
+
+/*
+ * Define the number of bits in each fraction and exponent.
+ *
+ * k k+1
+ * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented
+ *
+ * (-exp_bias+1)
+ * as fractions that look like 0.fffff x 2 . This means that
+ *
+ * -126
+ * the number 0.10000 x 2 , for instance, is the same as the normalized
+ *
+ * -127 -128
+ * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero
+ *
+ * -129
+ * in the fraction; to represent 2 , we need two, and so on. This
+ *
+ * (-exp_bias-fracbits+1)
+ * implies that the smallest denormalized number is 2
+ *
+ * for whichever format we are talking about: for single precision, for
+ *
+ * -126 -149
+ * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and
+ *
+ * -149 == -127 - 23 + 1.
+ */
+#ifndef __MACHINE_IEEE_H__
+#define __MACHINE_IEEE_H__
+#define SNG_EXPBITS 8
+#define SNG_FRACBITS 23
+
+#define DBL_EXPBITS 11
+#define DBL_FRACBITS 52
+
+#ifdef notyet
+#define E80_EXPBITS 15
+#define E80_FRACBITS 64
+#endif
+
+#define EXT_EXPBITS 15
+#define EXT_FRACBITS 112
+
+struct ieee_single {
+ u_int sng_sign:1;
+ u_int sng_exp:8;
+ u_int sng_frac:23;
+};
+
+struct ieee_double {
+ u_int dbl_sign:1;
+ u_int dbl_exp:11;
+ u_int dbl_frach:20;
+ u_int dbl_fracl;
+};
+
+struct ieee_ext {
+ u_int ext_sign:1;
+ u_int ext_exp:15;
+ u_int ext_frach:16;
+ u_int ext_frachm;
+ u_int ext_fraclm;
+ u_int ext_fracl;
+};
+
+/*
+ * Floats whose exponent is in [1..INFNAN) (of whatever type) are
+ * `normal'. Floats whose exponent is INFNAN are either Inf or NaN.
+ * Floats whose exponent is zero are either zero (iff all fraction
+ * bits are zero) or subnormal values.
+ *
+ * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its
+ * high fraction; if the bit is set, it is a `quiet NaN'.
+ */
+#define SNG_EXP_INFNAN 255
+#define DBL_EXP_INFNAN 2047
+#define EXT_EXP_INFNAN 32767
+
+#if 0
+#define SNG_QUIETNAN (1 << 22)
+#define DBL_QUIETNAN (1 << 19)
+#define EXT_QUIETNAN (1 << 15)
+#endif
+
+/*
+ * Exponent biases.
+ */
+#define SNG_EXP_BIAS 127
+#define DBL_EXP_BIAS 1023
+#define EXT_EXP_BIAS 16383
+#endif /* __MACHINE_IEEE_H__ */
diff --git a/sys/arch/luna88k/include/ieeefp.h b/sys/arch/luna88k/include/ieeefp.h
new file mode 100644
index 00000000000..f09891419a0
--- /dev/null
+++ b/sys/arch/luna88k/include/ieeefp.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: ieeefp.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Values for fp_except are selected to match the bits in FPSR (see
+ * m88100 user's manual page 6-33). This file is derived from the
+ * definitions in the ABI/88k manual and sparc port.
+ * -- Nivas
+ */
+
+#ifndef _M88K_IEEEFP_H_
+#define _M88K_IEEEFP_H_
+
+typedef int fp_except;
+#define FP_X_INV 0x10 /* invalid operation exception */
+#define FP_X_DZ 0x08 /* divide-by-zero exception */
+#define FP_X_UFL 0x04 /* underflow exception */
+#define FP_X_OFL 0x02 /* overflow exception */
+#define FP_X_IMP 0x01 /* imprecise (loss of precision) */
+
+typedef enum {
+ FP_RN=0, /* round to nearest representable number */
+ FP_RZ=1, /* round to zero (truncate) */
+ FP_RM=2, /* round toward negative infinity */
+ FP_RP=3 /* round toward positive infinity */
+} fp_rnd;
+
+#endif /* _M88K_IEEEFP_H_ */
diff --git a/sys/arch/luna88k/include/internal_types.h b/sys/arch/luna88k/include/internal_types.h
new file mode 100644
index 00000000000..c54d7069649
--- /dev/null
+++ b/sys/arch/luna88k/include/internal_types.h
@@ -0,0 +1,6 @@
+/* $OpenBSD: internal_types.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/* Public domain */
+#ifndef _MACHINE_INTERNAL_TYPES_H_
+#define _MACHINE_INTERNAL_TYPES_H_
+
+#endif
diff --git a/sys/arch/luna88k/include/intr.h b/sys/arch/luna88k/include/intr.h
new file mode 100644
index 00000000000..b7855664edc
--- /dev/null
+++ b/sys/arch/luna88k/include/intr.h
@@ -0,0 +1,132 @@
+/* $OpenBSD: intr.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (C) 2000 Steve Murphree, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LUNA88K_INTR_H_
+#define _LUNA88K_INTR_H_
+/*
+ * INTERRUPT STAT levels. for 'systat vmstat'
+ * intrcnt and friends are defined in locore.S
+ * XXX smurph
+ */
+
+#ifndef _LOCORE
+
+#define M88K_NIRQ 12
+
+#define M88K_SPUR_IRQ 0
+#define M88K_LEVEL1_IRQ 1
+#define M88K_LEVEL2_IRQ 2
+#define M88K_LEVEL3_IRQ 3
+#define M88K_LEVEL4_IRQ 4
+#define M88K_LEVEL5_IRQ 5
+#define M88K_LEVEL6_IRQ 6
+#define M88K_LEVEL7_IRQ 7
+/*
+ * We keep track of these separately, but
+ * they will be reflected with the above also.
+ */
+#define M88K_CLK_IRQ 8
+#define M88K_SCLK_IRQ 9
+#define M88K_PCLK_IRQ 10
+#define M88K_NMI_IRQ 11
+
+extern int intrcnt[M88K_NIRQ];
+
+#endif
+
+/*
+ * IPL levels.
+ */
+
+#define IPL_NONE 0
+#define IPL_SOFTCLOCK 1
+#define IPL_SOFTNET 1
+#define IPL_BIO 3
+#define IPL_NET 4
+#define IPL_IMP 4
+#define IPL_TTY 5
+#define IPL_VM 5
+#define IPL_CLOCK 6
+#define IPL_STATCLOCK 6
+#define IPL_HIGH 7
+#define IPL_NMI 7
+#define IPL_ABORT 7
+
+#ifdef _KERNEL
+#ifndef _LOCORE
+unsigned setipl(unsigned level);
+unsigned raiseipl(unsigned level);
+int spl0(void);
+
+/* needs major cleanup - XXX nivas */
+
+/* SPL asserts */
+#ifdef DIAGNOSTIC
+/*
+ * Although this function is implemented in MI code, it must be in this MD
+ * header because we don't want this header to include MI includes.
+ */
+void splassert_fail(int, int, const char *);
+extern int splassert_ctl;
+void splassert_check(int, const char *);
+#define splassert(__wantipl) do { \
+ if (__predict_false(splassert_ctl > 0)) { \
+ splassert_check(__wantipl, __func__); \
+ } \
+} while (0)
+#else
+#define splassert(wantipl) do { /* nothing */ } while (0)
+#endif
+
+#endif /* _LOCORE */
+
+#define spl1() setipl(1)
+#define spl2() setipl(2)
+#define spl3() setipl(3)
+#define spl4() setipl(4)
+#define spl5() setipl(5)
+#define spl6() setipl(6)
+#define spl7() setipl(7)
+
+#define splnone spl0
+#define spllowersoftclock() setipl(IPL_SOFTCLOCK)
+#define splsoftclock() setipl(IPL_SOFTCLOCK)
+#define splsoftnet() setipl(IPL_SOFTNET)
+#define splbio() raiseipl(IPL_BIO)
+#define splnet() raiseipl(IPL_NET)
+#define spltty() raiseipl(IPL_TTY)
+#define splclock() raiseipl(IPL_CLOCK)
+#define splstatclock() raiseipl(IPL_STATCLOCK)
+#define splimp() raiseipl(IPL_IMP)
+#define splvm() raiseipl(IPL_VM)
+#define splhigh() setipl(IPL_HIGH)
+
+#define splx(x) ((x) ? setipl((x)) : spl0())
+
+#endif /* _KERNEL */
+#endif /* _LUNA88K_INTR_H_ */
diff --git a/sys/arch/luna88k/include/kcore.h b/sys/arch/luna88k/include/kcore.h
new file mode 100644
index 00000000000..c2c6af6c2c6
--- /dev/null
+++ b/sys/arch/luna88k/include/kcore.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: kcore.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+
+/*
+ * Copyright (c) 2001 Miodrag Vallat.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MVME88K_KCORE_H_
+#define _MVME88K_KCORE_H_
+
+/* Keep this define consistent with VM_PHYSSEG_MAX in <machine/vmparam.h> */
+#define NPHYS_RAM_SEGS 1
+
+typedef struct cpu_kcore_hdr {
+ int cputype; /* board type: 187, 188, 197 */
+ phys_ram_seg_t ram_segs[NPHYS_RAM_SEGS];
+} cpu_kcore_hdr_t;
+
+#endif /* _MVME88K_KCORE_H_ */
diff --git a/sys/arch/luna88k/include/limits.h b/sys/arch/luna88k/include/limits.h
new file mode 100644
index 00000000000..1ad4a47fc77
--- /dev/null
+++ b/sys/arch/luna88k/include/limits.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: limits.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 8.3 (Berkeley) 1/4/94
+ */
+
+#ifndef _MACHINE_LIMITS_H_
+#define _MACHINE_LIMITS_H_
+
+#define MB_LEN_MAX 6 /* Allow 31 bit UTF2 */
+
+#if !defined(_ANSI_SOURCE)
+#define SIZE_MAX UINT_MAX /* max value for a size_t */
+#define SSIZE_MAX INT_MAX /* max value for a ssize_t */
+
+#if !defined(_POSIX_SOURCE)
+#define SIZE_T_MAX UINT_MAX /* max value for a size_t */
+
+/* GCC requires that quad constants be written as expressions. */
+#define UQUAD_MAX ((u_quad_t)0-1) /* max value for a uquad_t */
+ /* max value for a quad_t */
+#define QUAD_MAX ((quad_t)(UQUAD_MAX >> 1))
+#define QUAD_MIN (-QUAD_MAX-1) /* min value for a quad_t */
+#endif /* !_POSIX_SOURCE */
+#endif /* !_ANSI_SOURCE */
+
+#endif /* _MACHINE_LIMITS_H_ */
diff --git a/sys/arch/luna88k/include/locore.h b/sys/arch/luna88k/include/locore.h
new file mode 100644
index 00000000000..ab5b2368a77
--- /dev/null
+++ b/sys/arch/luna88k/include/locore.h
@@ -0,0 +1,84 @@
+/* $OpenBSD: locore.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+
+#ifndef _MACHINE_LOCORE_H_
+#define _MACHINE_LOCORE_H_
+
+#include <uvm/uvm_param.h>
+
+/*
+ * C prototypes for various routines defined in locore_* and friends
+ */
+
+/* locore_asm_routines.S */
+
+unsigned int do_load_word(vaddr_t address,
+ boolean_t supervisor_mode);
+unsigned int do_load_half(vaddr_t address,
+ boolean_t supervisor_mode);
+unsigned int do_load_byte(vaddr_t address,
+ boolean_t supervisor_mode);
+
+void do_store_word(vaddr_t address, unsigned int data,
+ boolean_t supervisor_mode);
+void do_store_half(vaddr_t address, unsigned int data,
+ boolean_t supervisor_mode);
+void do_store_byte(vaddr_t address, unsigned int data,
+ boolean_t supervisor_mode);
+
+unsigned do_xmem_word(vaddr_t address, unsigned int data,
+ boolean_t supervisor_mode);
+unsigned do_xmem_byte(vaddr_t address, unsigned int data,
+ boolean_t supervisor_mode);
+
+unsigned read_processor_identification_register(void);
+int badaddr(vaddr_t addr, int size);
+#define badwordaddr(x) badaddr(x, 4)
+void set_cpu_number(unsigned number);
+void doboot(void);
+
+int guarded_access(unsigned char *volatile address,
+ unsigned len, u_char *vec);
+
+/* locore_c_routines.c */
+
+void dae_print(unsigned *eframe);
+void data_access_emulation(unsigned *eframe);
+
+unsigned getipl(void);
+
+/* machdep.c */
+
+void _doboot(void);
+vaddr_t get_slave_stack(void);
+void slave_pre_main(void);
+int slave_main(void);
+int intr_findvec(int start, int end);
+void bugsyscall(void);
+void myetheraddr(u_char *cp);
+void dosoftint(void);
+void MY_info(struct trapframe *f, caddr_t p, int flags, char *s);
+void MY_info_done(struct trapframe *f, int flags);
+void luna88k_bootstrap(void);
+void luna88k_ext_int(u_int v, struct trapframe *eframe);
+unsigned int safe_level(unsigned mask, unsigned curlevel);
+
+/* eh.S */
+
+struct proc;
+void proc_do_uret(struct proc *);
+void sigsys(void);
+void sigtrap(void);
+void stepbpt(void);
+void userbpt(void);
+void syscall_handler(void);
+void m88110_sigsys(void);
+void m88110_sigtrap(void);
+void m88110_stepbpt(void);
+void m88110_userbpt(void);
+void m88110_syscall_handler(void);
+
+/* process.S */
+void savectx(struct pcb *);
+void switch_exit(struct proc *);
+
+#endif /* _MACHINE_LOCORE_H_ */
diff --git a/sys/arch/luna88k/include/m88100.h b/sys/arch/luna88k/include/m88100.h
new file mode 100644
index 00000000000..9609924e648
--- /dev/null
+++ b/sys/arch/luna88k/include/m88100.h
@@ -0,0 +1,59 @@
+/* $OpenBSD: m88100.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef __MACHINE_M88100_H__
+#define __MACHINE_M88100_H__
+
+/*
+ * 88100 RISC definitions
+ */
+
+/*
+ * DMT0, DMT1, DMT2 layout
+ *
+ * The DMT_SKIP bit is never set by the cpu. It is used to mark 'known'
+ * transactions so that they don't get processed a second time by
+ * data_access_emulation().
+ */
+#define DMT_SKIP 0x00010000 /* skip this dmt */
+#define DMT_BO 0x00008000 /* Byte-Ordering */
+#define DMT_DAS 0x00004000 /* Data Access Space */
+#define DMT_DOUB1 0x00002000 /* Double Word */
+#define DMT_LOCKBAR 0x00001000 /* Bud Lock */
+#define DMT_DREG 0x00000F80 /* Destination Registers 5bits */
+#define DMT_SIGNED 0x00000040 /* Sign-Extended Bit */
+#define DMT_EN 0x0000003C /* Byte Enable Bit */
+#define DMT_WRITE 0x00000002 /* Read/Write Transaction Bit */
+#define DMT_VALID 0x00000001 /* Valid Transaction Bit */
+
+#define DMT_DREGSHIFT 7
+#define DMT_ENSHIFT 2
+
+#define DMT_DREGBITS(x) (((x) & DMT_DREG) >> DMT_DREGSHIFT)
+#define DMT_ENBITS(x) (((x) & DMT_EN) >> DMT_ENSHIFT)
+
+#endif /* __MACHINE_M88100_H__ */
diff --git a/sys/arch/luna88k/include/m8820x.h b/sys/arch/luna88k/include/m8820x.h
new file mode 100644
index 00000000000..94454ec7b81
--- /dev/null
+++ b/sys/arch/luna88k/include/m8820x.h
@@ -0,0 +1,169 @@
+/* $OpenBSD: m8820x.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 2004, Miodrag Vallat.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef __MACHINE_M8820X_H__
+#define __MACHINE_M8820X_H__
+
+/*
+ * 8820x CMMU definitions
+ */
+
+/* CMMU registers */
+#define CMMU_IDR (0x000 / 4) /* CMMU id register */
+#define CMMU_SCR (0x004 / 4) /* system command register */
+#define CMMU_SSR (0x008 / 4) /* system status register */
+#define CMMU_SAR (0x00c / 4) /* system address register */
+#define CMMU_SCTR (0x104 / 4) /* system control register */
+#define CMMU_PFSR (0x108 / 4) /* P bus fault status register */
+#define CMMU_PFAR (0x10c / 4) /* P bus fault address register */
+#define CMMU_SAPR (0x200 / 4) /* supervisor area pointer register */
+#define CMMU_UAPR (0x204 / 4) /* user area pointer register */
+#define CMMU_BWP0 (0x400 / 4) /* block ATC writer port 0 */
+#define CMMU_BWP1 (0x404 / 4) /* block ATC writer port 1 */
+#define CMMU_BWP2 (0x408 / 4) /* block ATC writer port 2 */
+#define CMMU_BWP3 (0x40c / 4) /* block ATC writer port 3 */
+#define CMMU_BWP4 (0x410 / 4) /* block ATC writer port 4 */
+#define CMMU_BWP5 (0x414 / 4) /* block ATC writer port 5 */
+#define CMMU_BWP6 (0x418 / 4) /* block ATC writer port 6 */
+#define CMMU_BWP7 (0x41c / 4) /* block ATC writer port 7 */
+#define CMMU_BWP(n) (CMMU_BWP0 + (n))
+#define CMMU_CDP0 (0x800 / 4) /* cache data port 0 */
+#define CMMU_CDP1 (0x804 / 4) /* cache data port 1 */
+#define CMMU_CDP2 (0x808 / 4) /* cache data port 2 */
+#define CMMU_CDP3 (0x80c / 4) /* cache data port 3 */
+#define CMMU_CTP0 (0x840 / 4) /* cache tag port 0 */
+#define CMMU_CTP1 (0x844 / 4) /* cache tag port 1 */
+#define CMMU_CTP2 (0x848 / 4) /* cache tag port 2 */
+#define CMMU_CTP3 (0x84c / 4) /* cache tag port 3 */
+#define CMMU_CSSP0 (0x880 / 4) /* cache set status register */
+#define CMMU_CSSP(n) (CMMU_CSSP0 + (n))
+/* the following only exist on 88204 */
+#define CMMU_CSSP1 (0x890 / 4) /* cache set status register */
+#define CMMU_CSSP2 (0x8a0 / 4) /* cache set status register */
+#define CMMU_CSSP3 (0x8b0 / 4) /* cache set status register */
+
+/* system commands */
+#define CMMU_FLUSH_CACHE_INV_LINE 0x14 /* data cache invalidate */
+#define CMMU_FLUSH_CACHE_INV_PAGE 0x15
+#define CMMU_FLUSH_CACHE_INV_SEGMENT 0x16
+#define CMMU_FLUSH_CACHE_INV_ALL 0x17
+#define CMMU_FLUSH_CACHE_CB_LINE 0x18 /* data cache copyback */
+#define CMMU_FLUSH_CACHE_CB_PAGE 0x19
+#define CMMU_FLUSH_CACHE_CB_SEGMENT 0x1a
+#define CMMU_FLUSH_CACHE_CB_ALL 0x1b
+#define CMMU_FLUSH_CACHE_CBI_LINE 0x1c /* copyback and invalidate */
+#define CMMU_FLUSH_CACHE_CBI_PAGE 0x1d
+#define CMMU_FLUSH_CACHE_CBI_SEGMENT 0x1e
+#define CMMU_FLUSH_CACHE_CBI_ALL 0x1f
+#define CMMU_PROBE_USER 0x20 /* probe user address */
+#define CMMU_PROBE_SUPER 0x24 /* probe supervisor address */
+#define CMMU_FLUSH_USER_LINE 0x30 /* flush PATC */
+#define CMMU_FLUSH_USER_PAGE 0x31
+#define CMMU_FLUSH_USER_SEGMENT 0x32
+#define CMMU_FLUSH_USER_ALL 0x33
+#define CMMU_FLUSH_SUPER_LINE 0x34
+#define CMMU_FLUSH_SUPER_PAGE 0x35
+#define CMMU_FLUSH_SUPER_SEGMENT 0x36
+#define CMMU_FLUSH_SUPER_ALL 0x37
+
+/* system control values */
+#define CMMU_SCTR_PE 0x00008000 /* parity enable */
+#define CMMU_SCTR_SE 0x00004000 /* snoop enable */
+#define CMMU_SCTR_PR 0x00002000 /* priority arbitration */
+
+/* P bus fault status */
+#define CMMU_PFSR_FAULT(pfsr) (((pfsr) >> 16) & 0x07)
+#define CMMU_PFSR_SUCCESS 0 /* no fault */
+#define CMMU_PFSR_BERROR 3 /* bus error */
+#define CMMU_PFSR_SFAULT 4 /* segment fault */
+#define CMMU_PFSR_PFAULT 5 /* page fault */
+#define CMMU_PFSR_SUPER 6 /* supervisor violation */
+#define CMMU_PFSR_WRITE 7 /* writer violation */
+
+/* CSSP values */
+#define CMMU_CSSP_L5 0x20000000
+#define CMMU_CSSP_L4 0x10000000
+#define CMMU_CSSP_L3 0x08000000
+#define CMMU_CSSP_L2 0x04000000
+#define CMMU_CSSP_L1 0x02000000
+#define CMMU_CSSP_L0 0x01000000
+#define CMMU_CSSP_D3 0x00800000
+#define CMMU_CSSP_D2 0x00400000
+#define CMMU_CSSP_D1 0x00200000
+#define CMMU_CSSP_D0 0x00100000
+#define CMMU_CSSP_VV(n,v) (((v) & 0x03) << (12 + 2 * (n)))
+#define CMMU_VV_EXCLUSIVE 0x00
+#define CMMU_VV_MODIFIED 0x01
+#define CMMU_VV_SHARED 0x02
+#define CMMU_VV_INVALID 0x03
+
+/* IDR values */
+#define CMMU_ID(idr) ((idr) >> 24)
+#define CMMU_TYPE(idr) (((idr) >> 21) & 0x07)
+#define CMMU_VERSION(idr) (((idr) >> 16) & 0x1f)
+#define M88200_ID 5
+#define M88204_ID 6
+
+/* SSR values */
+#define CMMU_SSR_CE 0x00008000 /* copyback error */
+#define CMMU_SSR_BE 0x00004000 /* bus error */
+#define CMMU_SSR_BH 0x00000002 /* probe BATC hit */
+
+/*
+ * Cache line information
+ */
+
+#define MC88200_CACHE_SHIFT 4
+#define MC88200_CACHE_LINE (1 << MC88200_CACHE_SHIFT)
+
+#define NBSG (1 << (PDT_BITS + PG_BITS)) /* segment size */
+
+#endif /* __MACHINE_M8820X_H__ */
diff --git a/sys/arch/luna88k/include/mmu.h b/sys/arch/luna88k/include/mmu.h
new file mode 100644
index 00000000000..4d35be5be6d
--- /dev/null
+++ b/sys/arch/luna88k/include/mmu.h
@@ -0,0 +1,252 @@
+/* $OpenBSD: mmu.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+
+/*
+ * This file bears almost no resemblance to the original m68k file,
+ * so the following copyright notice is questionable, but we are
+ * nice people.
+ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: pte.h 1.13 92/01/20$
+ *
+ * @(#)pte.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _MACHINE_MMU_H_
+#define _MACHINE_MMU_H_
+
+/*
+ * Parameters which determine the 'geometry' of the m88K page tables in memory.
+ */
+
+#define SDT_BITS 10 /* M88K segment table size bits */
+#define PDT_BITS 10 /* M88K page table size bits */
+#define PG_BITS PAGE_SHIFT /* M88K hardware page size bits */
+
+/*
+ * Common fields for APR, SDT and PTE
+ */
+
+/* address frame */
+#define PG_FRAME 0xfffff000
+#define PG_SHIFT PG_BITS
+#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT)
+
+/* cache control bits */
+#define CACHE_DFL 0x00000000
+#define CACHE_INH 0x00000040 /* cache inhibit */
+#define CACHE_GLOBAL 0x00000080 /* global scope */
+#define CACHE_WT 0x00000200 /* write through */
+
+#define CACHE_MASK (CACHE_INH | CACHE_GLOBAL | CACHE_WT)
+
+/*
+ * Area descriptors
+ */
+
+#define APR_V 0x00000001 /* valid bit */
+
+/*
+ * 88200 PATC (TLB)
+ */
+
+#define PATC_ENTRIES 56
+
+/*
+ * BATC entries
+ */
+
+#define BATC_V 0x00000001
+#define BATC_PROT 0x00000002
+#define BATC_INH 0x00000004
+#define BATC_GLOBAL 0x00000008
+#define BATC_WT 0x00000010
+#define BATC_SO 0x00000020
+
+
+/*
+ * Segment table entries
+ */
+
+typedef u_int32_t sdt_entry_t;
+
+#define SDT_ENTRY_NULL ((sdt_entry_t *) 0)
+
+#define SG_V 0x00000001
+#define SG_NV 0x00000000
+#define SG_PROT 0x00000004
+#define SG_RO 0x00000004
+#define SG_RW 0x00000000
+#define SG_SO 0x00000100
+
+#define SDT_VALID(sdt) (*(sdt) & SG_V)
+#define SDT_SUP(sdt) (*(sdt) & SG_SO)
+#define SDT_WP(sdt) (*(sdt) & SG_PROT)
+
+/*
+ * Page table entries
+ */
+
+typedef u_int32_t pt_entry_t;
+
+#define PT_ENTRY_NULL ((pt_entry_t *) 0)
+
+#define PG_V 0x00000001
+#define PG_NV 0x00000000
+#define PG_PROT 0x00000004
+#define PG_U 0x00000008
+#define PG_M 0x00000010
+#define PG_RO 0x00000004
+#define PG_RW 0x00000000
+#define PG_SO 0x00000100
+#define PG_W 0x00000020 /* XXX unused but reserved field */
+#define PG_U0 0x00000400 /* U0 bit for M88110 */
+#define PG_U1 0x00000800 /* U1 bit for M88110 */
+
+#define PDT_VALID(pte) (*(pte) & PG_V)
+#define PDT_SUP(pte) (*(pte) & PG_SO)
+#define PDT_WP(pte) (*(pte) & PG_PROT)
+
+/*
+ * Indirect descriptors (mc81110)
+ */
+
+typedef u_int32_t pt_ind_entry_t;
+
+/* validity bits */
+#define IND_V 0x00000001
+#define IND_NV 0x00000000
+#define IND_MASKED 0x00000002
+#define IND_UNMASKED 0x00000003
+#define IND_MASK 0x00000003
+
+#define IND_FRAME 0xfffffffc
+#define IND_SHIFT 2
+
+#define IND_PDA(x) ((x) & IND_FRAME >> IND_SHIFT)
+
+/*
+ * Number of entries in a page table.
+ */
+
+#define SDT_ENTRIES (1<<(SDT_BITS))
+#define PDT_ENTRIES (1<<(PDT_BITS))
+
+/*
+ * Size in bytes of a single page table.
+ */
+
+#define SDT_SIZE (sizeof(sdt_entry_t) * SDT_ENTRIES)
+#define PDT_SIZE (sizeof(pt_entry_t) * PDT_ENTRIES)
+
+/*
+ * Shifts and masks
+ */
+
+#define SDT_SHIFT (PDT_BITS + PG_BITS)
+#define PDT_SHIFT (PG_BITS)
+
+#define SDT_MASK (((1 << SDT_BITS) - 1) << SDT_SHIFT)
+#define PDT_MASK (((1 << PDT_BITS) - 1) << PDT_SHIFT)
+
+#define SDTIDX(va) (((va) & SDT_MASK) >> SDT_SHIFT)
+#define PDTIDX(va) (((va) & PDT_MASK) >> PDT_SHIFT)
+
+/* XXX uses knowledge of pmap structure */
+#define SDTENT(map, va) ((sdt_entry_t *)((map)->pm_stab + SDTIDX(va)))
+
+/*
+ * Va spaces mapped by tables and PDT table group.
+ */
+
+#define PDT_VA_SPACE (PDT_ENTRIES * PAGE_SIZE)
+
+/*
+ * Number of sdt entries used to map user and kernel space.
+ */
+
+#define USER_SDT_ENTRIES SDTIDX(VM_MIN_KERNEL_ADDRESS)
+#define KERNEL_SDT_ENTRIES (SDT_ENTRIES - USER_SDT_ENTRIES)
+
+/*
+ * Parameters and macros for BATC
+ */
+
+/* number of bits to BATC shift (log2(BATC_BLKBYTES)) */
+#define BATC_BLKSHIFT 19
+/* 'block' size of a BATC entry mapping */
+#define BATC_BLKBYTES (1 << BATC_BLKSHIFT)
+/* BATC block mask */
+#define BATC_BLKMASK (BATC_BLKBYTES-1)
+/* number of BATC entries */
+#define BATC_MAX 8
+
+/* physical and logical block address */
+#define BATC_PSHIFT 6
+#define BATC_VSHIFT (BATC_PSHIFT + (32 - BATC_BLKSHIFT))
+
+#define BATC_BLK_ALIGNED(x) ((x & BATC_BLKMASK) == 0)
+
+#define M88K_BTOBLK(x) (x >> BATC_BLKSHIFT)
+
+/*
+ * DMA and caching control
+ */
+#define DMA_CACHE_SYNC 0x1
+#define DMA_CACHE_SYNC_INVAL 0x2
+#define DMA_CACHE_INV 0x3
+
+static pt_entry_t invalidate_pte(pt_entry_t *);
+static __inline__ pt_entry_t
+invalidate_pte(pt_entry_t *pte)
+{
+ pt_entry_t oldpte;
+
+ oldpte = PG_NV;
+ __asm__ __volatile__
+ ("xmem %0, %2, r0" : "=r"(oldpte) : "0"(oldpte), "r"(pte));
+ __asm__ __volatile__ ("tb1 0, r0, 0");
+ return oldpte;
+}
+
+extern vaddr_t kmapva;
+
+#define kvtopte(va) \
+ ((pt_entry_t *)(PG_PFNUM(*((sdt_entry_t *)kmapva + \
+ SDTIDX(va) + SDT_ENTRIES)) << PDT_SHIFT) + PDTIDX(va))
+
+u_int kvtop(vaddr_t);
+
+#endif /* __MACHINE_MMU_H__ */
diff --git a/sys/arch/luna88k/include/param.h b/sys/arch/luna88k/include/param.h
new file mode 100644
index 00000000000..b4d43f2595b
--- /dev/null
+++ b/sys/arch/luna88k/include/param.h
@@ -0,0 +1,183 @@
+/* $OpenBSD: param.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 1999 Steve Murphree, Jr.
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: machparam.h 1.11 89/08/14$
+ *
+ * @(#)param.h 7.8 (Berkeley) 6/28/91
+ */
+#ifndef _MACHINE_PARAM_H_
+#define _MACHINE_PARAM_H_
+
+#ifdef _KERNEL
+#ifndef _LOCORE
+#include <machine/cpu.h>
+#endif /* _LOCORE */
+#endif
+
+#define _MACHINE luna88k
+#define MACHINE "luna88k"
+#define _MACHINE_ARCH m88k
+#define MACHINE_ARCH "m88k"
+#define MID_MACHINE MID_M88K
+
+/*
+ * Round p (pointer or byte index) down to a correctly-aligned value
+ * for all data types (int, long, ...). The result is u_int and
+ * must be cast to any desired pointer type. ALIGN() is used for
+ * aligning stack, which needs to be on a double word boundary for
+ * 88k.
+ */
+
+#define ALIGNBYTES 15 /* 64 bit alignment */
+#define ALIGN(p) (((u_int)(p) + ALIGNBYTES) & ~ALIGNBYTES)
+#define ALIGNED_POINTER(p,t) ((((u_long)(p)) & (sizeof(t)-1)) == 0)
+
+#define NBPG (1 << PGSHIFT) /* bytes/page */
+#define PGOFSET (NBPG-1) /* byte offset into page */
+#define PGSHIFT 12 /* LOG2(NBPG) */
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (PAGE_SIZE - 1)
+
+#define NPTEPG (PAGE_SIZE / (sizeof(pt_entry_t)))
+
+/*
+ * The ROM monitor uses the bottom 128KB. The kernel will allocate PTEs to map this
+ * space, but the kernel must be linked with a start address past these 128KB.
+ */
+#define KERNBASE 0x00000000 /* start of kernel virtual */
+#define KERNTEXTOFF 0x00020000 /* start of kernel text */
+
+#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */
+#define DEV_BSIZE (1 << DEV_BSHIFT)
+#define BLKDEV_IOSIZE 2048
+#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */
+
+#define SSIZE 1 /* initial stack size/NBPG */
+#define SINCR 1 /* increment of stack/NBPG */
+
+#define UPAGES 3 /* pages of u-area */
+#define USPACE (UPAGES * NBPG)
+
+#define UADDR 0xeee00000 /* address of u */
+
+/*
+ * Constants related to network buffer management.
+ * MCLBYTES must be no larger than the software page size, and,
+ * on machines that exchange pages of input or output buffers with mbuf
+ * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple
+ * of the hardware page size.
+ */
+#define MSIZE 256 /* size of an mbuf */
+#define MCLSHIFT 11 /* convert bytes to m_buf clusters */
+#define MCLBYTES (1 << MCLSHIFT) /* size of a m_buf cluster */
+#define MCLOFSET (MCLBYTES - 1) /* offset within a m_buf cluster */
+
+#ifndef NMBCLUSTERS
+#ifdef GATEWAY
+#define NMBCLUSTERS 1024 /* map size, max cluster allocation */
+#else
+#define NMBCLUSTERS 512 /* map size, max cluster allocation */
+#endif
+#endif
+
+/*
+ * Minimum and maximum sizes of the kernel malloc arena in PAGE_SIZE-sized
+ * logical pages.
+ */
+#define NKMEMPAGES_MIN_DEFAULT ((4 * 1024 * 1024) >> PAGE_SHIFT)
+#define NKMEMPAGES_MAX_DEFAULT ((4 * 1024 * 1024) >> PAGE_SHIFT)
+
+#define MSGBUFSIZE PAGE_SIZE
+
+/* pages ("clicks") to disk blocks */
+#define ctod(x) ((x) << (PGSHIFT - DEV_BSHIFT))
+#define dtoc(x) ((x) >> (PGSHIFT - DEV_BSHIFT))
+
+/* pages to bytes */
+#define ctob(x) ((x) << PGSHIFT)
+#define btoc(x) (((x) + PGOFSET) >> PGSHIFT)
+
+/* bytes to disk blocks */
+#define btodb(x) ((x) >> DEV_BSHIFT)
+#define dbtob(x) ((x) << DEV_BSHIFT)
+
+/*
+ * Map a ``block device block'' to a file system block.
+ * This should be device dependent, and should use the bsize
+ * field from the disk label.
+ * For now though just use DEV_BSIZE.
+ */
+#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE))
+
+/*
+ * Get interrupt glue.
+ */
+#include <machine/intr.h>
+
+#ifdef _KERNEL
+extern void delay(int);
+#define DELAY(x) delay(x)
+
+extern int cputyp;
+extern int brdtyp;
+extern int cpumod;
+#endif
+
+/*
+ * Values for the brdtyp variable.
+ */
+#define BRD_187 0x187
+#define BRD_188 0x188
+#define BRD_197 0x197
+#define BRD_8120 0x8120
+
+/*
+ * Values for the cputyp variable.
+ */
+#define CPU_88100 0x100
+#define CPU_88110 0x110
+
+/*
+ * Values for the cpumod variable.
+ */
+#define MOD_LE 0x01
+#define MOD_SP 0x02
+#define MOD_DP 0x03
+
+#endif /* !_MACHINE_PARAM_H_ */
+
+
diff --git a/sys/arch/luna88k/include/pcb.h b/sys/arch/luna88k/include/pcb.h
new file mode 100644
index 00000000000..3df7ed511e6
--- /dev/null
+++ b/sys/arch/luna88k/include/pcb.h
@@ -0,0 +1,149 @@
+/* $OpenBSD: pcb.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Copyright (c) 1996 Nivas Madhur
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Motorola 88100 pcb definitions
+ *
+ */
+/*
+ */
+#ifndef _M88K_PCB_H_
+#define _M88K_PCB_H_
+
+#include <machine/reg.h>
+
+/*
+ * Our PCB is the regular PCB+Save area for kernel frame.
+ * Upon entering kernel mode from user land, save the user context
+ * in the saved_state area - this is passed as the exception frame.
+ * On a context switch, only registers that need to be saved by the
+ * C calling convention and few other regs (pc, psr etc) are saved
+ * in the kernel_state part of the PCB. Typically, trap frames are
+ * saved on the stack (by low level handlers or by hardware) but,
+ * we just decided to do it in the PCB.
+ */
+
+struct m88100_pcb {
+ unsigned pcb_pc; /* address to return */
+ unsigned pcb_ipl;
+ unsigned pcb_r14;
+ unsigned pcb_r15;
+ unsigned pcb_r16;
+ unsigned pcb_r17;
+ unsigned pcb_r18;
+ unsigned pcb_r19;
+ unsigned pcb_r20;
+ unsigned pcb_r21;
+ unsigned pcb_r22;
+ unsigned pcb_r23;
+ unsigned pcb_r24;
+ unsigned pcb_r25;
+ unsigned pcb_r26;
+ unsigned pcb_r27;
+ unsigned pcb_r28;
+ unsigned pcb_r29;
+ unsigned pcb_r30;
+ unsigned pcb_sp; /* kernel stack pointer */
+ /* floating-point state */
+ unsigned pcb_fcr62;
+ unsigned pcb_fcr63;
+};
+
+struct trapframe {
+ struct reg tf_regs;
+ register_t tf_vector; /* exception vector number */
+ register_t tf_mask; /* interrupt mask level */
+ register_t tf_mode; /* interrupt mode */
+ register_t tf_scratch1; /* reserved for use by locore */
+ register_t tf_ipfsr; /* P BUS status */
+ register_t tf_dpfsr; /* P BUS status */
+ register_t tf_cpu; /* cpu number */
+};
+
+#define tf_r tf_regs.r
+#define tf_sp tf_regs.r[31]
+#define tf_epsr tf_regs.epsr
+#define tf_fpsr tf_regs.fpsr
+#define tf_fpcr tf_regs.fpcr
+#define tf_sxip tf_regs.sxip
+#define tf_snip tf_regs.snip
+#define tf_sfip tf_regs.sfip
+#define tf_exip tf_regs.sxip
+#define tf_enip tf_regs.snip
+#define tf_ssbr tf_regs.ssbr
+#define tf_dmt0 tf_regs.dmt0
+#define tf_dmd0 tf_regs.dmd0
+#define tf_dma0 tf_regs.dma0
+#define tf_dmt1 tf_regs.dmt1
+#define tf_dmd1 tf_regs.dmd1
+#define tf_dma1 tf_regs.dma1
+#define tf_dmt2 tf_regs.dmt2
+#define tf_dmd2 tf_regs.dmd2
+#define tf_dma2 tf_regs.dma2
+#define tf_duap tf_regs.ssbr
+#define tf_dsr tf_regs.dmt0
+#define tf_dlar tf_regs.dmd0
+#define tf_dpar tf_regs.dma0
+#define tf_isr tf_regs.dmt1
+#define tf_ilar tf_regs.dmd1
+#define tf_ipar tf_regs.dma1
+#define tf_isap tf_regs.dmt2
+#define tf_dsap tf_regs.dmd2
+#define tf_iuap tf_regs.dma2
+#define tf_fpecr tf_regs.fpecr
+#define tf_fphs1 tf_regs.fphs1
+#define tf_fpls1 tf_regs.fpls1
+#define tf_fphs2 tf_regs.fphs2
+#define tf_fpls2 tf_regs.fpls2
+#define tf_fppt tf_regs.fppt
+#define tf_fprh tf_regs.fprh
+#define tf_fprl tf_regs.fprl
+#define tf_fpit tf_regs.fpit
+
+struct pcb
+{
+ struct m88100_pcb kernel_state;
+ struct trapframe user_state;
+ int pcb_onfault;
+};
+
+/*
+ * Location of saved user registers for the proc.
+ */
+#define USER_REGS(p) \
+ (((struct reg *)(&((p)->p_addr->u_pcb.user_state))))
+/*
+ * The pcb is augmented with machine-dependent additional data for
+ * core dumps. Note that the trapframe here is a copy of the one
+ * from the top of the kernel stack (included here so that the kernel
+ * stack itself need not be dumped).
+ */
+struct md_coredump {
+ struct trapframe md_tf;
+};
+
+#endif /* _M88K_PCB_H_ */
diff --git a/sys/arch/luna88k/include/pmap.h b/sys/arch/luna88k/include/pmap.h
new file mode 100644
index 00000000000..27ba17dd1b1
--- /dev/null
+++ b/sys/arch/luna88k/include/pmap.h
@@ -0,0 +1,77 @@
+/* $OpenBSD: pmap.h,v 1.1 2004/04/21 15:23:57 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ */
+#ifndef _MACHINE_PMAP_H_
+#define _MACHINE_PMAP_H_
+
+#include <machine/mmu.h>
+#include <machine/pcb.h>
+
+/*
+ * PMAP structure
+ */
+
+/* #define PMAP_USE_BATC */
+struct pmap {
+ sdt_entry_t *pm_stab; /* virtual pointer to sdt */
+ u_int32_t pm_apr;
+ int pm_count; /* reference count */
+ /* cpus using of this pmap; NCPU must be <= 32 */
+ u_int32_t pm_cpus;
+ struct simplelock pm_lock;
+ struct pmap_statistics pm_stats; /* pmap statistics */
+#ifdef PMAP_USE_BATC
+ u_int32_t pm_ibatc[BATC_MAX]; /* instruction BATCs */
+ u_int32_t pm_dbatc[BATC_MAX]; /* data BATCs */
+#endif
+};
+
+#define PMAP_NULL ((pmap_t) 0)
+
+/* The PV (Physical to virtual) List.
+ *
+ * For each vm_page_t, pmap keeps a list of all currently valid virtual
+ * mappings of that page. An entry is a pv_entry_t; the list is the
+ * pv_head_table. This is used by things like pmap_remove, when we must
+ * find and remove all mappings for a particular physical page.
+ */
+/* XXX - struct pv_entry moved to vmparam.h because of include ordering issues */
+
+typedef struct pmap *pmap_t;
+typedef struct pv_entry *pv_entry_t;
+
+#ifdef _KERNEL
+
+extern pmap_t kernel_pmap;
+extern struct pmap kernel_pmap_store;
+extern caddr_t vmmap;
+
+#define pmap_kernel() (&kernel_pmap_store)
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count)
+#define pmap_phys_address(frame) ((paddr_t)(ptoa(frame)))
+
+#define pmap_copy(dp,sp,d,l,s) do { /* nothing */ } while (0)
+#define pmap_update(pmap) do { /* nothing (yet) */ } while (0)
+
+#define pmap_clear_modify(pg) pmap_unsetbit(pg, PG_M)
+#define pmap_clear_reference(pg) pmap_unsetbit(pg, PG_U)
+
+void pmap_bootstrap(vaddr_t, paddr_t *, paddr_t *, vaddr_t *, vaddr_t *);
+void pmap_cache_ctrl(pmap_t, vaddr_t, vaddr_t, u_int);
+boolean_t pmap_unsetbit(struct vm_page *, int);
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_PMAP_H_ */
diff --git a/sys/arch/luna88k/include/pmap_table.h b/sys/arch/luna88k/include/pmap_table.h
new file mode 100644
index 00000000000..be2a91cb8b1
--- /dev/null
+++ b/sys/arch/luna88k/include/pmap_table.h
@@ -0,0 +1,49 @@
+/* $OpenBSD: pmap_table.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef __MACHINE_PMAP_TABLE_H__
+#define __MACHINE_PMAP_TABLE_H__
+
+/*
+ * Built-in mappings list.
+ * An entry is considered invalid if pm_size = 0, and
+ * end of list is indicated by pm_size 0xffffffff
+ */
+typedef struct {
+ vaddr_t phys_start; /* in bytes */
+ vaddr_t virt_start; /* in bytes */
+ vsize_t size; /* in bytes */
+ unsigned int prot; /* vm_prot_read, vm_prot_write */
+ unsigned int cacheability; /* none, writeback, normal */
+} pmap_table_entry;
+
+typedef const pmap_table_entry *pmap_table_t;
+
+pmap_table_t pmap_table_build(void);
+
+#endif /* __MACHINE_PMAP_TABLE_H__ */
+
diff --git a/sys/arch/luna88k/include/proc.h b/sys/arch/luna88k/include/proc.h
new file mode 100644
index 00000000000..f5e679e8957
--- /dev/null
+++ b/sys/arch/luna88k/include/proc.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: proc.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)proc.h 8.1 (Berkeley) 6/11/93
+ *
+ * from: Header: proc.h,v 1.6 92/11/26 02:04:41 torek Exp (LBL)
+ */
+
+#ifndef __MACHINE_PROC_H__
+#define __MACHINE_PROC_H__
+
+#include <machine/pcb.h>
+
+/*
+ * Machine-dependent part of the proc structure for mvme88k.
+ */
+struct mdproc {
+ struct trapframe *md_tf; /* trap/syscall registers */
+ struct fpstate *md_fpstate; /* fpu state, if any; always resident */
+ int md_upte[UPAGES]; /* ptes for mapping u page */
+
+ unsigned md_ss_addr; /* single step address for ptrace */
+ unsigned md_ss_instr; /* single step instruction for ptrace */
+ unsigned md_ss_taken_addr; /* single step address for ptrace */
+ unsigned md_ss_taken_instr; /* single step instruction for ptrace */
+};
+
+#endif /* __MACHINE_PROC_H__ */
+
diff --git a/sys/arch/luna88k/include/psl.h b/sys/arch/luna88k/include/psl.h
new file mode 100644
index 00000000000..82afeafef2a
--- /dev/null
+++ b/sys/arch/luna88k/include/psl.h
@@ -0,0 +1,93 @@
+/* $OpenBSD: psl.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ */
+
+#ifndef __M88K_PSL_H__
+#define __M88K_PSL_H__
+
+/*
+ * 88100 control registers
+ */
+
+/*
+ * processor identification register (PID)
+ */
+#define PID_ARN 0x0000FF00U /* architectural revision number */
+#define PID_VN 0x000000FEU /* version number */
+#define PID_MC 0x00000001U /* master/checker */
+
+/*
+ * processor status register
+ */
+
+#define PSR_MODE 0x80000000U /* supervisor/user mode */
+#define PSR_BO 0x40000000U /* byte-ordering 0:big 1:little */
+#define PSR_SER 0x20000000U /* 88110 serial mode */
+#define PSR_C 0x10000000U /* carry */
+#define PSR_SGN 0x04000000U /* 88110 Signed Immediate mode */
+#define PSR_SRM 0x02000000U /* 88110 Serialize Memory */
+#define PSR_TRACE 0x00800000U /* 88110 hardware trace */
+#define PSR_SFD 0x000003E0U /* SFU disable */
+#define PSR_SFD2 0x00000010U /* 88110 SFU2 (Graphics) disable */
+#define PSR_SFD1 0x00000008U /* SFU1 (FPU) disable */
+#define PSR_MXM 0x00000004U /* misaligned access enable */
+#define PSR_IND 0x00000002U /* interrupt disable */
+#define PSR_SFRZ 0x00000001U /* shadow freeze */
+
+#define PSR_SUPERVISOR (PSR_MODE | PSR_SFD)
+#define PSR_USER (PSR_SFD)
+#define PSR_SET_BY_USER (PSR_BO | PSR_SER | PSR_C | PSR_MXM)
+
+#define FIP_V 0x00000002U /* valid */
+#define FIP_E 0x00000001U /* exception */
+#define FIP_ADDR 0xFFFFFFFCU /* address mask */
+#define NIP_V 0x00000002U /* valid */
+#define NIP_E 0x00000001U /* exception */
+#define NIP_ADDR 0xFFFFFFFCU /* address mask */
+#define XIP_V 0x00000002U /* valid */
+#define XIP_E 0x00000001U /* exception */
+#define XIP_ADDR 0xFFFFFFFCU /* address mask */
+
+#endif /* __M88K_PSL_H__ */
+
diff --git a/sys/arch/luna88k/include/ptrace.h b/sys/arch/luna88k/include/ptrace.h
new file mode 100644
index 00000000000..d375507d13b
--- /dev/null
+++ b/sys/arch/luna88k/include/ptrace.h
@@ -0,0 +1,62 @@
+/* $OpenBSD: ptrace.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1999, Steve Murphree, Jr.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ptrace.h 8.1 (Berkeley) 6/11/93
+ *
+ * from: Header: ptrace.h,v 1.6 92/11/26 02:04:43 torek Exp (LBL)
+ */
+
+/*
+ * m88k-dependent ptrace definitions.
+ */
+
+#ifndef __MACHINE_PTRACE_H__
+#define __MACHINE_PTRACE_H__
+
+#define PT_STEP (PT_FIRSTMACH + 0)
+#define PT_GETREGS (PT_FIRSTMACH + 1)
+#define PT_SETREGS (PT_FIRSTMACH + 2)
+#define PT_GETFPREGS (PT_FIRSTMACH + 3)
+#define PT_SETFPREGS (PT_FIRSTMACH + 4)
+
+#ifdef _KERNEL
+int cpu_singlestep(struct proc *);
+#endif
+
+#endif /* __MACHINE_PTRACE_H__ */
diff --git a/sys/arch/luna88k/include/reg.h b/sys/arch/luna88k/include/reg.h
new file mode 100644
index 00000000000..893a32042ea
--- /dev/null
+++ b/sys/arch/luna88k/include/reg.h
@@ -0,0 +1,90 @@
+/* $OpenBSD: reg.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1999 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _M88K_REG_H_
+#define _M88K_REG_H_
+
+struct reg {
+ unsigned int r[32]; /* 0 - 31 */
+ unsigned int epsr; /* 32 */
+ unsigned int fpsr;
+ unsigned int fpcr;
+ unsigned int sxip;
+#define exip sxip /* mc88110 */
+ unsigned int snip;
+#define enip snip /* mc88110 */
+ unsigned int sfip;
+ unsigned int ssbr;
+#define duap ssbr /* mc88110 */
+ unsigned int dmt0;
+#define dsr dmt0 /* mc88110 */
+ unsigned int dmd0;
+#define dlar dmd0 /* mc88110 */
+ unsigned int dma0;
+#define dpar dma0 /* mc88110 */
+ unsigned int dmt1;
+#define isr dmt1 /* mc88110 */
+ unsigned int dmd1;
+#define ilar dmd1 /* mc88110 */
+ unsigned int dma1;
+#define ipar dma1 /* mc88110 */
+ unsigned int dmt2;
+#define isap dmt2 /* mc88110 */
+ unsigned int dmd2;
+#define dsap dmd2 /* mc88110 */
+ unsigned int dma2;
+#define iuap dma2 /* mc88110 */
+ unsigned int fpecr;
+ unsigned int fphs1;
+ unsigned int fpls1;
+ unsigned int fphs2;
+ unsigned int fpls2;
+ unsigned int fppt;
+ unsigned int fprh;
+ unsigned int fprl;
+ unsigned int fpit;
+};
+
+struct fpreg {
+ unsigned int fp_fpecr;
+ unsigned int fp_fphs1;
+ unsigned int fp_fpls1;
+ unsigned int fp_fphs2;
+ unsigned int fp_fpls2;
+ unsigned int fp_fppt;
+ unsigned int fp_fprh;
+ unsigned int fp_fprl;
+ unsigned int fp_fpit;
+};
+
+#endif /* _M88K_REG_H_ */
diff --git a/sys/arch/luna88k/include/setjmp.h b/sys/arch/luna88k/include/setjmp.h
new file mode 100644
index 00000000000..aa7ab9e888a
--- /dev/null
+++ b/sys/arch/luna88k/include/setjmp.h
@@ -0,0 +1,9 @@
+/* $OpenBSD: setjmp.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+/*
+ * machine/setjmp.h: machine dependent setjmp-related information.
+ */
+#ifndef __MACHINE_SETJMP_H__
+#define __MACHINE_SETJMP_H__
+#define _JBLEN 21 /* size, in longs, of a jmp_buf */
+#endif /* __MACHINE_SETJMP_H__ */
diff --git a/sys/arch/luna88k/include/signal.h b/sys/arch/luna88k/include/signal.h
new file mode 100644
index 00000000000..abda50594f8
--- /dev/null
+++ b/sys/arch/luna88k/include/signal.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: signal.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __MACHINE_SIGNAL_H__
+#define __MACHINE_SIGNAL_H__
+
+#include <machine/reg.h>
+
+typedef int sig_atomic_t;
+
+/*
+ * Information pushed on stack when a signal is delivered.
+ * This is used by the kernel to restore state following
+ * execution of the signal handler. It is also made available
+ * to the handler to allow it to restore state properly if
+ * a non-standard exit is performed.
+ *
+ * All machines must have an sc_onstack and sc_mask.
+ */
+struct sigcontext {
+ int sc_onstack; /* sigstack state to restore */
+ int sc_mask; /* signal mask to restore */
+ /* begin machine dependent portion */
+ struct reg sc_regs;
+};
+
+#endif /* __MACHINE_SIGNAL_H__ */
diff --git a/sys/arch/luna88k/include/spinlock.h b/sys/arch/luna88k/include/spinlock.h
new file mode 100644
index 00000000000..c9a2369f12f
--- /dev/null
+++ b/sys/arch/luna88k/include/spinlock.h
@@ -0,0 +1,10 @@
+/* $OpenBSD: spinlock.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+#ifndef _M88K_SPINLOCK_H_
+#define _M88K_SPINLOCK_H_
+
+#define _SPINLOCK_UNLOCKED (0)
+#define _SPINLOCK_LOCKED (1)
+typedef int _spinlock_lock_t;
+
+#endif
diff --git a/sys/arch/luna88k/include/stdarg.h b/sys/arch/luna88k/include/stdarg.h
new file mode 100644
index 00000000000..95f5e13ab06
--- /dev/null
+++ b/sys/arch/luna88k/include/stdarg.h
@@ -0,0 +1,16 @@
+/* $OpenBSD: stdarg.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+#ifndef _M88K_STDARGS_H_
+#define _M88K_STDARGS_H_
+
+#include <machine/ansi.h>
+
+#ifndef _STDARG_H
+#define _STDARG_H
+#endif
+
+#include <machine/va-m88k.h>
+
+typedef _BSD_VA_LIST_ va_list;
+
+#endif /* _M88K_STDARGS_H_ */
diff --git a/sys/arch/luna88k/include/trap.h b/sys/arch/luna88k/include/trap.h
new file mode 100644
index 00000000000..d328d37464e
--- /dev/null
+++ b/sys/arch/luna88k/include/trap.h
@@ -0,0 +1,78 @@
+/* $OpenBSD: trap.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Trap codes
+ */
+#ifndef __MACHINE_TRAP_H__
+#define __MACHINE_TRAP_H__
+
+/*
+ * Trap type values
+ */
+
+#define T_RESADFLT 0 /* reserved addressing fault */
+#define T_PRIVINFLT 1 /* privileged instruction fault */
+#define T_RESOPFLT 2 /* reserved operand fault */
+#define T_INSTFLT 3 /* instruction access exception */
+#define T_DATAFLT 4 /* data access exception */
+#define T_MISALGNFLT 5 /* misaligned access exception */
+#define T_ILLFLT 6 /* unimplemented opcode exception */
+#define T_BNDFLT 7 /* bounds check violation exception */
+#define T_ZERODIV 8 /* illegal divide exception */
+#define T_OVFFLT 9 /* integer overflow exception */
+#define T_ERRORFLT 10 /* error exception */
+#define T_FPEPFLT 11 /* floating point precise exception */
+#define T_FPEIFLT 12 /* floating point imprecise exception */
+#define T_ASTFLT 13 /* software trap */
+#define T_KDB_ENTRY 14 /* force entry to kernel debugger */
+#define T_KDB_BREAK 15 /* break point hit */
+#define T_KDB_TRACE 16 /* trace */
+#define T_UNKNOWNFLT 17 /* unknown exception */
+#define T_SIGTRAP 18 /* generate SIGTRAP */
+#define T_SIGSYS 19 /* generate SIGSYS */
+#define T_STEPBPT 20 /* special breakpoint for single step */
+#define T_USERBPT 21 /* user set breakpoint (for debugger) */
+#define T_SYSCALL 22 /* Syscall */
+#define T_NON_MASK 23 /* MVME197 Non-Maskable Interrupt */
+#define T_KDB_WATCH 24 /* watchpoint hit */
+#define T_197_READ 25 /* MVME197 Data Read Miss (Software Table Searches) */
+#define T_197_WRITE 26 /* MVME197 Data Write Miss (Software Table Searches) */
+#define T_197_INST 27 /* MVME197 Inst ATC Miss (Software Table Searches) */
+#define T_INT 28 /* interrupt exception */
+#define T_USER 29 /* user mode fault */
+
+#ifndef _LOCORE
+
+void m88100_trap(unsigned, struct trapframe *);
+void m88100_syscall(register_t, struct trapframe *);
+
+void m88110_trap(unsigned, struct trapframe *);
+void m88110_syscall(register_t, struct trapframe *);
+
+#endif /* _LOCORE */
+
+#endif /* __MACHINE_TRAP_H__ */
diff --git a/sys/arch/luna88k/include/types.h b/sys/arch/luna88k/include/types.h
new file mode 100644
index 00000000000..562e969a0ad
--- /dev/null
+++ b/sys/arch/luna88k/include/types.h
@@ -0,0 +1,80 @@
+/* $NetBSD: types.h,v 1.7 1995/07/05 17:46:11 pk Exp $ */
+/* $OpenBSD: types.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)types.h 8.1 (Berkeley) 6/11/93
+ */
+
+#ifndef _MACHTYPES_H_
+#define _MACHTYPES_H_
+
+#include <sys/cdefs.h>
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+typedef struct label_t {
+ int val[19];
+} label_t;
+#endif
+
+typedef unsigned long vaddr_t;
+typedef unsigned long paddr_t;
+typedef unsigned long vsize_t;
+typedef unsigned long psize_t;
+
+/*
+ * Basic integral types. Omit the typedef if
+ * not possible for a machine/compiler combination.
+ */
+#define __BIT_TYPES_DEFINED__
+typedef __signed char int8_t;
+typedef unsigned char u_int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short u_int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int u_int32_t;
+typedef unsigned int uint32_t;
+typedef long long int64_t;
+typedef unsigned long long u_int64_t;
+typedef unsigned long long uint64_t;
+
+typedef int32_t register_t;
+
+#endif /* _MACHTYPES_H_ */
diff --git a/sys/arch/luna88k/include/va-m88k.h b/sys/arch/luna88k/include/va-m88k.h
new file mode 100644
index 00000000000..4e1e6b58ea1
--- /dev/null
+++ b/sys/arch/luna88k/include/va-m88k.h
@@ -0,0 +1,82 @@
+/* $OpenBSD: va-m88k.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+/* This file has local changes by MOTOROLA
+Thu Sep 9 09:06:29 CDT 1993 Dale Rahn (drahn@pacific)
+ * Due to C-Front's usage of __alignof__ builtin the
+ usage of it must be changed to have an object of that type
+ as the argument not just the type.
+ */
+/* GNU C varargs support for the Motorola 88100 */
+
+/* Define __gnuc_va_list. */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+
+typedef struct __va_list_tag {
+ unsigned int __va_arg; /* argument number */
+ unsigned int *__va_stk; /* start of args passed on stack */
+ unsigned int *__va_reg; /* start of args passed in regs */
+} __va_list[1], __gnuc_va_list[1];
+
+#endif /* not __GNUC_VA_LIST */
+
+/* If this is for internal libc use, don't define anything but
+ __gnuc_va_list. */
+#if defined (_STDARG_H) || defined (_VARARGS_H)
+
+#define __va_start_common(AP,FAKE) \
+__extension__ ({ \
+ (AP) = (struct __va_list_tag *)__builtin_alloca(sizeof(__gnuc_va_list)); \
+ __builtin_memcpy ((AP), __builtin_saveregs (), sizeof(__gnuc_va_list)); \
+ })
+
+#ifdef _STDARG_H /* stdarg.h support */
+
+/* Calling __builtin_next_arg gives the proper error message if LASTARG is
+ not indeed the last argument. */
+#define va_start(AP,LASTARG) \
+ (__builtin_next_arg (LASTARG), __va_start_common (AP, 0))
+
+#else /* varargs.h support */
+
+#define va_start(AP) __va_start_common (AP, 1)
+#define va_alist __va_1st_arg
+#define va_dcl register int va_alist; ...
+
+#endif /* _STDARG_H */
+
+#define __va_reg_p(TYPE) \
+ (__builtin_classify_type(*(TYPE *)0) < 12 \
+ ? sizeof(TYPE) <= 8 : sizeof(TYPE) == 4 && __alignof__(*(TYPE *)0) == 4)
+
+#define __va_size(TYPE) ((sizeof(TYPE) + 3) >> 2)
+
+/* We cast to void * and then to TYPE * because this avoids
+ a warning about increasing the alignment requirement. */
+#define va_arg(AP,TYPE) \
+ ( (AP)->__va_arg = (((AP)->__va_arg + (1 << (__alignof__(*(TYPE *)0) >> 3)) - 1) \
+ & ~((1 << (__alignof__(*(TYPE *)0) >> 3)) - 1)) \
+ + __va_size(TYPE), \
+ *((TYPE *) (void *) ((__va_reg_p(TYPE) \
+ && (AP)->__va_arg < 8 + __va_size(TYPE) \
+ ? (AP)->__va_reg : (AP)->__va_stk) \
+ + ((AP)->__va_arg - __va_size(TYPE)))))
+
+#define va_end(AP)
+
+/* Copy __gnuc_va_list into another variable of this type. */
+#define __va_copy(dest, src) \
+__extension__ ({ \
+ (dest) = \
+ (struct __va_list_tag *)__builtin_alloca(sizeof(__gnuc_va_list)); \
+ *(dest) = *(src);\
+ })
+
+#if !defined(_ANSI_SOURCE) && \
+ (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE) || \
+ defined(_ISOC99_SOURCE) || (__STDC_VERSION__ - 0) >= 199901L)
+#define va_copy(dest, src) __va_copy(dest, src)
+#endif
+
+#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
diff --git a/sys/arch/luna88k/include/varargs.h b/sys/arch/luna88k/include/varargs.h
new file mode 100644
index 00000000000..f85d4737ace
--- /dev/null
+++ b/sys/arch/luna88k/include/varargs.h
@@ -0,0 +1,13 @@
+/* $OpenBSD: varargs.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+#ifndef _M88K_VARARGS_H_
+#define _M88K_VARARGS_H_
+
+#define _VARARGS_H
+
+#include <machine/ansi.h>
+#include <machine/va-m88k.h>
+
+typedef _BSD_VA_LIST_ va_list;
+
+#endif /* _M88K_VARARGS_H_ */
diff --git a/sys/arch/luna88k/include/vmparam.h b/sys/arch/luna88k/include/vmparam.h
new file mode 100644
index 00000000000..129ef221832
--- /dev/null
+++ b/sys/arch/luna88k/include/vmparam.h
@@ -0,0 +1,133 @@
+/* $OpenBSD: vmparam.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * machine dependent virtual memory parameters.
+ */
+
+
+#ifndef _MACHINE_VM_PARAM_
+#define _MACHINE_VM_PARAM_
+
+/*
+ * USRTEXT is the start of the user text/data space, while USRSTACK
+ * is the top (end) of the user stack.
+ */
+#define USRTEXT 0x1000 /* Start of user text */
+#define USRSTACK 0x80000000 /* Start of user stack */
+
+/*
+ * Virtual memory related constants, all in bytes
+ */
+#ifndef MAXTSIZ
+#define MAXTSIZ (8*1024*1024) /* max text size */
+#endif
+#ifndef DFLDSIZ
+#define DFLDSIZ (32*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ (64*1024*1024) /* max data size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ (2*1024*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ MAXDSIZ /* max stack size */
+#endif
+
+/*
+ * Size of shared memory map
+ */
+#ifndef SHMMAXPGS
+#define SHMMAXPGS 1024
+#endif
+
+/*
+ * The time for a process to be blocked before being very swappable.
+ * This is a number of seconds which the system takes as being a non-trivial
+ * amount of real time. You probably shouldn't change this;
+ * it is used in subtle ways (fractions and multiples of it are, that is, like
+ * half of a ``long time'', almost a long time, etc.)
+ * It is related to human patience and other factors which don't really
+ * change over time.
+ */
+#define MAXSLP 20
+
+#define VM_MIN_ADDRESS ((vaddr_t) 0)
+#define VM_MAX_ADDRESS ((vaddr_t) 0xffc00000)
+#define VM_MAXUSER_ADDRESS VM_MAX_ADDRESS
+
+/* on vme188, max = 0xf0000000 */
+
+#define VM_MIN_KERNEL_ADDRESS ((vaddr_t) 0)
+#define VM_MAX_KERNEL_ADDRESS ((vaddr_t) 0x20000000)
+
+#define KERNEL_STACK_SIZE (3 * PAGE_SIZE) /* kernel stack size */
+#define INTSTACK_SIZE (4 * PAGE_SIZE) /* interrupt stack size */
+
+/* virtual sizes (bytes) for various kernel submaps */
+#define VM_PHYS_SIZE (1 * NPTEPG * PAGE_SIZE)
+
+/*
+ * Constants which control the way the VM system deals with memory segments.
+ * The mvme88k only has one physical memory segment.
+ */
+#define VM_PHYSSEG_MAX 1
+#define VM_PHYSSEG_STRAT VM_PSTRAT_BSEARCH
+#define VM_PHYSSEG_NOADD
+
+#define VM_NFREELIST 1
+#define VM_FREELIST_DEFAULT 0
+
+#ifndef _LOCORE
+/*
+ * pmap-specific data stored in the vm_physmem[] array.
+ */
+
+/* XXX - belongs in pmap.h, but put here because of ordering issues */
+struct pv_entry {
+ struct pv_entry *pv_next; /* next pv_entry */
+ struct pmap *pv_pmap; /* pmap where mapping lies */
+ vaddr_t pv_va; /* virtual address for mapping */
+ int pv_flags;
+};
+
+#define __HAVE_VM_PAGE_MD
+struct vm_page_md {
+ struct pv_entry pvent;
+};
+
+#define VM_MDPAGE_INIT(pg) do { \
+ (pg)->mdpage.pvent.pv_next = NULL; \
+ (pg)->mdpage.pvent.pv_pmap = PMAP_NULL; \
+ (pg)->mdpage.pvent.pv_va = 0; \
+ (pg)->mdpage.pvent.pv_flags = 0; \
+} while (0)
+
+#endif /* _LOCORE */
+
+#endif /* _MACHINE_VM_PARAM_ */
diff --git a/sys/arch/luna88k/luna88k/autoconf.c b/sys/arch/luna88k/luna88k/autoconf.c
new file mode 100644
index 00000000000..39e645d0596
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/autoconf.c
@@ -0,0 +1,415 @@
+/* $OpenBSD: autoconf.c,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * Copyright (c) 1994 Christian E. Hopps
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christian E. Hopps.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/dkstat.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/kernel.h>
+
+#include <machine/asm_macro.h> /* enable/disable interrupts */
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/disklabel.h>
+#include <machine/vmparam.h>
+
+#include <dev/cons.h>
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+
+struct device *parsedisk(char *, int, int, dev_t *);
+void setroot(void);
+void swapconf(void);
+void dumpconf(void);
+int findblkmajor(struct device *);
+struct device *getdisk(char *, int, int, dev_t *);
+struct device *getdevunit(char *name, int unit);
+
+int cold = 1; /* 1 if still booting */
+
+void *bootaddr;
+int bootpart;
+struct device *bootdv; /* set by device drivers (if found) */
+
+/*
+ * called at boot time, configure all devices on the system.
+ */
+void
+cpu_configure()
+{
+
+ if (config_rootfound("mainbus", "mainbus") == 0)
+ panic("no mainbus found");
+
+ /*
+ * Turn external interrupts on.
+ *
+ * XXX We have a race here. If we enable interrupts after setroot(),
+ * the kernel dies.
+ */
+ enable_interrupt();
+ spl0();
+ setroot();
+ swapconf();
+
+ cold = 0;
+}
+
+/*
+ * Configure swap space and related parameters.
+ */
+void
+swapconf()
+{
+ struct swdevt *swp;
+ int nblks;
+
+ for (swp = swdevt; swp->sw_dev != NODEV; swp++)
+ if (bdevsw[major(swp->sw_dev)].d_psize) {
+ nblks =
+ (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
+ if (nblks != -1 &&
+ (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+ swp->sw_nblks = nblks;
+ swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
+ }
+
+ dumpconf();
+}
+
+/*
+ * the rest of this file was adapted from Theo de Raadt's code in the
+ * sparc port to nuke the "options GENERIC" stuff.
+ */
+
+struct nam2blk {
+ char *name;
+ int maj;
+} nam2blk[] = {
+ { "sd", 4 },
+ { "st", 5 },
+ { "rd", 7 },
+};
+
+int
+findblkmajor(dv)
+ struct device *dv;
+{
+ char *name = dv->dv_xname;
+ int i;
+
+ for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); ++i)
+ if (strncmp(name, nam2blk[i].name, strlen(nam2blk[0].name)) == 0)
+ return (nam2blk[i].maj);
+ return (-1);
+}
+
+struct device *
+getdisk(str, len, defpart, devp)
+ char *str;
+ int len, defpart;
+ dev_t *devp;
+{
+ struct device *dv;
+
+ if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
+ printf("use one of:");
+ for (dv = alldevs.tqh_first; dv != NULL;
+ dv = dv->dv_list.tqe_next) {
+ if (dv->dv_class == DV_DISK)
+ printf(" %s[a-p]", dv->dv_xname);
+#ifdef NFSCLIENT
+ if (dv->dv_class == DV_IFNET)
+ printf(" %s", dv->dv_xname);
+#endif
+ }
+ printf("\n");
+ }
+ return (dv);
+}
+
+struct device *
+parsedisk(str, len, defpart, devp)
+ char *str;
+ int len, defpart;
+ dev_t *devp;
+{
+ struct device *dv;
+ char *cp, c;
+ int majdev, unit, part;
+
+ if (len == 0)
+ return (NULL);
+ cp = str + len - 1;
+ c = *cp;
+ if (c >= 'a' && (c - 'a') < MAXPARTITIONS) {
+ part = c - 'a';
+ *cp = '\0';
+ } else
+ part = defpart;
+
+ for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
+ if (dv->dv_class == DV_DISK &&
+ strcmp(str, dv->dv_xname) == 0) {
+ majdev = findblkmajor(dv);
+ unit = dv->dv_unit;
+ if (majdev < 0)
+ panic("parsedisk");
+ *devp = MAKEDISKDEV(majdev, unit, part);
+ break;
+ }
+#ifdef NFSCLIENT
+ if (dv->dv_class == DV_IFNET &&
+ strcmp(str, dv->dv_xname) == 0) {
+ *devp = NODEV;
+ break;
+ }
+#endif
+ }
+
+ *cp = c;
+ return (dv);
+}
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ *
+ * XXX Actually, swap and root must be on the same type of device,
+ * (ie. DV_DISK or DV_IFNET) because of how (*mountroot) is written.
+ * That should be fixed.
+ */
+void
+setroot()
+{
+ struct swdevt *swp;
+ struct device *dv;
+ int len, majdev, unit;
+ dev_t nrootdev, nswapdev = NODEV;
+ char buf[128];
+ dev_t temp;
+#if defined(NFSCLIENT)
+ extern char *nfsbootdevname;
+#endif
+
+ printf("boot device: %s\n",
+ (bootdv) ? bootdv->dv_xname : "<unknown>");
+
+ if (boothowto & RB_ASKNAME) {
+ for (;;) {
+ printf("root device ");
+ if (bootdv != NULL)
+ printf("(default %s%c)",
+ bootdv->dv_xname,
+ bootdv->dv_class == DV_DISK ? 'a' : ' ');
+ printf(": ");
+ len = getsn(buf, sizeof(buf));
+ if (len == 0 && bootdv != NULL) {
+ strlcpy(buf, bootdv->dv_xname, sizeof buf);
+ len = strlen(buf);
+ }
+ if (len > 0 && buf[len - 1] == '*') {
+ buf[--len] = '\0';
+ dv = getdisk(buf, len, 1, &nrootdev);
+ if (dv) {
+ bootdv = dv;
+ nswapdev = nrootdev;
+ goto gotswap;
+ }
+ }
+ dv = getdisk(buf, len, 0, &nrootdev);
+ if (dv) {
+ bootdv = dv;
+ break;
+ }
+ }
+
+ /*
+ * because swap must be on same device as root, for
+ * network devices this is easy.
+ */
+ if (bootdv->dv_class == DV_IFNET) {
+ goto gotswap;
+ }
+ for (;;) {
+ printf("swap device ");
+ if (bootdv != NULL)
+ printf("(default %s%c)",
+ bootdv->dv_xname,
+ bootdv->dv_class == DV_DISK ? 'b' : ' ');
+ printf(": ");
+ len = getsn(buf, sizeof(buf));
+ if (len == 0 && bootdv != NULL) {
+ switch (bootdv->dv_class) {
+ case DV_IFNET:
+ nswapdev = NODEV;
+ break;
+ case DV_DISK:
+ nswapdev = MAKEDISKDEV(major(nrootdev),
+ DISKUNIT(nrootdev), 1);
+ break;
+ case DV_TAPE:
+ case DV_TTY:
+ case DV_DULL:
+ case DV_CPU:
+ break;
+ }
+ break;
+ }
+ dv = getdisk(buf, len, 1, &nswapdev);
+ if (dv) {
+ if (dv->dv_class == DV_IFNET)
+ nswapdev = NODEV;
+ break;
+ }
+ }
+gotswap:
+ rootdev = nrootdev;
+ dumpdev = nswapdev;
+ swdevt[0].sw_dev = nswapdev;
+ swdevt[1].sw_dev = NODEV;
+ } else if (mountroot == NULL) {
+ /*
+ * `swap generic': Use the device the ROM told us to use.
+ */
+ if (bootdv == NULL)
+ panic("boot device not known");
+
+ majdev = findblkmajor(bootdv);
+ if (majdev >= 0) {
+ /*
+ * Root and swap are on a disk.
+ * val[2] of the boot device is the partition number.
+ * Assume swap is on partition b.
+ */
+ unit = bootdv->dv_unit;
+ rootdev = MAKEDISKDEV(majdev, unit, bootpart);
+ nswapdev = dumpdev = MAKEDISKDEV(major(rootdev),
+ DISKUNIT(rootdev), 1);
+ } else {
+ /*
+ * Root and swap are on a net.
+ */
+ nswapdev = dumpdev = NODEV;
+ }
+ swdevt[0].sw_dev = nswapdev;
+ swdevt[1].sw_dev = NODEV;
+ } else {
+ /*
+ * `root DEV swap DEV': honour rootdev/swdevt.
+ * rootdev/swdevt/mountroot already properly set.
+ */
+ return;
+ }
+
+ switch (bootdv->dv_class) {
+#if defined(NFSCLIENT)
+ case DV_IFNET:
+ mountroot = nfs_mountroot;
+ nfsbootdevname = bootdv->dv_xname;
+ return;
+#endif
+#if defined(FFS)
+ case DV_DISK:
+ mountroot = dk_mountroot;
+ majdev = major(rootdev);
+ unit = DISKUNIT(rootdev);
+ printf("root on %s%c\n", bootdv->dv_xname,
+ DISKPART(rootdev) + 'a');
+ break;
+#endif
+ default:
+ printf("can't figure root, hope your kernel is right\n");
+ return;
+ }
+
+ /*
+ * Make the swap partition on the root drive the primary swap.
+ */
+ temp = NODEV;
+ for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
+ if (majdev == major(swp->sw_dev) &&
+ unit == DISKUNIT(swp->sw_dev)) {
+ temp = swdevt[0].sw_dev;
+ swdevt[0].sw_dev = swp->sw_dev;
+ swp->sw_dev = temp;
+ break;
+ }
+ }
+ if (swp->sw_dev == NODEV)
+ return;
+
+ /*
+ * If dumpdev was the same as the old primary swap device, move
+ * it to the new primary swap device.
+ */
+ if (temp == dumpdev)
+ dumpdev = swdevt[0].sw_dev;
+}
+
+/*
+ * find a device matching "name" and unit number
+ */
+struct device *
+getdevunit(name, unit)
+ char *name;
+ int unit;
+{
+ struct device *dev = alldevs.tqh_first;
+ char num[10], fullname[16];
+ int lunit;
+
+ /* compute length of name and decimal expansion of unit number */
+ snprintf(num, sizeof num, "%d", unit);
+ lunit = strlen(num);
+ if (strlen(name) + lunit >= sizeof(fullname) - 1)
+ panic("config_attach: device name too long");
+
+ strlcpy(fullname, name, sizeof fullname);
+ strlcat(fullname, num, sizeof fullname);
+
+ while (strcmp(dev->dv_xname, fullname) != 0) {
+ if ((dev = dev->dv_list.tqe_next) == NULL)
+ return NULL;
+ }
+ return dev;
+}
diff --git a/sys/arch/luna88k/luna88k/clock.c b/sys/arch/luna88k/luna88k/clock.c
new file mode 100644
index 00000000000..475d0865b99
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/clock.c
@@ -0,0 +1,218 @@
+/* $OpenBSD: clock.c,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/* $NetBSD: clock.c,v 1.2 2000/01/11 10:29:35 nisimura Exp $ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah Hdr: clock.c 1.18 91/01/21
+ *
+ * @(#)clock.c 8.1 (Berkeley) 6/10/93
+ */
+
+/* from NetBSD/luna68k sys/arch/luna68k/luna68k/clock.c */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+
+#include <machine/cpu.h>
+
+#include <dev/clock_subr.h>
+#include <luna88k/luna88k/clockvar.h>
+
+#if 0 /* aoyama */
+#define CLOCK_LEVEL 5
+#include <luna68k/luna68k/isr.h>
+#endif /* aoyama */
+
+struct device *clockdev;
+const struct clockfns *clockfns;
+int clockinitted;
+
+void
+clockattach(dev, fns)
+ struct device *dev;
+ const struct clockfns *fns;
+{
+ /*
+ * Just bookkeeping.
+ */
+ if (clockfns != NULL)
+ panic("clockattach: multiple clocks");
+ clockdev = dev;
+ clockfns = fns;
+}
+
+/*
+ * Machine-dependent clock routines.
+ *
+ * Startrtclock restarts the real-time clock, which provides
+ * hardclock interrupts to kern_clock.c.
+ *
+ * Inittodr initializes the time of day hardware which provides
+ * date functions. Its primary function is to use some file
+ * system information in case the hardare clock lost state.
+ *
+ * Resettodr restores the time of day hardware after a time change.
+ */
+
+int clock_enable; /* XXX to be removed XXX */
+
+/*
+ * Start the real-time and statistics clocks. Leave stathz 0 since there
+ * are no other timers available.
+ */
+void
+cpu_initclocks()
+{
+ int s;
+
+ if (clockfns == NULL)
+ panic("cpu_initclocks: no clock attached");
+
+ tick = 1000000 / hz; /* number of microseconds between interrupts */
+ tickfix = 1000000 - (hz * tick);
+ if (tickfix) {
+ int ftp;
+
+ ftp = min(ffs(tickfix), ffs(hz));
+ tickfix >>= (ftp - 1);
+ tickfixinterval = hz >> (ftp - 1);
+ }
+ /*
+ * Get the clock started.
+ */
+ s = splhigh();
+ /*
+ * XXX
+ * I guess it's necessary to program clock source with
+ * approprivate mode/value.
+ * XXX
+ */
+ clock_enable = 1;
+ splx(s);
+}
+
+/*
+ * We assume newhz is either stathz or profhz, and that neither will
+ * change after being set up above. Could recalculate intervals here
+ * but that would be a drag.
+ */
+void
+setstatclockrate(newhz)
+ int newhz;
+{
+ /* nothing we can do */
+}
+
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem. Base provides the time to within six months,
+ * and the time of year clock (if any) provides the rest.
+ */
+void
+inittodr(base)
+ time_t base;
+{
+ struct clock_ymdhms dt;
+ time_t deltat;
+ int badbase;
+
+ if (base < 5*SECYR) {
+ printf("WARNING: preposterous time in file system");
+ /* read the system clock anyway */
+ base = 6*SECYR + 186*SECDAY + SECDAY/2;
+ badbase = 1;
+ } else
+ badbase = 0;
+
+ (*clockfns->cf_get)(clockdev, base, &dt);
+ clockinitted = 1;
+ /* simple sanity checks */
+ if (dt.dt_year < 1970 || dt.dt_mon < 1 || dt.dt_mon > 12
+ || dt.dt_day < 1 || dt.dt_day > 31
+ || dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 59) {
+ /*
+ * Believe the time in the file system for lack of
+ * anything better, resetting the TODR.
+ */
+ time.tv_sec = base;
+ if (!badbase) {
+ printf("WARNING: preposterous clock chip time");
+ resettodr();
+ }
+ goto bad;
+ }
+ /* now have days since Jan 1, 1970; the rest is easy... */
+ time.tv_sec = clock_ymdhms_to_secs(&dt);
+
+ if (!badbase) {
+ /*
+ * See if we gained/lost two or more days;
+ * if so, assume something is amiss.
+ */
+ deltat = time.tv_sec - base;
+ if (deltat < 0)
+ deltat = -deltat;
+ if (deltat < 2 * SECDAY)
+ return;
+ printf("WARNING: clock %s %d days",
+ time.tv_sec < base ? "lost" : "gained",
+ (int) (deltat / SECDAY));
+ }
+bad:
+ printf(" -- CHECK AND RESET THE DATE!\n");
+}
+
+/*
+ * Reset the TODR based on the time value; used when the TODR
+ * has a preposterous value and also when the time is reset
+ * by the stime system call. Also called when the TODR goes past
+ * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
+ * to wrap the TODR around.
+ */
+void
+resettodr()
+{
+ struct clock_ymdhms dt;
+
+ if (!clockinitted)
+ return;
+ clock_secs_to_ymdhms(time.tv_sec, &dt);
+ (*clockfns->cf_set)(clockdev, &dt);
+}
diff --git a/sys/arch/luna88k/luna88k/clockvar.h b/sys/arch/luna88k/luna88k/clockvar.h
new file mode 100644
index 00000000000..128d809d4af
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/clockvar.h
@@ -0,0 +1,54 @@
+/* $OpenBSD: clockvar.h,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/* $NetBSD: clockvar.h,v 1.1 2000/01/05 08:49:02 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct clock_ymdhms;
+
+/*
+ * clockfns structure:
+ *
+ * function switch used by chip-independent clock code, to access
+ * chip-dependent routines.
+ */
+struct clockfns {
+ void (*cf_init)(struct device *);
+ void (*cf_get)(struct device *, time_t, struct clock_ymdhms *);
+ void (*cf_set)(struct device *, struct clock_ymdhms *);
+};
+
+void clockattach(struct device *, const struct clockfns *);
diff --git a/sys/arch/luna88k/luna88k/cmmu.c b/sys/arch/luna88k/luna88k/cmmu.c
new file mode 100644
index 00000000000..375a8241e99
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/cmmu.c
@@ -0,0 +1,78 @@
+/* $OpenBSD: cmmu.c,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+/*
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/simplelock.h>
+#include <machine/cmmu.h>
+#include <machine/cpu_number.h>
+
+/*
+ * This lock protects the cmmu SAR and SCR's; other ports
+ * can be accessed without locking it.
+ *
+ * May be used from "db_interface.c".
+ */
+struct simplelock cmmu_cpu_lock;
+
+unsigned cpu_sets[MAX_CPUS];
+unsigned master_cpu = 0;
+int max_cpus, max_cmmus;
+
+struct cmmu_p *cmmu;
diff --git a/sys/arch/luna88k/luna88k/conf.c b/sys/arch/luna88k/luna88k/conf.c
new file mode 100644
index 00000000000..4d998d97f18
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/conf.c
@@ -0,0 +1,274 @@
+/* $OpenBSD: conf.c,v 1.1 2004/04/21 15:23:58 aoyama Exp $ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)conf.c 7.9 (Berkeley) 5/28/91
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+
+#define mmread mmrw
+#define mmwrite mmrw
+cdev_decl(mm);
+
+#include "pty.h"
+#include "bpfilter.h"
+#include "tun.h"
+#include "vnd.h"
+#include "ccd.h"
+#include "rd.h"
+#include "cd.h"
+#include "ch.h"
+#include "sd.h"
+#include "ss.h"
+#include "st.h"
+#include "uk.h"
+
+#ifdef XFS
+#include <xfs/nxfs.h>
+cdev_decl(xfs_dev);
+#endif
+#include "ksyms.h"
+
+#ifdef notyet
+#include "xd.h"
+bdev_decl(xd);
+cdev_decl(xd);
+#endif /* notyet */
+
+#include "siotty.h"
+cdev_decl(sio);
+
+#include "wsdisplay.h"
+#include "wskbd.h"
+#include "wsmouse.h"
+#include "wsmux.h"
+
+/* open, close, write, ioctl */
+#define cdev_lp_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+ 0, seltrue, (dev_type_mmap((*))) enodev }
+
+/* open, close, ioctl, mmap, ioctl */
+#define cdev_mdev_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \
+ dev_init(c,n,mmap) }
+
+#if notyet
+#include "lp.h"
+cdev_decl(lp);
+#include "lptwo.h"
+cdev_decl(lptwo);
+#endif /* notyet */
+
+#include "pf.h"
+
+#include "systrace.h"
+
+struct bdevsw bdevsw[] =
+{
+ bdev_notdef(), /* 0 */
+ bdev_notdef(), /* 1 */
+ bdev_notdef(), /* 2 */
+ bdev_swap_init(1,sw), /* 3: swap pseudo-device */
+ bdev_disk_init(NSD,sd), /* 4: SCSI disk */
+ bdev_tape_init(NST,st), /* 5: SCSI tape */
+ bdev_disk_init(NCD,cd), /* 6: SCSI CD-ROM */
+ bdev_disk_init(NRD,rd), /* 7: ramdisk */
+ bdev_disk_init(NVND,vnd), /* 8: vnode disk driver */
+ bdev_disk_init(NCCD,ccd), /* 9: concatenated disk driver */
+ bdev_notdef(), /* 10 */
+ bdev_notdef(), /* 11 */
+ bdev_notdef(), /* 12 */
+ bdev_lkm_dummy(), /* 13 */
+ bdev_lkm_dummy(), /* 14 */
+ bdev_lkm_dummy(), /* 15 */
+ bdev_lkm_dummy(), /* 16 */
+ bdev_lkm_dummy(), /* 17 */
+ bdev_lkm_dummy(), /* 18 */
+};
+int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
+
+struct cdevsw cdevsw[] =
+{
+ cdev_cn_init(1,cn), /* 0: virtual console */
+ cdev_ctty_init(1,ctty), /* 1: controlling terminal */
+ cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */
+ cdev_swap_init(1,sw), /* 3: /dev/drum (swap pseudo-device) */
+ cdev_tty_init(NPTY,pts), /* 4: pseudo-tty slave */
+ cdev_ptc_init(NPTY,ptc), /* 5: pseudo-tty master */
+ cdev_log_init(1,log), /* 6: /dev/klog */
+ cdev_notdef(), /* 7: */
+ cdev_disk_init(NSD,sd), /* 8: SCSI disk */
+ cdev_disk_init(NCD,cd), /* 9: SCSI CD-ROM */
+ cdev_notdef(), /* 10 */
+ cdev_notdef(), /* 11 */
+ cdev_tty_init(NSIOTTY,sio), /* 12: on-board UART (ttya) */
+ cdev_wsdisplay_init(NWSDISPLAY, /* 13: frame buffers, etc. */
+ wsdisplay),
+ cdev_mouse_init(NWSKBD,wskbd), /* 14: keyboard */
+ cdev_mouse_init(NWSMOUSE, /* 15: mouse */
+ wsmouse),
+ cdev_mouse_init(NWSMUX,wsmux), /* 16: ws multiplexor */
+ cdev_disk_init(NCCD,ccd), /* 17: concatenated disk */
+ cdev_disk_init(NRD,rd), /* 18: ramdisk disk */
+ cdev_disk_init(NVND,vnd), /* 19: vnode disk */
+ cdev_tape_init(NST,st), /* 20: SCSI tape */
+ cdev_fd_init(1,filedesc), /* 21: file descriptor pseudo-dev */
+ cdev_bpftun_init(NBPFILTER,bpf),/* 22: berkeley packet filter */
+ cdev_bpftun_init(NTUN,tun), /* 23: network tunnel */
+ cdev_lkm_init(NLKM,lkm), /* 24: loadable module driver */
+ cdev_notdef(), /* 25 */
+ cdev_notdef(), /* 26 */
+ cdev_notdef(), /* 27 */
+ cdev_notdef(), /* 28 */
+ cdev_notdef(), /* 29 */
+ cdev_notdef(), /* 30 */
+ cdev_notdef(), /* 31 */
+ cdev_notdef(), /* 32 */
+ cdev_lkm_dummy(), /* 33 */
+ cdev_lkm_dummy(), /* 34 */
+ cdev_lkm_dummy(), /* 35 */
+ cdev_lkm_dummy(), /* 36 */
+ cdev_lkm_dummy(), /* 37 */
+ cdev_lkm_dummy(), /* 38 */
+ cdev_pf_init(NPF,pf), /* 39: packet filter */
+ cdev_random_init(1,random), /* 40: random data source */
+ cdev_uk_init(NUK,uk), /* 41 */
+ cdev_ss_init(NSS,ss), /* 42 */
+ cdev_ksyms_init(NKSYMS,ksyms), /* 43: Kernel symbols device */
+ cdev_ch_init(NCH,ch), /* 44: SCSI autochanger */
+ cdev_notdef(), /* 45 */
+ cdev_notdef(), /* 46 */
+ cdev_notdef(), /* 47 */
+ cdev_notdef(), /* 48 */
+ cdev_notdef(), /* 49 */
+ cdev_systrace_init(NSYSTRACE,systrace), /* 50 system call tracing */
+#ifdef XFS
+ cdev_xfs_init(NXFS,xfs_dev), /* 51: xfs communication device */
+#else
+ cdev_notdef(), /* 51 */
+#endif
+ cdev_ptm_init(NPTY,ptm), /* 52: pseudo-tty ptm device */
+};
+int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
+
+int mem_no = 2; /* major device number of memory special file */
+
+/*
+ * Swapdev is a fake device implemented
+ * in sw.c used only internally to get to swstrategy.
+ * It cannot be provided to the users, because the
+ * swstrategy routine munches the b_dev and b_blkno entries
+ * before calling the appropriate driver. This would horribly
+ * confuse, e.g. the hashing routines. Instead, /dev/drum is
+ * provided as a character (raw) device.
+ */
+dev_t swapdev = makedev(3, 0);
+
+/*
+ * Returns true if dev is /dev/mem or /dev/kmem.
+ */
+int
+iskmemdev(dev)
+ dev_t dev;
+{
+
+ return (major(dev) == mem_no && minor(dev) < 2);
+}
+
+/*
+ * Returns true if dev is /dev/zero.
+ */
+int
+iszerodev(dev)
+ dev_t dev;
+{
+
+ return (major(dev) == mem_no && minor(dev) == 12);
+}
+
+dev_t
+getnulldev()
+{
+ return makedev(mem_no, 2);
+}
+
+int chrtoblktbl[] = {
+ /* XXXX This needs to be dynamic for LKMs. */
+ /*VCHR*/ /*VBLK*/
+ /* 0 */ NODEV,
+ /* 1 */ NODEV,
+ /* 2 */ NODEV,
+ /* 3 */ NODEV,
+ /* 4 */ NODEV,
+ /* 5 */ NODEV,
+ /* 6 */ NODEV,
+ /* 7 */ NODEV,
+ /* 8 */ 4, /* SCSI disk */
+ /* 9 */ 6, /* SCSI CD-ROM */
+ /* 10 */ NODEV,
+ /* 11 */ NODEV,
+ /* 12 */ NODEV,
+ /* 13 */ NODEV,
+ /* 14 */ NODEV,
+ /* 15 */ NODEV,
+ /* 16 */ NODEV,
+ /* 17 */ NODEV,
+ /* 18 */ 7, /* ram disk */
+ /* 19 */ 8, /* vnode disk */
+};
+int nchrtoblktbl = sizeof(chrtoblktbl) / sizeof(chrtoblktbl[0]);
+
+/*
+ * This entire table could be autoconfig()ed but that would mean that
+ * the kernel's idea of the console would be out of sync with that of
+ * the standalone boot. I think it best that they both use the same
+ * known algorithm unless we see a pressing need otherwise.
+ */
+#include <dev/cons.h>
+
+#define romttycnpollc nullcnpollc
+cons_decl(romtty);
+
+struct consdev constab[] = {
+#if 0
+ cons_init(romtty),
+#endif
+ { 0 },
+};
diff --git a/sys/arch/luna88k/luna88k/disksubr.c b/sys/arch/luna88k/luna88k/disksubr.c
new file mode 100644
index 00000000000..7e13d9f0fba
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/disksubr.c
@@ -0,0 +1,526 @@
+/* $OpenBSD: disksubr.c,v 1.1 2004/04/21 15:23:59 aoyama Exp $ */
+/* $NetBSD: disksubr.c,v 1.12 2002/02/19 17:09:44 wiz Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Gordon W. Ross
+ * Copyright (c) 1994 Theo de Raadt
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Credits:
+ * This file was based mostly on the i386/disksubr.c file:
+ * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
+ * The functions: disklabel_sun_to_bsd, disklabel_bsd_to_sun
+ * were originally taken from arch/sparc/scsi/sun_disklabel.c
+ * (which was written by Theo de Raadt) and then substantially
+ * rewritten by Gordon W. Ross.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/disk.h>
+#include <sys/dkbad.h>
+
+#include <dev/sun/disklabel.h>
+
+/*
+ * UniOS disklabel (== ISI disklabel) is very similar to SunOS.
+ * SunOS UniOS/ISI
+ * text 128 128
+ * (pad) 292 294
+ * rpm 2 -
+ * pcyl 2 badchk 2
+ * sparecyl 2 maxblk 4
+ * (pad) 4 dtype 2
+ * interleave 2 ndisk 2
+ * ncyl 2 2
+ * acyl 2 2
+ * ntrack 2 2
+ * nsect 2 2
+ * (pad) 4 bhead 2
+ * - ppart 2
+ * dkpart[8] 64 64
+ * magic 2 2
+ * cksum 2 2
+ *
+ * Magic number value and checksum calculation are identical. Subtle
+ * difference is partition start address; UniOS/ISI maintains sector
+ * numbers while SunOS label has cylinder number.
+ *
+ * It is found that LUNA Mach2.5 has BSD label embedded at offset 64
+ * retaining UniOS/ISI label at the end of label block. LUNA Mach
+ * manipulates BSD disklabel in the same manner as 4.4BSD. It's
+ * uncertain LUNA Mach can create a disklabel on fresh disks since
+ * Mach writedisklabel logic seems to fail when no BSD label is found.
+ *
+ * Kernel handles disklabel in this way;
+ * - searchs BSD label at offset 64
+ * - if not found, searchs UniOS/ISI label at the end of block
+ * - kernel can distinguish whether it was SunOS label or UniOS/ISI
+ * label and understand both
+ * - kernel writes UniOS/ISI label combined with BSD label to update
+ * the label block
+ */
+
+#if LABELSECTOR != 0
+#error "Default value of LABELSECTOR no longer zero?"
+#endif
+
+char *disklabel_om_to_bsd(char *, struct disklabel *);
+int disklabel_bsd_to_om(struct disklabel *, char *);
+
+/*
+ * Attempt to read a disk label from a device
+ * using the indicated strategy routine.
+ * The label must be partly set up before this:
+ * secpercyl, secsize and anything required for a block i/o read
+ * operation in the driver's strategy/start routines
+ * must be filled in before calling us.
+ *
+ * Return buffer for use in signalling errors if requested.
+ *
+ * Returns null on success and an error string on failure.
+ */
+char *
+readdisklabel(dev, strat, lp, clp, spoofonly)
+ dev_t dev;
+ void (*strat)(struct buf *);
+ struct disklabel *lp;
+ struct cpu_disklabel *clp;
+ int spoofonly;
+{
+ struct buf *bp;
+ struct disklabel *dlp;
+ struct sun_disklabel *slp;
+ int error;
+
+ /* minimal requirements for archtypal disk label */
+ if (lp->d_secperunit == 0)
+ lp->d_secperunit = 0x1fffffff;
+ lp->d_npartitions = 1;
+ if (lp->d_partitions[0].p_size == 0)
+ lp->d_partitions[0].p_size = 0x1fffffff;
+ lp->d_partitions[0].p_offset = 0;
+
+ /* don't read the on-disk label if we are in spoofed-only mode */
+ if (spoofonly)
+ return (NULL);
+
+ /* obtain buffer to probe drive with */
+ bp = geteblk((int)lp->d_secsize);
+
+ /* next, dig out disk label */
+ bp->b_dev = dev;
+ bp->b_blkno = LABELSECTOR;
+ bp->b_cylinder = 0;
+ bp->b_bcount = lp->d_secsize;
+ bp->b_flags |= B_READ;
+ (*strat)(bp);
+
+ /* if successful, locate disk label within block and validate */
+ error = biowait(bp);
+ if (!error) {
+ /* Save the whole block in case it has info we need. */
+ bcopy(bp->b_data, clp->cd_block, sizeof(clp->cd_block));
+ }
+ brelse(bp);
+ if (error)
+ return ("disk label read error");
+
+ /* Check for a BSD disk label first. */
+ dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET);
+ if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
+ if (dkcksum(dlp) == 0) {
+ *lp = *dlp; /* struct assignment */
+ return (NULL);
+ }
+ printf("BSD disk label corrupted");
+ }
+
+ /* Check for a UniOS/ISI disk label. */
+ slp = (struct sun_disklabel *)clp->cd_block;
+ if (slp->sl_magic == SUN_DKMAGIC) {
+ return (disklabel_om_to_bsd(clp->cd_block, lp));
+ }
+
+ memset(clp->cd_block, 0, sizeof(clp->cd_block));
+ return ("no disk label");
+}
+
+/*
+ * Check new disk label for sensibility
+ * before setting it.
+ */
+int
+setdisklabel(olp, nlp, openmask, clp)
+ struct disklabel *olp, *nlp;
+ u_long openmask;
+ struct cpu_disklabel *clp;
+{
+ struct partition *opp, *npp;
+ int i;
+
+ /* sanity clause */
+ if ((nlp->d_secpercyl == 0) || (nlp->d_secsize == 0) ||
+ (nlp->d_secsize % DEV_BSIZE) != 0)
+ return (EINVAL);
+
+ /* special case to allow disklabel to be invalidated */
+ if (nlp->d_magic == 0xffffffff) {
+ *olp = *nlp;
+ return (0);
+ }
+
+ if (nlp->d_magic != DISKMAGIC ||
+ nlp->d_magic2 != DISKMAGIC ||
+ dkcksum(nlp) != 0)
+ return (EINVAL);
+
+ while (openmask != 0) {
+ i = ffs(openmask) - 1;
+ openmask &= ~(1 << i);
+ if (nlp->d_npartitions <= i)
+ return (EBUSY);
+ opp = &olp->d_partitions[i];
+ npp = &nlp->d_partitions[i];
+ if (npp->p_offset != opp->p_offset ||
+ npp->p_size < opp->p_size)
+ return (EBUSY);
+ }
+
+ /* We did not modify the new label, so the checksum is OK. */
+ *olp = *nlp;
+ return (0);
+}
+
+
+/*
+ * Write disk label back to device after modification.
+ * Current label is already in clp->cd_block[]
+ */
+int
+writedisklabel(dev, strat, lp, clp)
+ dev_t dev;
+ void (*strat)(struct buf *);
+ struct disklabel *lp;
+ struct cpu_disklabel *clp;
+{
+ struct buf *bp;
+ struct disklabel *dlp;
+ int error;
+
+ /* implant NetBSD disklabel at LABELOFFSET. */
+ dlp = (struct disklabel *)(clp->cd_block + LABELOFFSET);
+ *dlp = *lp; /* struct assignment */
+
+ error = disklabel_bsd_to_om(lp, clp->cd_block);
+ if (error)
+ return (error);
+
+ /* Get a buffer and copy the new label into it. */
+ bp = geteblk((int)lp->d_secsize);
+ bcopy(clp->cd_block, bp->b_data, sizeof(clp->cd_block));
+
+ /* Write out the updated label. */
+ bp->b_dev = dev;
+ bp->b_blkno = LABELSECTOR;
+ bp->b_cylinder = 0;
+ bp->b_bcount = lp->d_secsize;
+ bp->b_flags |= B_WRITE;
+ (*strat)(bp);
+ error = biowait(bp);
+ brelse(bp);
+
+ return (error);
+}
+
+/*
+ * Determine the size of the transfer, and make sure it is
+ * within the boundaries of the partition. Adjust transfer
+ * if needed, and signal errors or early completion.
+ */
+int
+bounds_check_with_label(bp, lp, osdep, wlabel)
+ struct buf *bp;
+ struct disklabel *lp;
+ struct cpu_disklabel *osdep;
+ int wlabel;
+{
+ struct partition *p;
+ int sz, maxsz;
+
+ p = lp->d_partitions + DISKPART(bp->b_dev);
+ maxsz = p->p_size;
+ sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
+
+ /* overwriting disk label ? */
+ /* XXX should also protect bootstrap in first 8K */
+ /* XXX PR#2598: labelsect is always sector zero. */
+ if (((bp->b_blkno + p->p_offset) <= LABELSECTOR) &&
+ ((bp->b_flags & B_READ) == 0) && (wlabel == 0))
+ {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+
+ /* beyond partition? */
+ if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
+ /* if exactly at end of disk, return an EOF */
+ if (bp->b_blkno == maxsz) {
+ bp->b_resid = bp->b_bcount;
+ return (0);
+ }
+ /* or truncate if part of it fits */
+ sz = maxsz - bp->b_blkno;
+ if (sz <= 0) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+ bp->b_bcount = sz << DEV_BSHIFT;
+ }
+
+ /* calculate cylinder for disksort to order transfers with */
+ bp->b_cylinder = (bp->b_blkno + p->p_offset) / lp->d_secpercyl;
+ return (1);
+
+bad:
+ bp->b_flags |= B_ERROR;
+ return (-1);
+}
+
+void
+dk_establish(dk, dev)
+ struct disk *dk;
+ struct device *dev;
+{
+#if 0 /* taken from OpenBSD/mvme88k */
+ struct scsibus_softc *sbsc;
+ int target, lun;
+
+ if (bootpart == -1) /* ignore flag from controller driver? */
+ return;
+
+ /*
+ * scsi: sd,cd
+ */
+
+ if (strncmp("sd", dev->dv_xname, 2) == 0 ||
+ strncmp("cd", dev->dv_xname, 2) == 0) {
+
+ sbsc = (struct scsibus_softc *)dev->dv_parent;
+ target = get_target(); /* Work the Motorola Magic */
+ lun = 0;
+
+ if (sbsc->sc_link[target][lun] != NULL &&
+ sbsc->sc_link[target][lun]->device_softc == (void *)dev) {
+ bootdv = dev;
+ return;
+ }
+ }
+#endif
+}
+
+/************************************************************************
+ *
+ * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
+ * and then substantially rewritten by Gordon W. Ross
+ *
+ ************************************************************************/
+
+/* What partition types to assume for Sun disklabels: */
+static const u_char
+sun_fstypes[8] = {
+ FS_BSDFFS, /* a */
+ FS_SWAP, /* b */
+ FS_OTHER, /* c - whole disk */
+ FS_BSDFFS, /* d */
+ FS_BSDFFS, /* e */
+ FS_BSDFFS, /* f */
+ FS_BSDFFS, /* g */
+ FS_BSDFFS, /* h */
+};
+
+/*
+ * Given a UniOS/ISI disk label, set lp to a BSD disk label.
+ * Returns NULL on success, else an error string.
+ *
+ * The BSD label is cleared out before this is called.
+ */
+char *
+disklabel_om_to_bsd(cp, lp)
+ char *cp;
+ struct disklabel *lp;
+{
+ struct sun_disklabel *sl;
+ struct partition *npp;
+ struct sun_dkpart *spp;
+ int i, secpercyl;
+ u_short cksum, *sp1, *sp2;
+
+ sl = (struct sun_disklabel *)cp;
+
+ /* Verify the XOR check. */
+ sp1 = (u_short *)sl;
+ sp2 = (u_short *)(sl + 1);
+ cksum = 0;
+ while (sp1 < sp2)
+ cksum ^= *sp1++;
+ if (cksum != 0)
+ return ("UniOS disk label, bad checksum");
+
+ memset((caddr_t)lp, 0, sizeof(struct disklabel));
+ /* Format conversion. */
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
+
+ lp->d_type = DTYPE_SCSI;
+ lp->d_secsize = 512;
+ lp->d_nsectors = sl->sl_nsectors;
+ lp->d_ntracks = sl->sl_ntracks;
+ lp->d_ncylinders = sl->sl_ncylinders;
+
+ secpercyl = sl->sl_nsectors * sl->sl_ntracks;
+ lp->d_secpercyl = secpercyl;
+ lp->d_secperunit = secpercyl * sl->sl_ncylinders;
+
+ lp->d_sparespercyl = 0; /* no way to know */
+ lp->d_acylinders = sl->sl_acylinders;
+ lp->d_rpm = sl->sl_rpm; /* UniOS - (empty) */
+ lp->d_interleave = sl->sl_interleave; /* UniOS - ndisk */
+
+ if (sl->sl_rpm == 0) {
+ /* UniOS label has blkoffset, not cyloffset */
+ secpercyl = 1;
+ }
+
+ lp->d_npartitions = 8;
+ /* These are as defined in <ufs/ffs/fs.h> */
+ lp->d_bbsize = 8192; /* XXX */
+ lp->d_sbsize = 8192; /* XXX */
+ for (i = 0; i < 8; i++) {
+ spp = &sl->sl_part[i];
+ npp = &lp->d_partitions[i];
+ npp->p_offset = spp->sdkp_cyloffset * secpercyl;
+ npp->p_size = spp->sdkp_nsectors;
+ if (npp->p_size == 0)
+ npp->p_fstype = FS_UNUSED;
+ else {
+ /* Partition has non-zero size. Set type, etc. */
+ npp->p_fstype = sun_fstypes[i];
+
+ /*
+ * The sun label does not store the FFS fields,
+ * so just set them with default values here.
+ * XXX: This keeps newfs from trying to rewrite
+ * XXX: the disk label in the most common case.
+ * XXX: (Should remove that code from newfs...)
+ */
+ if (npp->p_fstype == FS_BSDFFS) {
+ npp->p_fsize = 1024;
+ npp->p_frag = 8;
+ npp->p_cpg = 16;
+ }
+ }
+ }
+
+ /*
+ * XXX BandAid XXX
+ * UniOS rootfs sits on part c which don't begin at sect 0,
+ * and impossible to mount. Thus, make it usable as part b.
+ */
+ if (sl->sl_rpm == 0 && lp->d_partitions[2].p_offset != 0) {
+ lp->d_partitions[1] = lp->d_partitions[2];
+ lp->d_partitions[1].p_fstype = FS_BSDFFS;
+ }
+
+ lp->d_checksum = dkcksum(lp);
+
+ return (NULL);
+}
+
+/*
+ * Given a BSD disk label, update the UniOS disklabel
+ * pointed to by cp with the new info. Note that the
+ * UniOS disklabel may have other info we need to keep.
+ * Returns zero or error code.
+ */
+int
+disklabel_bsd_to_om(lp, cp)
+ struct disklabel *lp;
+ char *cp;
+{
+ struct sun_disklabel *sl;
+ struct partition *npp;
+ struct sun_dkpart *spp;
+ int i;
+ u_short cksum, *sp1, *sp2;
+
+ if (lp->d_secsize != 512)
+ return (EINVAL);
+
+ sl = (struct sun_disklabel *)cp;
+
+ /* Format conversion. */
+ memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
+ sl->sl_rpm = 0; /* UniOS */
+#if 0 /* leave as was */
+ sl->sl_pcyl = lp->d_ncylinders + lp->d_acylinders; /* XXX */
+ sl->sl_sparespercyl = lp->d_sparespercyl;
+#endif
+ sl->sl_interleave = lp->d_interleave;
+ sl->sl_ncylinders = lp->d_ncylinders;
+ sl->sl_acylinders = lp->d_acylinders;
+ sl->sl_ntracks = lp->d_ntracks;
+ sl->sl_nsectors = lp->d_nsectors;
+
+ for (i = 0; i < 8; i++) {
+ spp = &sl->sl_part[i];
+ npp = &lp->d_partitions[i];
+
+ spp->sdkp_cyloffset = npp->p_offset; /* UniOS */
+ spp->sdkp_nsectors = npp->p_size;
+ }
+ sl->sl_magic = SUN_DKMAGIC;
+
+ /* Correct the XOR check. */
+ sp1 = (u_short *)sl;
+ sp2 = (u_short *)(sl + 1);
+ sl->sl_cksum = cksum = 0;
+ while (sp1 < sp2)
+ cksum ^= *sp1++;
+ sl->sl_cksum = cksum;
+
+ return (0);
+}
diff --git a/sys/arch/luna88k/luna88k/eh.S b/sys/arch/luna88k/luna88k/eh.S
new file mode 100644
index 00000000000..2b205580d3c
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/eh.S
@@ -0,0 +1,2709 @@
+/* $OpenBSD: eh.S,v 1.1 2004/04/21 15:24:00 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * Copyright (c) 1996 Nivas Madhur
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * In the following discussion, references are made to:
+ * MC88100 - RISC MICROPROCESSOR USER'S MANUAL
+ * (second edition). Reference in []s refer to section numbers.
+ *
+ * This discussion assumes that you are at least vaguely familiar with 88100
+ * exception handling (chapter 6), the MACH kernel, and that you have a brain
+ * (and use it while reading this).
+ *
+ * I also assume (and hope) that you're not offended by frequent misspellings.
+ *
+ * Jeffrey Friedl
+ * jfriedl@rna.ncl.omron.co.jp
+ * December, 1989
+ * -------------------------------------------------------------------
+ *
+ * EXCEPTIONS, INTERRUPTS, and TRAPS
+ * ---------------------------------
+ * This is the machine exception handler.
+ * In the MC88100, various "conditions" cause an exception, where
+ * processing momentarily jumps here to "service" the exception,
+ * and then continues where it left off.
+ *
+ * There are a number of different types of exceptions.
+ * For example, exception #6 is the privilege violation exception which
+ * is raised when the user tries to execute a supervisor-only instruction.
+ *
+ * Exception #1 is the interrupt exception, and is raised when an
+ * outside device raises the INT line on the CPU. This happens,
+ * for example, when the clock signals that it is time for a context
+ * switch, or perhaps the disk drive signaling that some operation
+ * is complete.
+ *
+ * Traps are also exceptions. Traps are ways for user programs to request
+ * kernel operations. For example, "tcnd eq0, r0, 128" will raise
+ * exception 128, the system call exception.
+ *
+ *
+ * SERVICING AN EXCEPTION
+ * -----------------------
+ * When an exception occurs, each control register is saved in its
+ * respective shadow register and execution continues from the
+ * appropriate exception handler. The exception handler must
+ * - save the context from the time of the exception
+ * - service the exception
+ * - restore the context (registers, etc)
+ * - pick up from where the exception occurred.
+ *
+ * The context is saved on a stack. Actually, in the user_state area
+ * in the PCB if the exception happens in user mode.
+ *
+ * Servicing the exception is usually straightforward and in fact not dealt
+ * with very much here. Usually a C routine is called to handle it.
+ * For example, when a privilege exception is raised, the routine that sends
+ * an "illegal instruction" signal to the offending process is called.
+ *
+ * When the exception has been serviced, the context is restored from the
+ * stack and execution resumes from where it left off.
+ *
+ * In more detail:
+ *
+ * Saving the exception-time context.
+ * ---------------------------------
+ * In saving the exception-time context, we copy the shadow and general
+ * purpose registers to memory. Since one exception may occur while
+ * servicing another, the memory used to save the exception-time context may
+ * not be static (i.e. the same every time). Thus, memory on a stack is set
+ * aside for the exception frame (area where the exception-time context is
+ * saved). The same stack is also used when C routines are called (to
+ * service the exception).
+ *
+ * Each process has a stack in kernel space (called the "kernel stack",
+ * short for "process's kernel stack) as well as the user space stack. When
+ * entering the kernel from user space, the kernel stack is unused. On this
+ * stack we save the exception state and (most likely call a C routine to)
+ * service the exception.
+ *
+ * Before servicing an exception, several issues must be addressed.
+ *
+ * 1) When an interrupt is recognized by the hardware, the data pipeline is
+ * allowed to clear. However, if one of these data accesses faults (bad
+ * reference, or a reference to a page which needs to be swapped in), that
+ * reference, as well as any others in the pipeline at the time (at most
+ * three total) are left there, to be taken care of by the exception
+ * handler [6.4.1]. This involves swapping in the proper page and
+ * manually doing the appropriate load or store.
+ *
+ * The other (at most, two other) data accesses that might have been in
+ * the pipeline must also be manually completed (even though they may not
+ * be at fault [yes, that's a bad pun, thank you]).
+ *
+ * 2) If any of the (at most three) uncompleted data access in the pipeline
+ * are loads (from memory to a register), then the bit for the destination
+ * register is set in the SSBR. Since the hardware will never complete
+ * that load (since we do it manually), the hardware will never clear that
+ * SSBR bit. Thus, we must clear it manually. If this isn't done, the
+ * system will hang waiting for a bit to clear that will never.
+ *
+ * 3) If the exception is the privilege violation exception, the bounds
+ * violation exception, or the misaligned access exception, the
+ * destination register bit in the SSBR may need to be cleared.
+ *
+ * 4) If the exception is one of the floating exceptions, then the
+ * destination register for that floating process won't be written,
+ * and the SSBR must be cleared explicitly.
+ *
+ * 5) The FPU must be enabled (as it is disabled by the exception processing
+ * hardware) and allowed to complete actions in progress. This is so
+ * so that it may be used in the servicing of any instruction.
+ * When the FPU is being restarted, operations attempting to complete
+ * may themselves fault (raising another exception).
+ *
+ * More on Restarting the FPU
+ * --------------------------
+ * The manual [section 6.4.3.4] gives only minor mention to this
+ * rather complex task. Before the FPU is restarted all SSBR bits are
+ * cleared for actions that the exception handler completes (as mentioned
+ * above) so that the SSBR is clear unless there are FPU operations that
+ * have not actually been completed (and hence not written to the registers).
+ * Also, all control registers (at least all those that we care about) are
+ * saved to the stack exception frame before the FPU is restarted (this
+ * is important... the reason comes later).
+ *
+ * The FPU is restarted by doing an rte to a trap-not-taken (the rte
+ * actually enables the fpu because we ensure that the EPSR has the
+ * FPU-enable bit on; the trap-not-taken ensures anything in the FPU
+ * completes by waiting until scoreboard register is clear).
+ *
+ * At the time the FPU is restarted (the rte to the trap-not-taken) the FPU
+ * can write to ANY of the general registers. Thus, we must make sure that
+ * all general registers (r1..r31) are in their pre-exception state so that
+ * when saved to the exception frame after the FPU is enabled, they properly
+ * reflect any changes made by the FPU in being restarted.
+ *
+ * Because we can't save the pointer to the exception frame in a general
+ * register during the FPU restart (it could get overwritten by the FPU!),
+ * we save it in a control register, SR3, during the restart.
+ *
+ *
+ * HOWEVER .....
+ *
+ * Because other uncompleted actions in the FPU may fault when the FPU is
+ * restarted, a new exception may be raised during the restart. This may
+ * happen recursively a number of times. Thus, during a restart, ANY register
+ * whatsoever may be modified, including control registers. Because of this
+ * we must make sure that the exception handler preserves SR3 throughout
+ * servicing an exception so that, if the exception had been raised during
+ * an FPU restart, it is returned unmolested when control returns to the FPU
+ * restart.
+ *
+ * Thus: if an exception is from kernel space, we MUST preserve SR3.
+ * (if it from user space, no FPU-enable can be in progress and SR3 is
+ * unimportant).
+ *
+ * Now is a good time to recap SR1..SR3 usage:
+ * SR1 - CPU flags (exception handler flags)
+ * SR2 - generally free
+ * SR3 - free only if the exception is from user mode
+ *
+ * Once the FPU has been restarted, the general registers are saved to the
+ * exception frame. If the exception is not the interrupt exception,
+ * interrupts are enabled and any faulted data accesses (see above) are
+ * serviced. In either case, the exception is then serviced (usually by
+ * calling a C routine). After servicing, any faulted data accesses are
+ * serviced (if it had been the interrupt exception). The context is then
+ * restored and control returns to where the exception occurred.
+ *
+ */
+
+#include "assym.h"
+
+#include <machine/param.h>
+#include <machine/asm.h>
+#include <machine/board.h>
+#include <machine/m8820x.h>
+#include <machine/trap.h>
+
+/*
+ * The exception frame as defined in "machine/pcb.h" (among other places) is
+ * a bit outdated and needs to be changed. Until then, we'll define some
+ * pseudo-fields there for our needs.
+ *
+ * EF_SR3
+ * A place to save the exception-time SR3 from just after the
+ * time when an exception is raised until just after the FPU
+ * has been restarted. This does not necessarly conflict with
+ * the general registers (though it can if you're not careful)
+ * and so we can use a spot later used to save a general register.
+ *
+ * EF_FLAGS
+ * This is just the old EF_MODE. "EF_MODE" isn't a very good name.
+ */
+#define EF_SR3 (EF_R0 + 5)
+#define EF_FLAGS EF_MODE
+
+ data
+ align 4
+ASLOCAL(sbadcpupanic)
+ string "eh.S: bad cpu number in FLAGS\000"
+
+ text
+ align 8
+
+ASLOCAL(Lbadcpupanic)
+ subu r31, r31, 32
+ or.u r2, r0, hi16(_ASM_LABEL(sbadcpupanic))
+ bsr.n _C_LABEL(panic)
+ or r2, r2, lo16(_ASM_LABEL(sbadcpupanic))
+ addu r31, r31, 32
+
+ align 8
+
+#ifdef M88110
+#define SAVE_CTX \
+ stcr r31, SRX ; \
+ or.u r31, r0, hi16(_ASM_LABEL(save_frame)) ; \
+ or r31, r31, lo16(_ASM_LABEL(save_frame)) ; \
+ /* save old R31 and other R registers */; \
+ st.d r0 , r31, GENREG_OFF(0) ; \
+ st.d r2 , r31, GENREG_OFF(2) ; \
+ st.d r4 , r31, GENREG_OFF(4) ; \
+ st.d r6 , r31, GENREG_OFF(6) ; \
+ st.d r8 , r31, GENREG_OFF(8) ; \
+ st.d r10, r31, GENREG_OFF(10) ; \
+ st.d r12, r31, GENREG_OFF(12) ; \
+ st.d r14, r31, GENREG_OFF(14) ; \
+ st.d r16, r31, GENREG_OFF(16) ; \
+ st.d r18, r31, GENREG_OFF(18) ; \
+ st.d r20, r31, GENREG_OFF(20) ; \
+ st.d r22, r31, GENREG_OFF(22) ; \
+ st.d r24, r31, GENREG_OFF(24) ; \
+ st.d r26, r31, GENREG_OFF(26) ; \
+ st.d r28, r31, GENREG_OFF(28) ; \
+ st r30, r31, GENREG_OFF(30) ; \
+ ldcr r1, SRX ; \
+ st r1, r31, GENREG_OFF(31) ; \
+ ldcr r1, EPSR ; \
+ ldcr r2, EXIP ; \
+ ldcr r3, ENIP ; \
+ st r1, r31, REG_OFF(EF_EPSR) ; \
+ st r2, r31, REG_OFF(EF_EXIP) ; \
+ st r3, r31, REG_OFF(EF_ENIP) ; \
+ ldcr r1, DSR ; \
+ ldcr r2, DLAR ; \
+ ldcr r3, DPAR ; \
+ st r1, r31, REG_OFF(EF_DSR) ; \
+ st r2, r31, REG_OFF(EF_DLAR) ; \
+ st r3, r31, REG_OFF(EF_DPAR) ; \
+ ldcr r1, ISR ; \
+ ldcr r2, ILAR ; \
+ ldcr r3, IPAR ; \
+ st r1, r31, REG_OFF(EF_ISR) ; \
+ st r2, r31, REG_OFF(EF_ILAR) ; \
+ st r3, r31, REG_OFF(EF_IPAR) ; \
+ ldcr r1, DSAP ; \
+ ldcr r2, DUAP ; \
+ st r1, r31, REG_OFF(EF_DSAP) ; \
+ st r2, r31, REG_OFF(EF_DUAP) ; \
+ ldcr r1, ISAP ; \
+ ldcr r2, IUAP ; \
+ st r1, r31, REG_OFF(EF_ISAP) ; \
+ st r2, r31, REG_OFF(EF_IUAP) ; \
+ /* Restore r1, r2, r3, and r31 */ ; \
+ ld r1 , r31, GENREG_OFF(1) ; \
+ ld r2 , r31, GENREG_OFF(2) ; \
+ ld r3 , r31, GENREG_OFF(3) ; \
+ ld r31, r31, GENREG_OFF(31)
+#endif
+
+/*
+ *
+ * #define PREP(NAME, NUM, BIT, SSBR_STUFF, FLAG_CHECK)
+ *
+ * This is the "exception processing preparaton" common to all exception
+ * processing. It is used in the following manner:
+ *
+ * ASGLOBAL(foo_handler)
+ * PREP("foo", 11, DEBUG_FOO_BIT, SSBR_Stuff, Precheck_Stuff)
+ * CALL(_C_LABEL(trapXXX), T_FOO_FAULT, r31)
+ * DONE(DEBUG_FOO_BIT)
+ *
+ * This defines the exception handler for the "foo" exception.
+ * The arguments ro PREP():
+ * NAME
+ * String for debugging (more info later)
+ * NUM
+ * The exception number [see the manual, Table 6-1]
+ * BIT
+ * Bit to check in eh_debug for debugging (more info later)
+ * SSBR_STUFF
+ * If the exception might leave some bits in the SSBR set,
+ * this should indicate how they are cleared.
+ * FLAG_PRECHECK
+ * This is for the data access exception only. See it for
+ * more info.
+ *
+ * What's in between PREP() and DONE() (usually a CALL) is the actual
+ * servicing of the interrupt. During this time, any register may
+ * be used freely as they've all been saved in the exception frame
+ * (which is pointed-to by r31).
+ */
+
+#ifdef M88100
+#define PREP(NAME, NUM, BIT, SSBR_STUFF, FLAG_PRECHECK) \
+ xcr FLAGS, FLAGS, SR1 ; \
+ FLAG_PRECHECK ; \
+ /* the bsr later clobbers r1, so save now */ \
+ stcr r1, SR2 /* r1 now free */ ; \
+ /* set or clear the FLAG_FROM_KERNEL bit */ \
+ ldcr r1, EPSR ; \
+ bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f ; \
+ clr FLAGS, FLAGS, 1<FLAG_FROM_KERNEL> ; \
+ set FLAGS, FLAGS, 1<FLAG_FROM_KERNEL> ; \
+ /* get a stack (exception frame) */ \
+1: bsr _ASM_LABEL(setup_phase_one) ; \
+ /* TMP2 now free -- use to set EF_VECTOR */ \
+ or TMP2, r0, NUM ; \
+ st TMP2, r31, REG_OFF(EF_VECTOR) ; \
+ /* Clear any bits in the SSBR (held in TMP) */ \
+ /* SSBR_STUFF may be empty, though. */ \
+ SSBR_STUFF ; \
+ /* call setup_phase_two to restart the FPU */ \
+ /* and to save all general registers. */ \
+ bsr _ASM_LABEL(setup_phase_two) ; \
+ /* All general regs free -- do any debugging */ \
+ PREP_DEBUG(BIT, NAME)
+#endif
+
+#ifdef M88110
+#define PREP2(NAME, NUM, BIT, FLAG_PRECHECK) \
+ SAVE_CTX ; \
+ xcr FLAGS, FLAGS, SR1 ; \
+ FLAG_PRECHECK ; \
+ /* the bsr later clobbers r1, so save now */ ; \
+ stcr r1, SR2 /* r1 now free */ ; \
+ /* set or clear the FLAG_FROM_KERNEL bit */ ; \
+ ldcr r1, EPSR ; \
+ bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f ; \
+ clr FLAGS, FLAGS, 1<FLAG_FROM_KERNEL> ; \
+ set FLAGS, FLAGS, 1<FLAG_FROM_KERNEL> ; \
+ /* get a stack (exception frame) */ ; \
+1: bsr _ASM_LABEL(m88110_setup_phase_one) ; \
+ /* TMP2 now free -- use to set EF_VECTOR */ ; \
+ or TMP2, r0, NUM ; \
+ st TMP2, r31, REG_OFF(EF_VECTOR) ; \
+ /* call setup_phase_two to restart the FPU */ ; \
+ /* and to save all general registers. */ ; \
+ bsr _ASM_LABEL(m88110_setup_phase_two) ; \
+ /* All general regs free -- do any debugging */ ; \
+ PREP_DEBUG(BIT, NAME)
+#endif
+
+/* Some defines for use with PREP() */
+#define Clear_SSBR_Dest \
+ bsr _ASM_LABEL(clear_dest_ssbr_bit)
+#define Data_Precheck \
+ bb1.n FLAG_IGNORE_DATA_EXCEPTION, FLAGS, \
+ _ASM_LABEL(ignore_data_exception)
+#define M88110_Data_Precheck \
+ bb1.n FLAG_IGNORE_DATA_EXCEPTION, FLAGS, \
+ _ASM_LABEL(m88110_ignore_data_exception)
+
+#ifdef EH_DEBUG
+/*
+ * If we allow debugging, there is a variable "eh_debug"
+ * in which there is a bit for each exception. If the bit
+ * is set for an exception, debugging information is printed
+ * about that exception whenever it occurs.
+ *
+ * The bits are defined in "asm.h"
+ */
+
+ASGLOBAL(eh_debug)
+ word 0x00000000
+
+/*
+ * additional pre-servicing preparation to be done when
+ * debugging... check eh_debug and make the call if
+ * need be.
+ */
+#define PREP_DEBUG(DebugNumber, Name) \
+ or.u r2, r0, hi16(_ASM_LABEL(eh_debug)) ; \
+ ld r3, r2, lo16(_ASM_LABEL(eh_debug)) ; \
+ bb0 DebugNumber, r3, 4f ; \
+ /* call MY_info(ef,SR0,flags,kind)*/ \
+ or r2, r30, r0 ; \
+ ldcr r3, SR0 ; \
+ ldcr r4, SR1 ; \
+ or.u r5, r0, hi16(2f) ; \
+ or r5, r5, lo16(2f) ; \
+ bsr.n _C_LABEL(MY_info) ; \
+ subu r31, r31, 32 ; \
+ br.n 4f ; \
+ addu r31, r31, 32 ; \
+ data ; \
+2: string Name ; \
+ byte 0 ; \
+ align 4 ; \
+ text ; \
+4:
+
+
+/*
+ * Post-servicing work to be done.
+ * When debugging, check "eh_debug" and call the
+ * debug routined if neeed be.
+ *
+ * Then, return from the interrupt handler.
+ */
+#define DONE(DebugNumber) \
+ or.u r2, r0, hi16(_ASM_LABEL(eh_debug)) ; \
+ ld r3, r2, lo16(_ASM_LABEL(eh_debug)) ; \
+ bb0 DebugNumber, r3, 2f ; \
+ ldcr r4, SR1 ; \
+ CALL(_C_LABEL(MY_info_done), r31, r4) ; \
+2: br _ASM_LABEL(return_from_exception_handler)
+#define DONE2(DebugNumber) \
+ or.u r2, r0, hi16(_ASM_LABEL(eh_debug)) ; \
+ ld r3, r2, lo16(_ASM_LABEL(eh_debug)) ; \
+ bb0 DebugNumber, r3, 2f ; \
+ ldcr r4, SR1 ; \
+ CALL(_C_LABEL(MY_info_done), r31, r4) ; \
+2: br _ASM_LABEL(m88110_return_code)
+#else
+/*
+ * If not debugging, then no debug-prep to do.
+ * Also, when you're done, you're done! (no debug check).
+ */
+#define PREP_DEBUG(bit, name)
+#define DONE(num) \
+ br _ASM_LABEL(return_from_exception_handler)
+#define DONE2(num) \
+ br _ASM_LABEL(m88110_return_code)
+#endif /* EH_DEBUG */
+
+#ifdef M88100
+/*
+ * MVME18x exception handlers
+ */
+
+/* unknown exception handler */
+GLOBAL(unknown_handler)
+ PREP("unknown", 0, DEBUG_UNKNOWN_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_UNKNOWNFLT, r30)
+ DONE(DEBUG_UNKNOWN_BIT)
+
+/* interrupt exception handler */
+GLOBAL(interrupt_handler)
+ PREP("interrupt", 1, DEBUG_INTERRUPT_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_INT, r30)
+ DONE(DEBUG_INTERRUPT_BIT)
+
+/* instruction access exception handler */
+GLOBAL(instruction_access_handler)
+ PREP("inst", 2, DEBUG_INSTRUCTION_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_INSTFLT, r30)
+ DONE(DEBUG_INSTRUCTION_BIT)
+
+/*
+ * data access exception handler --
+ * See badaddr() below for info about Data_Precheck.
+ */
+GLOBAL(data_exception_handler)
+ PREP("data", 3, DEBUG_DATA_BIT,, Data_Precheck)
+ /* No need to call m88100_trap(T_DATAFLT) as PREP will do this for us */
+ DONE(DEBUG_DATA_BIT)
+
+/* misaligned access exception handler */
+GLOBAL(misaligned_handler)
+ PREP("misalign", 4, DEBUG_MISALIGN_BIT, Clear_SSBR_Dest,)
+ CALL(_C_LABEL(m88100_trap), T_MISALGNFLT, r30)
+ DONE(DEBUG_MISALIGN_BIT)
+
+/* unimplemented opcode exception handler */
+GLOBAL(unimplemented_handler)
+ PREP("unimp", 5, DEBUG_UNIMPLEMENTED_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_ILLFLT, r30)
+ DONE(DEBUG_UNIMPLEMENTED_BIT)
+
+/*
+ * Some versions of the chip have a bug whereby false privilege
+ * violation exceptions are raised. If the valid bit in the SXIP is clear,
+ * it is false. If so, just return. The code before PREP handles this....
+ */
+GLOBAL(privilege_handler)
+ stcr r1, SR2 /* hold r1 for a moment */
+ ldcr r1, SXIP /* look at the sxip... valid bit set? */
+ bb1.n RTE_VALID_BIT, r1, 1f /* skip over if a valid exception */
+ ldcr r1, SR2 /* restore r1 */
+ RTE
+1: PREP("privilege", 6, DEBUG_PRIVILEGE_BIT, Clear_SSBR_Dest,)
+ CALL(_C_LABEL(m88100_trap), T_PRIVINFLT, r30)
+ DONE(DEBUG_PRIVILEGE_BIT)
+
+/* bounds checking exception handler */
+GLOBAL(bounds_handler)
+ PREP("bounds", 7, DEBUG_BOUNDS_BIT, Clear_SSBR_Dest,)
+ CALL(_C_LABEL(m88100_trap), T_BNDFLT, r30)
+ DONE(DEBUG_BOUNDS_BIT)
+
+/* integer divide-by-zero exception handler */
+GLOBAL(divide_handler)
+ PREP("divide", 8, DEBUG_DIVIDE_BIT, Clear_SSBR_Dest,)
+ CALL(_C_LABEL(m88100_trap), T_ZERODIV, r30)
+ DONE(DEBUG_DIVIDE_BIT)
+
+/* integer overflow exception handler */
+GLOBAL(overflow_handler)
+ PREP("overflow", 9, DEBUG_OVERFLOW_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_OVFFLT, r30)
+ DONE(DEBUG_OVERFLOW_BIT)
+
+/* Floating-point precise handler */
+#define FPp_SSBR_STUFF \
+ bsr _ASM_LABEL(clear_FPp_ssbr_bit)
+GLOBAL(fp_precise_handler)
+ PREP("FPU precise", 114, DEBUG_FPp_BIT, FPp_SSBR_STUFF,)
+ CALL(_ASM_LABEL(m88100_Xfp_precise), r0, r30)
+ DONE(DEBUG_FPp_BIT)
+
+/* Floating-point imprecise handler */
+#define FPi_SSBR_STUFF \
+ bsr _ASM_LABEL(clear_FPi_ssbr_bit)
+GLOBAL(fp_imprecise_handler)
+ PREP("FPU imprecise", 115, DEBUG_FPi_BIT, FPi_SSBR_STUFF,)
+ CALL(_ASM_LABEL(Xfp_imprecise), r0, r30)
+ DONE(DEBUG_FPi_BIT)
+
+/* All standard system calls. */
+GLOBAL(syscall_handler)
+ PREP("syscall", 128, DEBUG_SYSCALL_BIT,,)
+ ld r13, r30, GENREG_OFF(13)
+ CALL(_C_LABEL(m88100_syscall), r13, r30)
+ DONE(DEBUG_SYSCALL_BIT)
+
+/* trap 496 comes here */
+GLOBAL(bugtrap)
+ PREP("bugsyscall", 496, DEBUG_BUGCALL_BIT,,)
+ ld r9, r30, GENREG_OFF(9)
+ CALL(_C_LABEL(bugsyscall), r9, r30)
+ DONE(DEBUG_BUGCALL_BIT)
+
+GLOBAL(sigsys)
+ PREP("sigsys", 501, DEBUG_SIGSYS_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_SIGSYS, r30)
+ DONE(DEBUG_SIGSYS_BIT)
+
+GLOBAL(sigtrap)
+ PREP("sigtrap", 510, DEBUG_SIGTRAP_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_SIGTRAP, r30)
+ DONE(DEBUG_SIGTRAP_BIT)
+
+GLOBAL(stepbpt)
+ PREP("stepbpt", 504, DEBUG_SIGTRAP_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_STEPBPT, r30)
+ DONE(DEBUG_SIGTRAP_BIT)
+
+GLOBAL(userbpt)
+ PREP("userbpt", 511, DEBUG_SIGTRAP_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_USERBPT, r30)
+ DONE(DEBUG_SIGTRAP_BIT)
+
+#ifdef DDB
+GLOBAL(break)
+ PREP("break", 130, DEBUG_BREAK_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_KDB_BREAK, r30)
+ DONE(DEBUG_BREAK_BIT)
+
+GLOBAL(trace)
+ PREP("trace", 131, DEBUG_TRACE_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_KDB_TRACE, r30)
+ DONE(DEBUG_TRACE_BIT)
+
+GLOBAL(entry)
+ PREP("kdb", 132, DEBUG_KDB_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_KDB_ENTRY, r30)
+ DONE(DEBUG_KDB_BIT)
+#else
+GLOBAL(break)
+ PREP("break", 130, DEBUG_BREAK_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_UNKNOWNFLT, r30)
+ DONE(DEBUG_BREAK_BIT)
+
+GLOBAL(trace)
+ PREP("trace", 131, DEBUG_TRACE_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_UNKNOWNFLT, r30)
+ DONE(DEBUG_TRACE_BIT)
+
+GLOBAL(entry)
+ PREP("unknown", 132, DEBUG_KDB_BIT,,)
+ CALL(_C_LABEL(m88100_trap), T_UNKNOWNFLT, r30)
+ DONE(DEBUG_KDB_BIT)
+#endif
+
+/*
+ * The error exception and reset exception handler.
+ *
+ * The error exception is raised when any other non-trap exception is raised
+ * while shadowing is off. This is Bad News.
+ *
+ * The reset exception is raised when the RST signal is asserted (machine
+ * is reset), the value of VBR is changed after exceptions are enabled,
+ * or when a jmp, br/bsr to addr 0 (accidents do happen :-)
+ * To tell the difference, you should check the value of r1 and the valid
+ * bit of SXIP.
+ * Upon a real reset, VBR is set to zero (0), so code must be at addr 0
+ * to handle it!!!
+ *
+ * The shadow registers are not valid in this case (shadowing was off, if this
+ * was an error exception, and may not be on, if this was a reset exception).
+ * R1-R31 may be interesting though, so we'll save them.
+ *
+ * We'll not worry about trashing r26-29 here,
+ * since they aren't generally used.
+ */
+GLOBAL(error_handler)
+ br.n 1f
+ or r29, r0, 10
+GLOBAL(reset_handler)
+ or r29, r0, 0
+1:
+ /* pick up the slavestack */
+ or r26, r0, r31 /* save old stack */
+ or.u r31, r0, hi16(_ASM_LABEL(intstack_end))
+ or r31, r31, lo16(_ASM_LABEL(intstack_end))
+
+#ifdef DEBUG
+ /* zero the stack, so we'll know what we're lookin' at */
+ or.u r27, r0, hi16(_C_LABEL(intstack))
+ or r27, r27, lo16(_C_LABEL(intstack))
+1: cmp r28, r27, r31
+ bb1 ge, r28, 2f /* branch if at the end of the stack */
+ st r0, r0, r27
+ br.n 1b
+ addu r27, r27, 4 /* bump up */
+2: /* stack has been cleared */
+#endif
+
+ /* ensure that stack is 8-byte aligned */
+ clr r31, r31, 3<0> /* round down to 8-byte boundary */
+
+ /* create exception frame on stack */
+ subu r31, r31, SIZEOF_EF /* r31 now our E.F. */
+
+ /* save old R31 and other R registers */
+ st.d r0 , r31, GENREG_OFF(0)
+ st.d r2 , r31, GENREG_OFF(2)
+ st.d r4 , r31, GENREG_OFF(4)
+ st.d r6 , r31, GENREG_OFF(6)
+ st.d r8 , r31, GENREG_OFF(8)
+ st.d r10, r31, GENREG_OFF(10)
+ st.d r12, r31, GENREG_OFF(12)
+ st.d r14, r31, GENREG_OFF(14)
+ st.d r16, r31, GENREG_OFF(16)
+ st.d r18, r31, GENREG_OFF(18)
+ st.d r20, r31, GENREG_OFF(20)
+ st.d r22, r31, GENREG_OFF(22)
+ st.d r24, r31, GENREG_OFF(24)
+ st r30, r31, GENREG_OFF(30)
+ st r26, r31, GENREG_OFF(31)
+
+ /* save shadow registers (are OLD if error_handler, though) */
+ ldcr r10, EPSR
+ st r10, r31, REG_OFF(EF_EPSR)
+ ldcr r10, SXIP
+ st r10, r31, REG_OFF(EF_SXIP)
+ ldcr r10, SNIP
+ st r10, r31, REG_OFF(EF_SNIP)
+ ldcr r10, SR1
+ st r10, r31, REG_OFF(EF_MODE)
+ ldcr r10, SFIP
+ st r10, r31, REG_OFF(EF_SFIP)
+ ldcr r10, SSBR
+ st r10, r31, REG_OFF(EF_SSBR)
+ stcr r0, SSBR /* won't want shadow bits bothering us later */
+
+ ldcr r10, DMT0
+ st r10, r31, REG_OFF(EF_DMT0)
+ ldcr r11, DMD0
+ st r11, r31, REG_OFF(EF_DMD0)
+ ldcr r12, DMA0
+
+ st r12, r31, REG_OFF(EF_DMA0)
+ ldcr r10, DMT1
+ st r10, r31, REG_OFF(EF_DMT1)
+ FLUSH_PIPELINE
+ ldcr r11, DMD1
+ st r11, r31, REG_OFF(EF_DMD1)
+ ldcr r12, DMA1
+ st r12, r31, REG_OFF(EF_DMA1)
+
+ ldcr r10, DMT2
+ st r10, r31, REG_OFF(EF_DMT2)
+ ldcr r11, DMD2
+ st r11, r31, REG_OFF(EF_DMD2)
+ ldcr r12, DMA2
+ st r12, r31, REG_OFF(EF_DMA2)
+
+ /* shove sr2 into EF_FPLS1 */
+ ldcr r10, SR2
+ st r10, r31, REG_OFF(EF_FPLS1)
+
+ /* shove sr3 into EF_FPHS2 */
+ ldcr r10, SR3
+ st r10, r31, REG_OFF(EF_FPHS2)
+
+ /* save error vector */
+ st r29, r31, REG_OFF(EF_VECTOR)
+
+ /*
+ * Cheap way to enable FPU and start shadowing again.
+ */
+ ldcr r10, PSR
+ clr r10, r10, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */
+ clr r10, r10, 1<PSR_SHADOW_FREEZE_BIT> /* and shadowing */
+ stcr r10, PSR
+ FLUSH_PIPELINE
+
+ /* put pointer to regs into r30... r31 will become a simple stack */
+ or r30, r31, r0
+
+ subu r31, r31, 0x10 /* make some breathing space */
+ st r30, r31, 0x0c /* store frame pointer on the st */
+ st r30, r31, 0x08 /* store again for the debugger to recognize */
+ or.u r20, r0, hi16(0x87654321)
+ or r20, r20, lo16(0x87654321)
+ st r20, r31, 0x04
+ st r20, r31, 0x00
+
+ CALL(_C_LABEL(error_fatal), r30, r30)
+
+ /* turn interrupts back on */
+ ldcr r1, PSR
+ clr r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r1, PSR
+ FLUSH_PIPELINE
+
+1:
+ br 1b
+ /* NOTREACHED */
+#endif /* M88100 */
+
+/*
+ * This is part of baddadr (below).
+ */
+#ifdef M88100
+ASLOCAL(ignore_data_exception)
+ /*
+ * SR1: previous FLAGS reg
+ * SR2: free
+ * SR3: must presere
+ * FLAGS: CPU status flags
+ */
+ xcr FLAGS, FLAGS, SR1 /* replace SR1, FLAGS */
+
+ /*
+ * For more info, see badaddr() below.
+ *
+ * We just want to jump to "badaddr__return_nonzero" below.
+ *
+ * We don't worry about trashing R2 here because we're
+ * jumping back to the function badaddr() where we're allowed
+ * to blast r2..r9 as we see fit.
+ */
+
+ /* the "+2" below is to set the VALID bit. */
+ or.u r2, r0, hi16(_ASM_LABEL(badaddr__return_nonzero) + 2)
+ or r2, r2, lo16(_ASM_LABEL(badaddr__return_nonzero) + 2)
+ stcr r2, SNIP /* Make it the next instruction to execute */
+ addu r2, r2, 4
+ stcr r2, SFIP /* and the next one after that, too. */
+ stcr r0, SSBR /* make the scoreboard happy. */
+ RTE
+#endif /* M88100 */
+
+#ifdef M88110
+/*
+ * This is part of baddadr (below).
+ */
+ASLOCAL(m88110_ignore_data_exception)
+ /*
+ * SR1: previous FLAGS reg
+ * SR2: free
+ * SR3: must preserve
+ * FLAGS: CPU status flags
+ */
+ xcr FLAGS, FLAGS, SR1 /* replace SR1, FLAGS */
+
+ /*
+ * For more info, see badaddr() below.
+ *
+ * We just want to jump to "m88110_badaddr__return_nonzero" below.
+ *
+ * We don't worry about trashing R2 here because we're
+ * jumping back to the function badaddr() where we're allowd
+ * to blast r2..r9 as we see fit.
+ */
+
+ or.u r2, r0, hi16(_ASM_LABEL(m88110_badaddr__return_nonzero))
+ or r2, r2, lo16(_ASM_LABEL(m88110_badaddr__return_nonzero))
+ stcr r2, EXIP /* Make it the next instruction to execute */
+ RTE
+#endif /* M88110 */
+
+/*
+ * extern boolean_t badaddr(unsigned addr, unsigned len)
+ *
+ * Returns true (non-zero) if the given LEN bytes starting at ADDR are
+ * not all currently accessible by the kernel.
+ *
+ * If all LEN bytes starting at ADDR are accessible, zero is returned.
+ *
+ * Len may be be 1, 2, or 4.
+ *
+ * This is implemented by setting a special flag in SR1 before trying to access
+ * the given address. If a data access exception is raised, the address
+ * is inaccessible. The exception handler will notice the special CPU flag
+ * and not try to swap the address in. Rather, it will return to
+ * "badaddr__return_nonzero" in this routine so that we may return non-zero
+ * to the calling routine.
+ *
+ * If no fault is raised, we continue to where we return zero to the calling
+ * routine (after removing the special CPU flag).
+ */
+
+GLOBAL(badaddr)
+ /*
+ * Disable interrupts ... don't want a context switch while we're
+ * doing this! Also, save the old PSR in R8 to restore later.
+ */
+ ldcr r8, PSR
+ set r4, r8, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r4, PSR
+ FLUSH_PIPELINE
+
+ ldcr r5, SR1
+ set r5, r5, 1<FLAG_IGNORE_DATA_EXCEPTION>
+ /* resetting r5 to SR1 done in the delay slot below. */
+
+ /*
+ * If it's a word we're doing, do that here. Otherwise,
+ * see if it's a halfword.....
+ */
+ sub r6, r3, 4
+ bcnd.n ne0, r6, _ASM_LABEL(badaddr__maybe_halfword)
+ stcr r5, SR1
+ FLUSH_PIPELINE
+
+ /*
+ * It's a bad address if it's misaligned.
+ */
+ bb1 0, r2, _ASM_LABEL(badaddr__return_nonzero)
+ bb1 1, r2, _ASM_LABEL(badaddr__return_nonzero)
+ /*
+ * The next line will either fault or not. If it faults, execution
+ * will go to: data_access_handler (see above)
+ * and then to: ignore_data_exception (see above)
+ * and then to: badaddr__return_nonzero (see below)
+ * which will return to the calling function.
+ *
+ * If there is no fault, execution just continues as normal.
+ */
+ ld r5, r2, 0
+ FLUSH_PIPELINE
+ br.n _ASM_LABEL(badaddr__return)
+ or r2, r0, r0 /* indicate a zero (address not bad) return.*/
+
+ASLOCAL(badaddr__maybe_halfword)
+ /* More or less like the code for checking a word above */
+ sub r6, r3, 2
+ bcnd ne0, r6, _ASM_LABEL(badaddr__maybe_byte)
+
+ /* it's bad if it's misaligned */
+ bb1 0, r2, _ASM_LABEL(badaddr__return_nonzero)
+
+ FLUSH_PIPELINE
+ ld.h r5, r2, 0
+ FLUSH_PIPELINE
+ br.n _ASM_LABEL(badaddr__return)
+ or r2, r0, r0
+
+ASLOCAL(badaddr__maybe_byte)
+#ifdef DEBUG
+ /* More or less like the code for checking a word above */
+ sub r6, r3, 1
+ bcnd ne0, r6, _ASM_LABEL(badaddr__unknown_size)
+#endif
+ FLUSH_PIPELINE
+ ld.b r5, r2, 0
+ FLUSH_PIPELINE
+ br.n _ASM_LABEL(badaddr__return)
+ or r2, r0, r0
+ASLOCAL(badaddr__unknown_size)
+#ifdef DEBUG
+ data
+1: string "bad length (%d) to badaddr() from 0x%x\000"
+ text
+ subu r31, r31, 32
+ or.u r2, r0, hi16(1b)
+ or r2, r2, lo16(1b)
+ bsr.n _C_LABEL(panic)
+ or r4, r0, r1
+ addu r31, r31, 32
+ /*NOTREACHED*/
+#endif
+
+#ifdef M88110
+ASLOCAL(m88110_badaddr__return_nonzero)
+ /*
+ * On mc88110, we possibly took an exception and we have to clear
+ * DSR before the rte instruction clears the EFRZ bit in the PSR.
+ */
+ stcr r0, DSR
+ stcr r0, DLAR
+ stcr r0, DPAR
+ /* FALLTHROUGH */
+#endif
+ASLOCAL(badaddr__return_nonzero)
+ or r2, r0, 1
+ /* FALLTHROUGH */
+
+ASLOCAL(badaddr__return)
+ ldcr r4, SR1
+ clr r4, r4, 1<FLAG_IGNORE_DATA_EXCEPTION>
+ stcr r4, SR1
+
+ /*
+ * Restore the PSR to what it was before.
+ * The only difference is that we might be enabling interrupts
+ * (which we turned off above). If interrupts were already off,
+ * we do not want to turn them on now, so we just restore from
+ * where we saved it.
+ */
+ stcr r8, PSR
+ FLUSH_PIPELINE
+ jmp r1
+
+#ifdef M88100
+ASLOCAL(setup_phase_one)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: saved copy of exception-time r1
+ * SR3: must be preserved .. may be the exception-time stack
+ * r1: return address to calling exception handler
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * Decide where we're going to put the exception frame.
+ * Might be at the end of R31, SR3, or the thread's pcb.
+ */
+
+ /* Check if we are coming in from a FPU restart exception.
+ If so, the pcb will be in SR3 */
+ NOP
+ xcr r1, r1, SR2
+ NOP
+ NOP
+ NOP
+
+ bb1 FLAG_ENABLING_FPU, FLAGS, _ASM_LABEL(use_SR3_pcb)
+ /* are we coming in from user mode? If so, pick up thread pcb */
+ bb0 FLAG_FROM_KERNEL, FLAGS, _ASM_LABEL(pickup_stack)
+
+ /* Interrupt in kernel mode, not FPU restart */
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: must be preserved; may be important for other exceptions
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * We're already on the kernel stack, but not having
+ * needed to use SR3. We can just make room on the
+ * stack (r31) for our exception frame.
+ */
+ subu r31, r31, SIZEOF_EF /* r31 now our E.F. */
+ st FLAGS,r31, REG_OFF(EF_FLAGS) /* save flags */
+ st r1, r31, GENREG_OFF(1) /* save prev. r1 (now r1 free)*/
+
+ ldcr r1, SR3 /* save previous SR3 */
+ st r1, r31, REG_OFF(EF_SR3)
+
+ addu r1, r31, SIZEOF_EF /* save previous r31 */
+ br.n _ASM_LABEL(have_pcb)
+ st r1, r31, GENREG_OFF(31)
+
+ASLOCAL(use_SR3_pcb)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: must be preserved; exception-time stack pointer
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * An exception occurred while enabling the FPU. Since r31
+ * is the user's r31 while enabling the FPU, we had put
+ * our pcb pointer into SR3, so make room from
+ * there for our stack pointer.
+ * We need to check if SR3 is the old stack pointer or the
+ * pointer off to the user pcb. If it pointing to the user
+ * pcb, we need to pick up the kernel stack. Otherwise
+ * we need to allocate a frame upon it.
+ * We look at the EPSR to see if it was from user mode
+ * Unfortunately, we have no registers free at the moment
+ * But we know register 0 in the pcb frame will always be
+ * zero, so we can use it as scratch storage.
+ */
+ xcr r30, r30, SR3 /* r30 = old exception frame */
+ st r1, r30, GENREG_OFF(0) /* free up r1 */
+ ld r1, r30, REG_OFF(EF_EPSR) /* get back the epsr */
+ bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f /* if user mode */
+ ld r1, r30, GENREG_OFF(0) /* restore r1 */
+ /* we were in kernel mode - dump frame upon the stack */
+ st r0, r30, GENREG_OFF(0) /* repair old frame */
+ subu r30, r30, SIZEOF_EF /* r30 now our E.F. */
+ st FLAGS,r30, REG_OFF(EF_FLAGS) /* save flags */
+ st r1, r30, GENREG_OFF(1) /* save prev r1 (now free) */
+
+ st r31, r30, GENREG_OFF(31) /* save previous r31 */
+ or r31, r0, r30 /* make r31 our pointer. */
+ addu r30, r30, SIZEOF_EF /* r30 now has previous SR3 */
+ st r30, r31, REG_OFF(EF_SR3) /* save previous SR3 */
+ br.n _ASM_LABEL(have_pcb)
+ xcr r30, r30, SR3 /* restore r30 */
+1:
+ /* we took an exception while restarting the FPU from user space.
+ * Consequently, we never picked up a stack. Do so now.
+ * R1 is currently free (saved in the exception frame pointed at by
+ * r30) */
+ or.u r1, r0, hi16(_ASM_LABEL(kstack))
+ ld r1, r1, lo16(_ASM_LABEL(kstack))
+ addu r1, r1, USIZE-SIZEOF_EF
+ st FLAGS,r1, REG_OFF(EF_FLAGS) /* store flags */
+ st r31, r1, GENREG_OFF(31) /* store r31 - now free */
+ st r30, r1, REG_OFF(EF_SR3) /* store old SR3 (pcb) */
+ or r31, r1, r0 /* make r31 our exception fp */
+ ld r1, r30, GENREG_OFF(0) /* restore old r1 */
+ st r0, r30, GENREG_OFF(0) /* repair that frame */
+ st r1, r31, GENREG_OFF(1) /* store r1 */
+ br.n _ASM_LABEL(have_pcb)
+ xcr r30, r30, SR3 /* restore r30 */
+
+ASLOCAL(pickup_stack)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: free
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * Since we're servicing an exception from user mode, we
+ * know that SR3 is free. We use it to free up a temp.
+ * register to be used in getting the thread's pcb
+ */
+ stcr r31, SR3 /* save previous r31 */
+
+ /* switch to the thread's kernel stack. */
+ or.u r31, r0, hi16(_C_LABEL(curpcb))
+ ld r31, r31, lo16(_C_LABEL(curpcb))
+ addu r31, r31, PCB_USER_STATE /* point to user save area */
+ st FLAGS,r31, REG_OFF(EF_FLAGS) /* save flags */
+ st r1, r31, GENREG_OFF(1) /* save prev. r1 (now free) */
+ ldcr r1, SR3 /* save previous r31 */
+ st r1, r31, GENREG_OFF(31)
+ /* FALLTHROUGH */
+
+ASLOCAL(have_pcb)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: free
+ * r1: free
+ * FLAGS: CPU status flags
+ * r31: our exception frame
+ * Valid in the exception frame:
+ * Exception-time r1, r31, FLAGS.
+ * Exception SR3, if appropriate.
+ *
+ * immediate goal:
+ * Save the shadow registers that need to be saved to
+ * the exception frame.
+ */
+ stcr TMP, SR3 /* free up TMP, TMP2, TMP3 */
+ SAVE_TMP2
+ SAVE_TMP3
+
+ /* save some exception-time registers to the exception frame */
+ ldcr TMP, EPSR
+ st TMP, r31, REG_OFF(EF_EPSR)
+ ldcr TMP3, SNIP
+ st TMP3, r31, REG_OFF(EF_SNIP)
+ ldcr TMP2, SFIP
+ st TMP2, r31, REG_OFF(EF_SFIP)
+ /* get and store the cpu number */
+ extu TMP, FLAGS, FLAG_CPU_FIELD_WIDTH<0> /* TMP = cpu# */
+ st TMP, r31, REG_OFF(EF_CPU)
+
+ /*
+ * Save Pbus fault status register from data and inst CMMU.
+ */
+ extu TMP, FLAGS, FLAG_CPU_FIELD_WIDTH<0> /* TMP = cpu# */
+ cmp TMP2, TMP, 0x0 /* CPU0 ? */
+ bb1 eq, TMP2, 1f
+ cmp TMP2, TMP, 0x1 /* CPU1 ? */
+ bb1 eq, TMP2, 2f
+ cmp TMP2, TMP, 0x2 /* CPU2 ? */
+ bb1 eq, TMP2, 3f
+ cmp TMP2, TMP, 0x3 /* CPU3 ? */
+ bb1 eq, TMP2, 4f
+ /* Arrrrg! bad cpu# */
+ br _ASM_LABEL(Lbadcpupanic)
+ /* XXX WHAT ABOUT MODULES WITH SPLIT U/S CMMUS ??? */
+1:
+ /* must be CPU0 */
+ or.u TMP, r0, hi16(CMMU_I0)
+ ld TMP2, TMP, lo16(CMMU_I0) + 0x108
+ st TMP2, r31, REG_OFF(EF_IPFSR)
+ or.u TMP, r0, hi16(CMMU_D0)
+ ld TMP2, TMP, lo16(CMMU_D0) + 0x108
+ st TMP2, r31, REG_OFF(EF_DPFSR)
+ br _ASM_LABEL(pfsr_done)
+2:
+ /* must be CPU1 */
+ or.u TMP, r0, hi16(CMMU_I1)
+ ld TMP2, TMP, lo16(CMMU_I1) + 0x108
+ st TMP2, r31, REG_OFF(EF_IPFSR)
+ or.u TMP, r0, hi16(CMMU_D1)
+ ld TMP2, TMP, lo16(CMMU_D1) + 0x108
+ st TMP2, r31, REG_OFF(EF_DPFSR)
+ br _ASM_LABEL(pfsr_done)
+3:
+ /* must be CPU2 */
+ or.u TMP, r0, hi16(CMMU_I2)
+ ld TMP2, TMP, lo16(CMMU_I2) + 0x108
+ st TMP2, r31, REG_OFF(EF_IPFSR)
+ or.u TMP, r0, hi16(CMMU_D2)
+ ld TMP2, TMP, lo16(CMMU_D2) + 0x108
+ st TMP2, r31, REG_OFF(EF_DPFSR)
+ br _ASM_LABEL(pfsr_done)
+4:
+ /* must be CPU3 */
+ or.u TMP, r0, hi16(CMMU_I3)
+ ld TMP2, TMP, lo16(CMMU_I3) + 0x108
+ st TMP2, r31, REG_OFF(EF_IPFSR)
+ or.u TMP, r0, hi16(CMMU_D3)
+ ld TMP2, TMP, lo16(CMMU_D3) + 0x108
+ st TMP2, r31, REG_OFF(EF_DPFSR)
+ br _ASM_LABEL(pfsr_done)
+5:
+
+ASLOCAL(pfsr_done)
+ ldcr TMP, SSBR
+ ldcr TMP2, SXIP
+ ldcr TMP3, DMT0
+ st TMP2, r31, REG_OFF(EF_SXIP)
+
+/*
+ * The above shadow registers are obligatory for any and all
+ * exceptions. Now, if the data access pipeline is not clear,
+ * we must save the DMx shadow registers, as well as clear
+ * the appropriate SSBR bits for the destination registers of
+ * loads or xmems.
+ */
+ bb0.n DMT_VALID_BIT, TMP3, 8f
+ st TMP3, r31, REG_OFF(EF_DMT0)
+
+ ldcr TMP2, DMT1
+ ldcr TMP3, DMT2
+ st TMP2, r31, REG_OFF(EF_DMT1)
+ st TMP3, r31, REG_OFF(EF_DMT2)
+
+ ldcr TMP2, DMA0
+ ldcr TMP3, DMA1
+ st TMP2, r31, REG_OFF(EF_DMA0)
+ st TMP3, r31, REG_OFF(EF_DMA1)
+
+ ldcr TMP2, DMA2
+ ldcr TMP3, DMD0
+ st TMP2, r31, REG_OFF(EF_DMA2)
+ st TMP3, r31, REG_OFF(EF_DMD0)
+
+ FLUSH_PIPELINE
+ ldcr TMP2, DMD1
+ ldcr TMP3, DMD2
+ st TMP2, r31, REG_OFF(EF_DMD1)
+ st TMP3, r31, REG_OFF(EF_DMD2)
+
+/*
+ * need to clear "appropriate" bits in the SSBR before
+ * we restart the FPU
+ */
+
+ ldcr TMP2, DMT0
+ bb0.n DMT_VALID_BIT, TMP2, 8f
+ /* make sure an exception in fpu_enable will not see our DMT0 */
+ stcr r0, DMT0
+ bb1 DMT_LOCK_BIT, TMP2, 1f
+ bb1 DMT_WRITE_BIT, TMP2, 2f
+1:
+ extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
+ set TMP2, TMP2, 1<5>
+ clr TMP, TMP, TMP2
+2:
+ ldcr TMP2, DMT1
+ bb0 DMT_VALID_BIT, TMP2, 4f
+ bb1 DMT_LOCK_BIT, TMP2, 3f
+ bb1 DMT_WRITE_BIT, TMP2, 4f
+3:
+ extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
+ set TMP2, TMP2, 1<5>
+ clr TMP, TMP, TMP2
+4:
+ ldcr TMP2, DMT2
+ bb0 DMT_VALID_BIT, TMP2, 8f
+ bb1 DMT_LOCK_BIT, TMP2, 5f
+ bb1 DMT_WRITE_BIT, TMP2, 8f
+ bb1 DMT_DOUBLE_BIT,TMP2, 6f
+5:
+ extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
+ br.n 7f
+ set TMP2, TMP2, 1<5> /* single */
+6:
+ extu TMP2, TMP2, DMT_DREG_WIDTH <DMT_DREG_OFFSET>
+ set TMP2, TMP2, 1<6> /* double */
+7:
+ clr TMP, TMP, TMP2
+8:
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: saved TMP
+ * r1: free
+ * TMP: possibly revised SSBR
+ * TMP2: free
+ * TMP3: free
+ * FLAGS: CPU status flags
+ * r31: exception frame
+ * Valid in the exception frame:
+ * Exception-time r1, r31, FLAGS.
+ * Exception-time TMP2, TMP3.
+ * Exception-time espr, sfip, snip, sxip.
+ * Dmt0.
+ * Other data pipeline control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ */
+ ldcr r1, SR2
+ jmp r1 /* allow the handler to clear more SSBR bits */
+
+#endif /* M88100 */
+
+ASLOCAL(clear_FPi_ssbr_bit)
+ /*
+ * Clear floatingpoint-imprecise ssbr bits.
+ * Also, save appropriate FPU control registers to the E.F.
+ *
+ * r1: return address to calling exception handler
+ * TMP: (possibly) revised ssbr
+ * TMP2: free
+ * TMP3: free
+ */
+ fldcr TMP2, FPSR
+ fldcr TMP3, FPCR
+ st TMP2, r31, REG_OFF(EF_FPSR)
+ st TMP3, r31, REG_OFF(EF_FPCR)
+
+ fldcr TMP2, FPECR
+ fldcr TMP3, FPRH
+ st TMP2, r31, REG_OFF(EF_FPECR)
+ st TMP3, r31, REG_OFF(EF_FPRH)
+
+ fldcr TMP2, FPIT
+ fldcr TMP3, FPRL
+ st TMP2, r31, REG_OFF(EF_FPIT)
+ st TMP3, r31, REG_OFF(EF_FPRL)
+
+ /*
+ * We only need clear the bit in the SSBR for the
+ * 2nd reg of a double result [see section 6.8.5]
+ */
+#define FPIT_SIZE_BIT 10
+ bb0 FPIT_SIZE_BIT, TMP2, 1f
+ extu TMP2, TMP2, 5<0> /* get the reg. */
+ set TMP2, TMP2, 1<6> /* set width */
+ clr TMP, TMP, TMP2
+1:
+ jmp r1
+
+
+ASLOCAL(clear_FPp_ssbr_bit)
+ /*
+ * Clear floating pont precise ssbr bits.
+ * Also, save appropriate FPU control registers to the E.F.
+ *
+ * r1: return address to calling exception handler
+ * TMP: (possibly) revised ssbr
+ * TMP2: free
+ * TMP3: free
+ */
+ fldcr TMP2, FPSR
+ fldcr TMP3, FPCR
+ st TMP2, r31, REG_OFF(EF_FPSR)
+ st TMP3, r31, REG_OFF(EF_FPCR)
+
+ fldcr TMP3, FPECR
+ st TMP3, r31, REG_OFF(EF_FPECR)
+ fldcr TMP2, FPHS1
+ fldcr TMP3, FPHS2
+ st TMP2, r31, REG_OFF(EF_FPHS1)
+ st TMP3, r31, REG_OFF(EF_FPHS2)
+
+ fldcr TMP2, FPLS1
+ fldcr TMP3, FPLS2
+ st TMP2, r31, REG_OFF(EF_FPLS1)
+ st TMP3, r31, REG_OFF(EF_FPLS2)
+
+ fldcr TMP2, FPPT
+ st TMP2, r31, REG_OFF(EF_FPPT)
+1:
+
+#define FPPT_SIZE_BIT 5
+ bb1.n FPPT_SIZE_BIT, TMP2, 2f
+ extu TMP3, TMP2, 5<0> /* get FP operation dest reg */
+ br.n 3f
+ set TMP3, TMP3, 1<5> /* size=1 - clear one bit for float */
+2:
+ set TMP3, TMP3, 1<6> /* size=2 - clear two bit for double */
+3:
+ clr TMP, TMP, TMP3 /* clear bit(s) in ssbr. */
+ jmp r1
+
+
+ASLOCAL(clear_dest_ssbr_bit)
+ /*
+ * There are various cases where an exception can leave the
+ * destination register's bit in the SB set.
+ * Examples:
+ * misaligned or privilege exception on a LD or XMEM
+ * DIV or DIVU by zero.
+ *
+ * I think that if the instruction is LD.D, then two bits must
+ * be cleared.
+ *
+ * Even though there are a number of instructions/exception
+ * combinations that could fire this code up, it's only required
+ * to be run for the above cases. However, I don't think it'll
+ * ever be a problem to run this in other cases (ST instructions,
+ * for example), so I don't bother checking. If we had to check
+ * for every possible instruction, this code would be much larger.
+ *
+ * The only checking, then, is to see if it's a LD.D or not.
+ *
+ * At the moment....
+ * r1: return address to calling exception handler
+ * TMP: (possibly) revised ssbr
+ * TMP2: free
+ * TMP3: free
+ */
+
+ ldcr TMP3, EPSR /* going to check: user or system memory? */
+ ldcr TMP2, SXIP /* get the instruction's address */
+ bb1.n PSR_SUPERVISOR_MODE_BIT, TMP3, 2f
+ clr TMP2, TMP2, 2<0> /* get rid of valid and error bits. */
+
+ /* user space load here */
+#if ERRATA__XXX_USR
+ NOP
+ ld.usr TMP2,TMP2, r0 /* get the instruction itself */
+ NOP
+ NOP
+ NOP
+ br 3f
+#else
+ br.n 3f
+ ld.usr TMP2,TMP2, r0 /* get the instruction itself */
+#endif
+
+2: /* system space load here */
+ ld TMP2, TMP2, r0 /* get the instruction itself */
+
+3: /* now we have the instruction..... */
+ /*
+ * Now see if it's a double load
+ * There are three forms of double load [IMM16, scaled, unscaled],
+ * which can be checked by matching against two templates:
+ * -- 77776666555544443333222211110000 --
+ * if (((instruction & 11111100000000000000000000000000) ==
+ * 00010000000000000000000000000000) ;;
+ * ((instruction & 11111100000000001111110011100000) ==
+ * 11110100000000000001000000000000))
+ * {
+ * It's a load double, so
+ * clear two SSBR bits.
+ * } else {
+ * It's not a load double.
+ * Must be a load single, xmem, or st
+ * Thus, clear one SSBR bit.
+ * }
+ */
+ /* check the first pattern for ld.d */
+ extu TMP3, TMP2, 16<16> /* get the upper 16 bits */
+ mask TMP3, TMP3, 0xFC00 /* apply the mask */
+ cmp TMP3, TMP3, 0x1000 /* if equal, it's a load double */
+ bb1 eq, TMP3, 2f
+
+ /* still could be -- check the second pattern for ld.d */
+ /* look at the upper 16 bits first */
+ extu TMP3, TMP2, 16<16> /* get the upper 16 bits */
+ mask TMP3, TMP3, 0xFC00 /* apply the mask */
+ cmp TMP3, TMP3, 0xF400 /* if equal, might be a load double */
+ bb1 ne, TMP3, 1f /* not equal, must be single */
+
+ /* now look at the lower 16 bits */
+ extu TMP3, TMP2, 16<0> /* get the lower 16 bits */
+ mask TMP3, TMP3, 0xFCE0 /* apply the mask */
+ cmp TMP3, TMP3, 0x1000 /* if equal, it's a load double */
+ bb1 eq, TMP3, 2f
+
+1: /* misaligned single */
+ extu TMP2, TMP2, 5<21> /* get the destination register */
+ br.n 3f
+ set TMP2, TMP2, 1<5> /* set size=1 */
+
+2: /* misaligned double */
+ extu TMP2, TMP2, 5<21> /* get the destination register */
+ set TMP2, TMP2, 1<6> /* set size=2 -- clear two bits */
+3:
+ jmp.n r1
+ clr TMP, TMP, TMP2 /* clear bit(s) in ssbr. */
+
+#ifdef M88100
+
+ASLOCAL(setup_phase_two)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: free
+ * SR3: saved TMP
+ * r1: return address to calling exception handler
+ * TMP: possibly revised SSBR
+ * TMP2: free
+ * TMP3: free
+ * FLAGS: CPU status flags
+ * r31: our exception frame
+ * Valid in the exception frame:
+ * Exception-time r1, r31, FLAGS.
+ * Exception-time TMP2, TMP3.
+ * Exception-time espr, sfip, snip, sxip.
+ * Exception number (EF_VECTOR).
+ * Dmt0
+ * Other data pipeline control registers, if appropriate.
+ * FPU control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ *
+ * immediate goal:
+ * restore the system to the exception-time state (except
+ * SR3 will be OUR stack pointer) so that we may resart the FPU.
+ */
+
+ stcr TMP, SSBR /* done with SSBR, TMP now free */
+ RESTORE_TMP2 /* done with extra temp regs */
+ RESTORE_TMP3 /* done with extra temp regs */
+
+ /* Get the current PSR and modify for the rte to enable the FPU */
+ ldcr TMP, PSR
+ clr TMP, TMP, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */
+ clr TMP, TMP, 1<PSR_SHADOW_FREEZE_BIT> /* and shadowing */
+ stcr TMP, EPSR
+
+ /* the "+2" below is to set the VALID_BIT */
+ or.u TMP, r0, hi16(_ASM_LABEL(fpu_enable) + 2)
+ or TMP, TMP, lo16(_ASM_LABEL(fpu_enable) + 2)
+ stcr TMP, SNIP /* jump to here fpu_enable */
+ addu TMP, TMP, 4
+ stcr TMP, SFIP /* and then continue after that */
+
+ set FLAGS, FLAGS, 1<FLAG_ENABLING_FPU>
+ xcr FLAGS, FLAGS, SR1
+ st r1, r31, REG_OFF(EF_RET) /* save the return address */
+ ld r1, r31, GENREG_OFF(1) /* get original r1 */
+
+ xcr TMP, r31, SR3 /* TMP now restored. R31 now saved in SR3 */
+ ld r31, r31, GENREG_OFF(31) /* get original r31 */
+
+ /*
+ * SR1: CPU flags
+ * SR2: free
+ * SR3: pointer to our exception frame (our stack pointer)
+ * r1 through r31: original exception-time values
+ *
+ * Valid in the exception frame:
+ * Exception-time FLAGS.
+ * Exception-time espr, sfip, snip, sxip.
+ * Exception number (EF_VECTOR).
+ * Dmt0
+ * Other data pipeline control registers, if appropriate.
+ * FPU control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ * Held temporarly in the exception frame:
+ * Return address to the calling exception handler.
+ *
+ * immediate goal:
+ * Do an RTE to restart the fpu and jump to "fpu_enable"
+ * Another exception (or exceptions) may be raised in
+ * this, which is why FLAG_ENABLING_FPU is set in SR1.
+ */
+
+ RTE /* jumps to "fpu_enable" on the next line to enable the FPU. */
+
+ASLOCAL(fpu_enable)
+ FLUSH_PIPELINE
+ xcr TMP, TMP, SR3 /* get E.F. pointer */
+ st r30, TMP, GENREG_OFF(30) /* save previous r30, r31 */
+ st r31, TMP, GENREG_OFF(31) /* save previous r30, r31 */
+ or r31, TMP, r0 /* transfer E.F. pointer to r31 */
+ ld TMP, r31, REG_OFF(EF_SR3) /* get previous SR3 */
+
+ /* make sure that the FLAG_ENABLING_FPU bit is off */
+ xcr FLAGS,FLAGS,SR1
+ clr FLAGS,FLAGS,1<FLAG_ENABLING_FPU>
+ xcr FLAGS,FLAGS,SR1
+
+ xcr TMP, TMP, SR3 /* replace TMP, SR3 */
+
+ /* now save all regs to the exception frame. */
+ st r0 , r31, GENREG_OFF(0)
+ st r1 , r31, GENREG_OFF(1)
+ st r2 , r31, GENREG_OFF(2)
+ st r3 , r31, GENREG_OFF(3)
+ st r4 , r31, GENREG_OFF(4)
+ st r5 , r31, GENREG_OFF(5)
+ st r6 , r31, GENREG_OFF(6)
+ st r7 , r31, GENREG_OFF(7)
+ st r8 , r31, GENREG_OFF(8)
+ st r9 , r31, GENREG_OFF(9)
+ st r10, r31, GENREG_OFF(10)
+ st r11, r31, GENREG_OFF(11)
+ st r12, r31, GENREG_OFF(12)
+ st r13, r31, GENREG_OFF(13)
+ st r14, r31, GENREG_OFF(14)
+ st r15, r31, GENREG_OFF(15)
+ st r16, r31, GENREG_OFF(16)
+ st r17, r31, GENREG_OFF(17)
+ st r18, r31, GENREG_OFF(18)
+ st r19, r31, GENREG_OFF(19)
+ st r20, r31, GENREG_OFF(20)
+ st r21, r31, GENREG_OFF(21)
+ st r22, r31, GENREG_OFF(22)
+ st r23, r31, GENREG_OFF(23)
+ st r24, r31, GENREG_OFF(24)
+ st r25, r31, GENREG_OFF(25)
+ st r26, r31, GENREG_OFF(26)
+ st r27, r31, GENREG_OFF(27)
+ st r28, r31, GENREG_OFF(28)
+ st r29, r31, GENREG_OFF(29)
+#ifdef JEFF_DEBUG
+ /* mark beginning of frame with notable value */
+ or.u r20, r0, hi16(0x12345678)
+ or r20, r20, lo16(0x12345678)
+ st r20, r31, GENREG_OFF(0)
+#endif
+
+ /* get and save IPL */
+ bsr.n _C_LABEL(getipl)
+ subu r31, r31, 32
+ addu r31, r31, 32
+ st r2, r31, REG_OFF(EF_MASK)
+
+ /*
+ * SR1: free
+ * SR2: free
+ * SR3: previous exception-time SR3
+ * r1: return address to the calling exception handler
+ * r2 through r30: free
+ * r31: our exception frame
+ *
+ * Valid in the exception frame:
+ * Exception-time r0 through r31.
+ * Exception-time FLAGS.
+ * Exception-time espr, sfip, snip, sxip.
+ * Exception number (EF_VECTOR).
+ * Dmt0
+ * Other data pipeline control registers, if appropriate.
+ * FPU control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ *
+ * immediate goal:
+ * Pick up a stack if we came in from user mode.
+ * Put a copy of the exception frame pointer into r30
+ * Bump the stack a doubleword and write the exception frame pointer.
+ * If not an interrupt exception, turn on interrupts and service any
+ * outstanding data access exceptions.
+ * Return to calling exception handler to service the exception.
+ */
+
+ /*
+ * If it's not the interrupt exception, enable interrupts and
+ * take care of any data access exceptions......
+ */
+ or r30, r0, r31 /* get a copy of the e.f. pointer */
+ ld r2, r31, REG_OFF(EF_EPSR)
+ bb1 PSR_SUPERVISOR_MODE_BIT, r2, 1f /* if in kernel mode */
+
+ or.u r31, r0, hi16(_ASM_LABEL(kstack))
+ ld r31, r31, lo16(_ASM_LABEL(kstack))
+ addu r31, r31, USIZE /* point at proper end */
+1:
+
+ /*
+ * here - r30 holds a pointer to the exception frame.
+ * r31 is a pointer to the kernel stack/interrupt stack.
+ */
+ subu r31, r31, 8 /* make some breathing space */
+ st r30, r31, 0 /* store frame pointer on the stack */
+#ifdef DDB
+ st r30, r31, 4 /* store it for the debugger to recognize */
+#endif /* DDB */
+
+ ld r2, r30, REG_OFF(EF_VECTOR)
+ bcnd.n eq0, r2, 8f /* error exception */
+ ld r14, r30, REG_OFF(EF_RET)
+
+ /*
+ * Do not process possible data exceptions here if this is an interrupt.
+ * Instead, the interrupt handler will take care of this by itself.
+ */
+ cmp r3, r2, 1 /* is an interrupt? */
+ bb1.n eq, r3, 8f /* skip if so */
+
+#ifdef DDB
+ cmp r3, r2, 130 /* DDB break exception */
+ bb1.n eq, r3, 8f
+ cmp r3, r2, 132 /* DDB entry exception */
+ bb1.n eq, r3, 8f
+#endif
+
+ /* turn interrupts back on */
+ ldcr r2, PSR
+ clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r2, PSR
+ FLUSH_PIPELINE
+
+ /* service any outstanding data pipeline stuff */
+ ld r3, r30, REG_OFF(EF_DMT0)
+ bb0 DMT_VALID_BIT, r3, 8f
+
+ /*
+ * r30 can be clobbered by calls. So stuff its value into a preserved
+ * register, say r15. R14 is in use (see return_to_... below).
+ */
+ or r15, r0, r30
+ CALL(_C_LABEL(m88100_trap), T_DATAFLT, r15)
+ or r30, r0, r15
+
+8:
+ jmp r14 /* loaded above */
+#endif /* M88100 */
+
+/*
+ * proc_trampoline.
+ * When a process setup by cpu_set_kpc() resumes, it will find itself in
+ * proc_trampoline, with r31 pointing to a ksigframe. proc_trampoline will
+ * load func and proc values from ksigframe, call the function, and on return
+ * pop off the ksigframe. Then, it will load pc from the switchframe and
+ * jump there.
+ */
+
+ENTRY(proc_trampoline)
+ ld r1, r31, 0 /* load func */
+ ld r2, r31, 4 /* load proc pointer */
+ jsr.n r1
+ subu r31, r31, 32 /* create stack space for function */
+ addu r31, r31, 32 + 8 /* stack space above + ksigframe */
+ ld r1, r31, 0 /* load pc */
+ ld r2, r31, 4 /* & proc pointer from switch frame */
+ jsr.n r1
+ addu r31, r31, 8
+
+/*
+ * proc_do_uret
+ * this is called as proc_do_uret(proc) from proc_trampoline(). This function
+ * loads r31 with a pointer to the trap frame for the given proc and calls
+ * return_from_exception_handler which loads all the registers and does an
+ * rte.
+ */
+
+ENTRY(proc_do_uret)
+ ld r3,r2,P_ADDR /* p->p_addr */
+ addu r3,r3,PCB_USER_STATE /* p->p_addr.u_pcb.user_state */
+ st r3,r31,0 /* put it on the stack */
+#if defined(M88100) && defined(M88110)
+#ifdef M88110
+ or.u r2, r0, hi16(_C_LABEL(cputyp))
+ ld r3, r2, lo16(_C_LABEL(cputyp))
+ cmp r2, r3, CPU_88110
+ bb1 eq, r2, _ASM_LABEL(m88110_return_code)
+ /* br _ASM_LABEL(return_from_exception_handler) */
+#endif
+#endif
+
+ /*
+ * Regs r1-r30 are free. R31 is pointing at the word
+ * on the kernel stack where our pointer to the exception frame
+ * it stored. Reload it now.
+ *
+ * At this point, if EF_DMT0 is not zero on MC88100, then
+ * this must have been an interrupt where the fault didn't
+ * get corrected above. We'll do that now.
+ *
+ * We load it into r14 since it is preserved across function
+ * calls, and we may have to call some routines from within here.
+ *
+ * Control is transferred here from obvious places in this file.
+ */
+
+#ifdef M88100
+ASLOCAL(return_from_exception_handler)
+ /*
+ * if there happens to be a data fault that hasn't been serviced yet,
+ * go off and service that...
+ */
+
+#define FPTR r14
+ ld FPTR, r31, 0 /* grab exception frame pointer */
+ ld r3, FPTR, REG_OFF(EF_DMT0)
+ bb0 DMT_VALID_BIT, r3, _ASM_LABEL(check_ast)
+
+ /*
+ * If it's the interrupt exception, and interrupts were
+ * initially disabled, enable interrupts again...
+ */
+ ld r2, FPTR, REG_OFF(EF_VECTOR)
+ cmp r2, r2, 1 /* is an interrupt? */
+ bb1.n ne, r2, 1f /* if not so, skip */
+
+ /* ...unless they were already disabled */
+ ld r2, FPTR, REG_OFF(EF_EPSR)
+ bb1.n PSR_INTERRUPT_DISABLE_BIT, r2, 1f
+
+ ldcr r2, PSR
+ clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r2, PSR
+ FLUSH_PIPELINE
+1:
+
+ CALL(_C_LABEL(m88100_trap), T_DATAFLT, r30)
+ br _ASM_LABEL(check_ast)
+#endif /* M88100 */
+
+#ifdef M88110
+ASLOCAL(m88110_return_code)
+#define FPTR r14
+ ld FPTR, r31, 0 /* grab exception frame pointer */
+
+#if 0
+ /*
+ * If it's the interrupt exception, enable interrupt.
+ */
+
+ /*
+ * Is it ever possible to have interrupt exception while EPSR has
+ * it disabled? I don't think so.. XXX nivas
+ *
+ * On mc88110, you can. The NMI interrupt. aka ABORT. XXX smurph
+ */
+ ld r2, FPTR, REG_OFF(EF_VECTOR)
+ cmp r2, r2, 1 /* Is it an interrupt? */
+ bb1.n ne, r2, 1f /* If not, skip */
+
+ /* ...unless they were already disabled */
+ ld r2, FPTR, REG_OFF(EF_EPSR)
+ bb1.n PSR_INTERRUPT_DISABLE_BIT, r2, 1f
+
+ ldcr r2, PSR
+ clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* enable interrupts */
+ stcr r2, PSR
+ FLUSH_PIPELINE
+1:
+#endif
+#endif /* M88110 */
+
+/*
+ * If the saved ipl is 0, then call dosoftint() to process soft
+ * interrupts.
+ * If returning to user land, look for ASTs
+ */
+ASLOCAL(check_ast)
+ ld r2, FPTR, REG_OFF(EF_EPSR) /* get pre-exception PSR */
+ bb1 PSR_INTERRUPT_DISABLE_BIT, r2, 1f /* skip if ints off */
+ ld r2, FPTR, REG_OFF(EF_MASK) /* get pre-exception ipl */
+ bcnd ne0, r2, 1f /* can't do softint's */
+
+ subu r31, r31, 32
+ bsr.n _C_LABEL(setipl)
+ or r2, r0, IPL_SOFTCLOCK
+ /* at ipl 1 now */
+ bsr _C_LABEL(dosoftint)
+ /* is this needed? we are going to restore the ipl below XXX nivas */
+ bsr.n _C_LABEL(setipl)
+ or r2, r0, IPL_NONE /* ints are enabled */
+ addu r31, r31, 32
+ /* at ipl 0 now */
+1:
+ ld r2, FPTR, REG_OFF(EF_EPSR) /* get pre-exception PSR */
+ bb1 PSR_SUPERVISOR_MODE_BIT, r2, no_ast /*skip if system mode */
+
+ /* should assert here - not in user mode with ints off XXX nivas */
+ /* get and check want_ast */
+ or.u r2, r0, hi16(_C_LABEL(want_ast))
+ ld r3, r2, lo16(_C_LABEL(want_ast))
+ bcnd eq0, r3, no_ast
+
+ /*
+ * trap(AST,...) will service ast's.
+ */
+#if defined(M88110) && defined(M88100)
+ or.u r2, r0, hi16(_C_LABEL(cputyp))
+ ld r3, r2, lo16(_C_LABEL(cputyp))
+ cmp r2, r3, CPU_88110
+ bb0 eq, r2, 2f
+#endif
+#if defined(M88110)
+ CALL(_C_LABEL(m88110_trap), T_ASTFLT, FPTR)
+#endif
+#if defined(M88110) && defined(M88100)
+ br no_ast
+2:
+#endif
+#ifdef M88100
+ CALL(_C_LABEL(m88100_trap), T_ASTFLT, FPTR)
+#endif
+
+ASLOCAL(no_ast)
+ /* disable interrupts */
+ ldcr r1, PSR
+ set r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r1, PSR
+ FLUSH_PIPELINE
+
+ /* now ready to return....*/
+ subu r31, r31, 32
+ bsr.n _C_LABEL(setipl)
+ ld r2, FPTR, REG_OFF(EF_MASK) /* get pre-exception ipl */
+ addu r31, r31, 32
+
+ /*
+ * Transfer the frame pointer to r31, since we no longer need a stack.
+ * No page faults here, and interrupts are disabled.
+ */
+ or r31, r0, FPTR
+ /* restore r1 later */
+ ld r2 , r31, GENREG_OFF(2)
+ ld r3 , r31, GENREG_OFF(3)
+ ld r4 , r31, GENREG_OFF(4)
+ ld r5 , r31, GENREG_OFF(5)
+ ld r6 , r31, GENREG_OFF(6)
+ ld r7 , r31, GENREG_OFF(7)
+ ld r8 , r31, GENREG_OFF(8)
+ ld r9 , r31, GENREG_OFF(9)
+ ld r10, r31, GENREG_OFF(10)
+ ld r11, r31, GENREG_OFF(11)
+ ld r12, r31, GENREG_OFF(12)
+ ld r13, r31, GENREG_OFF(13)
+ ld r14, r31, GENREG_OFF(14)
+ ld r15, r31, GENREG_OFF(15)
+ ld r16, r31, GENREG_OFF(16)
+ ld r17, r31, GENREG_OFF(17)
+ ld r18, r31, GENREG_OFF(18)
+ ld r19, r31, GENREG_OFF(19)
+ ld r20, r31, GENREG_OFF(20)
+ ld r21, r31, GENREG_OFF(21)
+ ld r22, r31, GENREG_OFF(22)
+ ld r23, r31, GENREG_OFF(23)
+ ld r24, r31, GENREG_OFF(24)
+ ld r25, r31, GENREG_OFF(25)
+ ld r26, r31, GENREG_OFF(26)
+ ld r27, r31, GENREG_OFF(27)
+ ld r28, r31, GENREG_OFF(28)
+ ld r29, r31, GENREG_OFF(29)
+ /* restore r1, r30, r31 later */
+
+ /* disable shadowing */
+ ldcr r1, PSR
+ set r1, r1, 1<PSR_SHADOW_FREEZE_BIT>
+ stcr r1, PSR
+ FLUSH_PIPELINE
+
+ /* reload the control regs*/
+#ifdef M88110
+#ifdef M88100
+ or.u r1, r0, hi16(_C_LABEL(cputyp))
+ ld r30, r1, lo16(_C_LABEL(cputyp))
+ cmp r1, r30, CPU_88110
+ bb1 ne, r1, 1f
+#endif
+ /* mc88110 needs the EXIP */
+ ld r30, r31, REG_OFF(EF_ENIP)
+ ld r1, r31, REG_OFF(EF_EXIP)
+ stcr r30, ENIP
+ stcr r1, EXIP
+#ifdef M88100
+ br 2f
+1:
+#endif
+#endif
+#ifdef M88100
+ st r0, r31, REG_OFF(EF_IPFSR)
+ st r0, r31, REG_OFF(EF_DPFSR)
+
+ /*
+ * Note: no need to restore the SXIP.
+ * When the "rte" causes execution to continue
+ * first with the instruction pointed to by the NIP
+ * and then the FIP.
+ *
+ * See MC88100 Risc Processor User's Manual, 2nd Edition,
+ * section 6.4.3.1.2-4
+ */
+ ld r30, r31, REG_OFF(EF_SNIP)
+ ld r1, r31, REG_OFF(EF_SFIP)
+ stcr r0, SSBR
+ stcr r30, SNIP
+ stcr r1, SFIP
+2:
+#endif
+ ld r30, r31, REG_OFF(EF_EPSR)
+ ld r1, r31, REG_OFF(EF_MODE)
+ stcr r30, EPSR
+
+ /* Now restore r1, r30, and r31 */
+ ld r1, r31, GENREG_OFF(1)
+ ld r30, r31, GENREG_OFF(30)
+ ld r31, r31, GENREG_OFF(31)
+
+ RTE
+
+#ifdef M88110
+/*
+ * MVME197 exception handlers
+ */
+
+/* unknown exception handler */
+GLOBAL(m88110_unknown_handler)
+ PREP2("unknown", 0, DEBUG_UNKNOWN_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_UNKNOWNFLT, r30)
+ DONE2(DEBUG_UNKNOWN_BIT)
+
+/* interrupt exception handler */
+GLOBAL(m88110_interrupt_handler)
+ PREP2("interrupt", 1, DEBUG_INTERRUPT_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_INT, r30)
+ DONE2(DEBUG_INTERRUPT_BIT)
+
+/* instruction access exception handler */
+GLOBAL(m88110_instruction_access_handler)
+ PREP2("inst", 2, DEBUG_INSTRUCTION_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_INSTFLT, r30)
+ DONE2(DEBUG_INSTRUCTION_BIT)
+/*
+ * data access exception handler --
+ * See badaddr() below for info about Data_Precheck.
+ */
+GLOBAL(m88110_data_exception_handler)
+ PREP2("data", 3, DEBUG_DATA_BIT, M88110_Data_Precheck)
+ CALL(_C_LABEL(m88110_trap), T_DATAFLT, r30)
+ DONE2(DEBUG_DATA_BIT)
+
+/* misaligned access exception handler */
+GLOBAL(m88110_misaligned_handler)
+ PREP2("misalign", 4, DEBUG_MISALIGN_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_MISALGNFLT, r30)
+ DONE2(DEBUG_MISALIGN_BIT)
+
+/* unimplemented opcode exception handler */
+GLOBAL(m88110_unimplemented_handler)
+ PREP2("unimp", 5, DEBUG_UNIMPLEMENTED_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_ILLFLT, r30)
+ DONE2(DEBUG_UNIMPLEMENTED_BIT)
+
+/* privilege exception handler */
+GLOBAL(m88110_privilege_handler)
+ PREP2("privilege", 6, DEBUG_PRIVILEGE_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_PRIVINFLT, r30)
+ DONE2(DEBUG_PRIVILEGE_BIT)
+
+/*
+ * I'm not sure what the trap(T_BNDFLT,...) does, but it doesn't send
+ * a signal to the process...
+ */
+GLOBAL(m88110_bounds_handler)
+ PREP2("bounds", 7, DEBUG_BOUNDS_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_BNDFLT, r30)
+ DONE2(DEBUG_BOUNDS_BIT)
+
+/* integer divide-by-zero exception handler */
+GLOBAL(m88110_divide_handler)
+ PREP2("divide", 8, DEBUG_DIVIDE_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_ZERODIV, r30)
+ DONE2(DEBUG_DIVIDE_BIT)
+
+/* integer overflow exception handler */
+GLOBAL(m88110_overflow_handler)
+ PREP2("overflow", 9, DEBUG_OVERFLOW_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_OVFFLT, r30)
+ DONE2(DEBUG_OVERFLOW_BIT)
+
+/* Floating-point precise handler */
+GLOBAL(m88110_fp_precise_handler)
+ PREP2("FPU precise", 114, DEBUG_FPp_BIT,)
+ CALL(_ASM_LABEL(m88110_Xfp_precise), r0, r30)
+ DONE2(DEBUG_FPp_BIT)
+
+/* MVME197 non-maskable interrupt handler (ABORT button) */
+GLOBAL(m88110_nonmaskable)
+ PREP2("MVME197 non-mask", 11, DEBUG_NON_MASK_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_NON_MASK, r30)
+ DONE2(DEBUG_NON_MASK_BIT)
+
+/* MVME197 data MMU read miss handler */
+GLOBAL(m88110_data_read_miss)
+ PREP2("MVME197 read miss", 12, DEBUG_197_READ_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_197_READ, r30)
+ DONE2(DEBUG_197_READ_BIT)
+
+/* MVME197 data MMU write miss handler */
+GLOBAL(m88110_data_write_miss)
+ PREP2("MVME197 write miss", 13, DEBUG_197_WRITE_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_197_WRITE, r30)
+ DONE2(DEBUG_197_WRITE_BIT)
+
+/* MVME197 inst MMU ATC miss handler */
+GLOBAL(m88110_inst_atc_miss)
+ PREP2("MVME197 inst miss", 14, DEBUG_197_INST_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_197_INST, r30)
+ DONE2(DEBUG_197_INST_BIT)
+
+/* All standard system calls. */
+GLOBAL(m88110_syscall_handler)
+ PREP2("syscall", 128, DEBUG_SYSCALL_BIT,)
+ ld r13, r30, GENREG_OFF(13)
+ CALL(_C_LABEL(m88110_syscall), r13, r30)
+ DONE2(DEBUG_SYSCALL_BIT)
+
+/* trap 496 comes here */
+GLOBAL(m88110_bugtrap)
+ PREP2("bugsyscall", 496, DEBUG_BUGCALL_BIT,)
+ ld r9, r30, GENREG_OFF(9)
+ CALL(_C_LABEL(bugsyscall), r9, r30)
+ DONE2(DEBUG_BUGCALL_BIT)
+
+GLOBAL(m88110_sigsys)
+ PREP2("sigsys", 501, DEBUG_SIGSYS_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_SIGSYS, r30)
+ DONE2(DEBUG_SIGSYS_BIT)
+
+GLOBAL(m88110_sigtrap)
+ PREP2("sigtrap", 510, DEBUG_SIGTRAP_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_SIGTRAP, r30)
+ DONE2(DEBUG_SIGTRAP_BIT)
+
+GLOBAL(m88110_stepbpt)
+ PREP2("stepbpt", 504, DEBUG_SIGTRAP_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_STEPBPT, r30)
+ DONE2(DEBUG_SIGTRAP_BIT)
+
+GLOBAL(m88110_userbpt)
+ PREP2("userbpt", 511, DEBUG_SIGTRAP_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_USERBPT, r30)
+ DONE2(DEBUG_SIGTRAP_BIT)
+
+#ifdef DDB
+GLOBAL(m88110_break)
+ PREP2("break", 130, DEBUG_BREAK_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_KDB_BREAK, r30)
+ DONE2(DEBUG_BREAK_BIT)
+
+GLOBAL(m88110_trace)
+ PREP2("trace", 131, DEBUG_TRACE_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_KDB_TRACE, r30)
+ DONE2(DEBUG_TRACE_BIT)
+
+GLOBAL(m88110_entry)
+ PREP2("kdb", 132, DEBUG_KDB_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_KDB_ENTRY, r30)
+ DONE2(DEBUG_KDB_BIT)
+#else
+GLOBAL(m88110_break)
+ PREP2("break", 130, DEBUG_BREAK_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_UNKNOWNFLT, r30)
+ DONE2(DEBUG_BREAK_BIT)
+
+GLOBAL(m88110_trace)
+ PREP2("trace", 131, DEBUG_TRACE_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_UNKNOWNFLT, r30)
+ DONE2(DEBUG_TRACE_BIT)
+
+GLOBAL(m88110_entry)
+ PREP2("unknown", 132, DEBUG_KDB_BIT,)
+ CALL(_C_LABEL(m88110_trap), T_UNKNOWNFLT, r30)
+ DONE2(DEBUG_KDB_BIT)
+#endif
+
+/*
+ * The error exception and reset exception handler.
+ *
+ * The error exception is raised when any other non-trap exception is raised
+ * while shadowing is off. This is Bad News.
+ *
+ * The reset exception is raised when the RST signal is asserted (machine
+ * is reset), the value of VBR is changed after exceptions are enabled,
+ * or when a jmp, br/bsr to addr 0 (accidents do happen :-)
+ * Upon a real reset, VBR is set to zero (0), so code must be at addr 0
+ * to handle it!!!
+ *
+ * The shadow registers are not valid in this case (shadowing was off, if this
+ * was an error exception, and may not be on, if this was a reset exception).
+ * R1-R31 may be interesting though, so we'll save them.
+ *
+ * We'll not worry about trashing r26-29 here,
+ * since they aren't generally used.
+ */
+GLOBAL(m88110_error_handler)
+ br.n 1f
+ or r29, r0, 10
+GLOBAL(m88110_reset_handler)
+ or r29, r0, 0
+1:
+ /* pick up the slavestack */
+ or r26, r0, r31 /* save old stack */
+ or.u r31, r0, hi16(_ASM_LABEL(intstack_end))
+ or r31, r31, lo16(_ASM_LABEL(intstack_end))
+
+#ifdef DEBUG
+ /* zero the stack, so we'll know what we're lookin' at */
+ or.u r27, r0, hi16(_C_LABEL(intstack))
+ or r27, r27, lo16(_C_LABEL(intstack))
+1: cmp r28, r27, r31
+ bb1 ge, r28, 2f /* branch if at the end of the stack */
+ st r0, r0, r27
+ br.n 1b
+ addu r27, r27, 4 /* bump up */
+2: /* stack has been cleared */
+#endif
+
+ /* ensure that stack is 8-byte aligned */
+ clr r31, r31, 3<0> /* round down to 8-byte boundary */
+
+ /* create exception frame on stack */
+ subu r31, r31, SIZEOF_EF /* r31 now our E.F. */
+
+ /* save old R31 and other R registers */
+ st.d r0 , r31, GENREG_OFF(0)
+ st.d r2 , r31, GENREG_OFF(2)
+ st.d r4 , r31, GENREG_OFF(4)
+ st.d r6 , r31, GENREG_OFF(6)
+ st.d r8 , r31, GENREG_OFF(8)
+ st.d r10, r31, GENREG_OFF(10)
+ st.d r12, r31, GENREG_OFF(12)
+ st.d r14, r31, GENREG_OFF(14)
+ st.d r16, r31, GENREG_OFF(16)
+ st.d r18, r31, GENREG_OFF(18)
+ st.d r20, r31, GENREG_OFF(20)
+ st.d r22, r31, GENREG_OFF(22)
+ st.d r24, r31, GENREG_OFF(24)
+ st r30, r31, GENREG_OFF(30)
+ st r26, r31, GENREG_OFF(31)
+
+ /* vector is put in SRO (either 0 or 10 at this point) */
+ st r29, r31, REG_OFF(EF_VECTOR)
+ cmp r29, r29, 0 /* is it the reset exception? */
+ bb1.n ne, r29, 1f /* if not, skip */
+
+ /* save shadow registers (are OLD if error_handler, though) */
+ ldcr r10, EPSR
+ st r10, r31, REG_OFF(EF_EPSR)
+ ldcr r10, EXIP
+ st r10, r31, REG_OFF(EF_EXIP)
+ ldcr r10, ENIP
+ st r10, r31, REG_OFF(EF_ENIP)
+ ldcr r10, DSR
+ st r10, r31, REG_OFF(EF_DSR)
+ ldcr r10, DLAR
+ st r10, r31, REG_OFF(EF_DLAR)
+ ldcr r10, DPAR
+ st r10, r31, REG_OFF(EF_DPAR)
+ ldcr r10, ISR
+ st r10, r31, REG_OFF(EF_ISR)
+ ldcr r10, ILAR
+ st r10, r31, REG_OFF(EF_ILAR)
+ ldcr r10, IPAR
+ st r10, r31, REG_OFF(EF_IPAR)
+ ldcr r10, SR1
+ br.n 2f
+ st r10, r31, REG_OFF(EF_MODE)
+
+1:
+ /* retrieve saved shadow registers for error_handler, though) */
+ or.u r30, r0, hi16(_ASM_LABEL(save_frame))
+ or r30, r30, lo16(_ASM_LABEL(save_frame))
+ ld r10, r30, REG_OFF(EF_EPSR)
+ st r10, r31, REG_OFF(EF_EPSR)
+ ld r10, r30, REG_OFF(EF_EXIP)
+ st r10, r31, REG_OFF(EF_ENIP)
+ ld r10, r30, REG_OFF(EF_DSR)
+ st r10, r31, REG_OFF(EF_DSR)
+ ld r10, r30, REG_OFF(EF_DLAR)
+ st r10, r31, REG_OFF(EF_DLAR)
+ ld r10, r30, REG_OFF(EF_DPAR)
+ st r10, r31, REG_OFF(EF_DPAR)
+ ld r10, r30, REG_OFF(EF_ISR)
+ st r10, r31, REG_OFF(EF_ISR)
+ ld r10, r30, REG_OFF(EF_ILAR)
+ st r10, r31, REG_OFF(EF_ILAR)
+ ld r10, r30, REG_OFF(EF_IPAR)
+ st r10, r31, REG_OFF(EF_IPAR)
+ ld r10, r30, REG_OFF(EF_ISAP)
+ st r10, r31, REG_OFF(EF_ISAP)
+ ld r10, r30, REG_OFF(EF_DSAP)
+ st r10, r31, REG_OFF(EF_DSAP)
+ ld r10, r30, REG_OFF(EF_IUAP)
+ st r10, r31, REG_OFF(EF_IUAP)
+ ld r10, r30, REG_OFF(EF_DUAP)
+ st r10, r31, REG_OFF(EF_DUAP)
+ ldcr r10, SR1
+ st r10, r31, REG_OFF(EF_MODE)
+2:
+ /* shove sr2 into EF_FPLS1 */
+ ldcr r10, SR2
+ st r10, r31, REG_OFF(EF_FPLS1)
+
+ /* shove sr3 into EF_FPHS2 */
+ ldcr r10, SR3
+ st r10, r31, REG_OFF(EF_FPHS2)
+
+ /*
+ * Cheap way to enable FPU and start shadowing again.
+ */
+ ldcr r10, PSR
+ clr r10, r10, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */
+ clr r10, r10, 1<PSR_SHADOW_FREEZE_BIT> /* and shadowing */
+ stcr r10, PSR
+ FLUSH_PIPELINE
+
+ /* put pointer to regs into r30... r31 will become a simple stack */
+ or r30, r31, r0
+
+ subu r31, r31, 0x10 /* make some breathing space */
+ st r30, r31, 0x0c /* store frame pointer on the st */
+ st r30, r31, 0x08 /* store again for the debugger to recognize */
+ or.u r20, r0, hi16(0x87654321)
+ or r20, r20, lo16(0x87654321)
+ st r20, r31, 0x04
+ st r20, r31, 0x00
+
+ CALL(_C_LABEL(error_fatal), r30, r30)
+
+ /* turn interrupts back on */
+ ldcr r1, PSR
+ clr r1, r1, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r1, PSR
+ FLUSH_PIPELINE
+
+1:
+ br 1b
+ /* NOTREACHED */
+
+ASLOCAL(m88110_setup_phase_one)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: saved copy of exception-time r1
+ * SR3: must be preserved .. may be the exception-time stack
+ * r1: return address to calling exception handler
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * Decide where we're going to put the exception frame.
+ * Might be at the end of R31, SR3, or the thread's pcb.
+ */
+
+ /* Check if we are coming in from a FPU restart exception.
+ If so, the pcb will be in SR3 */
+ NOP
+ xcr r1, r1, SR2
+ NOP
+ NOP
+ NOP
+
+ bb1 FLAG_ENABLING_FPU, FLAGS, _ASM_LABEL(m88110_use_SR3_pcb)
+ /* are we coming in from user mode? If so, pick up process pcb */
+ bb0 FLAG_FROM_KERNEL, FLAGS, _ASM_LABEL(m88110_pickup_stack)
+
+ /* Interrupt in kernel mode, not FPU restart */
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: must be preserved; may be important for other exceptions
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * We're already on the kernel stack, but not having
+ * needed to use SR3. We can just make room on the
+ * stack (r31) for our exception frame.
+ */
+ subu r31, r31, SIZEOF_EF /* r31 now our E.F. */
+ st FLAGS,r31, REG_OFF(EF_FLAGS) /* save flags */
+ st r1, r31, GENREG_OFF(1) /* save prev. r1 (now free) */
+
+ ldcr r1, SR3 /* save previous SR3 */
+ st r1, r31, REG_OFF(EF_SR3)
+
+ addu r1, r31, SIZEOF_EF /* save previous r31 */
+ br.n _ASM_LABEL(m88110_have_pcb)
+ st r1, r31, GENREG_OFF(31)
+
+ASLOCAL(m88110_use_SR3_pcb)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: must be preserved; exception-time stack pointer
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * An exception occurred while enabling the FPU. Since r31 is the
+ * user's r31 while enabling the FPU, we had put our pcb pointer
+ * into SR3, so make room from there for our stack pointer.
+ * We need to check if SR3 is the old stack pointer or the pointer
+ * off to the user pcb. If it pointing to the user pcb, we need to
+ * pick up the kernel stack. Otherwise we need to allocate a frame
+ * upon it.
+ * We look at the EPSR to see if it was from user mode
+ * Unfortunately, we have no registers free at the moment, but we
+ * know register 0 in the pcb frame will always be zero, so we can
+ * use it as scratch storage.
+ */
+#if 1
+ br _C_LABEL(m88110_error_handler)
+#else
+ /* Testing!!! */
+ xcr r30, r30, SR3 /* r30 = old exception frame */
+ st r1, r30, GENREG_OFF(0) /* free up r1 */
+ ld r1, r30, REG_OFF(EF_EPSR) /* get back the epsr */
+ bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f /* if user mode */
+ ld r1, r30, GENREG_OFF(0) /* restore r1 */
+ /* we were in kernel mode - dump frame upon the stack */
+ st r0, r30, GENREG_OFF(0) /* repair old frame */
+ subu r30, r30, SIZEOF_EF /* r30 now our E.F. */
+ st FLAGS,r30, REG_OFF(EF_FLAGS) /* save flags */
+ st r1, r30, GENREG_OFF(1) /* save prev. r1 (now free) */
+
+ st r31, r30, GENREG_OFF(31) /* save previous r31 */
+ or r31, r0, r30 /* make r31 our pointer. */
+ addu r30, r30, SIZEOF_EF /* r30 now has previous SR3 */
+ st r30, r31, REG_OFF(EF_SR3) /* save previous SR3 */
+ br.n _ASM_LABEL(m88110_have_pcb)
+ xcr r30, r30, SR3 /* restore r30 */
+1:
+ /*
+ * We took an exception while restarting the FPU from user space.
+ * Consequently, we never picked up a stack. Do so now.
+ * R1 is currently free (saved in the exception frame pointed at by
+ * r30)
+ */
+ or.u r1, r0, hi16(_ASM_LABEL(kstack))
+ ld r1, r1, lo16(_ASM_LABEL(kstack))
+ addu r1, r1, USIZE-SIZEOF_EF
+ st FLAGS,r1, REG_OFF(EF_FLAGS) /* store flags */
+ st r31, r1, GENREG_OFF(31) /* store r31 - now free */
+ st r30, r1, REG_OFF(EF_SR3) /* store old SR3 (pcb) */
+ or r31, r1, r0 /* make r31 our exception fp */
+ ld r1, r30, GENREG_OFF(0) /* restore old r1 */
+ st r0, r30, GENREG_OFF(0) /* repair that frame */
+ st r1, r31, GENREG_OFF(1) /* store r1 */
+ br.n _ASM_LABEL(m88110_have_pcb)
+ xcr r30, r30, SR3 /* restore r30 */
+#endif
+
+ASLOCAL(m88110_pickup_stack)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: free
+ * FLAGS: CPU status flags
+ *
+ * immediate goal:
+ * Since we're servicing an exception from user mode, we
+ * know that SR3 is free. We use it to free up a temporary
+ * register to be used in getting the thread's pcb.
+ */
+ stcr r31, SR3 /* save previous r31 */
+
+ /* switch to the thread's kernel stack. */
+ or.u r31, r0, hi16(_C_LABEL(curpcb))
+ ld r31, r31, lo16(_C_LABEL(curpcb))
+ addu r31, r31, PCB_USER_STATE /* point to user save area */
+ st FLAGS,r31, REG_OFF(EF_FLAGS) /* save flags */
+ st r1, r31, GENREG_OFF(1) /* save prev. r1 (now free)*/
+ ldcr r1, SR3 /* save previous r31 */
+ st r1, r31, GENREG_OFF(31)
+ /* FALLTHROUGH */
+
+ASLOCAL(m88110_have_pcb)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: return address to the calling exception handler
+ * SR3: free
+ * r1: free
+ * FLAGS: CPU status flags
+ * r31: our exception frame
+ * Valid in the exception frame:
+ * Exception-time r1, r31, FLAGS.
+ * Exception SR3, if appropriate.
+ *
+ * immediate goal:
+ * Save the shadow registers that need to be saved to
+ * the exception frame.
+ */
+ stcr TMP, SR3 /* free up TMP, TMP2, TMP3 */
+ SAVE_TMP2
+ SAVE_TMP3
+
+ /* save some exception-time registers to the exception frame */
+ ldcr TMP, EPSR
+ st TMP, r31, REG_OFF(EF_EPSR)
+ ldcr TMP2, EXIP
+ /* if the instruction was NOT in the delay slot, ignore ENIP */
+ bb0.n 0, TMP2, 1f
+ st TMP2, r31, REG_OFF(EF_EXIP)
+ ldcr TMP3, ENIP
+ st TMP3, r31, REG_OFF(EF_ENIP)
+1:
+
+ /* get and store the cpu number */
+ extu TMP, FLAGS, FLAG_CPU_FIELD_WIDTH<0> /* TMP = cpu# */
+ st TMP, r31, REG_OFF(EF_CPU)
+
+ /*
+ * Save Pbus fault status register from data and inst CMMU.
+ */
+ ldcr TMP, ISR
+ ldcr TMP2, ILAR
+ ldcr TMP3, IPAR
+ st TMP, r31, REG_OFF(EF_ISR)
+ st TMP2, r31, REG_OFF(EF_ILAR)
+ st TMP3, r31, REG_OFF(EF_IPAR)
+ ldcr TMP, ISAP
+ ldcr TMP2, IUAP
+ st TMP, r31, REG_OFF(EF_ISAP)
+ st TMP2, r31, REG_OFF(EF_IUAP)
+ ldcr TMP, DSR
+ ldcr TMP2, DLAR
+ ldcr TMP3, DPAR
+ st TMP, r31, REG_OFF(EF_DSR)
+ st TMP2, r31, REG_OFF(EF_DLAR)
+ st TMP3, r31, REG_OFF(EF_DPAR)
+ ldcr TMP, DSAP
+ ldcr TMP2, DUAP
+ st TMP, r31, REG_OFF(EF_DSAP)
+ st TMP2, r31, REG_OFF(EF_DUAP)
+
+ ldcr r1, SR2
+ jmp r1
+
+ASLOCAL(m88110_setup_phase_two)
+ /*
+ * SR1: saved copy of exception-time register now holding FLAGS
+ * SR2: free
+ * SR3: saved TMP
+ * r1: return address to calling exception handler
+ * TMP: possibly revised SSBR
+ * TMP2: free
+ * TMP3: free
+ * FLAGS: CPU status flags
+ * r31: our exception frame
+ * Valid in the exception frame:
+ * Exception-time r1, r31, FLAGS.
+ * Exception-time TMP2, TMP3.
+ * Exception-time espr, enip, exip.
+ * Exception number (EF_VECTOR).
+ * Dmt0
+ * Other data pipeline control registers, if appropriate.
+ * FPU control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ *
+ * immediate goal:
+ * restore the system to the exception-time state (except SR3 will
+ * be OUR stack pointer) so that we may resart the FPU.
+ */
+
+ RESTORE_TMP2 /* done with extra temp regs */
+ RESTORE_TMP3 /* done with extra temp regs */
+
+ ldcr TMP, PSR
+ clr TMP, TMP, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */
+ clr TMP, TMP, 1<PSR_SHADOW_FREEZE_BIT> /* and shadowing */
+ stcr TMP, EPSR
+
+ or.u TMP, r0, hi16(_ASM_LABEL(m88110_fpu_enable))
+ or TMP, TMP, lo16(_ASM_LABEL(m88110_fpu_enable))
+ stcr TMP, EXIP /* jump to here m88110_fpu_enable */
+ addu TMP, TMP, 4
+ stcr TMP, ENIP /* and then continue after that */
+
+ set FLAGS, FLAGS, 1<FLAG_ENABLING_FPU>
+ xcr FLAGS, FLAGS, SR1
+ st r1, r31, REG_OFF(EF_RET) /* save the return address */
+ ld r1, r31, GENREG_OFF(1) /* get original r1 */
+
+ ldcr TMP, SR3
+ stcr r31, SR3 /* TMP now restored. R31 now saved in SR3 */
+ ld r31, r31, GENREG_OFF(31) /* get original r31 */
+
+ /*
+ * SR1: CPU flags
+ * SR2: free
+ * SR3: pointer to our exception frame (our stack pointer)
+ * r1 through r31: original exception-time values
+ *
+ * Valid in the exception frame:
+ * Exception-time FLAGS.
+ * Exception-time espr, sfip, enip, exip.
+ * Exception number (EF_VECTOR).
+ * Dmt0
+ * Other data pipeline control registers, if appropriate.
+ * FPU control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ * Held temporarily in the exception frame:
+ * Return address to the calling exception handler.
+ *
+ * immediate goal:
+ * Do an RTE to restart the fpu and jump to "m88110_fpu_enable"
+ * Another exception (or exceptions) may be raised in
+ * this, which is why FLAG_ENABLING_FPU is set in SR1.
+ */
+ NOP
+ RTE /* jumps to "m88110_fpu_enable" on the next line to enable the FPU. */
+
+ASLOCAL(m88110_fpu_enable)
+ FLUSH_PIPELINE
+ /* Now we can handle another exception!!! */
+ /* Now that EFRZ is cleared, we can clear these */
+ stcr r0, ISR /* Clear ISR */
+ stcr r0, ILAR /* Clear ILAR */
+ stcr r0, IPAR /* Clear IPAR */
+ stcr r0, DSR /* Clear DSR */
+ stcr r0, DLAR /* Clear DLAR */
+ stcr r0, DPAR /* Clear DPAR */
+ xcr TMP, TMP, SR3 /* get E.F. pointer */
+ st r30, TMP, GENREG_OFF(30) /* save previous r30, r31 */
+ st r31, TMP, GENREG_OFF(31) /* save previous r30, r31 */
+ or r31, TMP, r0 /* transfer E.F. pointer */
+ ld TMP, r31, REG_OFF(EF_SR3) /* get previous SR3 */
+
+ /* make sure that the FLAG_ENABLING_FPU bit is off */
+ xcr FLAGS,FLAGS,SR1
+ clr FLAGS,FLAGS,1<FLAG_ENABLING_FPU>
+ xcr FLAGS,FLAGS,SR1
+
+ xcr TMP, TMP, SR3 /* replace TMP, SR3 */
+
+ /* now save all regs to the exception frame. */
+ st r0 , r31, GENREG_OFF(0)
+ st r1 , r31, GENREG_OFF(1)
+ st r2 , r31, GENREG_OFF(2)
+ st r3 , r31, GENREG_OFF(3)
+ st r4 , r31, GENREG_OFF(4)
+ st r5 , r31, GENREG_OFF(5)
+ st r6 , r31, GENREG_OFF(6)
+ st r7 , r31, GENREG_OFF(7)
+ st r8 , r31, GENREG_OFF(8)
+ st r9 , r31, GENREG_OFF(9)
+ st r10, r31, GENREG_OFF(10)
+ st r11, r31, GENREG_OFF(11)
+ st r12, r31, GENREG_OFF(12)
+ st r13, r31, GENREG_OFF(13)
+ st r14, r31, GENREG_OFF(14)
+ st r15, r31, GENREG_OFF(15)
+ st r16, r31, GENREG_OFF(16)
+ st r17, r31, GENREG_OFF(17)
+ st r18, r31, GENREG_OFF(18)
+ st r19, r31, GENREG_OFF(19)
+ st r20, r31, GENREG_OFF(20)
+ st r21, r31, GENREG_OFF(21)
+ st r22, r31, GENREG_OFF(22)
+ st r23, r31, GENREG_OFF(23)
+ st r24, r31, GENREG_OFF(24)
+ st r25, r31, GENREG_OFF(25)
+ st r26, r31, GENREG_OFF(26)
+ st r27, r31, GENREG_OFF(27)
+ st r28, r31, GENREG_OFF(28)
+ st r29, r31, GENREG_OFF(29)
+#ifdef JEFF_DEBUG
+ /* mark beginning of frame with notable value */
+ or.u r20, r0, hi16(0x12345678)
+ or r20, r20, lo16(0x12345678)
+ st r20, r31, GENREG_OFF(0)
+#endif
+
+ /* get and save IPL */
+ bsr.n _C_LABEL(getipl)
+ subu r31, r31, 32
+ addu r31, r31, 32
+ st r2, r31, REG_OFF(EF_MASK)
+
+ /*
+ * SR1: free
+ * SR2: free
+ * SR3: previous exception-time SR3
+ * r1: return address to the calling exception handler
+ * r2 through r30: free
+ * r31: our exception frame
+ *
+ * Valid in the exception frame:
+ * Exception-time r0 through r31.
+ * Exception-time FLAGS.
+ * Exception-time espr, enip, exip.
+ * Exception number (EF_VECTOR).
+ * DSR
+ * Other data pipeline control registers, if appropriate.
+ * FPU control registers, if appropriate.
+ * Exception SR3, if appropriate.
+ *
+ * immediate goal:
+ * Pick up a stack if we came in from user mode.
+ * Put a copy of the exception frame pointer into r30
+ * Bump the stack a doubleword and write the exception frame pointer.
+ * If not an interrupt exception, turn on interrupts and service any
+ * outstanding data access exceptions.
+ * Return to calling exception handler to service the exception.
+ */
+
+ /*
+ * If it's not the interrupt exception, enable interrupts and
+ * take care of any data access exceptions......
+ */
+ or r30, r0, r31 /* get a copy of the e.f. pointer */
+ ld r2, r31, REG_OFF(EF_EPSR)
+ bb1 PSR_SUPERVISOR_MODE_BIT, r2, 1f /* if in kernel mode */
+
+ or.u r31, r0, hi16(_ASM_LABEL(kstack))
+ ld r31, r31, lo16(_ASM_LABEL(kstack))
+ addu r31, r31, USIZE /* point at proper end */
+1:
+
+ /*
+ * here - r30 holds a pointer to the exception frame.
+ * r31 is a pointer to the kernel stack/interrupt stack.
+ */
+ subu r31, r31, 8 /* make some breathing space */
+ st r30, r31, 0 /* store frame pointer on the stack */
+#ifdef DDB
+ st r30, r31, 4 /* store it again for the debugger */
+#endif /* DDB */
+
+ ld r2, r30, REG_OFF(EF_VECTOR)
+ bcnd.n eq0, r2, 8f
+ ld r14, r30, REG_OFF(EF_RET) /* load return value XXX!!! */
+ cmp r3, r2, 1 /* is an interrupt? */
+ bb1.n eq, r3, 8f
+
+#ifdef DDB
+ cmp r3, r2, 130 /* DDB break exception */
+ bb1.n eq, r3, 8f
+
+ cmp r3, r2, 132 /* DDB entry exception */
+ bb1.n eq, r3, 8f
+#endif
+
+ /* turn interrupts back on */
+ ldcr r2, PSR
+ clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r2, PSR
+ FLUSH_PIPELINE
+
+8:
+ jmp r14 /* loaded above */
+
+ data
+ .align 8 /* needs align 8 for ld.d/st.d */
+ASLOCAL(save_frame)
+ space SIZEOF_EF
+#endif /* M88110 */
diff --git a/sys/arch/luna88k/luna88k/genassym.cf b/sys/arch/luna88k/luna88k/genassym.cf
new file mode 100644
index 00000000000..dfe4af42192
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/genassym.cf
@@ -0,0 +1,144 @@
+# $OpenBSD: genassym.cf,v 1.1 2004/04/21 15:24:00 aoyama Exp $
+#
+# Copyright (c) 1982, 1990 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)genassym.c 7.8 (Berkeley) 5/7/91
+# $Id: genassym.cf,v 1.1 2004/04/21 15:24:00 aoyama Exp $
+#
+
+include <sys/param.h>
+include <sys/buf.h>
+include <sys/time.h>
+include <sys/proc.h>
+include <sys/mbuf.h>
+include <sys/msgbuf.h>
+include <machine/cpu.h>
+include <machine/trap.h>
+include <machine/psl.h>
+include <machine/vmparam.h>
+include <sys/syscall.h>
+include <sys/user.h>
+
+# proc fields and values
+struct proc
+member p_forw
+member p_back
+member p_addr
+member p_stat
+member p_wchan
+
+export SRUN
+
+# general constants
+export UPAGES
+define USIZE USPACE
+
+# pcb fields
+struct pcb
+member pcb_onfault
+member PCB_USER_STATE user_state
+
+# system calls
+export SYS_exit
+export SYS_sigreturn
+
+# trapframe element indexes
+define EF_R0 offsetof(struct trapframe, tf_r[0]) / sizeof(int)
+define EF_FPSR offsetof(struct trapframe, tf_fpsr) / sizeof(int)
+define EF_FPCR offsetof(struct trapframe, tf_fpcr) / sizeof(int)
+define EF_EPSR offsetof(struct trapframe, tf_epsr) / sizeof(int)
+define EF_SXIP offsetof(struct trapframe, tf_sxip) / sizeof(int)
+define EF_SFIP offsetof(struct trapframe, tf_sfip) / sizeof(int)
+define EF_SNIP offsetof(struct trapframe, tf_snip) / sizeof(int)
+define EF_SSBR offsetof(struct trapframe, tf_ssbr) / sizeof(int)
+define EF_DMT0 offsetof(struct trapframe, tf_dmt0) / sizeof(int)
+define EF_DMD0 offsetof(struct trapframe, tf_dmd0) / sizeof(int)
+define EF_DMA0 offsetof(struct trapframe, tf_dma0) / sizeof(int)
+define EF_DMT1 offsetof(struct trapframe, tf_dmt1) / sizeof(int)
+define EF_DMD1 offsetof(struct trapframe, tf_dmd1) / sizeof(int)
+define EF_DMA1 offsetof(struct trapframe, tf_dma1) / sizeof(int)
+define EF_DMT2 offsetof(struct trapframe, tf_dmt2) / sizeof(int)
+define EF_DMD2 offsetof(struct trapframe, tf_dmd2) / sizeof(int)
+define EF_DMA2 offsetof(struct trapframe, tf_dma2) / sizeof(int)
+define EF_FPECR offsetof(struct trapframe, tf_fpecr) / sizeof(int)
+define EF_FPHS1 offsetof(struct trapframe, tf_fphs1) / sizeof(int)
+define EF_FPLS1 offsetof(struct trapframe, tf_fpls1) / sizeof(int)
+define EF_FPHS2 offsetof(struct trapframe, tf_fphs2) / sizeof(int)
+define EF_FPLS2 offsetof(struct trapframe, tf_fpls2) / sizeof(int)
+define EF_FPPT offsetof(struct trapframe, tf_fppt) / sizeof(int)
+define EF_FPRH offsetof(struct trapframe, tf_fprh) / sizeof(int)
+define EF_FPRL offsetof(struct trapframe, tf_fprl) / sizeof(int)
+define EF_FPIT offsetof(struct trapframe, tf_fpit) / sizeof(int)
+define EF_VECTOR offsetof(struct trapframe, tf_vector) / sizeof(int)
+define EF_MASK offsetof(struct trapframe, tf_mask) / sizeof(int)
+define EF_MODE offsetof(struct trapframe, tf_mode) / sizeof(int)
+define EF_RET offsetof(struct trapframe, tf_scratch1) / sizeof(int)
+define EF_IPFSR offsetof(struct trapframe, tf_ipfsr) / sizeof(int)
+define EF_DPFSR offsetof(struct trapframe, tf_dpfsr) / sizeof(int)
+define EF_CPU offsetof(struct trapframe, tf_cpu) / sizeof(int)
+
+# m88110 trapframe element indexes
+define EF_EXIP offsetof(struct trapframe, tf_exip) / sizeof(int)
+define EF_ENIP offsetof(struct trapframe, tf_enip) / sizeof(int)
+define EF_DSR offsetof(struct trapframe, tf_dsr) / sizeof(int)
+define EF_DLAR offsetof(struct trapframe, tf_dlar) / sizeof(int)
+define EF_DPAR offsetof(struct trapframe, tf_dpar) / sizeof(int)
+define EF_ISR offsetof(struct trapframe, tf_isr) / sizeof(int)
+define EF_ILAR offsetof(struct trapframe, tf_ilar) / sizeof(int)
+define EF_IPAR offsetof(struct trapframe, tf_ipar) / sizeof(int)
+define EF_ISAP offsetof(struct trapframe, tf_isap) / sizeof(int)
+define EF_DSAP offsetof(struct trapframe, tf_dsap) / sizeof(int)
+define EF_IUAP offsetof(struct trapframe, tf_iuap) / sizeof(int)
+define EF_DUAP offsetof(struct trapframe, tf_duap) / sizeof(int)
+
+define SIZEOF_EF sizeof(struct trapframe)
+
+# more (machine-dependent) pcb fields
+struct m88100_pcb
+member pcb_pc
+member pcb_ipl
+member pcb_r14
+member pcb_r15
+member pcb_r16
+member pcb_r17
+member pcb_r18
+member pcb_r19
+member pcb_r20
+member pcb_r21
+member pcb_r22
+member pcb_r23
+member pcb_r24
+member pcb_r25
+member pcb_r26
+member pcb_r27
+member pcb_r28
+member pcb_r29
+member pcb_r30
+member pcb_sp
+member pcb_fcr62
+member pcb_fcr63
diff --git a/sys/arch/luna88k/luna88k/isr.c b/sys/arch/luna88k/luna88k/isr.c
new file mode 100644
index 00000000000..0ecaa9ba9b9
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/isr.c
@@ -0,0 +1,204 @@
+/* $OpenBSD: isr.c,v 1.1 2004/04/21 15:24:00 aoyama Exp $ */
+/* $NetBSD: isr.c,v 1.5 2000/07/09 08:08:20 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Link and dispatch interrupts.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/vmmeter.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <net/netisr.h>
+
+#include <machine/cpu.h>
+
+#include <luna88k/luna88k/isr.h>
+
+isr_autovec_list_t isr_autovec[NISRAUTOVEC];
+
+extern int intrcnt[]; /* from locore.s */
+
+void
+isrinit()
+{
+ int i;
+
+ /* Initialize the autovector lists. */
+ for (i = 0; i < NISRAUTOVEC; ++i) {
+ LIST_INIT(&isr_autovec[i]);
+ }
+}
+
+/*
+ * Establish an autovectored interrupt handler.
+ * Called by driver attach functions.
+ */
+void
+isrlink_autovec(func, arg, ipl, priority)
+ int (*func)(void *);
+ void *arg;
+ int ipl;
+ int priority;
+{
+ struct isr_autovec *newisr, *curisr;
+ isr_autovec_list_t *list;
+
+ if ((ipl < 0) || (ipl >= NISRAUTOVEC))
+ panic("isrlink_autovec: bad ipl %d", ipl);
+
+ newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec),
+ M_DEVBUF, M_NOWAIT);
+ if (newisr == NULL)
+ panic("isrlink_autovec: can't allocate space for isr");
+
+ /* Fill in the new entry. */
+ newisr->isr_func = func;
+ newisr->isr_arg = arg;
+ newisr->isr_ipl = ipl;
+ newisr->isr_priority = priority;
+
+ /*
+ * Some devices are particularly sensitive to interrupt
+ * handling latency. The SCC, for example, can lose many
+ * characters if its interrupt isn't handled with reasonable
+ * speed.
+ *
+ * To work around this problem, each device can give itself a
+ * "priority". An unbuffered SCC would give itself a higher
+ * priority than a SCSI device, for example.
+ *
+ * This solution was originally developed for the hp300, which
+ * has a flat spl scheme (by necessity). Thankfully, the
+ * MVME systems don't have this problem, though this may serve
+ * a useful purpose in any case.
+ */
+
+ /*
+ * Get the appropriate ISR list. If the list is empty, no
+ * additional work is necessary; we simply insert ourselves
+ * at the head of the list.
+ */
+ list = &isr_autovec[ipl];
+ if (list->lh_first == NULL) {
+ LIST_INSERT_HEAD(list, newisr, isr_link);
+ return;
+ }
+
+ /*
+ * A little extra work is required. We traverse the list
+ * and place ourselves after any ISRs with our current (or
+ * higher) priority.
+ */
+ for (curisr = list->lh_first; curisr->isr_link.le_next != NULL;
+ curisr = curisr->isr_link.le_next) {
+ if (newisr->isr_priority > curisr->isr_priority) {
+ LIST_INSERT_BEFORE(curisr, newisr, isr_link);
+ return;
+ }
+ }
+
+ /*
+ * We're the least important entry, it seems. We just go
+ * on the end.
+ */
+ LIST_INSERT_AFTER(curisr, newisr, isr_link);
+}
+
+/*
+ * This is the dispatcher called by the low-level
+ * assembly language autovectored interrupt routine.
+ */
+void
+isrdispatch_autovec(ipl)
+ int ipl;
+{
+ struct isr_autovec *isr;
+ isr_autovec_list_t *list;
+ int handled = 0;
+ static int straycount, unexpected;
+
+ if ((ipl < 0) || (ipl >= NISRAUTOVEC))
+ panic("isrdispatch_autovec: bad ipl 0x%d\n", ipl);
+
+ intrcnt[ipl]++;
+#if 0 /* XXX: already counted in machdep.c */
+ uvmexp.intrs++;
+#endif
+
+ list = &isr_autovec[ipl];
+ if (list->lh_first == NULL) {
+ printf("isrdispatch_autovec: ipl %d unexpected\n", ipl);
+ if (++unexpected > 10)
+ panic("too many unexpected interrupts");
+ return;
+ }
+
+ /* Give all the handlers a chance. */
+ for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next)
+ handled |= (*isr->isr_func)(isr->isr_arg);
+
+ if (handled)
+ straycount = 0;
+ else if (++straycount > 50)
+ panic("isr_dispatch_autovec: too many stray interrupts");
+ else
+ printf("isrdispatch_autovec: stray level %d interrupt\n", ipl);
+}
+
+void netintr(void);
+
+void
+netintr()
+{
+#define DONETISR(bit, fn) do { \
+ if (netisr & (1 << bit)) { \
+ netisr &= ~(1 << bit); \
+ fn(); \
+ } \
+} while (0)
+
+#include <net/netisr_dispatch.h>
+
+#undef DONETISR
+
+}
diff --git a/sys/arch/luna88k/luna88k/isr.h b/sys/arch/luna88k/luna88k/isr.h
new file mode 100644
index 00000000000..dafe618da6e
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/isr.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: isr.h,v 1.1 2004/04/21 15:24:00 aoyama Exp $ */
+/* $NetBSD: isr.h,v 1.1 2000/01/05 08:49:04 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+
+/*
+ * The max size of the autovectored interrupt.
+ */
+#define NISRAUTOVEC 8
+
+/*
+ * Autovectored interupt handler cookie.
+ */
+struct isr_autovec {
+ LIST_ENTRY(isr_autovec) isr_link;
+ int (*isr_func)(void *);
+ void *isr_arg;
+ int isr_ipl;
+ int isr_priority;
+};
+
+typedef LIST_HEAD(, isr_autovec) isr_autovec_list_t;
+
+/*
+ * Autovectored ISR priorities. These are not the same as interrupt levels.
+ */
+#define ISRPRI_BIO 0
+#define ISRPRI_NET 1
+#define ISRPRI_TTY 2
+#define ISRPRI_TTYNOBUF 3
+
+void isrinit(void);
+void isrlink_autovec(int (*)(void *), void *, int, int);
+void isrdispatch_autovec(int);
diff --git a/sys/arch/luna88k/luna88k/locore.S b/sys/arch/luna88k/luna88k/locore.S
new file mode 100644
index 00000000000..6016368af90
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/locore.S
@@ -0,0 +1,545 @@
+/* $OpenBSD: locore.S,v 1.1 2004/04/21 15:24:00 aoyama Exp $ */
+/*
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "assym.h"
+#include "ksyms.h"
+
+#include <machine/asm.h>
+#include <machine/trap.h>
+#include <machine/m88100.h>
+#include <machine/psl.h>
+#include <machine/param.h>
+#include <machine/vmparam.h>
+
+/*
+ * The memory looks like:
+ * 0x00000 - 0x01000 trap vectors
+ * 0x10000 - 0x20000 ROM monitor work area
+ * 0x20000 == start Boot loader jumps here.
+ */
+ text
+
+GLOBAL(kernelstart)
+GLOBAL(kernel_text)
+GLOBAL(start)
+ASGLOBAL(start)
+ br _C_LABEL(start_text)
+ br _C_LABEL(start_text)
+ br _C_LABEL(start_text)
+ br _C_LABEL(start_text)
+
+ /* This is the *real* start upon poweron or reset */
+GLOBAL(start_text)
+ /*
+ * XXX: OpenBSD/luna88k does not have its native boot
+ * loader, so no args are passed ...
+ * (below is the comment for mvme88k.)
+ *
+ * Args passed by boot loader
+ * r2 howto
+ * r3 boot controller address
+ * r4 esym
+ * r5 start of mini
+ * r6 end miniroot
+ * r7 ((Clun << 8) ; Dlun & FF) -> bootdev
+ * r8 cpu type (0x187, 0x188, 0x197)
+ */
+#if 0 /* not yet */
+/*
+ * (*entry)(flag, bugargs.ctrl_addr, cp, kernel.smini,kernel.emini,
+ * bootdev, brdtyp);
+ */
+ or.u r13, r0, hi16(_C_LABEL(boothowto))
+ st r2, r13, lo16(_C_LABEL(boothowto))
+ or.u r13, r0, hi16(_C_LABEL(bootaddr))
+ st r3, r13, lo16(_C_LABEL(bootaddr))
+ or.u r13, r0, hi16(_C_LABEL(first_addr))
+ st r4, r13, lo16(_C_LABEL(first_addr))
+#if defined(DDB) || NKSYMS > 0
+ or.u r13, r0, hi16(_C_LABEL(esym))
+ st r4, r13, lo16(_C_LABEL(esym))
+#endif
+ or.u r13, r0, hi16(_C_LABEL(bootdev))
+ st r7, r13, lo16(_C_LABEL(bootdev))
+ or.u r13, r0, hi16(_C_LABEL(brdtyp))
+ st r8, r13, lo16(_C_LABEL(brdtyp))
+
+ /* set _cputyp */
+ cmp r2, r8, BRD_197 /* r8 contains brdtyp */
+ bb1 ne, r2, 1f /* if it's a '197, CPU is 88110 */
+ or.u r13, r0, hi16(CPU_88110)
+ or r8, r13, lo16(CPU_88110)
+ br 2f
+1:
+ or.u r13, r0, hi16(CPU_88100)
+ or r8, r13, lo16(CPU_88100)
+2:
+ or.u r13, r0, hi16(_C_LABEL(cputyp))
+ st r8, r13, lo16(_C_LABEL(cputyp))
+#endif /* not yet */
+
+ /*
+ * CPU Initialization
+ *
+ * Every CPU starts from here..
+ * (well, from 'start' above, which just jumps here).
+ *
+ * I use r11 and r22 here 'cause they're easy to not
+ * get mixed up -- r10, for example, looks too similar
+ * to r0 when not being careful....
+ *
+ * Ensure that the PSR is as we like:
+ * supervisor mode
+ * big-endian byte ordering
+ * concurrent operation allowed
+ * carry bit clear (I don't think we really care about this)
+ * FPU enabled
+ * misaligned access raises an exception
+ * interrupts disabled
+ * shadow registers frozen
+ *
+ * The manual says not to disable interrupts and freeze shadowing
+ * at the same time because interrupts are not actually disabled
+ * until after the next instruction. Well, if an interrupt
+ * occurs now, we're in deep anyway, so I'm going to do
+ * the two together.
+ *
+ * Upon a reset (or poweron, I guess), the PSR indicates:
+ * supervisor mode
+ * interrupts, shadowing, FPU, missaligned exception: all disabled
+ *
+ * We'll just construct our own turning on what we want.
+ *
+ * jfriedl@omron.co.jp
+ */
+
+ stcr r0, SSBR /* clear this for later */
+ stcr r0, SR0 /* clear "current thread" */
+ stcr r0, SR1 /* clear the CPU flags */
+
+ set r11, r0, 1<PSR_SUPERVISOR_MODE_BIT>
+ set r11, r11, 1<PSR_INTERRUPT_DISABLE_BIT>
+ set r11, r11, 1<PSR_GRAPHICS_DISABLE_BIT>
+
+ stcr r11, PSR
+ FLUSH_PIPELINE
+ stcr r0, VBR /* set Vector Base Register to 0, ALWAYS! */
+ FLUSH_PIPELINE
+
+ /* clear BSS. Boot loader might have already done this... */
+ or.u r2, r0, hi16(_C_LABEL(edata))
+ or r2, r2, lo16(_C_LABEL(edata))
+ or.u r4, r0, hi16(_C_LABEL(end))
+ or r4, r4, lo16(_C_LABEL(end))
+ bsr.n _bzero /* bzero(edata, end-edata) */
+ subu r3, r4, r2
+
+ /*
+ * First time to count how many CPUs to attach
+ */
+ or.u r11, r0, hi16(_ASM_LABEL(initialized_cpu_lock))
+ or r11, r11, lo16(_ASM_LABEL(initialized_cpu_lock))
+1:
+ FLUSH_PIPELINE
+ or r22, r0, 1
+ xmem r22, r11, r0 /* If r22 gets 0, we have the lock.. */
+ bcnd eq0, r22, 3f /* ..but if not, we must wait */
+2:
+ /* just watch the lock until it looks clear */
+ ld r22, r11, r0
+ bcnd eq0, r22, 1b
+ br 2b /* looks clear -- try to grab */
+3:
+ FLUSH_PIPELINE
+ or.u r11, r0, hi16(_ASM_LABEL(initialized_cpus))
+ ld r22, r11, lo16(_ASM_LABEL(initialized_cpus))
+ add r23, r22, 1
+ st r23, r11, lo16(_ASM_LABEL(initialized_cpus))
+
+ or.u r11, r0, hi16(_ASM_LABEL(initialized_cpu_lock))
+ st r0, r11, lo16(_ASM_LABEL(initialized_cpu_lock))
+ /*
+ * Now we view with any other processors to see who's the master.
+ * We first try to obtain a lock to see who's allowed
+ * to check/set the master lock.
+ */
+ or.u r11, r0, hi16(_ASM_LABEL(inter_processor_lock))
+ or r11, r11, lo16(_ASM_LABEL(inter_processor_lock))
+1:
+ FLUSH_PIPELINE
+ or r22, r0, 1
+ xmem r22, r11, r0 /* If r22 gets 0, we have the lock.. */
+ bcnd eq0, r22, 4f /* ..but if not, we must wait */
+2:
+ /* just watch the lock until it looks clear */
+ ld r22, r11, r0
+ bcnd ne0, r22, 2b
+ /* since we can be here with caches off, add a few nops to
+ keep the bus from getting overloaded */
+ or r2, r0, lo16(1000)
+3:
+ subu r2, r2, 1
+ bcnd eq0, r2, 3b
+ br 1b /* looks clear -- try to grab */
+4:
+ /* now try to grab the master_processor_chosen prize */
+ FLUSH_PIPELINE
+ or.u r11, r0, hi16(_ASM_LABEL(master_processor_chosen))
+ or r11, r11, lo16(_ASM_LABEL(master_processor_chosen))
+ or r22, r0, 1
+ xmem r22, r11, r0
+
+ /*
+ * If r22 is not clear we're a slave,
+ * otherwise we're first and the master.
+ *
+ * Note that we haven't released the interprocessor lock....
+ * We'll do that when we're ready for another CPU to go.
+ * (if we're the master, we'll do that in master_start below.
+ * if we're a slave, we'll do it in slave_start below).
+ */
+ bcnd ne0, r22, _ASM_LABEL(slave_start)
+ /* fall through to master start if that's appropriate */
+
+ASLOCAL(master_start)
+ /*
+ * Switch to interrupt stack
+ * Use idle_u's stack instead?
+ */
+ or.u r31, r0, hi16(_ASM_LABEL(intstack_end))
+ or r31, r31, lo16(_ASM_LABEL(intstack_end))
+ clr r31, r31, 3<0> /* round down to 8-byte boundary */
+
+ or.u r3, r0, hi16(_C_LABEL(vector_list))
+ or r3, r3, lo16(_C_LABEL(vector_list))
+
+ bsr.n _C_LABEL(vector_init)
+ ldcr r2, VBR
+
+ /* PIO stuff */
+ or r10, r0, 0xb6 /* initialize pio 0 */
+ or.u r11, r0, hi16(0x4900000c) /* 0x4900000c: PIO0 ctrl */
+ st.b r10, r11, lo16(0x4900000c)
+
+ /* read dispswitch setting */
+ ld.bu r10, r11, lo16(0x49000000) /* dipsw-1 (from portA) */
+ mak r10, r10, 0<8> /* shift left 8 bit */
+ ld.bu r12, r11, lo16(0x49000004) /* dipsw-2 (from portB) */
+ or r10, r10, r12
+
+ or.u r11, r0, hi16(_dipswitch)
+ st.h r10, r11, lo16(_dipswitch)
+
+ bb1 14, r10, 1f /* XXX: if dipsw-1:2 is on, */
+ or r10, r0, r0 /* XXX: console is ttya */
+ or.u r11, r0, hi16(_sysconsole)
+ st r10, r11, lo16(_sysconsole)
+
+1:
+ or r10, r0, 0x84 /* initialize pio1 */
+ or.u r11, r0, hi16(0x4d00000c)
+ st.b r10, r11, lo16(0x4d00000c)
+ or r10, r0, 0x9 /* port c bit 1 on */
+ st.b r10, r11, lo16(0x4d00000c)
+
+ or.u r10, r0, hi16(0xe1000010) /* clear scsi int */
+ ld.b r11, r10, lo16(0xe1000010)
+ st.b r11, r10, lo16(0xe1000010)
+
+ /* write 0x41000000 to escape rom */
+ or.u r2, r0, hi16(0x41000000)
+ st r0, r2, lo16(0x41000000)
+
+ /* still on int stack */
+ bsr.n _C_LABEL(luna88k_bootstrap)
+ subu r31, r31, 40
+ addu r31, r31, 40
+
+ /*
+ * we now know our cpu number, so we
+ * can set interrupt_stack[cpu_number()] = intstack
+ */
+ ldcr r10, SR1
+ extu r10, r10, FLAG_CPU_FIELD_WIDTH<0> /* r10 <-- CPU# */
+
+ /* figure interrupt_stack[cpu_number()] */
+ or.u r11, r0, hi16(_C_LABEL(interrupt_stack))
+ or r11, r11, lo16(_C_LABEL(interrupt_stack))
+ or.u r12, r0, hi16(_C_LABEL(intstack))
+ or r12, r12, lo16(_C_LABEL(intstack))
+ st r12, r11 [r10]
+
+ /* switch to proc0 uarea */
+ or.u r10, r0, hi16(UADDR)
+ or r31, r10,lo16(UADDR)
+ addu r31, r31, USIZE - 8
+
+ /* make the call: main() */
+ or.u r2, r0, hi16(UADDR)
+ or r2, r2,lo16(UADDR)
+ addu r2, r2, USIZE - 8
+ subu r31, r31, 40
+ bsr _C_LABEL(main)
+ addu r31, r31, 40
+ bsr _C_LABEL(panic)
+
+/*
+ * slave CPUs starts here
+ */
+ASLOCAL(slave_start)
+ /*
+ * While holding the inter_processor_lock, the slave cpu can use
+ * the slavestack to call slave_pre_main and determine its cpu number.
+ * After that, however, it should switch over to the interrupt stack
+ * associated with its cpu.
+ */
+
+ /* r31 <-- slavestack */
+ or.u r31, r0, hi16(_ASM_LABEL(slavestack_end))
+ or r31, r31, lo16(_ASM_LABEL(slavestack_end))
+ clr r31, r31, 3<0> /* round down to 8-byte boundary */
+
+ bsr.n _C_LABEL(slave_pre_main) /* set cpu number */
+ subu r31, r31, 48 /* allocate frame */
+
+ bsr _C_LABEL(get_slave_stack)
+ addu r31, r2, INTSTACK_SIZE
+
+ /*
+ * SR1 now contains our cpu number. We can now release the
+ * inter_processor_lock, as we are done with the slavestack.
+ * We also have an interrupt stack
+ */
+
+ or.u r10, r0, hi16(_ASM_LABEL(inter_processor_lock))
+ st r0, r10, lo16(_ASM_LABEL(inter_processor_lock))
+
+ br.n _C_LABEL(slave_main) /* does not return */
+ subu r31, r31, 40 /* allocate frame */
+
+GLOBAL(spin_cpu)
+ or.u r3, r0, hi16(_C_LABEL(start_text))
+ or r3, r3, lo16(_C_LABEL(start_text))
+ or r9, r0, 0x100 /* .FORKMPU */
+ tb0 0, r0, 0x200-16 /* call 188Bug */
+ jmp r1
+
+/*
+ * void delay(int count)
+ *
+ * The processor loops (busy waits) for the given number of microseconds:
+ * Thus, delay(1000000) will delay for one second.
+ * (originally from Mach 2.5)
+ *
+ * REGISTER USAGE:
+ * IN r1 - return address
+ * IN r2 - (signed int) number of microseconds
+ * r3 - (float) number of microseconds
+ * r4/5 - (double) number of cycles per microsecond
+ * r6 - (float) number of cycles to delay
+ * r7 - (signed) number of cycles to delay
+ */
+
+GLOBAL(delay)
+ flt.ss r3, r2 /* convert microseconds from signed int to float */
+ or.u r4, r0, hi16(_cycles_per_microsecond)
+ ld.d r4, r4, lo16(_cycles_per_microsecond)
+ fmul.ssd r6, r3, r4 /* convert microseconds to cycles */
+ int.ss r7, r6 /* convert cycles from float to signed int */
+ subu r7, r7, 25 /* subtract for overhead of above instruction */
+
+ /* now loop for the given number of cycles */
+1:
+ bcnd.n gt0, r7, 1b
+ subu r7, r7, 2 /* two cycles per iteration */
+
+ jmp r1 /* return */
+
+/*****************************************************************************/
+
+ data
+ .align 4096 /* SDT (segment descriptor table */
+GLOBAL(kernel_sdt)
+ space (0x2000) /* 8K - 4K phys, 4K virt*/
+GLOBAL(ret_addr)
+ word 0
+ASLOCAL(initialized_cpu_lock)
+ /* XMEM spin lock -- to count CPUs */
+ word 0
+ASLOCAL(initialized_cpus)
+ /* CPU counter to initialize */
+ word 0
+ASLOCAL(master_processor_chosen)
+ /* The first processor that XMEMs this becomes the master */
+ word 0
+ASLOCAL(inter_processor_lock)
+ /* XMEM spin lock -- controls access to master_processor_chosen */
+ word 0
+
+ .align 4096
+GLOBAL(intstack)
+ space (INTSTACK_SIZE) /* 16K, just to be safe */
+ASGLOBAL(intstack_end)
+ASGLOBAL(slavestack)
+ space (NBPG) /* 4K, small, interim stack */
+ASGLOBAL(slavestack_end)
+
+/*
+ * When a process exits and its u. area goes away, we set curpcb to point
+ * to this `u.', leaving us with something to use for an interrupt stack,
+ * and letting all the register save code have a pcb_uw to examine.
+ * This is also carefully arranged (to come just before u0, so that
+ * process 0's kernel stack can quietly overrun into it during bootup, if
+ * we feel like doing that).
+ * Should be page aligned.
+ */
+ .align 4096
+GLOBAL(idle_u)
+ space UPAGES * NBPG
+
+/*
+ * Process 0's u.
+ *
+ * This must be page aligned
+ */
+ .align 4096
+ASLOCAL(u0)
+ space UPAGES * NBPG
+
+/*
+ * UPAGES get mapped to kstack
+ */
+
+ASGLOBAL(kstack)
+ word UADDR
+
+#if defined(DDB) || NKSYMS > 0
+GLOBAL(esym)
+ word 0
+#endif /* DDB || NKSYMS > 0 */
+
+GLOBAL(intiobase)
+ word 0 | KVA of base of internal IO space
+GLOBAL(intiolimit)
+ word 0 | KVA of end of internal IO space
+
+GLOBAL(proc0paddr)
+ word _ASM_LABEL(u0) /* KVA of proc0 uarea */
+
+/*
+ * curpcb points to the current pcb (and hence u. area).
+ * Initially this is the special one.
+ */
+/*
+ * pcb is composed of kernel state + user state
+ * I may have to change curpcb to u0 + PCB_USER based on what
+ * other parts expect XXX nivas
+ */
+GLOBAL(curpcb)
+ word _ASM_LABEL(u0) /* curpcb = &u0 */
+
+/*
+ * Trampoline code. Gets copied to the top of
+ * user stack in exec.
+ */
+GLOBAL(sigcode) /* r31 points to sigframe */
+ ld r2, r31, 0 /* signo */
+ ld r3, r31, 4 /* siginfo_t* */
+ ld r4, r31, 8 /* sigcontext* */
+ ld r5, r31, 12 /* handler */
+ jsr.n r5
+ subu r31, r31, 40 /* give some stack space */
+ addu r31, r31, 40 /* restore old sp value */
+ ld r2, r31, 8 /* sigcontext* */
+ or r13, r0, SYS_sigreturn
+ tb0 0, r0, 128 /* syscall trap, calling sigreturn */
+ NOP | failure return
+#if 0
+ NOP | success return
+#endif
+ /* sigreturn will not return unless it fails */
+ or r13, r0, SYS_exit
+ tb0 0, r0, 128 /* syscall trap, exit */
+ /*
+ * this never returns, but we need to provide fetchable instructions
+ * for the 88100 pipeline.
+ */
+ NOP
+ NOP
+GLOBAL(esigcode)
+
+/* interrupt counters */
+GLOBAL(intrnames)
+ string "spur\0"
+ string "lev1\0"
+ string "lev2\0"
+ string "lev3\0"
+ string "lev4\0"
+ string "lev5\0"
+ string "lev6\0"
+ string "lev7\0"
+ string "clk\0"
+ string "sclk\0"
+ string "pclk\0"
+ string "nmi\0"
+GLOBAL(eintrnames)
+ .align 8
+GLOBAL(intrcnt)
+ word 0,0,0,0,0,0,0,0,0,0,0,0
+GLOBAL(eintrcnt)
diff --git a/sys/arch/luna88k/luna88k/locore_asm_routines.S b/sys/arch/luna88k/luna88k/locore_asm_routines.S
new file mode 100644
index 00000000000..d8b52dce159
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/locore_asm_routines.S
@@ -0,0 +1,1621 @@
+/* $OpenBSD: locore_asm_routines.S,v 1.1 2004/04/21 15:24:01 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * Copyright (c) 1996 Nivas Madhur
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "assym.h"
+
+#include <sys/errno.h>
+
+#include <machine/asm.h>
+#include <machine/board.h>
+#include <machine/cpu_number.h>
+#include <machine/trap.h>
+
+/*****************************************************************************
+ * DO_LOAD_ADDRESS
+ *
+ * unsigned int do_load_word(address, supervisor_mode)
+ * vaddr_t address; \\ in r2
+ * boolean_t supervisor_mode; \\ in r3
+ *
+ * Return the word at ADDRESS (from user space if SUPERVISOR_MODE is zero,
+ * supervisor space if non-zero).
+ *
+ */
+
+ENTRY(do_load_word) /* do_load_word(address, supervisor) */
+ bcnd ne0,r3,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.usr r2,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ ld.usr r2,r2,r0
+#endif
+ br 2f
+1: ld r2,r2,r0
+2: jmp r1
+
+ENTRY(do_load_half) /* do_load_half(address, supervisor) */
+ bcnd ne0,r3,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.h.usr r2,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ ld.h.usr r2,r2,r0
+#endif
+ br 2f
+1: ld.h r2,r2,r0
+2: jmp r1
+
+ENTRY(do_load_byte) /* do_load_byte(address, supervisor) */
+ bcnd ne0,r3,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.b.usr r2,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ ld.b.usr r2,r2,r0
+#endif
+ br 2f
+1: ld.b r2,r2,r0
+2: jmp r1
+
+ENTRY(do_store_word) /* do_store_word(address, data, supervisor) */
+ bcnd ne0,r4,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.usr r3,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ st.usr r3,r2,r0
+#endif
+ br 2f
+1: st r3,r2,r0
+2: jmp r1
+
+ENTRY(do_store_half) /* do_store_half(address, data, supervisor) */
+ bcnd ne0,r4,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.h.usr r3,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ st.h.usr r3,r2,r0
+#endif
+ br 2f
+1: st.h r3,r2,r0
+2: jmp r1
+
+ENTRY(do_store_byte) /* do_store_byte(address, data, supervisor) */
+ bcnd ne0,r4,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.b.usr r3,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ st.b.usr r3,r2,r0
+#endif
+ br 2f
+1: st.b r3,r2,r0
+2: jmp r1
+
+ENTRY(do_xmem_word) /* do_xmem_word(address, data, supervisor) */
+ bcnd ne0,r4,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ xmem.usr r3,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ xmem.usr r3,r2,r0
+#endif
+ br 2f
+1: xmem r3,r2,r0
+2: jmp r1
+
+ENTRY(do_xmem_byte) /* do_xmem_byte(address, data, supervisor) */
+ bcnd ne0,r4,1f
+#ifdef ERRATA__XXX_USR
+ NOP
+ xmem.bu.usr r3,r2,r0
+ NOP
+ NOP
+ NOP
+#else
+ xmem.bu.usr r3,r2,r0
+#endif
+ br 2f
+1: xmem.bu r3,r2,r0
+2: jmp r1
+
+/*
+ * Copy specified amount of data from user space into the kernel
+ * copyin(from, to, len)
+ * r2 == from (user source address)
+ * r3 == to (kernel destination address)
+ * r4 == length
+ * (r1=return addr)
+ */
+
+#define SRC r2
+#define DEST r3
+#define LEN r4
+
+ENTRY(copyin)
+ /* set up fault handler */
+ or.u r5, r0, hi16(_C_LABEL(curpcb))
+ ld r6, r5, lo16(_C_LABEL(curpcb))
+ or.u r5, r0, hi16(_ASM_LABEL(Lciflt))
+ or r5, r5, lo16(_ASM_LABEL(Lciflt))
+ st r5, r6, PCB_ONFAULT /* pcb_onfault = Lciflt */
+
+#if 0
+ bcnd ne0, LEN, 1f /* XXX optimize len = 0 case */
+ or r2, r0, 0
+ br _ASM_LABEL(Lcidone)
+1: bcnd lt0, LEN, _ASM_LABEL(Lciflt) /* EFAULT if len < 0 */
+#endif
+
+ /* If it's a small length (less than 8), then do byte-by-byte */
+ cmp r9, LEN, 8
+ bb1 lt, r9, _ASM_LABEL(copyin_byte_only)
+
+ /* If they're not aligned similarly, use byte only... */
+ xor r9, SRC, DEST
+ mask r8, r9, 0x3
+ bcnd ne0, r8, _ASM_LABEL(copyin_byte_only)
+
+ /*
+ * At this point, we don't know if they're word aligned or not,
+ * but we know that what needs to be done to one to align
+ * it is what's needed for the other.
+ */
+ bb1 0, SRC, _ASM_LABEL(copyin_left_align_to_halfword)
+ASLOCAL(copyin_left_aligned_to_halfword)
+ bb1 1, SRC, _ASM_LABEL(copyin_left_align_to_word)
+ASLOCAL(copyin_left_aligned_to_word)
+ bb1 0, LEN, _ASM_LABEL(copyin_right_align_to_halfword)
+ASLOCAL(copyin_right_aligned_to_halfword)
+ bb1 1, LEN, _ASM_LABEL(copyin_right_align_to_word)
+ASLOCAL(copyin_right_aligned_to_word)
+
+ /* At this point, both SRC and DEST are aligned to a word */
+ /* boundry, and LEN is an even multiple of 4. */
+ bb1.n 2, LEN, _ASM_LABEL(copyin_right_align_to_doubleword)
+ or r7, r0, 4
+
+ASLOCAL(copyin_right_aligned_to_doubleword)
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.usr r5, SRC, r0
+ NOP
+ NOP
+ NOP
+ ld.usr r6, SRC, r7
+ NOP
+ NOP
+ NOP
+#else
+ ld.usr r5, SRC, r0
+ ld.usr r6, SRC, r7
+#endif
+ subu LEN, LEN, 8
+ st r5, DEST, r0
+ addu SRC, SRC, 8
+ st r6, DEST, r7
+ bcnd.n ne0, LEN, _ASM_LABEL(copyin_right_aligned_to_doubleword)
+ addu DEST, DEST, 8
+ br.n _ASM_LABEL(Lcidone)
+ or r2, r0, r0 /* successful return */
+
+ /***************************************************/
+
+ASLOCAL(copyin_left_align_to_halfword)
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.b.usr r5, SRC, r0
+ NOP
+ NOP
+ NOP
+#else
+ ld.b.usr r5, SRC, r0
+#endif
+ subu LEN, LEN, 1
+ st.b r5, DEST, r0
+ addu SRC, SRC, 1
+ br.n _ASM_LABEL(copyin_left_aligned_to_halfword)
+ addu DEST, DEST, 1
+
+ASLOCAL(copyin_left_align_to_word)
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.h.usr r5, SRC, r0
+ NOP
+ NOP
+ NOP
+#else
+ ld.h.usr r5, SRC, r0
+#endif
+ subu LEN, LEN, 2
+ st.h r5, DEST, r0
+ addu SRC, SRC, 2
+ br.n _ASM_LABEL(copyin_left_aligned_to_word)
+ addu DEST, DEST, 2
+
+ASLOCAL(copyin_right_align_to_halfword)
+ subu LEN, LEN, 1
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.b.usr r5, SRC, LEN
+ NOP
+ NOP
+ NOP
+#else
+ ld.b.usr r5, SRC, LEN
+#endif
+ br.n _ASM_LABEL(copyin_right_aligned_to_halfword)
+ st.b r5, DEST, LEN
+
+ASLOCAL(copyin_right_align_to_word)
+ subu LEN, LEN, 2
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.h.usr r5, SRC, LEN
+ NOP
+ NOP
+ NOP
+#else
+ ld.h.usr r5, SRC, LEN
+#endif
+ br.n _ASM_LABEL(copyin_right_aligned_to_word)
+ st.h r5, DEST, LEN
+
+ASLOCAL(copyin_right_align_to_doubleword)
+ subu LEN, LEN, 4
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.usr r5, SRC, LEN
+ NOP
+ NOP
+ NOP
+#else
+ ld.usr r5, SRC, LEN
+#endif
+ bcnd.n ne0, LEN, _ASM_LABEL(copyin_right_aligned_to_doubleword)
+ st r5, DEST, LEN
+ br.n _ASM_LABEL(Lcidone)
+ or r2, r0, r0 /* successful return */
+
+ASLOCAL(copyin_byte_only)
+ bcnd eq0, LEN, 2f
+1:
+ subu LEN, LEN, 1
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.b.usr r5, SRC, LEN
+ NOP
+ NOP
+ NOP
+#else
+ ld.b.usr r5, SRC, LEN
+#endif
+ bcnd.n ne0, LEN, 1b
+ st.b r5, DEST, LEN
+2:
+ br.n _ASM_LABEL(Lcidone)
+ or r2, r0, r0 /* successful return */
+
+ASLOCAL(Lcidone)
+ or.u r5,r0,hi16(_C_LABEL(curpcb))
+ ld r6,r5,lo16(_C_LABEL(curpcb))
+ jmp.n r1
+ st r0,r6,PCB_ONFAULT
+
+ASLOCAL(Lciflt)
+ br.n _ASM_LABEL(Lcidone)
+ or r2, r0, EFAULT /* return fault */
+
+#undef SRC
+#undef DEST
+#undef LEN
+/*######################################################################*/
+/*######################################################################*/
+
+/*
+ * Copy a null terminated string from the user space to the kernel
+ * address space.
+ *
+ * copyinstr(from, to, maxlen, &lencopied)
+ * r2 == from
+ * r3 == to
+ * r4 == maxlen
+ * r5 == len actually transferred (includes the terminating NULL!!!)
+ * r6 & r7 - used as temporaries
+ */
+#define SRC r2
+#define DEST r3
+#define CNT r4
+#define LEN r5
+
+ENTRY(copyinstr)
+
+ /* setup fault handler */
+ or.u r6, r0, hi16(_C_LABEL(curpcb))
+ ld r7, r6, lo16(_C_LABEL(curpcb))
+ or.u r6, r0, hi16(_ASM_LABEL(Lcisflt))
+ or r6, r6, lo16(_ASM_LABEL(Lcisflt))
+ st r6, r7, PCB_ONFAULT
+ or r6, r0, 0
+ bcnd lt0, CNT, _ASM_LABEL(Lcisflt)
+ bcnd eq0, CNT, _ASM_LABEL(Lcistoolong)
+1:
+#ifdef ERRATA__XXX_USR
+ NOP
+ ld.bu.usr r7, SRC, r6
+ NOP
+ NOP
+ NOP
+#else
+ ld.bu.usr r7, SRC, r6
+#endif
+ st.b r7, DEST, r6
+ bcnd.n eq0, r7, 2f /* all done */
+ addu r6, r6, 1
+ cmp r7, r6, CNT
+ bb1 lt, r7, 1b
+
+ASLOCAL(Lcistoolong)
+ or r2, r0, ENAMETOOLONG /* overflow */
+
+ASLOCAL(Lcisnull)
+ bcnd eq0,r6, _ASM_LABEL(Lcisdone) /* do not attempt to clear last byte */
+ /* if we did not write to the string */
+ subu r6, r6, 1
+ st.b r0, DEST, r6 /* clear last byte */
+ br.n _ASM_LABEL(Lcisdone)
+ addu r6, r6, 1
+2: /* all done */
+ or r2, r0, 0
+
+ASLOCAL(Lcisdone)
+ bcnd eq0, LEN, 3f
+ st r6, r0, LEN
+3:
+ or.u r5,r0,hi16(_C_LABEL(curpcb))
+ ld r6,r5,lo16(_C_LABEL(curpcb))
+ jmp.n r1
+ st r0,r6,PCB_ONFAULT /* clear the handler */
+
+ASLOCAL(Lcisflt)
+ br.n _ASM_LABEL(Lcisnull)
+ or r2, r0, EFAULT /* return fault */
+
+#undef SRC
+#undef DEST
+#undef CNT
+#undef LEN
+
+/*
+ * Copy specified amount of data from kernel to the user space
+ * Copyout(from, to, len)
+ * r2 == from (kernel source address)
+ * r3 == to (user destination address)
+ * r4 == length
+ */
+
+#define SRC r2
+#define DEST r3
+#define LEN r4
+
+ENTRY(copyout)
+ /* setup fault handler */
+ or.u r5, r0, hi16(_C_LABEL(curpcb))
+ ld r6, r5, lo16(_C_LABEL(curpcb))
+ or.u r5, r0, hi16(_ASM_LABEL(Lcoflt))
+ or r5, r5, lo16(_ASM_LABEL(Lcoflt))
+ st r5, r6, PCB_ONFAULT /* pcb_onfault = Lcoflt */
+#if 0
+ bcnd ne0, LEN, 1f /* XXX optimize len = 0 case */
+ or r2, r0, 0
+ br _ASM_LABEL(Lcodone)
+1: bcnd lt0, LEN, _ASM_LABEL(Lcoflt) /* EFAULT if len < 0 */
+#endif
+ /* If it's a small length (less than 8), then do byte-by-byte */
+ cmp r9, LEN, 8
+ bb1 lt, r9, _ASM_LABEL(copyout_byte_only)
+
+ /* If they're not aligned similarly, use byte only... */
+ xor r9, SRC, DEST
+ mask r8, r9, 0x3
+ bcnd ne0, r8, _ASM_LABEL(copyout_byte_only)
+
+ /*
+ * At this point, we don't know if they're word aligned or not,
+ * but we know that what needs to be done to one to align
+ * it is what's needed for the other.
+ */
+ bb1 0, SRC, _ASM_LABEL(copyout_left_align_to_halfword)
+ASLOCAL(copyout_left_aligned_to_halfword)
+ bb1 1, SRC, _ASM_LABEL(copyout_left_align_to_word)
+ASLOCAL(copyout_left_aligned_to_word)
+ bb1 0, LEN, _ASM_LABEL(copyout_right_align_to_halfword)
+ASLOCAL(copyout_right_aligned_to_halfword)
+ bb1 1, LEN, _ASM_LABEL(copyout_right_align_to_word)
+ASLOCAL(copyout_right_aligned_to_word)
+
+ /*
+ * At this point, both SRC and DEST are aligned to a word
+ * boundry, and LEN is an even multiple of 4.
+ */
+ bb1.n 2, LEN, _ASM_LABEL(copyout_right_align_to_doubleword)
+ or r7, r0, 4
+
+ASLOCAL(copyout_right_aligned_to_doubleword)
+ ld r5, SRC, r0
+ ld r6, SRC, r7
+ subu LEN, LEN, 8
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.usr r5, DEST, r0
+ NOP
+ NOP
+ NOP
+#else
+ st.usr r5, DEST, r0
+#endif
+ addu SRC, SRC, 8
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.usr r6, DEST, r7
+ NOP
+ NOP
+ NOP
+#else
+ st.usr r6, DEST, r7
+#endif
+ bcnd.n ne0, LEN, _ASM_LABEL(copyout_right_aligned_to_doubleword)
+ addu DEST, DEST, 8
+ or r2, r0, r0 /* successful return */
+ br _ASM_LABEL(Lcodone)
+
+ /***************************************************/
+ASLOCAL(copyout_left_align_to_halfword)
+ ld.b r5, SRC, r0
+ subu LEN, LEN, 1
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.b.usr r5, DEST, r0
+ NOP
+ NOP
+ NOP
+#else
+ st.b.usr r5, DEST, r0
+#endif
+ addu SRC, SRC, 1
+ br.n _ASM_LABEL(copyout_left_aligned_to_halfword)
+ addu DEST, DEST, 1
+
+ASLOCAL(copyout_left_align_to_word)
+ ld.h r5, SRC, r0
+ subu LEN, LEN, 2
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.h.usr r5, DEST, r0
+ NOP
+ NOP
+ NOP
+#else
+ st.h.usr r5, DEST, r0
+#endif
+ addu SRC, SRC, 2
+ br.n _ASM_LABEL(copyout_left_aligned_to_word)
+ addu DEST, DEST, 2
+
+ASLOCAL(copyout_right_align_to_halfword)
+ subu LEN, LEN, 1
+ ld.b r5, SRC, LEN
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.b.usr r5, DEST, LEN
+ NOP
+ NOP
+ NOP
+ br _ASM_LABEL(copyout_right_aligned_to_halfword)
+#else
+ br.n _ASM_LABEL(copyout_right_aligned_to_halfword)
+ st.b.usr r5, DEST, LEN
+#endif
+
+ASLOCAL(copyout_right_align_to_word)
+ subu LEN, LEN, 2
+ ld.h r5, SRC, LEN
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.h.usr r5, DEST, LEN
+ NOP
+ NOP
+ NOP
+ br _ASM_LABEL(copyout_right_aligned_to_word)
+#else
+ br.n _ASM_LABEL(copyout_right_aligned_to_word)
+ st.h.usr r5, DEST, LEN
+#endif
+
+ASLOCAL(copyout_right_align_to_doubleword)
+ subu LEN, LEN, 4
+ ld r5, SRC, LEN
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.usr r5, DEST, LEN
+ NOP
+ NOP
+ NOP
+ bcnd ne0, LEN, _ASM_LABEL(copyout_right_aligned_to_doubleword)
+#else
+ bcnd.n ne0, LEN, _ASM_LABEL(copyout_right_aligned_to_doubleword)
+ st.usr r5, DEST, LEN
+#endif
+ br.n _ASM_LABEL(Lcodone)
+ or r2, r0, r0 /* successful return */
+
+ASLOCAL(copyout_byte_only)
+ bcnd eq0, LEN, 2f
+1:
+ subu LEN, LEN, 1
+ ld.b r5, SRC, LEN
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.b.usr r5, DEST, LEN
+ NOP
+ NOP
+ NOP
+ bcnd ne0, LEN, 1b
+#else
+ bcnd.n ne0, LEN, 1b
+ st.b.usr r5, DEST, LEN
+#endif
+
+2:
+ br.n _ASM_LABEL(Lcodone)
+ or r2, r0, r0 /* successful return */
+
+ASLOCAL(Lcodone)
+ or.u r5,r0,hi16(_C_LABEL(curpcb))
+ ld r6,r5,lo16(_C_LABEL(curpcb))
+ jmp.n r1
+ st r0,r6,PCB_ONFAULT /* clear the handler */
+
+ASLOCAL(Lcoflt)
+ br.n _ASM_LABEL(Lcodone)
+ or r2, r0, EFAULT /* return fault */
+
+#undef SRC
+#undef DEST
+#undef LEN
+
+/*
+ * Copy a null terminated string from the kernel space to the user
+ * address space.
+ *
+ * copyoutstr(from, to, maxlen, &lencopied)
+ * r2 == from
+ * r3 == to
+ * r4 == maxlen that can be copied
+ * r5 == len actually copied (including the terminating NULL!!!)
+ */
+
+#define SRC r2
+#define DEST r3
+#define CNT r4
+#define LEN r5
+
+ENTRY(copyoutstr)
+ /* setup fault handler */
+ or.u r6, r0, hi16(_C_LABEL(curpcb))
+ ld r7, r6, lo16(_C_LABEL(curpcb))
+ or.u r6, r0, hi16(_ASM_LABEL(Lcosflt))
+ or r6, r6, lo16(_ASM_LABEL(Lcosflt))
+ st r6, r7, PCB_ONFAULT
+ bcnd lt0, CNT, _ASM_LABEL(Lcosflt)
+ bcnd eq0, CNT, _ASM_LABEL(Lcosdone)
+ or r6, r0, 0
+1:
+ ld.bu r7, SRC, r6
+#ifdef ERRATA__XXX_USR
+ NOP
+ st.b.usr r7, DEST, r6
+ NOP
+ NOP
+ NOP
+#else
+ st.b.usr r7, DEST, r6
+#endif
+ bcnd.n eq0, r7, 2f /* all done */
+ addu r6, r6, 1
+ cmp r7, r6, CNT
+ bb1 lt, r7, 1b
+ br.n _ASM_LABEL(Lcosdone)
+ or r2, r0, ENAMETOOLONG
+2:
+ br.n _ASM_LABEL(Lcosdone)
+ or r2, r0, 0
+
+ASLOCAL(Lcosflt)
+ br.n _ASM_LABEL(Lcosdone)
+ or r2, r0, EFAULT
+
+ASLOCAL(Lcosdone)
+ bcnd eq0, LEN, 3f
+ st r6, r0, LEN
+3: or.u r5,r0,hi16(_C_LABEL(curpcb))
+ ld r6,r5,lo16(_C_LABEL(curpcb))
+ jmp.n r1
+ st r0,r6,PCB_ONFAULT /* clear the handler */
+
+#undef SRC
+#undef DEST
+#undef CNT
+#undef LEN
+
+/*######################################################################*/
+
+/*
+ * kcopy(const void *src, void *dst, size_t len);
+ *
+ * Copy len bytes from src to dst, aborting if we encounter a page fault.
+ */
+ENTRY(kcopy)
+ or.u r5, r0, hi16(_C_LABEL(curpcb))
+ ld r6, r5, lo16(_C_LABEL(curpcb))
+ or.u r5, r0, hi16(_ASM_LABEL(kcopy_fault))
+ or r5, r5, lo16(_ASM_LABEL(kcopy_fault))
+ st r5, r6, PCB_ONFAULT /* pcb_onfault = kcopy_fault */
+ bcnd le0,r4,_ASM_LABEL(kcopy_out) /* nothing to do if <= 0 */
+/*
+ * check position of source and destination data
+ */
+ cmp r9,r2,r3 /* compare source address to destination */
+ bb1 eq,r9,_ASM_LABEL(kcopy_out) /* nothing to do if equal */
+ bb1 lo,r9,_ASM_LABEL(kcopy_revers)e /* reverse copy if src < dest */
+/*
+ * source address is greater than destination address, copy forward
+ */
+ cmp r9,r4,16 /* see if we have at least 16 bytes */
+ bb1 lt,r9,_ASM_LABEL(kf_byte_copy) /* copy bytes for small length */
+/*
+ * determine copy strategy based on alignment of source and destination
+ */
+ mask r6,r2,3 /* get 2 low order bits of source address */
+ mask r7,r3,3 /* get 2 low order bits of destintation addr */
+ mak r6,r6,0<4> /* convert source bits to table offset */
+ mak r7,r7,0<2> /* convert destination bits to table offset */
+ or.u r12,r0,hi16(_ASM_LABEL(kf_strat))
+ or r12,r12,lo16(_ASM_LABEL(kf_strat))
+ addu r6,r6,r7 /* compute final table offset for strategy */
+ ld r12,r12,r6 /* load the strategy routine */
+ jmp r12 /* branch to strategy routine */
+
+/*
+ * Copy three bytes from src to destination then copy words
+ */
+ASLOCAL(kf_3byte_word_copy)
+ ld.bu r6,r2,0 /* load byte from source */
+ ld.bu r7,r2,1 /* load byte from source */
+ ld.bu r8,r2,2 /* load byte from source */
+ st.b r6,r3,0 /* store byte to destination */
+ st.b r7,r3,1 /* store byte to destination */
+ st.b r8,r3,2 /* store byte to destination */
+ addu r2,r2,3 /* increment source pointer */
+ addu r3,r3,3 /* increment destination pointer */
+ br.n _ASM_LABEL(kf_word_copy) /* copy full words */
+ subu r4,r4,3 /* decrement length */
+
+/*
+ * Copy 1 halfword from src to destination then copy words
+ */
+ASLOCAL(kf_1half_word_copy)
+ ld.hu r6,r2,0 /* load half-word from source */
+ st.h r6,r3,0 /* store half-word to destination */
+ addu r2,r2,2 /* increment source pointer */
+ addu r3,r3,2 /* increment destination pointer */
+ br.n _ASM_LABEL(kf_word_copy) /* copy full words */
+ subu r4,r4,2 /* decrement remaining length */
+
+/*
+ * Copy 1 byte from src to destination then copy words
+ */
+ASLOCAL(kf_1byte_word_copy)
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ addu r2,r2,1 /* increment source pointer */
+ addu r3,r3,1 /* increment destination pointer */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to word copy */
+/*
+ * Copy as many full words as possible, 4 words per loop
+ */
+ASLOCAL(kf_word_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(kf_byte_copy) /* not enough left, copy bytes */
+ ld r6,r2,0 /* load first word */
+ ld r7,r2,4 /* load second word */
+ ld r8,r2,8 /* load third word */
+ ld r9,r2,12 /* load fourth word */
+ st r6,r3,0 /* store first word */
+ st r7,r3,4 /* store second word */
+ st r8,r3,8 /* store third word */
+ st r9,r3,12 /* store fourth word */
+ addu r2,r2,16 /* increment source pointer */
+ addu r3,r3,16 /* increment destination pointer */
+ br.n _ASM_LABEL(kf_word_copy) /* copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(kf_1byte_half_copy)
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ addu r2,r2,1 /* increment source pointer */
+ addu r3,r3,1 /* increment destination pointer */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to half copy */
+
+ASLOCAL(kf_half_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(kf_byte_copy) /* not enough left, copy bytes */
+ ld.hu r6,r2,0 /* load first half-word */
+ ld.hu r7,r2,2 /* load second half-word */
+ ld.hu r8,r2,4 /* load third half-word */
+ ld.hu r9,r2,6 /* load fourth half-word */
+ ld.hu r10,r2,8 /* load fifth half-word */
+ ld.hu r11,r2,10 /* load sixth half-word */
+ ld.hu r12,r2,12 /* load seventh half-word */
+ ld.hu r13,r2,14 /* load eighth half-word */
+ st.h r6,r3,0 /* store first half-word */
+ st.h r7,r3,2 /* store second half-word */
+ st.h r8,r3,4 /* store third half-word */
+ st.h r9,r3,6 /* store fourth half-word */
+ st.h r10,r3,8 /* store fifth half-word */
+ st.h r11,r3,10 /* store sixth half-word */
+ st.h r12,r3,12 /* store seventh half-word */
+ st.h r13,r3,14 /* store eighth half-word */
+ addu r2,r2,16 /* increment source pointer */
+ addu r3,r3,16 /* increment destination pointer */
+ br.n _ASM_LABEL(kf_half_copy) /* copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(kf_byte_copy)
+ bcnd eq0,r4,_ASM_LABEL(kcopy_out) /* branch if nothing left to copy */
+ ld.bu r6,r2,0 /* load byte from source */
+ st.b r6,r3,0 /* store byte in destination */
+ addu r2,r2,1 /* increment source pointer */
+ addu r3,r3,1 /* increment destination pointer */
+ br.n _ASM_LABEL(kf_byte_copy) /* branch for next byte */
+ subu r4,r4,1 /* decrement remaining length */
+
+/*
+ * source address is less than destination address, copy in reverse
+ */
+ASLOCAL(kcopy_reverse)
+/*
+ * start copy pointers at end of data
+ */
+ addu r2,r2,r4 /* start source at end of data */
+ addu r3,r3,r4 /* start destination at end of data */
+/*
+ * check for short data
+ */
+ cmp r9,r4,16 /* see if we have at least 16 bytes */
+ bb1 lt,r9,_ASM_LABEL(kr_byte_copy) /* copy bytes for small data length */
+/*
+ * determine copy strategy based on alignment of source and destination
+ */
+ mask r6,r2,3 /* get 2 low order bits of source address */
+ mask r7,r3,3 /* get 2 low order bits of destintation addr */
+ mak r6,r6,0<4> /* convert source bits to table offset */
+ mak r7,r7,0<2> /* convert destination bits to table offset */
+ or.u r12,r0,hi16(_ASM_LABEL(kr_strat))
+ or r12,r12,lo16(_ASM_LABEL(kr_strat))
+ addu r6,r6,r7 /* compute final table offset for strategy */
+ ld r12,r12,r6 /* load the strategy routine */
+ jmp r12 /* branch to strategy routine */
+
+/*
+ * Copy three bytes from src to destination then copy words
+ */
+ASLOCAL(kr_3byte_word_copy)
+ subu r2,r2,3 /* decrement source pointer */
+ subu r3,r3,3 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load byte from source */
+ ld.bu r7,r2,1 /* load byte from source */
+ ld.bu r8,r2,2 /* load byte from source */
+ st.b r6,r3,0 /* store byte to destination */
+ st.b r7,r3,1 /* store byte to destination */
+ st.b r8,r3,2 /* store byte to destination */
+ br.n _ASM_LABEL(kr_word_copy) /* copy full words */
+ subu r4,r4,3 /* decrement length */
+
+/*
+ * Copy 1 halfword from src to destination then copy words
+ */
+ASLOCAL(kr_1half_word_copy)
+ subu r2,r2,2 /* decrement source pointer */
+ subu r3,r3,2 /* decrement destination pointer */
+ ld.hu r6,r2,0 /* load half-word from source */
+ st.h r6,r3,0 /* store half-word to destination */
+ br.n _ASM_LABEL(kr_word_copy) /* copy full words */
+ subu r4,r4,2 /* decrement remaining length */
+
+/*
+ * Copy 1 byte from src to destination then copy words
+ */
+ASLOCAL(kr_1byte_word_copy)
+ subu r2,r2,1 /* decrement source pointer */
+ subu r3,r3,1 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to word copy */
+/*
+ * Copy as many full words as possible, 4 words per loop
+ */
+ASLOCAL(kr_word_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(kr_byte_copy) /* not enough left, copy bytes */
+ subu r2,r2,16 /* decrement source pointer */
+ subu r3,r3,16 /* decrement destination pointer */
+ ld r6,r2,0 /* load first word */
+ ld r7,r2,4 /* load second word */
+ ld r8,r2,8 /* load third word */
+ ld r9,r2,12 /* load fourth word */
+ st r6,r3,0 /* store first word */
+ st r7,r3,4 /* store second word */
+ st r8,r3,8 /* store third word */
+ st r9,r3,12 /* store fourth word */
+ br.n _ASM_LABEL(kr_word_copy) /* copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(kr_1byte_half_copy)
+ subu r2,r2,1 /* decrement source pointer */
+ subu r3,r3,1 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to half copy */
+
+ASLOCAL(kr_half_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(kr_byte_copy) /* not enough left, copy bytes */
+ subu r2,r2,16 /* decrement source pointer */
+ subu r3,r3,16 /* decrement destination pointer */
+ ld.hu r6,r2,0 /* load first half-word */
+ ld.hu r7,r2,2 /* load second half-word */
+ ld.hu r8,r2,4 /* load third half-word */
+ ld.hu r9,r2,6 /* load fourth half-word */
+ ld.hu r10,r2,8 /* load fifth half-word */
+ ld.hu r11,r2,10 /* load sixth half-word */
+ ld.hu r12,r2,12 /* load seventh half-word */
+ ld.hu r13,r2,14 /* load eighth half-word */
+ st.h r6,r3,0 /* store first half-word */
+ st.h r7,r3,2 /* store second half-word */
+ st.h r8,r3,4 /* store third half-word */
+ st.h r9,r3,6 /* store fourth half-word */
+ st.h r10,r3,8 /* store fifth half-word */
+ st.h r11,r3,10 /* store sixth half-word */
+ st.h r12,r3,12 /* store seventh half-word */
+ st.h r13,r3,14 /* store eighth half-word */
+ br.n _ASM_LABEL(kr_half_copy) /* copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(kr_byte_copy)
+ bcnd eq0,r4,_ASM_LABEL(kcopy_out) /* branch if nothing left to copy */
+ subu r2,r2,1 /* decrement source pointer */
+ subu r3,r3,1 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load byte from source */
+ st.b r6,r3,0 /* store byte in destination */
+ br.n _ASM_LABEL(kr_byte_copy) /* branch for next byte */
+ subu r4,r4,1 /* decrement remaining length */
+
+ASLOCAL(kcopy_out)
+ or r2, r0, 0 /* return success */
+ASLOCAL(kcopy_out_fault)
+ or.u r5,r0,hi16(_C_LABEL(curpcb))
+ ld r6,r5,lo16(_C_LABEL(curpcb))
+ st r0,r6,PCB_ONFAULT /* clear the handler */
+ jmp r1 /* all done, return to caller */
+
+ASLOCAL(kcopy_fault)
+ or r2, r0, EFAULT /* return fault */
+ br _ASM_LABEL(kcopy_out_fault)
+
+ data
+ align 4
+ASLOCAL(kf_strat)
+ word _ASM_LABEL(kf_word_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_half_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_3byte_word_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_1byte_half_copy)
+ word _ASM_LABEL(kf_half_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_1half_word_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_1byte_half_copy)
+ word _ASM_LABEL(kf_byte_copy)
+ word _ASM_LABEL(kf_1byte_word_copy)
+
+ASLOCAL(kr_strat)
+ word _ASM_LABEL(kr_word_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_half_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_1byte_word_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_1byte_half_copy)
+ word _ASM_LABEL(kr_half_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_1half_word_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_1byte_half_copy)
+ word _ASM_LABEL(kr_byte_copy)
+ word _ASM_LABEL(kr_3byte_word_copy)
+
+/*
+ * Gcc 2 generates calls to memcpy for bcopies of unknown size. memcpy can
+ * simply be implemented as ovbcopy but the src (r2, r3) and dst args need to
+ * be switched.
+ */
+/*
+ * void memcpy(dest, source, count)
+ *
+ */
+ENTRY(memcpy)
+ or r5, r0, r2 /* dst -> tmp */
+ or r2, r0, r3 /* src -> 1st arg */
+ br.n _C_LABEL(ovbcopy)
+ or r3, r0, r5 /* dst -> 2nd arg */
+
+/*
+ * void bcopy(source, destination, count)
+ *
+ * copy count bytes of data from source to destination
+ * Don Harper (don@omron.co.jp), Omron Corporation.
+ *
+ */
+
+ENTRY(bcopy)
+ENTRY(ovbcopy)
+ bcnd le0,r4,_ASM_LABEL(bcopy_out) /* nothing to do if <= 0 */
+/*
+ * check position of source and destination data
+ */
+ cmp r9,r2,r3 /* compare source address to destination */
+ bb1 eq,r9,_ASM_LABEL(bcopy_out) /* nothing to do if equal */
+ bb1 lo,r9,_ASM_LABEL(bcopy_reverse) /* reverse copy if src < dest */
+/*
+ * source address is greater than destination address, copy forward
+ */
+ cmp r9,r4,16 /* see if we have at least 16 bytes */
+ bb1 lt,r9,_ASM_LABEL(f_byte_copy) /* copy bytes for small data length */
+/*
+ * determine copy strategy based on alignment of source and destination
+ */
+ mask r6,r2,3 /* get 2 low order bits of source address */
+ mask r7,r3,3 /* get 2 low order bits of destintation addr */
+ mak r6,r6,0<4> /* convert source bits to table offset */
+ mak r7,r7,0<2> /* convert destination bits to table offset */
+ or.u r12,r0,hi16(_ASM_LABEL(f_strat))
+ or r12,r12,lo16(_ASM_LABEL(f_strat))
+ addu r6,r6,r7 /* compute final table offset for strategy */
+ ld r12,r12,r6 /* load the strategy routine */
+ jmp r12 /* branch to strategy routine */
+
+
+/*
+ * Copy three bytes from src to destination then copy words
+ */
+ASLOCAL(f_3byte_word_copy)
+ ld.bu r6,r2,0 /* load byte from source */
+ ld.bu r7,r2,1 /* load byte from source */
+ ld.bu r8,r2,2 /* load byte from source */
+ st.b r6,r3,0 /* store byte to destination */
+ st.b r7,r3,1 /* store byte to destination */
+ st.b r8,r3,2 /* store byte to destination */
+ addu r2,r2,3 /* increment source pointer */
+ addu r3,r3,3 /* increment destination pointer */
+ br.n _ASM_LABEL(f_word_copy) /* copy full words */
+ subu r4,r4,3 /* decrement length */
+
+/*
+ * Copy 1 halfword from src to destination then copy words
+ */
+ASLOCAL(f_1half_word_copy)
+ ld.hu r6,r2,0 /* load half-word from source */
+ st.h r6,r3,0 /* store half-word to destination */
+ addu r2,r2,2 /* increment source pointer */
+ addu r3,r3,2 /* increment destination pointer */
+ br.n _ASM_LABEL(f_word_copy) /* copy full words */
+ subu r4,r4,2 /* decrement remaining length */
+
+/*
+ * Copy 1 byte from src to destination then copy words
+ */
+ASLOCAL(f_1byte_word_copy)
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ addu r2,r2,1 /* increment source pointer */
+ addu r3,r3,1 /* increment destination pointer */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to word copy */
+/*
+ * Copy as many full words as possible, 4 words per loop
+ */
+ASLOCAL(f_word_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(f_byte_copy) /* not enough left, copy bytes */
+ ld r6,r2,0 /* load first word */
+ ld r7,r2,4 /* load second word */
+ ld r8,r2,8 /* load third word */
+ ld r9,r2,12 /* load fourth word */
+ st r6,r3,0 /* store first word */
+ st r7,r3,4 /* store second word */
+ st r8,r3,8 /* store third word */
+ st r9,r3,12 /* store fourth word */
+ addu r2,r2,16 /* increment source pointer */
+ addu r3,r3,16 /* increment destination pointer */
+ br.n _ASM_LABEL(f_word_copy) /* branch to copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(f_1byte_half_copy)
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ addu r2,r2,1 /* increment source pointer */
+ addu r3,r3,1 /* increment destination pointer */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to half copy */
+
+ASLOCAL(f_half_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(f_byte_copy) /* not enough left, copy bytes */
+ ld.hu r6,r2,0 /* load first half-word */
+ ld.hu r7,r2,2 /* load second half-word */
+ ld.hu r8,r2,4 /* load third half-word */
+ ld.hu r9,r2,6 /* load fourth half-word */
+ ld.hu r10,r2,8 /* load fifth half-word */
+ ld.hu r11,r2,10 /* load sixth half-word */
+ ld.hu r12,r2,12 /* load seventh half-word */
+ ld.hu r13,r2,14 /* load eighth half-word */
+ st.h r6,r3,0 /* store first half-word */
+ st.h r7,r3,2 /* store second half-word */
+ st.h r8,r3,4 /* store third half-word */
+ st.h r9,r3,6 /* store fourth half-word */
+ st.h r10,r3,8 /* store fifth half-word */
+ st.h r11,r3,10 /* store sixth half-word */
+ st.h r12,r3,12 /* store seventh half-word */
+ st.h r13,r3,14 /* store eighth half-word */
+ addu r2,r2,16 /* increment source pointer */
+ addu r3,r3,16 /* increment destination pointer */
+ br.n _ASM_LABEL(f_half_copy) /* branch to copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(f_byte_copy)
+ bcnd eq0,r4,_ASM_LABEL(bcopy_out) /* branch if nothing left to copy */
+ ld.bu r6,r2,0 /* load byte from source */
+ st.b r6,r3,0 /* store byte in destination */
+ addu r2,r2,1 /* increment source pointer */
+ addu r3,r3,1 /* increment destination pointer */
+ br.n _ASM_LABEL(f_byte_copy) /* branch for next byte */
+ subu r4,r4,1 /* decrement remaining length */
+
+/*
+ * source address is less than destination address, copy in reverse
+ */
+ASLOCAL(bcopy_reverse)
+/*
+ * start copy pointers at end of data
+ */
+ addu r2,r2,r4 /* start source at end of data */
+ addu r3,r3,r4 /* start destination at end of data */
+/*
+ * check for short data
+ */
+ cmp r9,r4,16 /* see if we have at least 16 bytes */
+ bb1 lt,r9,_ASM_LABEL(r_byte_copy) /* copy bytes for small data length */
+/*
+ * determine copy strategy based on alignment of source and destination
+ */
+ mask r6,r2,3 /* get 2 low order bits of source address */
+ mask r7,r3,3 /* get 2 low order bits of destintation addr */
+ mak r6,r6,0<4> /* convert source bits to table offset */
+ mak r7,r7,0<2> /* convert destination bits to table offset */
+ or.u r12,r0,hi16(_ASM_LABEL(r_strat))
+ or r12,r12,lo16(_ASM_LABEL(r_strat))
+ addu r6,r6,r7 /* compute final table offset for strategy */
+ ld r12,r12,r6 /* load the strategy routine */
+ jmp r12 /* branch to strategy routine */
+
+/*
+ * Copy three bytes from src to destination then copy words
+ */
+ASLOCAL(r_3byte_word_copy)
+ subu r2,r2,3 /* decrement source pointer */
+ subu r3,r3,3 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load byte from source */
+ ld.bu r7,r2,1 /* load byte from source */
+ ld.bu r8,r2,2 /* load byte from source */
+ st.b r6,r3,0 /* store byte to destination */
+ st.b r7,r3,1 /* store byte to destination */
+ st.b r8,r3,2 /* store byte to destination */
+ br.n _ASM_LABEL(r_word_copy) /* copy full words */
+ subu r4,r4,3 /* decrement length */
+
+/*
+ * Copy 1 halfword from src to destination then copy words
+ */
+ASLOCAL(r_1half_word_copy)
+ subu r2,r2,2 /* decrement source pointer */
+ subu r3,r3,2 /* decrement destination pointer */
+ ld.hu r6,r2,0 /* load half-word from source */
+ st.h r6,r3,0 /* store half-word to destination */
+ br.n _ASM_LABEL(r_word_copy) /* copy full words */
+ subu r4,r4,2 /* decrement remaining length */
+
+/*
+ * Copy 1 byte from src to destination then copy words
+ */
+ASLOCAL(r_1byte_word_copy)
+ subu r2,r2,1 /* decrement source pointer */
+ subu r3,r3,1 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to word copy */
+/*
+ * Copy as many full words as possible, 4 words per loop
+ */
+ASLOCAL(r_word_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(r_byte_copy) /* not enough left, copy bytes */
+ subu r2,r2,16 /* decrement source pointer */
+ subu r3,r3,16 /* decrement destination pointer */
+ ld r6,r2,0 /* load first word */
+ ld r7,r2,4 /* load second word */
+ ld r8,r2,8 /* load third word */
+ ld r9,r2,12 /* load fourth word */
+ st r6,r3,0 /* store first word */
+ st r7,r3,4 /* store second word */
+ st r8,r3,8 /* store third word */
+ st r9,r3,12 /* store fourth word */
+ br.n _ASM_LABEL(r_word_copy) /* branch to copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(r_1byte_half_copy)
+ subu r2,r2,1 /* decrement source pointer */
+ subu r3,r3,1 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load 1 byte from source */
+ st.b r6,r3,0 /* store 1 byte to destination */
+ subu r4,r4,1 /* decrement remaining length */
+ /* fall through to half copy */
+
+ASLOCAL(r_half_copy)
+ cmp r10,r4,16 /* see if we have 16 bytes remaining */
+ bb1 lo,r10,_ASM_LABEL(r_byte_copy) /* not enough left, copy bytes */
+ subu r2,r2,16 /* decrement source pointer */
+ subu r3,r3,16 /* decrement destination pointer */
+ ld.hu r6,r2,0 /* load first half-word */
+ ld.hu r7,r2,2 /* load second half-word */
+ ld.hu r8,r2,4 /* load third half-word */
+ ld.hu r9,r2,6 /* load fourth half-word */
+ ld.hu r10,r2,8 /* load fifth half-word */
+ ld.hu r11,r2,10 /* load sixth half-word */
+ ld.hu r12,r2,12 /* load seventh half-word */
+ ld.hu r13,r2,14 /* load eighth half-word */
+ st.h r6,r3,0 /* store first half-word */
+ st.h r7,r3,2 /* store second half-word */
+ st.h r8,r3,4 /* store third half-word */
+ st.h r9,r3,6 /* store fourth half-word */
+ st.h r10,r3,8 /* store fifth half-word */
+ st.h r11,r3,10 /* store sixth half-word */
+ st.h r12,r3,12 /* store seventh half-word */
+ st.h r13,r3,14 /* store eighth half-word */
+ br.n _ASM_LABEL(r_half_copy) /* branch to copy another block */
+ subu r4,r4,16 /* decrement remaining length */
+
+ASLOCAL(r_byte_copy)
+ bcnd eq0,r4,_ASM_LABEL(bcopy_out) /* branch if nothing left to copy */
+ subu r2,r2,1 /* decrement source pointer */
+ subu r3,r3,1 /* decrement destination pointer */
+ ld.bu r6,r2,0 /* load byte from source */
+ st.b r6,r3,0 /* store byte in destination */
+ br.n _ASM_LABEL(r_byte_copy) /* branch for next byte */
+ subu r4,r4,1 /* decrement remaining length */
+
+ASLOCAL(bcopy_out)
+ jmp r1 /* all done, return to caller */
+
+ data
+ align 4
+ASLOCAL(f_strat)
+ word _ASM_LABEL(f_word_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_half_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_3byte_word_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_1byte_half_copy)
+ word _ASM_LABEL(f_half_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_1half_word_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_1byte_half_copy)
+ word _ASM_LABEL(f_byte_copy)
+ word _ASM_LABEL(f_1byte_word_copy)
+
+ASLOCAL(r_strat)
+ word _ASM_LABEL(r_word_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_half_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_1byte_word_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_1byte_half_copy)
+ word _ASM_LABEL(r_half_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_1half_word_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_1byte_half_copy)
+ word _ASM_LABEL(r_byte_copy)
+ word _ASM_LABEL(r_3byte_word_copy)
+
+ text
+
+/*######################################################################*/
+
+/*
+ * April 1990, Omron Corporation
+ * jfriedl@nff.ncl.omron.co.jp
+ *
+ * void bzero(destination, length)
+ *
+ * Clear (set to zero) LENGTH bytes of memory starting at DESTINATION.
+ * Note that there is no return value.
+ *
+ * This is fast. Really fast. Especially for long lengths.
+ */
+#define R_dest r2
+#define R_len r3
+
+#define R_bytes r4
+#define R_mark_address r5
+#define R_addr r6 /* R_addr && R_temp SHARE */
+#define R_temp r6 /* R_addr && R_temp SHARE */
+
+ENTRY(bzero)
+ /*
+ * If the destination is not word aligned, we'll word align
+ * it first to make things easier.
+ *
+ * We'll check to see first if bit #0 is set and then bit #1
+ * (of the destination address). If either are set, it's
+ * not word aligned.
+ */
+ bb1 0, R_dest, _ASM_LABEL(not_initially_word_aligned)
+ bb1 1, R_dest, _ASM_LABEL(not_initially_word_aligned)
+
+ASLOCAL(now_word_aligned)
+ /*
+ * before we get into the main loop, grab the
+ * address of the label "mark" below.
+ */
+ or.u R_mark_address, r0, hi16(_ASM_LABEL(mark))
+ or R_mark_address, R_mark_address, lo16(_ASM_LABEL(mark))
+
+ASLOCAL(top_of_main_loop)
+#define MAX_AT_ONE_TIME 128
+ /*
+ * Now we find out how many words we can zero-fill in a row.
+ * We do this by doing something like:
+ *
+ * bytes &= 0xfffffffc;
+ * if (bytes > MAX_AT_ONE_TIME)
+ * bytes = MAX_AT_ONE_TIME;
+ */
+
+ /*
+ * Clear lower two bits of length to give us the number of bytes
+ * ALIGNED TO THE WORD LENGTH remaining to move.
+ */
+ clr R_bytes, R_len, 2<0>
+
+ /* if we're done clearing WORDS, jump out */
+ bcnd eq0, R_bytes, _ASM_LABEL(done_doing_words)
+
+ /* if the number of bytes > MAX_AT_ONE_TIME, do only the max */
+ cmp R_temp, R_bytes, MAX_AT_ONE_TIME
+ bb1 lt, R_temp, 1f
+
+ /*
+ * Since we're doing the max, we know exactly where we're
+ * jumping (the first one in the list!), so we can jump
+ * right there. However, we've still got to adjust
+ * the length, so we'll jump to where we ajust the length
+ * which just happens to fall through to the first store zero
+ * in the list.
+ *
+ * Note, however, that we're jumping to an instruction that
+ * would be in the delay slot for the jump in front of it,
+ * so if you change things here, WATCH OUT.
+ */
+ br.n do_max
+ or R_bytes, r0, MAX_AT_ONE_TIME
+
+1:
+ /*
+ * Now we have the number of bytes to zero during this iteration,
+ * (which, as it happens, is the last iteration if we're here).
+ * We'll calculate the proper place to jump and then jump there,
+ * after adjusting the length. NOTE that there is a label between
+ * the "jmp.n" and the "subu" below... the "subu" is NOT always
+ * executed in the delay slot of the "jmp.n".
+ */
+ subu R_addr, R_mark_address, R_bytes
+
+ /* and go there (after adjusting the length via ".n") */
+ jmp.n R_addr
+ASLOCAL(do_max)
+ subu R_len, R_len, R_bytes /* NOTE: this is in the delay slot! */
+
+ st r0, R_dest, 0x7c /* 128 */
+ st r0, R_dest, 0x78 /* 124 */
+ st r0, R_dest, 0x74 /* 120 */
+ st r0, R_dest, 0x70 /* 116 */
+ st r0, R_dest, 0x6c /* 112 */
+ st r0, R_dest, 0x68 /* 108 */
+ st r0, R_dest, 0x64 /* 104 */
+ st r0, R_dest, 0x60 /* 100 */
+ st r0, R_dest, 0x5c /* 96 */
+ st r0, R_dest, 0x58 /* 92 */
+ st r0, R_dest, 0x54 /* 88 */
+ st r0, R_dest, 0x50 /* 84 */
+ st r0, R_dest, 0x4c /* 80 */
+ st r0, R_dest, 0x48 /* 76 */
+ st r0, R_dest, 0x44 /* 72 */
+ st r0, R_dest, 0x40 /* 68 */
+ st r0, R_dest, 0x3c /* 64 */
+ st r0, R_dest, 0x38 /* 60 */
+ st r0, R_dest, 0x34 /* 56 */
+ st r0, R_dest, 0x30 /* 52 */
+ st r0, R_dest, 0x2c /* 44 */
+ st r0, R_dest, 0x28 /* 40 */
+ st r0, R_dest, 0x24 /* 36 */
+ st r0, R_dest, 0x20 /* 32 */
+ st r0, R_dest, 0x1c /* 28 */
+ st r0, R_dest, 0x18 /* 24 */
+ st r0, R_dest, 0x14 /* 20 */
+ st r0, R_dest, 0x10 /* 16 */
+ st r0, R_dest, 0x0c /* 12 */
+ st r0, R_dest, 0x08 /* 8 */
+ st r0, R_dest, 0x04 /* 4 */
+ st r0, R_dest, 0x00 /* 0 */
+
+ASLOCAL(mark)
+ br.n _ASM_LABEL(top_of_main_loop)
+ addu R_dest, R_dest, R_bytes /* bump up the dest address */
+
+ASLOCAL(done_doing_words)
+ bcnd ne0, R_len, 1f
+ jmp r1
+
+1:
+ subu R_len, R_len, 1
+ bcnd.n ne0, R_len, 1b
+ st.b r0, R_dest, R_len
+1:
+ jmp r1
+
+ASLOCAL(not_initially_word_aligned)
+ /*
+ * Bzero to word-align the address (at least if the length allows it).
+ */
+ bcnd eq0, R_len, 1b
+ st.b r0, R_dest, 0
+ addu R_dest, R_dest, 1
+ mask R_temp, R_dest, 0x3
+ bcnd.n eq0, R_temp, _ASM_LABEL(now_word_aligned)
+ subu R_len, R_len, 1
+ br _ASM_LABEL(not_initially_word_aligned)
+
+#undef R_dest
+#undef R_len
+#undef R_bytes
+#undef R_mark_address
+#undef R_addr
+#undef R_temp
+#undef MAX_AT_ONE_TIME
+
+/*
+ * non-local goto
+ * int setjmp(label_t *);
+ * void longjmp(label_t*);
+ */
+ENTRY(setjmp)
+ st r1,r2,0
+ st r14,r2,4
+ st r15,r2,2*4
+ st r16,r2,3*4
+ st r17,r2,4*4
+ st r18,r2,5*4
+ st r19,r2,6*4
+ st r20,r2,7*4
+ st r21,r2,8*4
+ st r22,r2,9*4
+ st r23,r2,10*4
+ st r24,r2,11*4
+ st r25,r2,12*4
+ st r26,r2,13*4
+ st r27,r2,14*4
+ st r28,r2,15*4
+ st r29,r2,16*4
+ st r30,r2,17*4
+ st r31,r2,18*4
+ jmp.n r1
+ or r2,r0,r0
+
+ENTRY(longjmp)
+ ld r1,r2,0
+ ld r14,r2,4
+ ld r15,r2,2*4
+ ld r16,r2,3*4
+ ld r17,r2,4*4
+ ld r18,r2,5*4
+ ld r19,r2,6*4
+ ld r20,r2,7*4
+ ld r21,r2,8*4
+ ld r22,r2,9*4
+ ld r23,r2,10*4
+ ld r24,r2,11*4
+ ld r25,r2,12*4
+ ld r26,r2,13*4
+ ld r27,r2,14*4
+ ld r28,r2,15*4
+ ld r29,r2,16*4
+ ld r30,r2,17*4
+ ld r31,r2,18*4
+ jmp.n r1
+ or r2,r0,1
+
+ENTRY(read_processor_identification_register)
+ jmp.n r1
+ ldcr r2, PID
+
+GLOBAL(guarded_access_start)
+ENTRY(guarded_access)
+ cmp r9,r3,4
+ bb1 eq,r9,@L145
+ cmp r9,r3,2
+ bb1 eq,r9,@L144
+ cmp r9,r3,1
+ bb1 eq,r9,@L143
+ br _C_LABEL(guarded_access_bad)
+@L143:
+ ld.b r9,r0,r2
+ tb1 0, r0, 0
+ st.b r9,r0,r4
+ br @L142
+@L144:
+ ld.h r9,r0,r2
+ tb1 0, r0, 0
+ st.h r9,r0,r4
+ br @L142
+@L145:
+ ld r9,r0,r2
+ tb1 0, r0, 0
+ st r9,r0,r4
+ br @L142
+
+GLOBAL(guarded_access_bad)
+ jmp.n r1
+ or r2,r0,EFAULT
+
+@L142:
+ jmp.n r1
+ or r2,r0,0
+
+GLOBAL(guarded_access_end)
+
+/*
+ * void set_cpu_number(unsigned number);
+ *
+ * Sets the kernel cpu number for this cpu to the given value.
+ *
+ * Input:
+ * r1 return address
+ * r2 the number (should be 0, 1, 2, or 3).
+ *
+ * Other registers used:
+ * r3 temp
+ * r4 original PSR
+ * r5 temporary new PSR
+ */
+ENTRY(set_cpu_number)
+#ifdef DEBUG
+ /* make sure the CPU number is valid */
+ clr r3, r2, FLAG_CPU_FIELD_WIDTH<0>
+ bcnd ne0, r3, 1f /* bad cpu number */
+#endif
+
+ /* going to change a control register -- disable interrupts */
+ ldcr r4, PSR
+ set r5, r4, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r5, PSR
+ FLUSH_PIPELINE
+
+ /* put in the cpu number */
+ ldcr r3, SR1 /* get the flags */
+ clr r3, r3, FLAG_CPU_FIELD_WIDTH<0> /* clean the slate */
+ or r3, r3, r2 /* add the cpu number */
+ stcr r3, SR1 /* put back */
+
+ /* put back the PSR to what it was before and return */
+ stcr r4, PSR
+ FLUSH_PIPELINE
+ jmp r1
+
+#ifdef DEBUG
+1: /* bad cpu number*/
+ or.u r2, r0, hi16(9f)
+ bsr.n _C_LABEL(panic)
+ or r2, r2, lo16(9f)
+
+ data
+9: string "set_cpu_number: bad CPU number %x\0"
+#endif
diff --git a/sys/arch/luna88k/luna88k/locore_c_routines.c b/sys/arch/luna88k/luna88k/locore_c_routines.c
new file mode 100644
index 00000000000..432f9d11f45
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/locore_c_routines.c
@@ -0,0 +1,512 @@
+/* $OpenBSD: locore_c_routines.c,v 1.1 2004/04/21 15:24:01 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "assym.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <machine/board.h> /* m188 bit defines */
+#include <machine/cmmu.h> /* DMT_VALID */
+#include <machine/asm.h> /* END_OF_VECTOR_LIST, etc. */
+#include <machine/asm_macro.h> /* enable/disable interrupts */
+#include <machine/cpu_number.h> /* cpu_number() */
+#include <machine/locore.h>
+#include <machine/trap.h>
+#ifdef M88100
+#include <machine/m88100.h>
+#endif
+
+#ifdef DDB
+#include <ddb/db_output.h>
+#endif /* DDB */
+
+#if defined(DDB) && defined(JEFF_DEBUG)
+#define DATA_DEBUG
+#endif
+
+#if DDB
+#define DEBUG_MSG db_printf
+#else
+#define DEBUG_MSG printf
+#endif /* DDB */
+
+typedef struct {
+ unsigned word_one, word_two;
+} m88k_exception_vector_area;
+
+extern unsigned int *volatile int_mask_reg[MAX_CPUS]; /* in machdep.c */
+extern unsigned master_cpu; /* in cmmu.c */
+
+/* FORWARDS */
+void setlevel(unsigned int);
+void vector_init(m88k_exception_vector_area *, unsigned *);
+
+#ifdef M88100
+
+/*
+ * data access emulation for M88100 exceptions
+ */
+
+#define DMT_BYTE 1
+#define DMT_HALF 2
+#define DMT_WORD 4
+
+const struct {
+ unsigned char offset;
+ unsigned char size;
+} dmt_en_info[16] = {
+ {0, 0}, {3, DMT_BYTE}, {2, DMT_BYTE}, {2, DMT_HALF},
+ {1, DMT_BYTE}, {0, 0}, {0, 0}, {0, 0},
+ {0, DMT_BYTE}, {0, 0}, {0, 0}, {0, 0},
+ {0, DMT_HALF}, {0, 0}, {0, 0}, {0, DMT_WORD}
+};
+
+#ifdef DATA_DEBUG
+int data_access_emulation_debug = 0;
+#define DAE_DEBUG(stuff) \
+ do { \
+ if (data_access_emulation_debug != 0) { \
+ stuff; \
+ } \
+ } while (0)
+#else
+#define DAE_DEBUG(stuff)
+#endif
+
+void
+dae_print(unsigned *eframe)
+{
+ int x;
+ unsigned dmax, dmdx, dmtx;
+
+ if (!ISSET(eframe[EF_DMT0], DMT_VALID))
+ return;
+
+ for (x = 0; x < 3; x++) {
+ dmtx = eframe[EF_DMT0 + x * 3];
+ if (!ISSET(dmtx, DMT_VALID))
+ continue;
+
+ dmdx = eframe[EF_DMD0 + x * 3];
+ dmax = eframe[EF_DMA0 + x * 3];
+
+ if (ISSET(dmtx, DMT_WRITE))
+ printf("[DMT%d=%x: st.%c %x to %x as %d %s %s]\n",
+ x, dmtx, dmtx & DMT_DAS ? 's' : 'u', dmdx, dmax,
+ DMT_ENBITS(dmtx),
+ dmtx & DMT_DOUB1 ? "double": "not double",
+ dmtx & DMT_LOCKBAR ? "xmem": "not xmem");
+ else
+ printf("[DMT%d=%x: ld.%c r%d <- %x as %d %s %s]\n",
+ x, dmtx, dmtx & DMT_DAS ? 's' : 'u',
+ DMT_DREGBITS(dmtx), dmax, DMT_ENBITS(dmtx),
+ dmtx & DMT_DOUB1 ? "double": "not double",
+ dmtx & DMT_LOCKBAR ? "xmem": "not xmem");
+ }
+}
+
+void
+data_access_emulation(unsigned *eframe)
+{
+ int x;
+ unsigned dmax, dmdx, dmtx;
+ unsigned v, reg;
+
+ dmtx = eframe[EF_DMT0];
+ if (!ISSET(dmtx, DMT_VALID))
+ return;
+
+ for (x = 0; x < 3; x++) {
+ dmtx = eframe[EF_DMT0 + x * 3];
+ if (!ISSET(dmtx, DMT_VALID) || ISSET(dmtx, DMT_SKIP))
+ continue;
+
+ dmdx = eframe[EF_DMD0 + x * 3];
+ dmax = eframe[EF_DMA0 + x * 3];
+
+ DAE_DEBUG(
+ if (ISSET(dmtx, DMT_WRITE))
+ printf("[DMT%d=%x: st.%c %x to %x as %d %s %s]\n",
+ x, dmtx, dmtx & DMT_DAS ? 's' : 'u', dmdx, dmax,
+ DMT_ENBITS(dmtx),
+ dmtx & DMT_DOUB1 ? "double": "not double",
+ dmtx & DMT_LOCKBAR ? "xmem": "not xmem");
+ else
+ printf("[DMT%d=%x: ld.%c r%d <- %x as %d %s %s]\n",
+ x, dmtx, dmtx & DMT_DAS ? 's' : 'u',
+ DMT_DREGBITS(dmtx), dmax, DMT_ENBITS(dmtx),
+ dmtx & DMT_DOUB1 ? "double": "not double",
+ dmtx & DMT_LOCKBAR ? "xmem": "not xmem")
+ );
+
+ dmax += dmt_en_info[DMT_ENBITS(dmtx)].offset;
+ reg = DMT_DREGBITS(dmtx);
+
+ if (!ISSET(dmtx, DMT_LOCKBAR)) {
+ /* the fault is not during an XMEM */
+
+ if (x == 2 && ISSET(dmtx, DMT_DOUB1)) {
+ /* pipeline 2 (earliest stage) for a double */
+
+ if (ISSET(dmtx, DMT_WRITE)) {
+ /*
+ * STORE DOUBLE WILL BE REINITIATED
+ * BY rte
+ */
+ } else {
+ /* EMULATE ld.d INSTRUCTION */
+ v = do_load_word(dmax, dmtx & DMT_DAS);
+ if (reg != 0)
+ eframe[EF_R0 + reg] = v;
+ v = do_load_word(dmax ^ 4,
+ dmtx & DMT_DAS);
+ if (reg != 31)
+ eframe[EF_R0 + reg + 1] = v;
+ }
+ } else {
+ /* not pipeline #2 with a double */
+ if (dmtx & DMT_WRITE) {
+ switch (dmt_en_info[DMT_ENBITS(dmtx)].size) {
+ case DMT_BYTE:
+ DAE_DEBUG(
+ DEBUG_MSG("[byte %x -> [%x(%c)]\n",
+ dmdx & 0xff, dmax,
+ ISSET(dmtx, DMT_DAS) ? 's' : 'u')
+ );
+ do_store_byte(dmax, dmdx,
+ dmtx & DMT_DAS);
+ break;
+ case DMT_HALF:
+ DAE_DEBUG(
+ DEBUG_MSG("[half %x -> [%x(%c)]\n",
+ dmdx & 0xffff, dmax,
+ ISSET(dmtx, DMT_DAS) ? 's' : 'u')
+ );
+ do_store_half(dmax, dmdx,
+ dmtx & DMT_DAS);
+ break;
+ case DMT_WORD:
+ DAE_DEBUG(
+ DEBUG_MSG("[word %x -> [%x(%c)]\n",
+ dmdx, dmax,
+ ISSET(dmtx, DMT_DAS) ? 's' : 'u')
+ );
+ do_store_word(dmax, dmdx,
+ dmtx & DMT_DAS);
+ break;
+ }
+ } else {
+ /* else it's a read */
+ switch (dmt_en_info[DMT_ENBITS(dmtx)].size) {
+ case DMT_BYTE:
+ v = do_load_byte(dmax,
+ dmtx & DMT_DAS);
+ if (!ISSET(dmtx, DMT_SIGNED))
+ v &= 0x000000ff;
+ break;
+ case DMT_HALF:
+ v = do_load_half(dmax,
+ dmtx & DMT_DAS);
+ if (!ISSET(dmtx, DMT_SIGNED))
+ v &= 0x0000ffff;
+ break;
+ case DMT_WORD:
+ v = do_load_word(dmax,
+ dmtx & DMT_DAS);
+ break;
+ }
+ DAE_DEBUG(
+ if (reg == 0)
+ DEBUG_MSG("[no write to r0 done]\n");
+ else
+ DEBUG_MSG("[r%d <- %x]\n", reg, v);
+ );
+ if (reg != 0)
+ eframe[EF_R0 + reg] = v;
+ }
+ }
+ } else {
+ /* if lockbar is set... it's part of an XMEM */
+ /*
+ * According to Motorola's "General Information",
+ * the DMT_DOUB1 bit is never set in this case, as it
+ * should be.
+ * If lockbar is set (as it is if we're here) and if
+ * the write is not set, then it's the same as if DOUB1
+ * was set...
+ */
+ if (!ISSET(dmtx, DMT_WRITE)) {
+ if (x != 2) {
+ /* RERUN xmem WITH DMD(x+1) */
+ x++;
+ dmdx = eframe[EF_DMD0 + x * 3];
+ } else {
+ /* RERUN xmem WITH DMD2 */
+ }
+
+ if (dmt_en_info[DMT_ENBITS(dmtx)].size ==
+ DMT_WORD) {
+ v = do_xmem_word(dmax, dmdx,
+ dmtx & DMT_DAS);
+ } else {
+ v = do_xmem_byte(dmax, dmdx,
+ dmtx & DMT_DAS);
+ }
+ if (reg != 0)
+ eframe[EF_R0 + reg] = v;
+ } else {
+ if (x == 0) {
+ if (reg != 0)
+ eframe[EF_R0 + reg] = dmdx;
+ eframe[EF_SFIP] = eframe[EF_SNIP];
+ eframe[EF_SNIP] = eframe[EF_SXIP];
+ eframe[EF_SXIP] = 0;
+ /* xmem RERUN ON rte */
+ eframe[EF_DMT0] = 0;
+ return;
+ }
+ }
+ }
+ }
+ eframe[EF_DMT0] = 0;
+}
+#endif /* M88100 */
+
+#define SIGSYS_MAX 501
+#define SIGTRAP_MAX 510
+
+#define EMPTY_BR 0xc0000000 /* empty "br" instruction */
+#define NO_OP 0xf4005800 /* "or r0, r0, r0" */
+
+#define BRANCH(FROM, TO) \
+ (EMPTY_BR | ((unsigned)(TO) - (unsigned)(FROM)) >> 2)
+
+#define SET_VECTOR(NUM, VALUE) \
+ do { \
+ vector[NUM].word_one = NO_OP; \
+ vector[NUM].word_two = BRANCH(&vector[NUM].word_two, VALUE); \
+ } while (0)
+
+/*
+ * vector_init(vector, vector_init_list)
+ *
+ * This routine sets up the m88k vector table for the running processor.
+ * It is called with a very little stack, and interrupts disabled,
+ * so don't call any other functions!
+ * XXX clean this - nivas
+ */
+void
+vector_init(m88k_exception_vector_area *vector, unsigned *vector_init_list)
+{
+ unsigned num;
+ unsigned vec;
+ extern void bugtrap(void);
+ extern void m88110_bugtrap(void);
+
+ for (num = 0; (vec = vector_init_list[num]) != END_OF_VECTOR_LIST;
+ num++) {
+ if (vec != UNKNOWN_HANDLER)
+ SET_VECTOR(num, vec);
+ }
+
+ for (; num <= SIGSYS_MAX; num++)
+ SET_VECTOR(num, sigsys);
+
+ for (; num <= SIGTRAP_MAX; num++)
+ SET_VECTOR(num, sigtrap);
+
+ SET_VECTOR(450, syscall_handler);
+ SET_VECTOR(504, stepbpt);
+ SET_VECTOR(511, userbpt);
+
+ /* GCC will by default produce explicit trap 503 for division by zero */
+ SET_VECTOR(503, vector_init_list[T_ZERODIV]);
+}
+
+unsigned int luna88k_curspl[MAX_CPUS] = {0, 0, 0, 0};
+
+unsigned int int_mask_val[INT_LEVEL] = {
+ INT_MASK_LV0,
+ INT_MASK_LV1,
+ INT_MASK_LV2,
+ INT_MASK_LV3,
+ INT_MASK_LV4,
+ INT_MASK_LV5,
+ INT_MASK_LV6,
+ INT_MASK_LV7
+};
+
+unsigned int int_set_val[INT_LEVEL] = {
+ INT_SET_LV0,
+ INT_SET_LV1,
+ INT_SET_LV2,
+ INT_SET_LV3,
+ INT_SET_LV4,
+ INT_SET_LV5,
+ INT_SET_LV6,
+ INT_SET_LV7
+};
+
+/*
+ * return next safe spl to reenable interrupts.
+ */
+unsigned int
+safe_level(mask, curlevel)
+ unsigned mask;
+ unsigned curlevel;
+{
+ int i;
+
+ for (i = curlevel; i < 8; i++)
+ if (!(int_mask_val[i] & mask))
+ return i;
+
+ panic("safe_level: no safe level for mask 0x%08x level %d found",
+ mask, curlevel);
+ /* NOTREACHED */
+}
+
+void
+setlevel(unsigned int level)
+{
+ unsigned int set_value;
+ int cpu = cpu_number();
+
+ set_value = int_set_val[level];
+
+ if (cpu != master_cpu)
+ set_value &= INT_SLAVE_MASK;
+
+#if 0
+ set_value &= ISR_SOFTINT_EXCEPT_MASK(cpu);
+ set_value &= ~blocked_interrupts_mask;
+#endif
+
+ *int_mask_reg[cpu] = set_value;
+#if 0
+ int_mask_shadow[cpu] = set_value;
+#endif
+ luna88k_curspl[cpu] = level;
+}
+
+unsigned
+getipl(void)
+{
+ unsigned curspl;
+ m88k_psr_type psr; /* processor status register */
+
+ psr = disable_interrupts_return_psr();
+ curspl = luna88k_curspl[cpu_number()];
+ set_psr(psr);
+ return curspl;
+}
+
+unsigned
+setipl(unsigned level)
+{
+ unsigned curspl;
+ m88k_psr_type psr; /* processor status register */
+
+#ifdef DEBUG
+ if (level > 7) {
+ printf("setipl: invoked with invalid level %x\n", level);
+ level &= 0x07; /* and pray it will work */
+ }
+#endif
+
+ psr = disable_interrupts_return_psr();
+ curspl = luna88k_curspl[cpu_number()];
+ setlevel(level);
+
+ flush_pipeline();
+
+ /* The flush pipeline is required to make sure the above write gets
+ * through the data pipe and to the hardware; otherwise, the next
+ * bunch of instructions could execute at the wrong spl protection
+ */
+ set_psr(psr);
+ return curspl;
+}
+
+unsigned
+raiseipl(unsigned level)
+{
+ unsigned curspl;
+ m88k_psr_type psr; /* processor status register */
+
+#ifdef DEBUG
+ if (level > 7) {
+ printf("raiseipl: invoked with invalid level %x\n", level);
+ level &= 0x07; /* and pray it will work */
+ }
+#endif
+
+ psr = disable_interrupts_return_psr();
+ curspl = luna88k_curspl[cpu_number()];
+ if (curspl < level)
+ setlevel(level);
+
+ flush_pipeline();
+
+ /* The flush pipeline is required to make sure the above write gets
+ * through the data pipe and to the hardware; otherwise, the next
+ * bunch of instructions could execute at the wrong spl protection
+ */
+ set_psr(psr);
+ return curspl;
+}
+
+/* XXX Utterly bogus */
+#if NCPUS > 1
+#include <sys/simplelock.h>
+void
+simple_lock_init(lkp)
+ struct simplelock *volatile lkp;
+{
+ lkp->lock_data = 0;
+}
+
+int
+test_and_set(lock)
+ int *volatile lock;
+{
+#if 0
+ int oldlock = *lock;
+ if (*lock == 0) {
+ *lock = 1;
+ return 0;
+ }
+#else
+ return *lock;
+ *lock = 1;
+ return 0;
+#endif
+}
+#endif
diff --git a/sys/arch/luna88k/luna88k/m88100_fp.S b/sys/arch/luna88k/luna88k/m88100_fp.S
new file mode 100644
index 00000000000..c3959e4879f
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/m88100_fp.S
@@ -0,0 +1,2516 @@
+/* $OpenBSD: m88100_fp.S,v 1.1 2004/04/21 15:24:02 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/* Floating point trouble routines */
+#include "assym.h"
+#include <machine/trap.h>
+#include <machine/asm.h>
+
+#define destsize 10
+
+/* Floating-Point Status Register bits */
+#define inexact 0
+#define overflow 1
+#define underflow 2
+#define divzero 3
+#define oper 4
+
+#define sign 31
+#define s1size 9
+#define s2size 7
+#define dsize 5
+
+#define FADDop 0x05
+#define FSUBop 0x06
+#define FCMPop 0x07
+#define FMULop 0x00
+#define FDIVop 0x0e
+#define FSQRTop 0x0f
+#define INTop 0x09
+#define NINTop 0x0a
+#define TRNCop 0x0b
+
+#define s1nan 7
+#define s2nan 6
+#define s1inf 5
+#define s2inf 4
+#define s1zero 3
+#define s2zero 2
+#define sigbit 19
+
+#define modehi 30
+#define modelo 29
+#define rndhi 15
+#define rndlo 14
+#define efunf 7
+#define efovf 6
+#define efinx 5
+
+ASENTRY(m88100_Xfp_precise)
+ or r29, r3, r0 /* r29 is now the E.F. */
+ subu r31, r31, 40
+ st r1, r31, 32
+ st r29, r31, 36
+
+ ld r2, r29, EF_FPSR * 4
+ ld r3, r29, EF_FPCR * 4
+ ld r4, r29, EF_FPECR * 4
+ ld r5, r29, EF_FPHS1 * 4
+ ld r6, r29, EF_FPLS1 * 4
+ ld r7, r29, EF_FPHS2 * 4
+ ld r8, r29, EF_FPLS2 * 4
+ ld r9, r29, EF_FPPT * 4
+
+
+ /*
+ * Load into r1 the return address for the 0 handlers. Looking at
+ * FPECR, branch to the appropriate 0 handler. However, if none of the
+ * 0 bits are enabled, then a floating point instruction was issued
+ * with the floating point unit disabled. This will cause an
+ * unimplemented opcode 0.
+ */
+
+ or.u r1,r0,hi16(wrapup) /* load return address of function */
+ or r1,r1,lo16(wrapup)
+
+ bb0 6,r4, 3f /* branch to FPunimp if bit set */
+ br FPuimp
+3:
+ bb0 7,r4, 4f /* branch to FPintover if bit set */
+ br FPintover
+4:
+#if 0
+ bb0 5,r4, 5f /* branch to FPpriviol if bit set */
+ br FPpriviol
+#endif
+5:
+ bb0 4,r4, 6f /* branch to FPresoper if bit set */
+ br FPresoper
+6:
+ bb0 3,r4, 7f /* branch to FPdivzero if bit set */
+ br FPdivzero
+7:
+ or.u r4, r4, 0xffff
+
+ASLOCAL(FPuimp)
+ subu r31,r31,40 /* allocate stack */
+ st r1,r31,36 /* save return address */
+ st r3,r31,32 /* save exception frame */
+ or r2,r0,T_FPEPFLT /* load trap type */
+ or r3, r29, r0
+ bsr _C_LABEL(m88100_trap)
+ ld r1,r31,36 /* recover return address */
+ addu r31,r31,40 /* deallocate stack */
+ jmp r1
+
+ /*
+ * To write back the results to the user registers, disable exceptions
+ * and the floating point unit. Write FPSR and FPCR and load the SNIP
+ * and SFIP.
+ * r5 will contain the upper word of the result
+ * r6 will contain the lower word of the result
+ */
+
+ASLOCAL(wrapup)
+ tb1 0,r0,0 /* make sure all floating point operations */
+ /* have finished */
+ ldcr r10, cr1 /* load the PSR */
+#if 0
+ set r10, r10, 1<PSR_FPU_DISABLE_BIT>
+#endif
+ set r10, r10, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r10, cr1
+
+ ld r1, r31, 32
+ ld r29, r31, 36
+ addu r31, r31, 40
+
+ fstcr r2, FPSR /* write revised value of FPSR */
+ fstcr r3, FPCR /* write revised value of FPCR */
+
+ /* result writeback routine */
+ addu r3, r29, EF_R0 * 4
+ extu r2, r9, 5<0> /* get 5 bits of destination register */
+ bb0 5, r9, writesingle /* branch if destination is single */
+
+/* writedouble here */
+ st r5, r3 [r2] /* write high word */
+ add r2, r2, 1 /* for double, the low word is the */
+ /* unspecified register */
+ clr r2, r2, 27<5> /* perform equivalent of mod 32 */
+ASLOCAL(writesingle)
+ st r6, r3 [r2] /* write low word into memory */
+ jmp r1
+
+/*
+ * Check if the numerator is zero. If the numerator is zero, then handle
+ * this instruction as you would a 0/0 invalid operation.
+ */
+
+ASLOCAL(FPdivzero)
+ st r1,r31,0 /* save return address */
+ bb1 s1size,r9,1f /* branch if numerator double */
+/* single number */
+ clr r10,r5,1<sign> /* clear sign bit */
+ extu r11,r6,3<29> /* grab upper bits of lower word */
+ or r10,r10,r11 /* combine ones of mantissa */
+ bcnd eq0,r10,resoper /* numerator is zero, handle reserved operand */
+ br setbit /* set divzero bit */
+1:
+/* double number */
+ clr r10,r5,1<sign> /* clear sign bit */
+ or r10,r10,r6 /* or high and low words */
+ bcnd ne0,r10,setbit /* set divzero bit */
+
+/*
+ * The numerator is zero, so handle the invalid operation by setting the
+ * invalid operation bit and branching to the user handler if there is one
+ * or writing a quiet NaN to the destination.
+ */
+
+ASLOCAL(resoper)
+ set r2,r2,1<oper>
+#ifdef HANDLER
+ bb0 oper,r3,noreshand /* branch to execute default handling */
+ /* for reserved operands */
+ bsr _handler /* branch to user handler */
+ br FP_div_return
+#endif
+
+noreshand:
+ set r5,r0,0<0> /* put a NaN in high word */
+ set r6,r0,0<0> /* put a NaN in low word */
+ br FP_div_return
+ /* writing to a word which may be ignored */
+ /* is just as quick as checking the precision */
+ /* of the destination */
+
+/*
+ * The operation is divide by zero, so set the divide by zero bit in the
+ * FPSR. If the user handler is set, then go to the user handler, else
+ * go to the default mode.
+ */
+
+setbit:
+ set r2,r2,1<divzero>
+#ifdef HANDLER
+ bb0 divzero,r3,default /* go to default routine if no hdlr */
+ bsr _handler /* execute handler routine */
+ br FP_div_return
+#endif
+
+/*
+ * Considering the sign of the numerator and zero, write a correctly
+ * signed infinity of the proper precision into the destination.
+ */
+
+default:
+ bb1 dsize,r9,FPzero_double /* branch to handle double result */
+FPzero_single:
+ clr r10,r5,31<0> /* clear all of S1HI except sign bit */
+ xor r10,r7,r10 /* xor the sign bits of the operands */
+ or.u r6,r0,0x7f80 /* load single precision infinity */
+ br.n FP_div_return
+ or r6,r6,r10 /* load correctly signed infinity */
+
+FPzero_double:
+ clr r10,r5,31<0> /* clear all of S1HI except sign bit */
+ xor r10,r7,r10 /* xor the sign bits of the operands */
+ or.u r5,r0,0x7ff0 /* load double precision infinity */
+ or r5,r5,r10 /* load correctly signed infinity */
+ or r6,r0,r0 /* clear lower word of double */
+
+FP_div_return:
+ ld r1,r31,0 /* load return address */
+ jmp r1
+
+/*
+ * Both NINT and TRNC require a certain rounding mode, so check which
+ * instruction caused the integer conversion overflow. Use a substitute
+ * FPCR in r1, and modify the rounding mode if the instruction is NINT
+ * or TRNC.
+ */
+ASLOCAL(FPintover)
+ extu r10,r9,5<11> /* extract opcode */
+ cmp r11,r10,INTop /* see if instruction is INT */
+ st r1,r31,0 /* save return address */
+ bb1.n eq,r11,checksize /* instruction is INT, do not modify */
+ /* rounding mode */
+ or r1,r0,r3 /* load FPCR into r1 */
+ cmp r11,r10,NINTop /* see if instruction is NINT */
+ bb1 eq,r11,NINT /* instruction is NINT */
+TRNC:
+ clr r1,r1,2<rndlo> /* clear rounding mode bits, */
+ /* instruction is TRNC */
+ br.n checksize /* branch to check size */
+ set r1,r1,1<rndlo> /* make rounding mode round towards */
+ /* zero */
+NINT:
+ clr r1,r1,2<rndlo> /* make rounding mode round to */
+ /* nearest */
+
+/* See whether the source is single or double precision. */
+
+checksize:
+ bb1 s2size,r9,checkdoub /* S2 is double, branch to see if */
+ /* there is a false alarm */
+
+/*
+ * An integer has more bits than the mantissa of a single precision floating
+ * point number, so to check for false alarms (i.e. valid conversion), simply
+ * check the exponents. False alarms are detected for 2**30 to (2**30) - 1
+ * and -2**30 to -2**31. Only seven bits need to be looked at since an
+ * exception will not occur for the other half of the numbering system.
+ * To speed up the processing, first check to see if the exponent is 32 or
+ * greater.
+ *
+ * This code was originally written for the exponent in the control
+ * register to have the most significant bit (8 - single, 11 - double)
+ * flipped and sign extended. For precise exceptions, however, the most
+ * significant bit is only sign extended. Therefore, the code was chopped
+ * up so that it would work for positive values of real exponent which were
+ * only sign extended.
+ */
+
+checksing:
+ extu r10,r7,7<20> /* internal representation for single */
+ /* precision is IEEE 8 bits sign extended */
+ /* to 11 bits; for real exp. = 30, the */
+ /* above instruction gives a result exp. */
+ /* that has the MSB flipped and sign */
+ /* extended like in the IMPCR */
+ cmp r11,r10,31 /* compare to 32,but exp. off by 1 */
+ /* these 2 instructions to speed up valid */
+ /* execution of valid cases */
+ bb1 ge,r11,overflw /* valid case, perform overflow routine */
+ bb1 sign,r7,checksingn /* source operand is negative */
+
+/*
+ * If the number is positve and the exponent is greater than 30, than it is
+ * overflow.
+ */
+checksingp:
+ cmp r10,r10,29 /* compare to 30, but exp. off by 1 */
+ bb1 gt,r10,overflw /* no false alarm, its overflow */
+ br conversionsp /* finish single precision conversion */
+
+/*
+ * If the number is negative, and the exponent is 30, or 31 with a mantissa
+ * of 0, then it is a false alarm.
+ */
+checksingn:
+ cmp r11,r10,30 /* compare to 31,but exp. off by 1 */
+ bb1 lt,r11,conversionsn /* exp. less than 31, so convert */
+ extu r10,r8,3<29> /* get upper three bits of lower */
+ /* mantissa */
+ mak r12,r7,20<3> /* get upper 20 bits of mantissa */
+ or r10,r10,r12 /* form complete mantissa */
+ bcnd eq0,r10,conversionsn /* complete conversion if mantissa */
+ /* is 0 */
+ br overflw /* no false alarm, its overflow */
+
+/*
+ * False alarms are detected for 2**30 to (2**30) - 1 and -2**30 to -2**31.
+ * Only seven bits need to be looked at since an exception will not occur
+ * for the other half of the numbering system.
+ * To speed up the processing, first check to see if the exponent is 32 or
+ * greater. Since there are more mantissa bits than integer bits, rounding
+ * could cause overflow. (2**31) - 1 needs to be checked so that it does
+ * not round to 2**31, and -2**31 needs to be checked in case it rounds to
+ * -((2**31) + 1).
+ */
+checkdoub:
+ extu r10,r7,10<20> /* internal representation for double */
+ /* precision is the same IEEE 11 bits */
+ /* for real exp. = 30, the */
+ /* above instruction gives a result exp. */
+ /* that has the MSB flipped and sign */
+ /* extended like in the IMPCR */
+ cmp r11,r10,31 /* compare to 32,but exp. off by 1 */
+ /* these 2 instructions to speed up valid */
+ /* execution of valid cases */
+ bb1 ge,r11,overflw /* valid case, perform overflow routine */
+ bb1 sign,r7,checkdoubn /* source operand is negative */
+
+/*
+ * If the exponent is not 31, then the floating point number will be rounded
+ * before the conversion is done. A branch table is set up with bits 4 and 3
+ * being the rounding mode, and bits 2, 1, and 0 are the guard, round, and
+ * sticky bits.
+ */
+checkdoubp:
+ cmp r11,r10,30 /* compare to 31, but exponent off by 1 */
+ bb1 eq,r11,overflw /* no false alarm, its overflow */
+ extu r12,r8,1<22> /* get LSB for integer with exp. = 30 */
+ mak r12,r12,1<2> /* start to set up field for branch table */
+ extu r11,r8,1<21> /* get guard bit */
+ mak r11,r11,1<1> /* set up field for branch table */
+ or r12,r11,r12 /* set up field for branch table */
+ extu r11,r8,21<0> /* get bits for sticky bit */
+ bcnd eq0,r11,nostickyp /* do not set sticky */
+ set r12,r12,1<0> /* set sticky bit */
+nostickyp:
+ rot r11,r1,0<rndlo> /* shift rounding mode to 2 LSB''s */
+ mak r11,r11,2<3> /* set up field, clear other bits */
+ or r12,r11,r12 /* set up field for branch table */
+ lda r12,r0[r12] /* scale r12 */
+ or.u r12,r12,hi16(ptable) /* load pointer into table */
+ addu r12,r12,lo16(ptable)
+ jmp r12
+
+ptable:
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br paddone
+ br conversiondp
+ br conversiondp
+ br paddone
+ br paddone
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br conversiondp
+ br paddone
+ br paddone
+ br paddone
+ br conversiondp
+ br paddone
+ br paddone
+ br paddone
+
+/*
+ * Add one to the bit of the mantissa which corresponds to the LSB of an
+ * integer. If the mantissa overflows, then there is a valid integer
+ * overflow conversion; otherwise, the mantissa can be converted to the
+ * integer.
+ */
+paddone:
+ or r10,r0,r0 /* clear r10 */
+ set r10,r10,1<22> /* set LSB bit to 1 for adding */
+ addu.co r8,r8,r10 /* add the 1 obtained from rounding */
+ clr r11,r7,12<20> /* clear exponent and sign */
+ addu.ci r11,r0,r11 /* add carry */
+ bb1 20,r11,overflw /* overflow to 2**31, abort the rest */
+ br.n conversiondp /* since the exp. was 30, and the exp. */
+ /* did not round up to 31, the largest */
+ /* number that S2 could become is 2**31-1 */
+ or r7,r0,r11 /* store r11 into r7 for conversion */
+
+/*
+ * Now check for negative double precision sources. If the exponent is 30,
+ * then convert the false alarm. If the exponent is 31, then check the
+ * mantissa bits which correspond to integer bits. If any of them are a one,
+ * then there is overflow. If they are zero, then check the guard, round,
+ * and sticky bits.
+ * Round toward zero and positive will not cause a roundup, but round toward
+ * nearest and negative may, so perform those roundings. If there is no
+ * overflow, then convert and return.
+ */
+checkdoubn:
+ cmp r11,r10,29 /* compare to 30, but exp. off by 1 */
+ bb1 eq,r11,conversiondn /* false alarm if exp. = 30 */
+ extu r10,r8,11<21> /* check upper bits of lower mantissa */
+ bcnd ne0,r10,overflw /* one of the bits is a 1, so oflow */
+ extu r10,r7,20<0> /* check upper bits of upper mantissa */
+ bcnd ne0,r10,overflw /* one of the bits is a 1, so oflow */
+ bb0 rndlo,r1,possround /* rounding mode is either round near */
+ /* or round negative, which may cause */
+ /* a round */
+ br.n FPintov_return /* round positive, which will not */
+ /* cause a round */
+ set r6,r0,1<sign>
+possround:
+ extu r12,r8,1<20> /* get guard bit */
+ extu r11,r8,20<0> /* get bits for sticky bit */
+ bcnd.n eq0,r11,nostickyn /* do not set sticky */
+ mak r12,r12,1<1> /* set up field for branch table */
+ set r12,r12,1<0> /* set sticky bit */
+nostickyn:
+ bb1 rndhi,r1,negative /* rounding mode is negative */
+nearest:
+ cmp r12,r12,3 /* are both guard and sticky set */
+ bb1 eq,r12,overflw /* both guard and sticky are set, */
+ /* so signal overflow */
+ or r6,r0,r0 /* clear destination register r6 */
+ br.n FPintov_return
+ set r6,r6,1<sign> /* set the sign bit and take care of */
+ /* this special case */
+negative:
+ bcnd ne0,r12,overflw /* -2**31 will be rounded to */
+ /* -(2**31+1), so signal overflow */
+ or r6,r0,r0 /* clear destination register r6 */
+ br.n FPintov_return
+ set r6,r6,1<sign> /* set the sign bit and take care of */
+ /* this special case */
+
+ /*
+ * Since the exp. was 30, and there was no round-up, the largest
+ * number that S2 could have been was 2**31 - 1
+ */
+
+
+ /* Convert the single precision positive floating point number. */
+
+conversionsp:
+ extu r6,r8,3<29> /* extract lower bits of integer */
+ mak r6,r6,3<7> /* shift left to correct place in integer */
+ mak r10,r7,20<10> /* shift left upper bits of integer */
+ or r6,r6,r10 /* form most of integer */
+ br.n FPintov_return
+ set r6,r6,1<30> /* set hidden one */
+
+ /* Convert the single precision negative floating point number. */
+
+conversionsn:
+ bb1 eq,r11,exp31s /* use old r11 to see if exp. is 31 */
+ extu r6,r8,3<29> /* extract lower bits of mantissa */
+ mak r6,r6,3<7> /* shift left to correct place in integer */
+ mak r10,r7,20<10> /* shift left upper bits of integer */
+ or r6,r6,r10 /* form most of integer */
+ set r6,r6,1<30> /* set hidden one */
+ or.c r6,r0,r6 /* negate result */
+ br.n FPintov_return
+ addu r6,r6,1 /* add 1 to get 2''s complement */
+exp31s:
+ or r6,r0,r0 /* clear r6 */
+ br.n FPintov_return
+ set r6,r6,1<sign> /* set sign bit */
+
+ /* Convert the double precision positive floating point number. */
+
+conversiondp:
+ extu r6,r8,10<22> /* extract lower bits of integer */
+ mak r10,r7,20<10> /* shift left upper bits of integer */
+ or r6,r6,r10 /* form most of integer */
+ br.n FPintov_return
+ set r6,r6,1<30> /* set hidden one */
+
+ /*
+ * Convert the double precision negative floating point number.
+ * The number, whose exponent is 30, must be rounded before converting.
+ * Bits 4 and 3 are the rounding mode, and bits 2, 1, and 0 are the
+ * guard, round, and sticky bits for the branch table.
+ */
+
+conversiondn:
+ extu r12,r8,1<22> /* get LSB for integer with exp. = 30 */
+ mak r12,r12,1<2> /* start to set up field for branch table */
+ extu r11,r8,1<21> /* get guard bit */
+ mak r11,r11,1<1> /* set up field for branch table */
+ or r12,r11,r12 /* set up field for branch table */
+ extu r11,r8,21<0> /* get bits for sticky bit */
+ bcnd eq0,r11,nostkyn /* do not set sticky */
+ set r12,r12,1<0> /* set sticky bit */
+nostkyn:
+ rot r11,r1,0<rndlo> /* shift rounding mode to 2 LSB''s */
+ mak r11,r11,2<3> /* set up field, clear other bits */
+ or r12,r11,r12 /* set up field for branch table */
+ lda r12,r0[r12] /* scale r12 */
+ or.u r12,r12,hi16(ntable) /* load pointer into table */
+ addu r12,r12,lo16(ntable)
+ jmp r12
+
+ntable:
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br naddone
+ br nnoaddone
+ br nnoaddone
+ br naddone
+ br naddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br naddone
+ br naddone
+ br naddone
+ br nnoaddone
+ br naddone
+ br naddone
+ br naddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+ br nnoaddone
+
+/*
+ * Add one to the mantissa, and check to see if it overflows to -2**31.
+ * The conversion is done in nnoaddone.
+ */
+
+naddone:
+ or r10,r0,r0 /* clear r10 */
+ set r10,r10,1<22> /* set LSB bit to 1 for adding */
+ add.co r8,r8,r10 /* add the 1 obtained from rounding */
+ clr r7,r7,12<20> /* clear exponent and sign */
+ add.ci r7,r0,r7 /* add carry */
+ bb1 20,r7,maxneg /* rounded to -2**31,handle separately */
+ /* the exponent was originally 30 */
+nnoaddone:
+ extu r6,r8,11<22> /* extract lower bits of integer */
+ mak r10,r7,20<10> /* shift left upper bits of integer */
+ or r6,r6,r10 /* form most of integer */
+ set r6,r6,1<30> /* set hidden one */
+ or.c r6,r0,r6 /* negate integer */
+ br.n FPintov_return
+ addu r6,r6,1 /* add 1 to get 2''s complement */
+
+maxneg:
+ or r6,r0,r0 /* clear integer */
+ br.n FPintov_return
+ set r6,r6,1<sign> /* set sign bit */
+
+ /*
+ * For valid overflows, check to see if the integer overflow user
+ * handler is set. If it is set, then go to user handler, else write
+ * the correctly signed largest integer.
+ */
+
+overflw:
+ set r2,r2,1<oper>
+#ifdef HANDLER
+ bb0 oper,r3,nohandler /* do not go to user handler routine */
+ bsr _handler /* go to user handler routine */
+ br FPintov_return
+nohandler:
+#endif
+ bb0.n sign,r7,FPintov_return /* if positive then return */
+ set r6,r6,31<0> /* set result to largest positive int */
+ or.c r6,r0,r6 /* negate r6, giving largest negative */
+ /* integer */
+
+FPintov_return:
+ ld r1,r31,0 /* load return address from memory */
+ jmp r1
+
+/*
+ * Some instructions only have the S2 operations, so clear S1HI and S1LO
+ * for those instructions so that the previous contents of S1HI and S1LO
+ * do not influence this instruction.
+ */
+
+ASLOCAL(FPresoper)
+ st r1, r31, 0
+ extu r10,r9,5<11> /* extract opcode */
+#if 0
+ cmp r11,r10,FSQRTop /* compare to FSQRT */
+ bb1 eq,r11,S1clear /* clear S1 if instruction only had S2 operand */
+#endif
+ cmp r11,r10,INTop /* compare to INT */
+ bb1 eq,r11,S1clear /* clear S1 if instruction only had S2 operand */
+ cmp r11,r10,NINTop /* compare to NINT */
+ bb1 eq,r11,S1clear /* clear S1 if instruction only had S2 operand */
+ cmp r11,r10,TRNCop /* compare to TRNC */
+ bb0 eq,r11,opercheck /* check for reserved operands */
+
+ASLOCAL(S1clear)
+ or r5,r0,r0 /* clear any NaN''s, denorms, or infinities */
+ or r6,r0,r0 /* that may be left in S1HI,S1LO from a */
+ /* previous instruction */
+
+/*
+ * r12 contains the following flags:
+ * bit 9 -- s1sign
+ * bit 8 -- s2sign
+ * bit 7 -- s1nan
+ * bit 6 -- s2nan
+ * bit 5 -- s1inf
+ * bit 4 -- s2inf
+ * bit 3 -- s1zero
+ * bit 2 -- s2zero
+ * bit 1 -- s1denorm
+ * bit 0 -- s2denorm
+ */
+
+/*
+ * Using code for both single and double precision, check if S1 is either
+ * a NaN or infinity and set the appropriate flags in r12. Then check if
+ * S2 is a NaN or infinity. If it is a NaN, then branch to the NaN routine.
+ */
+
+ASLOCAL(opercheck)
+ extu r10,r5,11<20> /* internal representation for double */
+ bb1.n s1size,r9,S1NaNdoub /* S1 is double precision */
+ or r12,r0,r0 /* clear operand flag register */
+ASLOCAL(S1NaNsing)
+ xor r10,r10,0x0080 /* internal representation for single */
+ ext r10,r10,8<0> /* precision is IEEE 8 bits sign extended */
+ /* to 11 bits; for real exp. > 0, the */
+ /* above instructions gives a result exp. */
+ /* that has the MSB flipped and sign */
+ /* extended like in the IMPCR */
+ cmp r11,r10,127 /* Is exponent equal to IEEE 255 (here 127) */
+ bb1 ne,r11,S2NaN /* source 1 is not a NaN or infinity */
+ mak r10,r5,20<0> /* load r10 with upper bits of S1 mantissa */
+ extu r11,r6,3<29> /* get 3 upper bits of lower word */
+ or r11,r10,r11 /* combine any existing 1 */
+ bcnd eq0,r11,noS1NaNs /* since r11 can only hold 0 or a */
+ /* > 0 number, branch to noS1NaN when eq0 */
+ br.n S2NaN /* see if S2 has a NaN */
+ set r12,r12,1<s1nan> /* indicate that S1 has a NaN */
+ASLOCAL(noS1NaNs)
+ br.n S2NaN /* check contents of S2 */
+ set r12,r0,1<s1inf> /* indicate that S1 has an infinity */
+
+ASLOCAL(S1NaNdoub)
+ xor r10,r10,0x0400 /* precision is the same IEEE 11 bits */
+ /* The above instructions gives a result exp. */
+ /* that has the MSB flipped and sign */
+ /* extended like in the IMPCR */
+ cmp r11,r10,1023 /* Is exp. equal to IEEE 2047 (internal 1023) */
+ bb1 ne,r11,S2NaN /* source 1 is not a NaN or infinity */
+ mak r10,r5,20<0> /* load r10 with upper bits of S1 mantissa */
+ or r11,r6,r10 /* combine existing 1''s of mantissa */
+ bcnd eq0,r11,noS1NaNd /* since r11 can only hold 0 or a > 0 */
+ /* number, branch to noS1NaN when eq0 */
+ br.n S2NaN /* see if S2 has a NaN */
+ set r12,r12,1<s1nan> /* indicate that S1 has a NaN */
+ASLOCAL(noS1NaNd)
+ set r12,r0,1<s1inf> /* indicate that S1 has an infinity */
+
+ASLOCAL(S2NaN)
+ bb1.n s2size,r9,S2NaNdoub /* S1 is double precision */
+ extu r10,r7,11<20> /* internal representation for double */
+ASLOCAL(S2NaNsing)
+ xor r10,r10,0x0080 /* internal representation for single */
+ ext r10,r10,8<0> /* precision is IEEE 8 bits sign extended */
+ /* to 11 bits; for real exp. > 0, the */
+ /* above instruction gives a result exp. */
+ /* that has the MSB flipped and sign */
+ /* extended like in the IMPCR */
+ cmp r11,r10,127 /* Is exponent equal to IEEE 255 (here 127) */
+ bb1 ne,r11,inf /* source 2 is not a NaN or infinity */
+ mak r10,r7,20<0> /* load r10 with upper bits of S1 mantissa */
+ extu r11,r8,3<29> /* get 3 upper bits of lower word */
+ or r11,r10,r11 /* combine any existing 1''s */
+ bcnd eq0,r11,noS2NaNs /* since r11 can only hold 0 or a > 0 */
+ /* number, branch to noS2NaNs when eq0 */
+ br.n _ASM_LABEL(NaN) /* branch to NaN routine */
+ set r12,r12,1<s2nan> /* indicate that s2 has a NaN */
+ASLOCAL(noS2NaNs)
+ bb0 s1nan,r12, 1f /* branch to NaN if S1 is a NaN */
+ br _ASM_LABEL(NaN)
+1:
+ br.n _ASM_LABEL(infinity) /* If S1 had a NaN we would have */
+ /* already branched, and S2 does not have a */
+ /* NaN, but it does have an infinity, so */
+ /* branch to handle the finity */
+ set r12,r12,1<s2inf> /* indicate that S2 has an infinity */
+
+ASLOCAL(S2NaNdoub)
+ xor r10,r10,0x0400 /* precision is the same IEEE 11 bits */
+ /* The above instruction gives a result exp. */
+ /* that has the MSB flipped and sign */
+ /* extended like in the IMPCR */
+ cmp r11,r10,1023 /* Is exp. equal to IEEE 2047 (internal 1023) */
+ bb1 ne,r11,inf /* source 2 is not a NaN or infinity */
+ mak r10,r7,20<0> /* load r10 with upper bits of S2 mantissa */
+ or r11,r8,r10 /* combine existing 1''s of mantissa */
+ bcnd eq0,r11,noS2NaNd /* since r11 can only hold 0 or a > 0 */
+ /* number, branch to noS2NaNd when eq0 */
+ br.n _ASM_LABEL(NaN) /* branch to NaN routine */
+ set r12,r12,1<s2nan> /* indicate that s2 has a NaN */
+ASLOCAL(noS2NaNd)
+ bb0 s1nan,r12,1f /* branch to NaN if S1 is a NaN */
+ br _ASM_LABEL(NaN)
+1:
+ br.n _ASM_LABEL(infinity) /* If S1 had a NaN we would have */
+ /* already branched, and S2 does not have a */
+ /* NaN, but it does have an infinity, so */
+ /* branch to handle the finity */
+ set r12,r12,1<s2inf> /* indicate that S2 has an infinity */
+
+/*
+ * If S2 was a NaN, the routine would have already branched to NaN. If S1
+ * is a NaN, then branch to NaN. If S1 is not a NaN and S2 is infinity, then
+ * we would have already branched to infinity. If S1 is infinity, then branch.
+ * If the routine still has not branched, then branch to denorm, the only
+ * reserved operand left.
+ */
+
+ASLOCAL(inf)
+ bb0 s1nan,r12,1f /* branch if S1 has a NaN and S2 does not */
+ br _ASM_LABEL(NaN)
+1:
+ bb0 s1inf,r12,2f /* Neither S1 or S2 has a NaN, and we would */
+ /* have branched already if S2 had an */
+ /* infinity, so branch if S1 is infinity */
+ br _ASM_LABEL(infinity)
+2:
+ br _ASM_LABEL(denorm) /* branch to denorm, the only */
+ /* remaining alternative */
+
+/*
+ * First check for an underflow user handler. If there is not one, then
+ * branch to the routine to make a denormalized number. Before branching
+ * to the underflow user handler, add 192 to a single precision exponent
+ * and 1536 to a double precision exponent.
+ */
+
+ASLOCAL(FPunderflow)
+ st r1,r31,0 /* save return address */
+ set r2,r2,1<underflow>
+ set r2,r2,1<inexact>
+#ifdef HANDLER
+ bb0 efunf,r12,FPU_denorm /* jump to default procedure */
+ bb1 destsize,r12,doubleprec /* double precision destination */
+singleprec:
+ or.u r6,r0,0x0c00 /* load exponent adjust 192 */
+ br.n callundhand /* branch to call handler for user handler */
+ add r12,r6,r12 /* adjust single precision exponent */
+doubleprec:
+ or.u r6,r0,0x6000 /* load exponent adjust 1536 */
+ add r12,r6,r12 /* adjust double precision exponent */
+callundhand:
+ bsr _handler /* call handler for user handler */
+ br Ureturn
+#endif
+
+/*
+ * Now the floating point number, which has an exponent smaller than what
+ * IEEE allows, must be denormalized. Denormalization is done by calculating
+ * the difference between a denormalized exponent and an underflow exponent
+ * and shifting the mantissa by that amount. A one may need to be subtracted
+ * from the LSB if a one was added during rounding.
+ * r9 is used to contain the guard, round, sticky, and an inaccuracy bit in
+ * case some bits were shifted off the mantissa during denormalization.
+ * r9 will contain:
+ * bit 4 -- new addone if one added during rounding after denormalization
+ * bit 3 -- inaccuracy flag caused by denormalization or pre-denormalization
+ * inexactness
+ * bit 2 -- guard bit of result
+ * bit 1 -- round bit of result
+ * bit 0 -- sticky bit of result
+ */
+
+FPU_denorm:
+ bb1.n destsize,r12,Udouble /* denorm for double */
+ extu r9,r10,3<26> /* load r9 with grs */
+Usingle:
+ mak r5,r10,21<3> /* extract high 21 bits of mantissa */
+ extu r6,r11,3<29> /* extract low 3 bits of mantissa */
+ or r11,r5,r6 /* form 24 bits of mantissa */
+
+/* See if the addone bit is set and unround if it is. */
+ bb0.n 25,r10,nounrounds /* do not unround if addone bit clear */
+ extu r6,r12,12<20> /* extract signed exponent from IMPCR */
+unrounds:
+ subu r11,r11,1 /* subtract 1 from mantissa */
+
+/*
+ * If the hidden bit is cleared after subtracting the one, then the one added
+ * during the rounding must have propagated through the mantissa. The exponent
+ * will need to be decremented.
+ */
+ bb1 23,r11,nounrounds /* if hidden bit is set,then exponent */
+ /* does not need to be decremented */
+decexps:
+ sub r6,r6,1 /* decrement exponent 1 */
+ set r11,r11,1<23> /* set the hidden bit */
+
+/*
+ * For both single and double precision, there are cases where it is easier
+ * and quicker to make a special case. Examples of this are if the shift
+ * amount is only 1 or 2, or all the mantissa is shifted off, or all the
+ * mantissa is shifted off and it is still shifting, or, in the case of
+ * doubles, if the shift amount is around the boundary of MANTLO and MANTHI.
+ */
+
+nounrounds:
+ or r8,r0,lo16(0x00000f81) /* load r8 with -127 in decimal */
+ /* for lowest 12 bits */
+ sub r7,r8,r6 /* find difference between two exponents, */
+ /* this amount is the shift amount */
+ cmp r6,r7,3 /* check to see if r7 contains 3 or more */
+ bb1 ge,r6,threesing /* br to code that handles shifts of >=3 */
+ cmp r6,r7,2 /* check to see if r7 contains 2 */
+ bb1 eq,r6,twosing /* br to code that handles shifts of 2 */
+one:
+ rot r9,r9,0<1> /* rotate roundoff register once, this places */
+ /* guard in round and round in sticky */
+ bb0 31,r9,nosticky1s /* do not or round and sticky if sticky is */
+ /* 0, this lost bit will be cleared later */
+ set r9,r9,1<0> /* or round and sticky */
+nosticky1s:
+ bb0 0,r11,guardclr1s /* do not set guard bit if LSB = 0 */
+ set r9,r9,1<2> /* set guard bit */
+guardclr1s:
+ extu r11,r11,31<1> /* shift mantissa right 1 */
+ br.n round /* round result */
+ mak r9,r9,3<0> /* clear bits lost during rotation */
+
+twosing:
+ rot r9,r9,0<2> /* rotate roundff register twice, this places */
+ /* guard in sticky */
+ bb0 30,r9,nosticky2s /* do not or guard and sticky if stick is 0 */
+ /* this lost bit will be cleared later */
+ br.n noround2s /* skip or old guard and old round if old */
+ /* sticky set */
+ set r9,r9,1<0> /* or guard and sticky */
+nosticky2s:
+ bb0 31,r9,noround2s /* do not or guard and round if round is 0 */
+ /* this lost bit will be cleared later */
+ set r9,r9,1<0> /* or guard and round */
+noround2s:
+ bb0 0,r11,roundclr2s /* do not set round bit if LSB = 0 */
+ set r9,r9,1<1> /* set round bit */
+roundclr2s:
+ bb0 1,r11,guardclr2s /* do not set guard bit if LSB + 1 = 0 */
+ set r9,r9,1<2> /* set guard bit */
+guardclr2s:
+ extu r11,r11,30<2> /* shift mantissa right 2 */
+ br.n round /* round result */
+ mak r9,r9,3<0> /* clear bits lost during rotation */
+
+threesing:
+ bb1 0,r9,noguard3s /* check sticky initially */
+ /* sticky is set, forget most of the oring */
+nosticky3s:
+ bb0 1,r9,noround3s /* check round initially, do not set sticky */
+ br.n noguard3s /* forget most of the rest of oring */
+ set r9,r9,1<0> /* if round is clear,set sticky if round set */
+noround3s:
+ bb0.n 2,r9,noguard3s /* check guard initially, do not set sticky */
+ clr r9,r9,2<1> /* clear the original guard and round for when */
+ /* you get to round section */
+ set r9,r9,1<0> /* if guard is clear,set sticky if guard set */
+noguard3s:
+ cmp r6,r7,23 /* check if # of shifts is <=23 */
+ bb1 gt,r6,s24 /* branch to see if shifts = 24 */
+ sub r6,r7,2 /* get number of bits to check for sticky */
+ mak r6,r6,5<5> /* shift width into width field */
+ mak r8,r11,r6 /* mask off shifted bits -2 */
+ ff1 r8,r8 /* see if r8 has any ones */
+ bb1 5,r8,nostky23 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky23:
+ or r8,r0,34 /* start code to get new mantissa plus two */
+ /* extra bits for new round and new guard */
+ /* bits */
+ subu r8,r8,r7
+ mak r8,r8,5<5> /* shift field width into second five bits */
+ extu r6,r6,5<5> /* shift previous shifted -2 into offset field */
+ or r6,r6,r8 /* complete field */
+ extu r11,r11,r6 /* form new mantissa with two extra bits */
+
+ bb0 0,r11,nornd3s /* do not set new round bit */
+ set r9,r9,1<1> /* set new round bit */
+nornd3s:
+ bb0 1,r11,nogrd3s /* do not set new guard bit */
+ set r9,r9,1<2> /* set new guard bit */
+nogrd3s:
+ br.n round /* round mantissa */
+ extu r11,r11,30<2> /* shift off remaining two bits */
+
+s24:
+ cmp r6,r7,24 /* check to see if # of shifts is 24 */
+ bb1 gt,r6,s25 /* branch to see if shifts = 25 */
+ bb1 0,r9,nostky24 /* skip checking if old sticky set */
+ extu r8,r11,22<0> /* prepare to check bits that will be shifted */
+ /* into the sticky */
+ ff1 r8,r8 /* see if there are any 1''s */
+ bb1 5,r8,nostky24 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky24:
+ bb0 22,r11,nornd24 /* do not set new round bit */
+ set r9,r9,1<1> /* set new round bit */
+nornd24:
+ set r9,r9,1<2> /* set new guard bit,this is hidden bit */
+ br.n round /* round mantissa */
+ or r11,r0,r0 /* clear r11, all of mantissa shifted off */
+
+s25:
+ cmp r6,r7,25 /* check to see if # of shifts is 25 */
+ bb1 gt,r6,s26 /* branch to execute for shifts => 26 */
+ bb1 0,r9,nostky25 /* skip checking if old sticky set */
+ extu r8,r11,23<0> /* prepare to check bits that will be shifted */
+ /* into the sticky */
+ ff1 r8,r8 /* see if there are any 1''s */
+ bb1 5,r8,nostky25 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky25:
+ set r9,r9,1<1> /* set new round bit,this is hidden bit */
+ clr r9,r9,1<2> /* clear guard bit since nothing shifted in */
+ br.n round /* round and assemble result */
+ or r11,r0,r0 /* clear r11, all of mantissa shifted off */
+
+s26:
+ set r9,r9,1<0> /* set sticky bit,this contains hidden bit */
+ clr r9,r9,2<1> /* clear guard and round bits since nothing */
+ /* shifted in */
+ br.n round /* round and assemble result */
+ or r11,r0,r0 /* clear mantissa */
+
+Udouble:
+ mak r5,r10,21<0> /* extract upper bits of mantissa */
+ bb0.n 25,r10,nounroundd /* do not unround if addone bit clear */
+ extu r6,r12,12<20> /* extract signed exponenet from IMPCR */
+unroundd:
+ or r8,r0,1
+ subu.co r11,r11,r8 /* subtract 1 from mantissa */
+ subu.ci r5,r5,r0 /* subtract borrow from upper word */
+ bb1 20,r5,nounroundd /* if hidden bit is set, then exponent does */
+ /* not need to be decremented */
+decexpd:
+ sub r6,r6,1 /* decrement exponent 1 */
+ set r5,r5,1<20> /* set the hidden bit */
+
+nounroundd:
+ or r8,r0,lo16(0x00000c01) /* load r8 with -1023 in decimal */
+ /* for lowest 12 bits */
+ sub r7,r8,r6 /* find difference between two exponents, */
+ /* this amount is the shift amount */
+ cmp r6,r7,3 /* check to see if r7 contains 3 or more */
+ bb1 ge,r6,threedoub /* br to code that handles shifts of >=3 */
+ cmp r6,r7,2 /* check to see if r7 contains 2 */
+ bb1 eq,r6,twodoub /* br to code that handles shifts of 2 */
+
+onedoub:
+ rot r9,r9,0<1> /* rotate roundoff register once, this places */
+ /* guard in round and round in sticky */
+ bb0 31,r9,nosticky1d/* do not or round and sticky if sticky is 0 */
+ /* this lost bit will be cleared later */
+ set r9,r9,1<0> /* or old round and old sticky into new sticky */
+nosticky1d:
+ bb0 0,r11,guardclr1d /* do not set new guard bit if old LSB = 0 */
+ set r9,r9,1<2> /* set new guard bit */
+guardclr1d:
+ extu r11,r11,31<1> /* shift lower mantissa over 1 */
+ mak r6,r5,1<31> /* shift off low bit of high mantissa */
+ or r11,r6,r11 /* load high bit onto lower mantissa */
+ extu r5,r5,20<1> /* shift right once upper 20 bits of mantissa */
+ br.n round /* round mantissa and assemble result */
+ mak r9,r9,3<0> /* clear bits lost during rotation */
+
+twodoub:
+ rot r9,r9,0<2> /* rotate roundoff register twice, this places */
+ /* old guard into sticky */
+ bb0 30,r9,nosticky2d /* do not or old guard and old sticky if */
+ /* old sticky is 0 */
+ br.n noround2d /* skip or of old guard and old round if old */
+ /* sticky set */
+ set r9,r9,1<0> /* or old guard and old sticky into new sticky */
+nosticky2d:
+ bb0 31,r9,noround2d /* do not or old guard and old round if */
+ /* old round is 0 */
+ set r9,r9,1<0> /* or old guard and old round into new sticky */
+noround2d:
+ bb0 0,r11,roundclr2d /* do not set round bit if old LSB = 0 */
+ set r9,r9,1<1> /* set new round bit */
+roundclr2d:
+ bb0 1,r11,guardclr2d /* do not set guard bit if old LSB + 1 = 0 */
+ set r9,r9,1<2> /* set new guard bit */
+guardclr2d:
+ extu r11,r11,30<2> /* shift lower mantissa over 2 */
+ mak r6,r5,2<30> /* shift off low bits of high mantissa */
+ or r11,r6,r11 /* load high bit onto lower mantissa */
+ extu r5,r5,19<2> /* shift right twice upper 19 bits of mantissa */
+ br.n round /* round mantissa and assemble result */
+ mak r9,r9,3<0> /* clear bits lost during rotation */
+
+threedoub:
+ bb1 0,r9,noguard3d /* checky sticky initially */
+ /* sticky is set, forget most of rest of oring */
+nosticky3d:
+ bb0 1,r9,noround3d /* check old round, do not set sticky if */
+ /* old round is clear, set otherwise */
+ br.n noguard3d /* sticky is set, forget most of rest of oring */
+ set r9,r9,1<0> /* set sticky if old round is set */
+noround3d:
+ bb0 2,r9,noguard3d /* check old guard, do not set sticky if 0 */
+ clr r9,r9,2<1> /* clear the original guard and round for when */
+ /* you get to round section */
+ set r9,r9,1<0> /* set sticky if old guard is set */
+noguard3d:
+ cmp r6,r7,32 /* do I need to work with a 1 or 2 word mant. */
+ /* when forming sticky, round and guard */
+ bb1 gt,r6,d33 /* jump to code that handles 2 word mantissas */
+ sub r6,r7,2 /* get number of bits to check for sticky */
+ mak r6,r6,5<5> /* shift width into width field */
+ mak r8,r11,r6 /* mask off shifted bits -2 */
+ ff1 r8,r8 /* see if r8 has any ones */
+ bb1 5,r8,nostky32 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky32:
+ or r8,r0,34 /* start code to get new mantissa plus two */
+ /* extra bits for new round and new guard bits, */
+ /* the upper word bits will be shifted after */
+ /* the round and guard bits are handled */
+ subu r8,r8,r7
+ mak r8,r8,5<5> /* shift field width into second five bits */
+ extu r6,r6,5<5> /* shift previous shifted -2 into offset field */
+ or r6,r6,r8 /* complete bit field */
+ extu r11,r11,r6 /* partially form new low mantissa with 2 more */
+ /* bits */
+ bb0 0,r11,nornd32d /* do not set new round bit */
+ set r9,r9,1<1> /* set new round bit */
+nornd32d:
+ bb0 1,r11,nogrd32d /* do not set new guard bit */
+ set r9,r9,1<2> /* set new guard bit */
+nogrd32d:
+ extu r11,r11,30<2> /* shift off remaining two bits */
+ mak r6,r7,5<5> /* shift field width into second 5 bits, if the */
+ /* width is 32, then these bits will be 0 */
+ or r8,r0,32 /* load word length into r8 */
+ sub r8,r8,r7 /* form offset for high bits moved to low word */
+ or r6,r6,r8 /* form complete bit field */
+ mak r6,r5,r6 /* get shifted bits of high word */
+ or r11,r6,r11 /* form new low word of mantissa */
+ bcnd ne0,r8,regular33 /* do not adjust for special case of r8 */
+ br.n round /* containing zeros, which would cause */
+ or r5,r0,r0 /* all of the bits to be extracted under */
+ /* the regular method */
+regular33:
+ mak r6,r7,5<0> /* place lower 5 bits of shift into r6 */
+ mak r8,r8,5<5> /* shift r8 into width field */
+ or r6,r6,r8 /* form field for shifting of upper bits */
+ br.n round /* round and assemble result */
+ extu r5,r5,r6 /* form new high word mantissa */
+
+d33:
+ cmp r6,r7,33 /* is the number of bits to be shifted is 33? */
+ bb1 gt,r6,d34 /* check to see if # of bits is 34 */
+ bb1 0,r9,nostky33 /* skip checking if old sticky set */
+ mak r6,r11,31<0> /* check bits that will be shifted into sticky */
+ ff1 r8,r8 /* check for ones */
+ bb1 5,r8,nostky33 /* do not set sticky if there are no ones */
+ set r9,r9,1<0> /* set new sticky bit */
+nostky33:
+ bb0 31,r11,nornd33 /* do not set round if bit is not a 1 */
+ set r9,r9,1<1> /* set new round bit */
+nornd33:
+ bb0 0,r5,nogrd33 /* do not set guard bit if bit is not a 1 */
+ set r9,r9,1<2> /* set new guard bit */
+nogrd33:
+ extu r11,r5,31<1> /* shift high bits into low word */
+ br.n round /* round and assemble result */
+ or r5,r0,r0 /* clear high word */
+
+d34:
+ cmp r6,r7,34 /* is the number of bits to be shifted 34? */
+ bb1 gt,r6,d35 /* check to see if # of bits is >= 35 */
+ bb1 0,r9,nostky34 /* skip checking if old sticky set */
+ ff1 r8,r11 /* check bits that will be shifted into sticky */
+ bb1 5,r8,nostky34 /* do not set sticky if there are no ones */
+ set r9,r9,1<0> /* set new sticky bit */
+nostky34:
+ bb0 0,r5,nornd34 /* do not set round if bit is not a 1 */
+ set r9,r9,1<1> /* set new round bit */
+nornd34:
+ bb0 1,r5,nogrd34 /* do not set guard bit if bit is not a 1 */
+ set r9,r9,1<2> /* set new guard bit */
+nogrd34:
+ extu r11,r5,30<2> /* shift high bits into low word */
+ br.n round /* round and assemble result */
+ or r5,r0,r0 /* clear high word */
+
+d35:
+ cmp r6,r7,52 /* see if # of shifts is 35 <= X <= 52 */
+ bb1 gt,r6,d53 /* check to see if # of shifts is 52 */
+ bb1.n 0,r9,nostky35 /* skip checking if old sticky set */
+ sub r7,r7,34 /* subtract 32 from # of shifts so that opera- */
+ /* tions can be done on the upper word, and */
+ /* then subtract two more checking guard and */
+ /* sticky bits */
+ ff1 r8,r11 /* see if lower word has a bit for sticky */
+ bb1 5,r8,stkycheck35 /* see if upper word has any sticky bits */
+ br.n nostky35 /* quit checking for sticky */
+ set r9,r9,1<0> /* set sticky bit */
+stkycheck35:
+ mak r6,r7,5<5> /* place width into width field */
+ mak r8,r5,r6 /* mask off shifted bits - 2 */
+ ff1 r8,r8 /* see if r8 has any ones */
+ bb1 5,r8,nostky35 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky35:
+ or r8,r0,32 /* look at what does not get shifted off plus */
+ /* round and sticky, remember that the r7 value */
+ /* was adjusted so that it did not include */
+ /* new round or new sticky in shifted off bits */
+ subu r8,r8,r7 /* complement width */
+ mak r8,r8,5<5> /* shift width into width field */
+ or r8,r7,r8 /* add offset field */
+ extu r11,r5,r8 /* extract upper bits into low word */
+ bb0 0,r11,nornd35 /* do not set new round bit */
+ set r9,r9,1<1> /* set new round bit */
+nornd35:
+ bb0 1,r11,nogrd35 /* do not set new guard bit */
+ set r9,r9,1<2> /* set new guard bit */
+nogrd35:
+ extu r11,r11,30<2> /* shift off remaining guard and round bits */
+ br.n round /* round and assemble result */
+ or r5,r0,r0 /* clear high word */
+
+d53:
+ cmp r6,r7,53 /* check to see if # of shifts is 53 */
+ bb1 gt,r6,d54 /* branch to see if shifts = 54 */
+ bb1 0,r9,nostky53 /* skip checking if old sticky set */
+ ff1 r8,r11 /* see if lower word has a bit for sticky */
+ bb1 5,r8,stkycheck53 /* see if upper word has any sticky bits */
+ br.n nostky53 /* quit checking for sticky */
+ set r9,r9,1<0> /* set sticky bit */
+stkycheck53:
+ mak r6,r5,19<0> /* check bits that are shifted into sticky */
+ ff1 r8,r6 /* see if r6 has any ones */
+ bb1 5,r8,nostky53 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky53:
+ bb0 19,r5,nornd53 /* do not set new round bit */
+ set r9,r9,1<1> /* set new round bit */
+nornd53:
+ set r9,r9,1<2> /* set new guard bit,this is hidden bit */
+ or r5,r0,r0 /* clear high word */
+ br.n round /* round and assemble result */
+ or r11,r0,r0 /* clear low word */
+
+d54:
+ cmp r6,r7,54 /* check to see if # of shifts is 54 */
+ bb1 gt,r6,d55 /* branch to execute for shifts =>55 */
+ bb1 0,r9,nostky54 /* skip checking if old sticky set */
+ ff1 r8,r11 /* see if lower word has a bit for sticky */
+ bb1 5,r8,stkycheck54 /* see if upper word has any sticky bits */
+ br.n nostky54 /* quit checking for sticky */
+ set r9,r9,1<0> /* set sticky bit */
+stkycheck54:
+ mak r6,r5,20<0> /* check bits that are shifted into sticky */
+ ff1 r8,r6 /* see if r6 has any ones */
+ bb1 5,r8,nostky54 /* do not set sticky if no ones found */
+ set r9,r9,1<0> /* set sticky bit */
+nostky54:
+ set r9,r9,1<1> /* set new round bit,this is hidden bit */
+ clr r9,r9,1<2> /* clear guard bit since nothing shifted in */
+ or r5,r0,r0 /* clear high word */
+ br.n round /* round and assemble result */
+ or r11,r0,r0 /* clear low word */
+
+d55:
+ set r9,r9,1<0> /* set new sticky bit,this contains hidden bit */
+ clr r9,r9,2<1> /* clear guard and round bits since nothing */
+ /* shifted in */
+ or r5,r0,r0 /* clear high word */
+ or r11,r0,r0 /* clear low word */
+
+
+/* The first item that the rounding code does is see if either guard, round, */
+/* or sticky is set. If all are clear, then there is no denormalization loss */
+/* and no need to round, then branch to assemble answer. */
+/* For rounding, a branch table is set up. The left two most bits are the */
+/* rounding mode. The third bit is either the LSB of the mantissa or the */
+/* sign bit, depending on the rounding mode. The three LSB''s are the guard, */
+/* round and sticky bits. */
+
+round:
+ ff1 r8,r9 /* see if there is denormalization loss */
+ bb1 5,r8,assemble /* no denormalization loss or inexactness */
+ extu r6,r10,2<modelo> /* extract rounding mode */
+ bb1.n modehi,r10,signext /* use sign bit instead of LSB */
+ mak r6,r6,2<4> /* shift over rounding mode */
+ extu r7,r11,1<0> /* extract LSB */
+ br.n grs /* skip sign extraction */
+ mak r7,r7,1<3> /* shift over LSB */
+signext:
+ extu r7,r10,1<31> /* extract sign bit */
+ mak r7,r7,1<3> /* shift sign bit over */
+grs:
+ or r6,r6,r7
+ or r6,r6,r9 /* or in guard, round, and sticky */
+ or.u r1,r0,hi16(roundtable) /* form address of branch table */
+ or r1,r1,lo16(roundtable)
+ lda r6,r1[r6] /* scale offset into branch table */
+ jmp.n r6 /* jump to branch table */
+ set r9,r9,1<3> /* set inexact flag in r9 */
+
+roundtable:
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br addone
+ br addone
+ br addone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br addone
+ br addone
+ br addone
+ br addone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br addone
+ br addone
+ br addone
+ br addone
+ br addone
+ br addone
+ br addone
+ br noaddone
+ br addone
+ br addone
+ br addone
+ br addone
+ br addone
+ br addone
+ br addone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+ br noaddone
+
+/* Round by adding a one to the LSB of the mantissa. */
+addone:
+ or r6,r0,1 /* load a 1 into r6 so that add.co can be used */
+ add.co r11,r11,r6 /* add a one to the lower word of result */
+ bb0.n destsize,r12,noaddone /* single result,forget carry */
+ set r9,r9,1<4> /* indicate that a 1 has been added */
+ add.ci r5,r5,r0 /* propagate carry into high word */
+
+
+/* Branch to inexact user handler if there is one. */
+
+noaddone:
+ set r2,r2,1<inexact>
+ set r2,r2,1<underflow>
+#ifdef HANDLER
+ bb1 efinx,r12,modformdef /* branch to modify form for user */
+ /* handler */
+#endif
+
+
+/* Assemble the result of the denormalization routine for writeback to the */
+/* destination register. The exponent of a denormalized number is zero, */
+/* so simply assemble the sign and the new mantissa. */
+
+assemble:
+ bb1 destsize,r12,doubassem /* assemble double result */
+ bb0 sign,r10,exassems /* exit assemble if sign is zero */
+ set r11,r11,1<sign> /* make result negative */
+exassems:
+ br Ureturn
+
+doubassem:
+ bb0.n sign,r10,signclr /* do not set sign in r10 */
+ or r10,r5,r0 /* load high word from r5 into r10 */
+ set r10,r10,1<sign> /* high word with sign loaded */
+signclr:
+ br Ureturn
+
+
+/* modfordef modifies the result of denormalization to the input format of */
+/* the inexact user handler. This input format is the same format that */
+/* MANTHI, MANTLO, and IMPCR were initially loaded with. */
+
+#ifdef HANDLER
+modformdef:
+ clr r12,r12,12<20> /* clear result exponent,IMPCR complete */
+ clr r10,r10,4<25> /* clear old guard,round,sticky,and addone */
+ mak r5,r9,3<26> /* make grs field */
+ bb0.n 4,r9,newaddone /* do not set new addone in MANTHI */
+ or r10,r5,r10 /* or in new grs field */
+ set r10,r10,1<25> /* set new addone */
+newaddone:
+ bb1.n destsize,r12,moddefd /* branch to handle double precision */
+ clr r10,r10,21<0> /* clear upper bits of old mantissa */
+moddefs:
+ extu r5,r11,20<3> /* extract upper bits */
+ or r10,r5,r10 /* MANTHI complete */
+ bsr.n _handler /* execute user handler for inexact */
+ rot r11,r11,0<3> /* MANTLO complete */
+ br Ureturn
+moddefd:
+ bsr.n _handler /* execute user handler for inexact */
+ or r10,r5,r10 /* MANTHI complete,r5 should be set to OR */
+#endif
+
+/* Return to fpui. */
+
+Ureturn:
+ ld r1,r31,0 /* load return address */
+ jmp r1
+
+/*
+ * FPoverflow
+ */
+/* If the overflow user handler bit is not set, then the inexact bit in the */
+/* FPSR is set, and the inexact user handler bit is checked. If it is set, */
+/* then the inexact user handler is executed, else the default routine for */
+/* overflow is executed. */
+
+ASLOCAL(FPoverflow)
+ st r1,r31,0 /* save return address */
+ set r2,r2,1<overflow>
+ set r2,r2,1<inexact>
+#ifdef HANDLER
+ bb1 efovf,r12,hand /* go to user handler if bit set for overflow */
+ bb0 efinx,r12,nohandler/* if userhandler for inexact not set,then */
+ /* round result */
+ br callhandler /* branch to user handler for inexact */
+
+/* Before the overflow user handler is executed, the exponent is modified */
+/* by subtracting 192 for single precision and 1536 for double precision. */
+
+hand:
+ bb1 10,r12,doubleprec /* double precision result */
+singleprec:
+ or.u r5,r0,0x0c00 /* load exponent adjust */
+ br.n callhandler /* prepare to call user handler */
+ subu r12,r12,r5 /* adjust single precision exponent */
+doubleprec:
+ or.u r5,r0,0x6000 /* load exponent adjust */
+ subu r12,r12,r5 /* adjust double precision exponent */
+callhandler:
+ bsr _handler /* branch to common handler routine */
+ br return
+#endif
+
+/* Determine which rounding mode to use for the default procedure. */
+
+nohandler:
+ bb1 modehi,r10,signed /* mode is either round toward pos. or neg. */
+ bb0 modelo,r10,OFnearest /* rounding mode is round nearest */
+ br OFzero /* rounding mode is round zero */
+signed:
+ bb0 modelo,r10,OFnegative /* rounding mode is round negative */
+ br positive /* rounding mode is round positive */
+
+
+/* In the round toward nearest mode, positive values are rounded to */
+/* positive infinity and negative values are loaded toward negative infinity. */
+/* The value for single or double precision is loaded from a data table. */
+
+OFnearest:
+ bb1.n destsize,r12,neardouble /* branch to neardouble of */
+ /* double result */
+ mask.u r5,r10,0x8000 /* mask off sign bit from MANTHI */
+ or.u r11,r0,hi16(0x7f800000) /* load single infinity constant */
+ or r11,r11,lo16(0x7f800000)
+ br.n return /* return with result */
+ or r11,r5,r11 /* adjust sign */
+neardouble:
+ or r11,r0,r0 /* load lower word of infinity */
+ or.u r10,r0,hi16(0x7ff00000) /* load upper word of infinity */
+ or r10,r10,lo16(0x7ff00000)
+ br.n return /* return with result */
+ or r10,r5,r10 /* adjust sign */
+
+
+/* In the round toward zero mode, positive values are rounded to the largest */
+/* postive finite number and negative values are rounded toward the largest */
+/* negative finite number. */
+/* The value for single or double precision is loaded from a data table. */
+
+OFzero:
+ bb1.n destsize,r12,zerodouble /* branch to zerodouble of */
+ /* double result */
+ mask.u r5,r10,0x8000 /* mask off sign bit from MANTHI */
+ or.u r11,r0,hi16(0x7f7fffff) /* load single finite number constant */
+ or r11,r11,lo16(0x7f7fffff)
+ br.n return /* return with result */
+ or r11,r5,r11 /* adjust sign */
+zerodouble:
+ set r11,r0,0<0> /* load lower word of finite number */
+ or.u r10,r0,hi16(0x7fefffff) /* load upper word of finite number */
+ or r10,r10,lo16(0x7fefffff)
+ br.n return /* return with result */
+ or r10,r5,r10 /* adjust sign */
+
+
+/* In the round toward positve mode, positive values are rounded to */
+/* postive infinity and negative values are loaded toward the largest */
+/* negative finite number. */
+/* The value for single or double precision is loaded from a data table. */
+
+positive:
+ bb1 destsize,r12,posdouble /* branch to section for double result */
+possingle:
+ bb1 sign,r10,possingleneg /* branch to section for negatives */
+possinglepos:
+ or.u r11,r0,hi16(0x7f800000) /* load single infinity constant */
+ br.n return /* return with result */
+ or r11,r11,lo16(0x7f800000)
+possingleneg:
+ or.u r11,r0,hi16(0x7f7fffff) /* load single finite number constant */
+ or r11,r11,lo16(0x7f7fffff)
+ br.n return /* return with result */
+ set r11,r11,1<sign> /* set sign for negative */
+posdouble:
+ bb1 sign,r10,posdoubleneg /* branch to negative double results */
+posdoublepos:
+ or r11,r0,r0 /* load lower word of double infinity */
+ or.u r10,r0,hi16(0x7ff00000) /* load upper word of infinity */
+ br.n return /* return with result */
+ or r10,r10,lo16(0x7ff00000)
+posdoubleneg:
+ set r11,r0,0<0> /* load lower word of finite number */
+ or.u r10,r0,hi16(0x7fefffff) /* load upper word of finite number */
+ or r10,r10,lo16(0x7fefffff)
+ br.n return /* return with result */
+ set r10,r10,1<sign> /* set sign for negative */
+
+
+/* In the round toward negative mode, positive values are rounded to the largest */
+/* postive finite number and negative values are rounded to negative infinity. */
+/* The value for single or double precision is loaded from a data table. */
+
+OFnegative:
+ bb1 destsize,r12,negdouble /* branch to section for double result */
+negsingle:
+ bb1 sign,r10,negsingleneg /* branch to section for negatives */
+negsinglepos:
+ or.u r11,r0,hi16(0x7f7fffff) /* load single finite number constant */
+ br.n return /* return with result */
+ or r11,r11,lo16(0x7f7fffff)
+negsingleneg:
+ or.u r11,r0,hi16(0x7f800000) /* load single infinity constant */
+ or r11,r11,lo16(0x7f800000)
+ br.n return /* return with result */
+ set r11,r11,1<sign> /* set sign for negative */
+negdouble:
+ bb1 sign,r10,negdoubleneg /* branch to negative double results */
+negdoublepos:
+ set r11,r0,0<0> /* load lower word of finite number */
+ or.u r10,r0,hi16(0x7fefffff) /* load upper word of finite number */
+ br.n return /* return with result */
+ or r10,r10,lo16(0x7fefffff)
+negdoubleneg:
+ or r11,r0,r0 /* load lower word of double infinity */
+ or.u r10,r0,hi16(0x7ff00000) /* load upper word of infinity */
+ or r10,r10,lo16(0x7ff00000)
+ set r10,r10,1<sign> /* set sign for negative */
+
+return:
+ ld r1,r31,0 /* ld return address */
+ jmp r1
+
+ data
+
+
+/* If either S1 or S2 is a signalling NaN, then set the invalid operation */
+/* bit of the FPSR. If the invalid operation user handler flag is set and */
+/* then NaN is signalling, then branch to the handler routine to go to the */
+/* user handler. */
+/* If S1 is the only NaN or one of two NaN''s, then write */
+/* a quiet S1 to the result. A signalling NaN must be made quiet before */
+/* it can be written, but a signalling S2 is not modified in this routine */
+/* if S1 is a NaN. */
+ text
+ASLOCAL(NaN)
+ bb0.n s1nan,r12,S2sigcheck /* S1 is not a NaN */
+ st r1,r31,0 /* save return address */
+ bb1 sigbit,r5,S2sigcheck /* S1 is not a signaling NaN */
+ set r2,r2,1<oper>
+#ifdef HANDLER
+ bb0 oper,r3,S1nohandler /* branch if no user handler */
+ bsr _handler /* branch to handler */
+ br FPnan_return
+ASLOCAL(S1nohandler)
+#endif
+ br.n S1write /* FPSR bit already set, S1 is made quiet, */
+ /* and since we always write S1 if it is a */
+ /* NaN, write S1 and skip rest of routine */
+ set r5,r5,1<sigbit> /* make S1 a quiet NaN */
+
+ASLOCAL(S2sigcheck)
+ bb0 s2nan,r12,S1write /* S2 is not a NaN */
+ bb1 sigbit,r7,S1write /* S2 is not a signaling NaN */
+ set r2,r2,1<oper>
+#ifdef HANDLER
+ bb0 oper,r3,S2nohandler /* branch if no user handler */
+ bsr _handler /* branch to handler */
+ br FPnan_return
+#endif
+
+ASLOCAL(S2nohandler)
+ set r7,r7,1<sigbit> /* make S2 a quiet NaN */
+
+
+/* Write a single or double precision quiet NaN unless the opeation is FCMP. */
+/* If the operation is FCMP, then set the not comparable bit in the result. */
+
+ASLOCAL(S1write)
+ bb0 s1nan,r12,S2write /* do not write S1 if it is not a NaN */
+ extu r10,r9,5<11> /* extract opcode */
+ cmp r11,r10,FCMPop /* compare to FCMP */
+ bb1 ne,r11,S1noFCMP /* operation is not FCMP */
+ set r6,r0,1<nc> /* set the not comparable bit */
+ br.n FPnan_return
+ set r6,r6,1<ne> /* set the not equal bit */
+ASLOCAL(S1noFCMP)
+ bb1.n dsize,r9,wrdoubS1 /* double destination */
+ set r5,r5,11<20> /* set all exponent bits to 1 */
+/* The single result will be formed the same way whether S1 is a single or double */
+ASLOCAL(wrsingS1)
+ mak r10,r5,28<3> /* wipe out extra exponent bits */
+ extu r11,r6,3<29> /* get lower three bits of mantissa */
+ or r10,r10,r11 /* combine all of result except sign */
+ clr r6,r5,31<0> /* clear all but sign */
+ br.n FPnan_return
+ or r6,r6,r10 /* form result */
+
+ASLOCAL(wrdoubS1)
+ set r6,r6,29<0> /* set extra bits of lower word */
+ br FPnan_return /* no modification necessary for writing */
+ /* double to double, so return */
+
+ASLOCAL(S2write)
+ extu r10,r9,5<11> /* extract opcode */
+ cmp r11,r10,FCMPop /* compare to FCMP */
+ bb1.n ne,r11,S2noFCMP /* operation is not FCMP */
+ set r7,r7,11<20> /* set all exponent bits to 1 */
+ set r6,r0,1<nc> /* set the not comparable bit */
+ br.n FPnan_return
+ set r6,r6,1<ne> /* set the not equal bit */
+ASLOCAL(S2noFCMP)
+ bb1.n dsize,r9,wrdoubS2 /* double destination */
+ set r5,r5,11<20> /* set all exponent bits to 1 */
+/* The single result will be formed the same way whether S1 is a single or double */
+ASLOCAL(wrsingS2)
+ mak r10,r7,28<3> /* wipe out extra exponent bits */
+ extu r11,r8,3<29> /* get lower three bits of mantissa */
+ or r10,r10,r11 /* combine all of result except sign */
+ clr r6,r7,31<0> /* clear all but sign */
+ br.n FPnan_return
+ or r6,r6,r10 /* form result */
+
+ASLOCAL(wrdoubS2)
+ set r6,r8,29<0> /* set extra bits of lower word */
+
+/* Return from this subroutine with the result. */
+
+ASLOCAL(FPnan_return)
+ /* no modification necessary for writing */
+ /* double to double, so return */
+ ld r1,r31, 0 /* retrieve return address */
+ jmp r1
+
+ data
+
+/*
+ * infinity
+ */
+
+/* Extract the opcode, compare to a constant, and branch to the code */
+/* for the instruction. */
+
+ASLOCAL(infinity)
+ extu r10,r9,5<11> /* extract opcode */
+ cmp r11,r10,FADDop /* compare to FADD */
+ bb1.n eq,r11,FADD /* operation is FADD */
+ st r1,r31,0 /* save return address */
+ cmp r11,r10,FSUBop /* compare to FSUB */
+ bb1 eq,r11,FSUB /* operation is FSUB */
+ cmp r11,r10,FCMPop /* compare to FCMP */
+ bb1 eq,r11,FCMP /* operation is FCMP */
+ cmp r11,r10,FMULop /* compare to FMUL */
+ bb1 eq,r11,FMUL /* operation is FMUL */
+ cmp r11,r10,FDIVop /* compare to FDIV */
+ bb1 eq,r11,FDIV /* operation is FDIV */
+#if 0
+ cmp r11,r10,FSQRTop /* compare to FSQRT */
+ bb1 eq,r11,FSQRT /* operation is FSQRT */
+#endif
+ cmp r11,r10,INTop /* compare to INT */
+ bb1 eq,r11,FP_inf_overflw /* operation is INT */
+ cmp r11,r10,NINTop /* compare to NINT */
+ bb1 eq,r11,FP_inf_overflw /* operation is NINT */
+ cmp r11,r10,TRNCop /* compare to TRNC */
+ bb1 eq,r11,FP_inf_overflw /* operation is TRNC */
+
+
+/* Adding infinities of opposite signs will cause an exception, */
+/* but all other operands will result in a correctly signed infinity. */
+
+FADD:
+ bb0 s1inf,r12,addS2write /* branch if S1 not infinity */
+ bb0 s2inf,r12,addS1write /* S2 is not inf., so branch to write S1 */
+ bb1 sign,r5,addS1neg /* handle case of S1 negative */
+addS1pos:
+ bb1 sign,r7,excpt /* adding infinities of different */
+ /* signs causes an exception */
+ br poswrinf /* branch to write positive infinity */
+addS1neg:
+ bb0 sign,r7,excpt /* adding infinities of different */
+ /* signs causes an exception */
+ br negwrinf /* branch to write negative infinity */
+addS1write:
+ bb0 sign,r5,poswrinf /* branch to write positive infinity */
+ br negwrinf /* branch to write negative infinity */
+addS2write:
+ bb0 sign,r7,poswrinf /* branch to write positive infinity */
+ br negwrinf /* branch to write negative infinity */
+
+
+/* Subtracting infinities of the same sign will cause an exception, */
+/* but all other operands will result in a correctly signed infinity. */
+
+FSUB:
+ bb0 s1inf,r12,subS2write /* branch if S1 not infinity */
+ bb0 s2inf,r12,subS1write /* S2 is not inf., so branch to write S1 */
+ bb1 sign,r5,subS1neg /* handle case of S1 negative */
+subS1pos:
+ bb0 sign,r7,excpt /* subtracting infinities of the same */
+ /* sign causes an exception */
+ br poswrinf /* branch to write positive infinity */
+subS1neg:
+ bb1 sign,r7,excpt /* subtracting infinities of the same */
+ /* sign causes an exception */
+ br negwrinf /* branch to write negative infinity */
+subS1write:
+ bb0 sign,r5,poswrinf /* branch to write positive infinity */
+ br negwrinf /* branch to write negative infinity */
+subS2write:
+ bb1 sign,r7,poswrinf /* branch to write positive infinity */
+ br negwrinf /* branch to write negative infinity */
+
+
+/* Compare the operands, at least one of which is infinity, and set the */
+/* correct bits in the destination register. */
+
+FCMP:
+ bb0.n s1inf,r12,FCMPS1f /* branch for finite S1 */
+ set r4,r0,1<cp> /* since neither S1 or S2 is a NaN, */
+ /* set cp */
+FCMPS1i:
+ bb1 sign,r5,FCMPS1ni /* branch to negative S1i */
+FCMPS1pi:
+ bb0 s2inf,r12,FCMPS1piS2f /* branch to finite S2 with S1pi */
+FCMPS1piS2i:
+ bb1 sign,r7,FCMPS1piS2ni /* branch to negative S2i with S1pi */
+FCMPS1piS2pi:
+ set r4,r4,1<eq> /* set eq bit */
+ set r4,r4,1<le> /* set le bit */
+ set r4,r4,1<ge> /* set ge bit */
+ set r4,r4,1<ib> /* set ib bit */
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1piS2ni:
+ set r4,r4,1<ne> /* set ne bit */
+ set r4,r4,1<gt> /* set gt bit */
+ br.n move
+ set r4,r4,1<ge> /* set ge bit */
+FCMPS1piS2f:
+ set r4,r4,1<ne> /* set ne bit */
+ set r4,r4,1<gt> /* set gt bit */
+ bsr.n _ASM_LABEL(zero) /* see if any of the operands are zero */
+ set r4,r4,1<ge> /* set ge bit */
+ bb0 s2zero,r12,FCMPS1piS2nz /* check for negative if s2 not zero */
+ set r4,r4,1<ou> /* set ou bit */
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1piS2nz:
+ bb1 sign,r7,move /* return if s2 is negative */
+FCMPS1piS2pf:
+ set r4,r4,1<ou> /* set ou bit */
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1ni:
+ bb0 s2inf,r12,FCMPS1niS2f /* branch to finite S2 with S1ni */
+FCMPS1niS2i:
+ bb1 sign,r7,FCMPS1niS2ni /* branch to negative S2i with S1ni */
+FCMPS1niS2pi:
+ set r4,r4,1<ne> /* set eq bit */
+ set r4,r4,1<le> /* set le bit */
+ set r4,r4,1<lt> /* set lt bit */
+ set r4,r4,1<ou> /* set ou bit */
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1niS2ni:
+ set r4,r4,1<eq> /* set eq bit */
+ set r4,r4,1<le> /* set le bit */
+ br.n move
+ set r4,r4,1<ge> /* set ge bit */
+FCMPS1niS2f:
+ set r4,r4,1<ne> /* set eq bit */
+ set r4,r4,1<le> /* set le bit */
+ bsr.n _ASM_LABEL(zero) /* see if any of the operands are zero */
+ set r4,r4,1<lt> /* set lt bit */
+ bb0 s2zero,r12,FCMPS1niS2nz /* branch if s2 is not zero */
+ set r4,r4,1<ou> /* set ou bit */
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1niS2nz:
+ bb1 sign,r7,move /* return if s2 is negative */
+ set r4,r4,1<ou> /* set ou bit */
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1f:
+ bb1 sign,r5,FCMPS1nf /* branch to negative S1f */
+FCMPS1pf:
+ bb1.n sign,r7,FCMPS1pfS2ni /* branch to negative S2i with S1pf */
+ set r4,r4,1<ne> /* set ne bit */
+FCMPS1pfS2pi:
+ set r4,r4,1<le> /* set le bit */
+ set r4,r4,1<lt> /* set lt bit */
+ bsr.n _ASM_LABEL(zero)
+ set r4,r4,1<ib> /* set ib bit */
+ bb0 s1zero,r12,FCMPS1pfS2pinozero
+FCMPS1pfS2pizero:
+ br.n move
+ set r4,r4,1<ob> /* set ob bit */
+FCMPS1pfS2pinozero:
+ br.n move
+ set r4,r4,1<in> /* set in bit */
+FCMPS1pfS2ni:
+ set r4,r4,1<gt> /* set gt bit */
+ br.n move
+ set r4,r4,1<ge> /* set ge bit */
+FCMPS1nf:
+ bb1.n sign,r7,FCMPS1nfS2ni /* branch to negative S2i with S1nf */
+ set r4,r4,1<ne> /* set ne bit */
+ set r4,r4,1<le> /* set gt bit */
+ set r4,r4,1<lt> /* set ge bit */
+ bsr.n _ASM_LABEL(zero) /* see which of the operands are zero */
+ set r4,r4,1<ob> /* set ob bit */
+ bb0 s1zero,r12,FCMPS1nfS2pinozero /* no ls and lo */
+FCMPS1nfS2pizero:
+ br.n move
+ set r4,r4,1<ib> /* set ib bit */
+FCMPS1nfS2pinozero:
+ br.n move
+ set r4,r4,1<ou> /* set ou bit */
+FCMPS1nfS2ni:
+ set r4,r4,1<gt> /* set gt bit */
+ set r4,r4,1<ge> /* set ge bit */
+
+move:
+ br.n inf_return
+ or r6,r0,r4 /* transfer answer to r6 */
+
+
+/* Multiplying infinity and zero causes an exception, but all other */
+/* operations produce a correctly signed infinity. */
+
+FMUL:
+ bsr _ASM_LABEL(zero) /* see if any of the operands are zero */
+ bb1 s1zero,r12,excpt /* infinity X 0 causes an exception */
+ bb1 s2zero,r12,excpt /* infinity X 0 causes an exception */
+ bb1 sign,r5,FMULS1neg /* handle negative cases of S1 */
+ bb0 sign,r7,poswrinf /* + X + = + */
+ br negwrinf /* + X - = - */
+FMULS1neg:
+ bb1 sign,r7,poswrinf /* - X - = + */
+ br negwrinf /* - X + = - */
+
+
+/* Dividing infinity by infinity causes an exception, but dividing */
+/* infinity by a finite yields a correctly signed infinity, and */
+/* dividing a finite by an infinity produces a correctly signed zero. */
+
+FDIV:
+ bb1 s1inf,r12,FDIVS1inf /* handle case of S1 being infinity */
+ bb1 sign,r5,FDIVS1nf /* handle cases of S1 being neg. non-inf. */
+ bb1 sign,r7,FDIVS1pfS2mi /* handle case of negative S2 */
+FDIVS1pfS2pi:
+ br poswrzero /* +f / +inf = +0 */
+FDIVS1pfS2mi:
+ br negwrzero /* +f / -inf = -0 */
+FDIVS1nf:
+ bb1 sign,r7,FDIVS1nfS2mi /* handle case of negative S2 */
+FDIVS1nfS2pi:
+ br negwrzero /* -f / +inf = -0 */
+FDIVS1nfS2mi:
+ br poswrzero /* -f / -inf = +0 */
+FDIVS1inf:
+ bb1 s2inf,r12,excpt /* inf / inf = exception */
+ bb1 sign,r5,FDIVS1mi /* handle cases of S1 being neg. inf. */
+ bb1 sign,r7,FDIVS1piS2nf /* handle case of negative S2 */
+FDIVS1piS2pf:
+ br poswrinf /* +inf / +f = +inf */
+FDIVS1piS2nf:
+ br negwrinf /* +inf / -f = -inf */
+FDIVS1mi:
+ bb1 sign,r7,FDIVS1miS2nf /* handle case of negative S2 */
+FDIVS1miS2pf:
+ br negwrinf /* -inf / +f = -inf */
+FDIVS1miS2nf:
+ br poswrinf /* -inf / -f = +inf */
+
+
+/* The square root of positive infinity is positive infinity, */
+/* but the square root of negative infinity is a NaN */
+
+#if 0
+FSQRT:
+ bb0 sign,r7,poswrinf /* write sqrt(inf) = inf */
+ br excpt /* write sqrt(-inf) = NaN */
+#endif
+
+excpt:
+ set r2,r2,1<oper>
+#ifdef HANDLER
+ bb0 oper,r3,nohandler /* branch if no user handler */
+ bsr _handler /* branch to interface with user handler */
+ br inf_return
+nohandler:
+#endif
+ set r5,r0,0<0> /* write NaN into r5 */
+ br.n inf_return
+ set r6,r0,0<0> /* write NaN into r6, writing NaN''s into */
+ /* both of these registers is quicker than */
+ /* checking for single or double precision */
+
+
+/* Write positive infinity of the correct precision */
+
+poswrinf:
+ bb1 dsize,r9,poswrinfd /* branch to write double precision inf. */
+ br.n inf_return
+ or.u r6,r0,0x7f80 /* load r6 with single precision pos inf. */
+poswrinfd:
+ or.u r5,r0,0x7ff0 /* load double precision pos inf. */
+ br.n inf_return
+ or r6,r0,r0
+
+
+/* Write negative infinity of the correct precision */
+
+negwrinf:
+ bb1 dsize,r9,negwrinfd /* branch to write double precision inf. */
+ br.n inf_return
+ or.u r6,r0,0xff80 /* load r6 with single precision pos inf. */
+negwrinfd:
+ or.u r5,r0,0xfff0 /* load double precision pos inf. */
+ br.n inf_return
+ or r6,r0,r0
+
+
+/* Write a positive zero disregarding precision. */
+
+poswrzero:
+ or r5,r0,r0 /* write to both high word and low word now */
+ br.n inf_return /* it does not matter that both are written */
+ or r6,r0,r0
+
+
+/* Write a negative zero of the correct precision. */
+
+negwrzero:
+ or r6,r0,r0 /* clear low word */
+ bb1 dsize,r9,negwrzerod /* branch to write double precision zero */
+ br.n inf_return
+ set r6,r6,1<31> /* set sign bit */
+negwrzerod:
+ or r5,r0,r0 /* clear high word */
+ br.n inf_return
+ set r5,r5,1<31> /* set sign bit */
+
+FP_inf_overflw:
+ set r2,r2,1<oper>
+ set r2,r2,1<overflow>
+ set r2,r2,1<inexact>
+#ifdef HANDLER
+ bb0 oper,r3,nohandlero /* do not go to user handler routine */
+ bsr _handler /* go to user handler routine */
+ br inf_return
+#endif
+
+nohandlero:
+ bb0.n sign,r7,inf_return /* if positive then return */
+
+ set r6,r6,31<0> /* set result to largest positive integer */
+ or.c r6,r0,r6 /* negate r6,giving largest negative int. */
+
+inf_return:
+ ld r1,r31,0 /* load return address */
+ jmp r1
+
+ data
+
+#define FADD denorm_FADD
+#define FSUB denorm_FSUB
+#define FCMP denorm_FCMP
+#define FMUL denorm_FMUL
+#define FDIV denorm_FDIV
+#define NINT denorm_NINT
+#define TRNC denorm_TRNC
+#define return denorm_return
+
+/*
+ * denorm
+ */
+
+/* Check to see if either S1 or S2 is a denormalized number. First */
+/* extract the exponent to see if it is zero, and then check to see if */
+/* the mantissa is not zero. If the number is denormalized, then set the */
+/* 1 or 0 bit 10 r12. */
+
+ASLOCAL(denorm)
+ st r1,r31,0 /* save return address */
+dnmcheckS1:
+ extu r10,r5,11<20> /* extract exponent */
+ bcnd ne0,r10,dnmsetS2 /* S1 is not a denorm, so S2 must be */
+ bb1.n 9,r9,dnmcheckS1d /* S1 is double precision */
+ mak r10,r5,20<3> /* mak field with only mantissa bits */
+ /* into final result */
+dnmcheckS1s:
+ extu r11,r6,3<29> /* get three low bits of mantissa */
+ or r10,r10,r11 /* assemble all of the mantissa bits */
+ bcnd eq0,r10,dnmsetS2 /* S1 is not a denorm, so S2 must be */
+ br dnmsetS1 /* S1 is a denorm */
+
+dnmcheckS1d:
+ or r10,r6,r10 /* or all of mantissa bits */
+ bcnd eq0,r10,dnmsetS2 /* S1 is not a denorm, so S2 must be */
+dnmsetS1:
+ set r12,r12,1<1> /* S1 is a denorm */
+
+dnmcheckS2:
+ extu r10,r7,11<20> /* extract exponent */
+ bcnd ne0,r10,S1form /* S2 is not a denorm */
+ bb1.n 7,r9,dnmcheckS2d /* S2 is double precision */
+ mak r10,r7,20<3> /* mak field with only mantissa bits */
+dnmcheckS2s:
+ extu r11,r8,3<29> /* get three low bits of mantissa */
+ or r10,r10,r11 /* assemble all of the mantissa bits */
+ bcnd eq0,r10,S1form /* S2 is not a denorm */
+ br dnmsetS2 /* S1 is a denorm */
+dnmcheckS2d:
+ or r10,r8,r10 /* or all or mantissa bits */
+ bcnd eq0,r10,S1form /* S2 is not a denorm */
+dnmsetS2:
+ set r12,r12,1<0> /* S2 is a denorm */
+
+
+/* Since the operations are going to be reperformed with modified denorms, */
+/* the operands which were initially single precision need to be modified */
+/* back to single precision. */
+
+S1form:
+ bb1 9,r9,S2form /* S1 is double precision, so do not */
+ /* modify S1 into single format */
+ mak r11,r5,28<3> /* over final exponent and mantissa */
+ /* eliminating extra 3 bits of exponent */
+ extu r6,r6,3<29> /* get low 3 bits of mantissa */
+ or r11,r6,r11 /* form complete mantissa and exponent */
+ extu r10,r5,1<31> /* get the 31 bit */
+ mak r10,r10,1<31> /* place 31 bit 10 correct position */
+ or r6,r10,r11 /* or 31, exponent, and all of mantissa */
+
+S2form:
+ bb1 7,r9,checkop /* S2 is double precision, so do not */
+ /* modify S2 into single format */
+ mak r11,r7,28<3> /* over final exponent and mantissa */
+ /* eliminating extra 3 bits of exponent */
+ extu r8,r8,3<29> /* get low 3 bits of mantissa */
+ or r11,r8,r11 /* form complete mantissa and exponent */
+ extu r10,r7,1<31> /* get the 31 bit */
+ mak r10,r10,1<31> /* place 31 bit 10 correct position */
+ or r8,r10,r11 /* or 31, exponent, and all of mantissa */
+
+
+/* Extract the opcode, compare to a constant, and branch to the code that */
+/* deals with that opcode. */
+
+checkop:
+ extu r10,r9,5<11> /* extract opcode */
+ cmp r11,r10,0x05 /* compare to FADD */
+ bb1 2,r11,FADD /* operation is FADD */
+ cmp r11,r10,0x06 /* compare to FSUB */
+ bb1 2,r11,FSUB /* operation is FSUB */
+ cmp r11,r10,0x07 /* compare to FCMP */
+ bb1 2,r11,FCMP /* operation is FCMP */
+ cmp r11,r10,0x00 /* compare to FMUL */
+ bb1 2,r11,FMUL /* operation is FMUL */
+ cmp r11,r10,0x0e /* compare to FDIV */
+ bb1 2,r11,FDIV /* operation is FDIV */
+#if 0
+ cmp r11,r10,0x0f /* compare to FSQRT */
+ bb1 2,r11,FSQRT /* operation is FSQRT */
+#endif
+ cmp r11,r10,0x09 /* compare to INT */
+ bb1 2,r11,INT /* operation is INT */
+ cmp r11,r10,0x0a /* compare to NINT */
+ bb1 2,r11,NINT /* operation is NINT */
+ cmp r11,r10,0x0b /* compare to TRNC */
+ bb1 2,r11,TRNC /* operation is TRNC */
+
+
+/* For all the following operations, the denormalized number is set to */
+/* zero and the operation is reperformed the correct destination and source */
+/* sizes. */
+
+FADD:
+ bb0 1,r12,FADDS2dnm /* S1 is not denorm, so S2 must be */
+ or r5,r0,r0 /* set S1 to zero */
+ or r6,r0,r0
+FADDS2chk:
+ bb0 0,r12,FADDcalc /* S2 is not a denorm */
+FADDS2dnm:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+FADDcalc:
+ bb1 5,r9,FADDdD /* branch for double precision destination */
+FADDsD:
+ bb1 9,r9,FADDsDdS1 /* branch for double precision S1 */
+FADDsDsS1:
+ bb1 7,r9,FADDsDsS1dS2 /* branch for double precision S2 */
+FADDsDsS1sS2:
+ br.n return
+ fadd.sss r6,r6,r8 /* add the two sources and place result 10 S1 */
+FADDsDsS1dS2:
+ br.n return
+ fadd.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */
+FADDsDdS1:
+ bb1 7,r9,FADDsDdS1dS2 /* branch for double precision S2 */
+FADDsDdS1sS2:
+ br.n return
+ fadd.sds r6,r5,r8 /* add the two sources and place result 10 S1 */
+FADDsDdS1dS2:
+ br.n return
+ fadd.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */
+FADDdD:
+ bb1 9,r9,FADDdDdS1 /* branch for double precision S1 */
+FADDdDsS1:
+ bb1 7,r9,FADDdDsS1dS2 /* branch for double precision S2 */
+FADDdDsS1sS2:
+ br.n return
+ fadd.dss r5,r6,r8 /* add the two sources and place result 10 S1 */
+FADDdDsS1dS2:
+ br.n return
+ fadd.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */
+FADDdDdS1:
+ bb1 7,r9,FADDdDdS1dS2 /* branch for double precision S2 */
+FADDdDdS1sS2:
+ br.n return
+ fadd.dds r5,r5,r8 /* add the two sources and place result 10 S1 */
+FADDdDdS1dS2:
+ br.n return
+ fadd.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */
+
+FSUB:
+ bb0 1,r12,FSUBS2dnm /* S1 is not denorm, so S2 must be */
+ or r5,r0,r0 /* set S1 to zero */
+ or r6,r0,r0
+FSUBS2chk:
+ bb0 0,r12,FSUBcalc /* S2 is not a denorm */
+FSUBS2dnm:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+FSUBcalc:
+ bb1 5,r9,FSUBdD /* branch for double precision destination */
+FSUBsD:
+ bb1 9,r9,FSUBsDdS1 /* branch for double precision S1 */
+FSUBsDsS1:
+ bb1 7,r9,FSUBsDsS1dS2 /* branch for double precision S2 */
+FSUBsDsS1sS2:
+ br.n return
+ fsub.sss r6,r6,r8 /* add the two sources and place result 10 S1 */
+FSUBsDsS1dS2:
+ br.n return
+ fsub.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */
+FSUBsDdS1:
+ bb1 7,r9,FSUBsDdS1dS2 /* branch for double precision S2 */
+FSUBsDdS1sS2:
+ br.n return
+ fsub.sds r6,r5,r8 /* add the two sources and place result 10 S1 */
+FSUBsDdS1dS2:
+ br.n return
+ fsub.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */
+FSUBdD:
+ bb1 9,r9,FSUBdDdS1 /* branch for double precision S1 */
+FSUBdDsS1:
+ bb1 7,r9,FSUBdDsS1dS2 /* branch for double precision S2 */
+FSUBdDsS1sS2:
+ br.n return
+ fsub.dss r5,r6,r8 /* add the two sources and place result 10 S1 */
+FSUBdDsS1dS2:
+ br.n return
+ fsub.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */
+FSUBdDdS1:
+ bb1 7,r9,FSUBdDdS1dS2 /* branch for double precision S2 */
+FSUBdDdS1sS2:
+ br.n return
+ fsub.dds r5,r5,r8 /* add the two sources and place result 10 S1 */
+FSUBdDdS1dS2:
+ br.n return
+ fsub.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */
+
+FCMP:
+ bb0 1,r12,FCMPS2dnm /* S1 is not denorm, so S2 must be */
+ or r5,r0,r0 /* set S1 to zero */
+ or r6,r0,r0
+FCMPS2chk:
+ bb0 0,r12,FCMPcalc /* S2 is not a denorm */
+FCMPS2dnm:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+FCMPcalc:
+ bb1 9,r9,FCMPdS1 /* branch for double precision S1 */
+FCMPsS1:
+ bb1 7,r9,FCMPsS1dS2 /* branch for double precision S2 */
+FCMPsS1sS2:
+ br.n return
+ fcmp.sss r6,r6,r8 /* add the two sources and place result 10 S1 */
+FCMPsS1dS2:
+ br.n return
+ fcmp.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */
+FCMPdS1:
+ bb1 7,r9,FCMPdS1dS2 /* branch for double precision S2 */
+FCMPdS1sS2:
+ br.n return
+ fcmp.sds r6,r5,r8 /* add the two sources and place result 10 S1 */
+FCMPdS1dS2:
+ br.n return
+ fcmp.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */
+
+FMUL:
+ bb0 1,r12,FMULS2dnm /* S1 is not denorm, so S2 must be */
+ or r5,r0,r0 /* set S1 to zero */
+ or r6,r0,r0
+FMULS2chk:
+ bb0 0,r12,FMULcalc /* S2 is not a denorm */
+FMULS2dnm:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+FMULcalc:
+ bb1 5,r9,FMULdD /* branch for double precision destination */
+FMULsD:
+ bb1 9,r9,FMULsDdS1 /* branch for double precision S1 */
+FMULsDsS1:
+ bb1 7,r9,FMULsDsS1dS2 /* branch for double precision S2 */
+FMULsDsS1sS2:
+ br.n return
+ fmul.sss r6,r6,r8 /* add the two sources and place result 10 S1 */
+FMULsDsS1dS2:
+ br.n return
+ fmul.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */
+FMULsDdS1:
+ bb1 7,r9,FMULsDdS1dS2 /* branch for double precision S2 */
+FMULsDdS1sS2:
+ br.n return
+ fmul.sds r6,r5,r8 /* add the two sources and place result 10 S1 */
+FMULsDdS1dS2:
+ br.n return
+ fmul.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */
+FMULdD:
+ bb1 9,r9,FMULdDdS1 /* branch for double precision S1 */
+FMULdDsS1:
+ bb1 7,r9,FMULdDsS1dS2 /* branch for double precision S2 */
+FMULdDsS1sS2:
+ br.n return
+ fmul.dss r5,r6,r8 /* add the two sources and place result 10 S1 */
+FMULdDsS1dS2:
+ br.n return
+ fmul.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */
+FMULdDdS1:
+ bb1 7,r9,FMULdDdS1dS2 /* branch for double precision S2 */
+FMULdDdS1sS2:
+ br.n return
+ fmul.dds r5,r5,r8 /* add the two sources and place result 10 S1 */
+FMULdDdS1dS2:
+ br.n return
+ fmul.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */
+
+FDIV:
+ bb0 1,r12,FDIVS2dnm /* S1 is not denorm, so S2 must be */
+ or r5,r0,r0 /* set S1 to zero */
+ or r6,r0,r0
+FDIVS2chk:
+ bb0 0,r12,FDIVcalc /* S2 is not a denorm */
+FDIVS2dnm:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+FDIVcalc:
+ bb1 5,r9,FDIVdD /* branch for double precision destination */
+FDIVsD:
+ bb1 9,r9,FDIVsDdS1 /* branch for double precision S1 */
+FDIVsDsS1:
+ bb1 7,r9,FDIVsDsS1dS2 /* branch for double precision S2 */
+FDIVsDsS1sS2:
+ fdiv.sss r6,r6,r8 /* add the two sources and place result 10 S1 */
+ br return
+FDIVsDsS1dS2:
+ fdiv.ssd r6,r6,r7 /* add the two sources and place result 10 S1 */
+ br return
+FDIVsDdS1:
+ bb1 7,r9,FDIVsDdS1dS2 /* branch for double precision S2 */
+FDIVsDdS1sS2:
+ fdiv.sds r6,r5,r8 /* add the two sources and place result 10 S1 */
+ br return
+FDIVsDdS1dS2:
+ fdiv.sdd r6,r5,r7 /* add the two sources and place result 10 S1 */
+ br return
+FDIVdD:
+ bb1 9,r9,FDIVdDdS1 /* branch for double precision S1 */
+FDIVdDsS1:
+ bb1 7,r9,FDIVdDsS1dS2 /* branch for double precision S2 */
+FDIVdDsS1sS2:
+ fdiv.dss r5,r6,r8 /* add the two sources and place result 10 S1 */
+ br return
+FDIVdDsS1dS2:
+ fdiv.dsd r5,r6,r7 /* add the two sources and place result 10 S1 */
+ br return
+FDIVdDdS1:
+ bb1 7,r9,FDIVdDdS1dS2 /* branch for double precision S2 */
+FDIVdDdS1sS2:
+ fdiv.dds r5,r5,r8 /* add the two sources and place result 10 S1 */
+ br return
+FDIVdDdS1dS2:
+ fdiv.ddd r5,r5,r7 /* add the two sources and place result 10 S1 */
+ br return
+
+#if 0
+FSQRT:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+FSQRTcalc:
+ bb1 5,r9,FSQRTdD /* branch for double precision destination */
+FSQRTsD:
+ bb1 7,r9,FSQRTsDdS2 /* branch for double precision S2 */
+FSQRTsDsS2:
+ br.n return
+ fsqrt.ss r6,r8 /* add the two sources and place result 10 S1 */
+FSQRTsDdS2:
+ br.n return
+ fsqrt.sd r6,r7 /* add the two sources and place result 10 S1 */
+FSQRTdD:
+ bb1 7,r9,FSQRTdDdS2 /* branch for double precision S2 */
+FSQRTdDsS2:
+ br.n return
+ fsqrt.ds r5,r8 /* add the two sources and place result 10 S1 */
+FSQRTdDdS2:
+ br.n return
+ fsqrt.dd r5,r7 /* add the two sources and place result 10 S1 */
+#endif
+
+INT:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+INTcalc:
+ bb1 7,r9,INTdS2 /* branch for double precision S2 */
+INTsS2:
+ br.n return
+ int.ss r6,r8 /* add the two sources and place result 10 S1 */
+INTdS2:
+ br.n return
+ int.sd r6,r7 /* add the two sources and place result 10 S1 */
+
+NINT:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+NINTcalc:
+ bb1 7,r9,NINTdS2 /* branch for double precision S2 */
+NINTsS2:
+ br.n return
+ nint.ss r6,r8 /* add the two sources and place result 10 S1 */
+NINTdS2:
+ br.n return
+ nint.sd r6,r7 /* add the two sources and place result 10 S1 */
+
+TRNC:
+ or r7,r0,r0 /* set S2 to zero */
+ or r8,r0,r0
+TRNCcalc:
+ bb1 7,r9,TRNCdS2 /* branch for double precision S2 */
+TRNCsS2:
+ br.n return
+ trnc.ss r6,r8 /* add the two sources and place result 10 S1 */
+TRNCdS2:
+ trnc.sd r6,r7 /* add the two sources and place result 10 S1 */
+
+
+/* Return to the routine that detected the reserved operand. */
+
+return:
+ ld r1,r31,0 /* load return address */
+ jmp r1
+
+ data
+
+
+/* S1 and/or S2 is an infinity, and the other operand may be a zero. */
+/* Knowing which operands are infinity, check the remaining operands for zeros. */
+
+ASLOCAL(zero)
+ bb0 s1inf,r12,S1noinf /* see if S1 is zero */
+ bb0 s2inf,r12,S2noinf /* see if S2 is zero */
+ jmp r1
+
+/* See if S1 is zero. Whether or not S1 is a zero, being in this routine */
+/* implies that S2 is infinity, so return to subroutine infinity after */
+/* completing this code. Set the s1zero flag in r12 if S1 is zero. */
+
+S1noinf:
+ bb1 s1size,r9,S1noinfd /* work with double precision operand */
+S1noinfs:
+ or r10,r0,r5 /* load high word into r10 */
+ clr r10,r10,1<sign> /* clear the sign bit */
+ extu r11,r6,3<29> /* extract lower 3 bits of mantissa */
+ or r10,r10,r11 /* or these 3 bits with high word */
+ bcnd ne0,r10,operation /* do not set zero flag */
+ jmp.n r1 /* since this operand was not */
+ /* infinity, S2 must have been, */
+ /* so return */
+ set r12,r12,1<s1zero> /* set zeroflag */
+S1noinfd:
+ clr r10,r5,1<sign> /* clear the sign bit */
+ or r10,r6,r10 /* or high and low word */
+ bcnd ne0,r10,operation /* do not set zero flag */
+ jmp.n r1 /* since this operand was not */
+ /* infinity, S2 must have been, */
+ /* so return */
+ set r12,r12,1<s1zero> /* set zeroflag */
+
+
+/* Check S2 for zero. If it is zero, then set the s2zero flag in r12. */
+
+S2noinf:
+ bb1 s2size,r9,S2noinfd /* work with double precision operand */
+S2noinfs:
+ or r10,r0,r7 /* load high word into r10 */
+ clr r10,r10,1<sign> /* clear the sign bit */
+ extu r11,r8,3<29> /* extract lower 3 bits of mantissa */
+ or r10,r10,r11 /* or these 3 bits with high word */
+ bcnd ne0,r10,operation /* do not set zero flag */
+ jmp.n r1 /* since this operand was not */
+ /* infinity, S1 must have been, */
+ /* so return */
+ set r12,r12,1<s2zero> /* set zeroflag */
+S2noinfd:
+ clr r10,r7,1<sign> /* clear the sign bit */
+ or r10,r8,r10 /* or high and low word */
+ bcnd ne0,r10,operation /* do not set zero flag */
+ set r12,r12,1<s2zero> /* set zeroflag */
+ /* since this operand was not */
+ /* infinity, S1 must have been, */
+ /* so return */
+operation:
+ jmp r1
+
+ASENTRY(Xfp_imprecise)
+/* input: r3 is the exception frame */
+ or r29, r3, r0 /* r29 is now the E.F. */
+ subu r31, r31, 40
+ st r1, r31, 32
+ st r29, r31, 36
+
+ ld r2 , r29, EF_FPSR * 4
+ ld r3 , r29, EF_FPCR * 4
+ ld r4 , r29, EF_FPECR * 4
+ ld r10, r29, EF_FPRH * 4
+ ld r11, r29, EF_FPRL * 4
+ ld r12, r29, EF_FPIT * 4
+
+/* Load into r1 the return address for the exception handlers. Looking */
+/* at FPECR, branch to the appropriate exception handler. */
+
+ or.u r1,r0,hi16(fpui_wrapup)/* load return address of functions */
+ or r1,r1,lo16(fpui_wrapup)
+
+ bb0 2,r4,2f /* branch to FPunderflow if bit set */
+ br _ASM_LABEL(FPunderflow)
+2:
+ bb0 1,r4,3f /* branch to FPoverflow if bit set */
+ br _ASM_LABEL(FPoverflow)
+3:
+ /* XXX handle inexact!!! */
+#ifdef HANDLER
+ br _handler /* branch to handler since bit will */
+ /* be set for inexact */
+#endif
+
+fpui_wrapup:
+ tb1 0,r0,0 /* make sure all floating point operations */
+ /* have finished */
+ ldcr r4, cr1 /* load the PSR */
+#if 0
+ set r4, r4, 1<PSR_FPU_DISABLE_BIT>
+#endif
+ set r4, r4, 1<PSR_INTERRUPT_DISABLE_BIT>
+ stcr r4, cr1
+ ld r1, r31, 32
+ ld r29,r31, 36
+ addu r31, r31, 40
+
+ fstcr r2, FPSR /* write revised value of FPSR */
+ fstcr r3, FPCR /* write revised value of FPCR */
+
+ /* write back the results */
+ extu r2, r12, 5<0>
+ addu r3, r29, EF_R0*4
+ bb0 destsize, r12, Iwritesingle
+ st r10, r3 [r2]
+ addu r2, r2, 1
+ clr r2, r2, 27<5>
+Iwritesingle:
+ st r11, r3 [r2]
+ jmp r1
diff --git a/sys/arch/luna88k/luna88k/m8820x.c b/sys/arch/luna88k/luna88k/m8820x.c
new file mode 100644
index 00000000000..2c7255f71d1
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/m8820x.c
@@ -0,0 +1,1595 @@
+/* $OpenBSD: m8820x.c,v 1.1 2004/04/21 15:24:03 aoyama Exp $ */
+/*
+ * Copyright (c) 2004, Miodrag Vallat.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2001 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/simplelock.h>
+
+#include <machine/asm_macro.h>
+#include <machine/board.h>
+#include <machine/cpu_number.h>
+#include <machine/locore.h>
+
+#include <machine/cmmu.h>
+#include <machine/m8820x.h>
+
+#include <uvm/uvm_extern.h>
+
+#ifdef DDB
+#include <ddb/db_output.h> /* db_printf() */
+#endif /* DDB */
+
+/*
+ * On some versions of the 88200, page size flushes don't work. I am using
+ * sledge hammer approach till I find for sure which ones are bad XXX nivas
+ */
+#define BROKEN_MMU_MASK
+
+#undef SHADOW_BATC /* don't use BATCs for now XXX nivas */
+
+#ifdef DEBUG
+unsigned int m8820x_debuglevel;
+#define dprintf(_X_) \
+ do { \
+ if (m8820x_debuglevel != 0) { \
+ unsigned int psr = disable_interrupts_return_psr(); \
+ printf("%d: ", cpu_number()); \
+ printf _X_; \
+ set_psr(psr); \
+ } \
+ } while (0)
+#else
+#define dprintf(_X_) do { } while (0)
+#endif
+
+void m8820x_cmmu_init(void);
+void m8820x_setup_board_config(void);
+void m8820x_cpu_configuration_print(int);
+void m8820x_cmmu_shutdown_now(void);
+void m8820x_cmmu_parity_enable(void);
+unsigned m8820x_cmmu_cpu_number(void);
+void m8820x_cmmu_set_sapr(unsigned, unsigned);
+void m8820x_cmmu_set_uapr(unsigned);
+void m8820x_cmmu_set_pair_batc_entry(unsigned, unsigned, unsigned);
+void m8820x_cmmu_flush_tlb(unsigned, unsigned, vaddr_t, vsize_t);
+void m8820x_cmmu_pmap_activate(unsigned, unsigned,
+ u_int32_t i_batc[BATC_MAX], u_int32_t d_batc[BATC_MAX]);
+void m8820x_cmmu_flush_cache(int, paddr_t, psize_t);
+void m8820x_cmmu_flush_inst_cache(int, paddr_t, psize_t);
+void m8820x_cmmu_flush_data_cache(int, paddr_t, psize_t);
+void m8820x_dma_cachectl(vaddr_t, vsize_t, int);
+void m8820x_cmmu_dump_config(void);
+void m8820x_cmmu_show_translation(unsigned, unsigned, unsigned, int);
+void m8820x_show_apr(unsigned);
+
+/* This is the function table for the mc8820x CMMUs */
+struct cmmu_p cmmu8820x = {
+ m8820x_cmmu_init,
+ m8820x_setup_board_config,
+ m8820x_cpu_configuration_print,
+ m8820x_cmmu_shutdown_now,
+ m8820x_cmmu_parity_enable,
+ m8820x_cmmu_cpu_number,
+ m8820x_cmmu_set_sapr,
+ m8820x_cmmu_set_uapr,
+ m8820x_cmmu_set_pair_batc_entry,
+ m8820x_cmmu_flush_tlb,
+ m8820x_cmmu_pmap_activate,
+ m8820x_cmmu_flush_cache,
+ m8820x_cmmu_flush_inst_cache,
+ m8820x_cmmu_flush_data_cache,
+ m8820x_dma_cachectl,
+#ifdef DDB
+ m8820x_cmmu_dump_config,
+ m8820x_cmmu_show_translation,
+#else
+ NULL,
+ NULL,
+#endif
+#ifdef DEBUG
+ m8820x_show_apr,
+#else
+ NULL,
+#endif
+};
+
+/*
+ * CMMU kernel information
+ */
+struct m8820x_cmmu {
+ unsigned *volatile cmmu_regs; /* CMMU "base" area */
+ unsigned int cmmu_cpu; /* cpu number it is attached to */
+ unsigned int cmmu_type;
+#define INST_CMMU 0
+#define DATA_CMMU 1
+ unsigned int cmmu_access;
+#define CMMU_ACS_USER 0
+#define CMMU_ACS_SUPER 1
+#define CMMU_ACS_BOTH 2
+ unsigned int cmmu_alive;
+#define CMMU_DEAD 0 /* This cmmu is not there */
+#define CMMU_AVAILABLE 1 /* It's there, but which cpu's? */
+#define CMMU_MARRIED 2 /* Know which cpu it belongs to. */
+ vaddr_t cmmu_addr; /* address range */
+ vaddr_t cmmu_addr_mask; /* address mask */
+ int cmmu_addr_match;/* return value of address comparison */
+#ifdef SHADOW_BATC
+ unsigned batc[BATC_MAX];
+#endif
+};
+
+#ifdef SHADOW_BATC
+/* CMMU(cpu,data) is the cmmu struct for the named cpu's indicated cmmu. */
+#define CMMU(cpu, data) cpu_cmmu[(cpu)].pair[(data) ? DATA_CMMU : INST_CMMU]
+#endif
+
+/*
+ * Structure for accessing MMUS properly
+ */
+
+struct m8820x_cmmu m8820x_cmmu[MAX_CMMUS] =
+{
+ /* address, cpu, mode, access, alive, addr, mask */
+ {(unsigned *volatile)CMMU_I0, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_D0, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_I1, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_D1, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_I2, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_D2, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_I3, -1, INST_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0},
+ {(unsigned *volatile)CMMU_D3, -1, DATA_CMMU, CMMU_ACS_BOTH, CMMU_DEAD, 0, 0}
+};
+
+struct cpu_cmmu {
+ struct m8820x_cmmu *pair[2];
+} cpu_cmmu[MAX_CPUS];
+
+/*
+ * CMMU per CPU split strategies
+ */
+
+#define CMMU_SPLIT_ADDRESS 0x00
+#define CMMU_SPLIT_SPV 0x01
+#define CMMU_SPLIT_SRAM_SPV 0x02
+#define CMMU_SPLIT_SRAM_ALL 0x03
+
+#define CMMU_SPLIT_MASK 0x03
+
+struct cmmu_strategy {
+ int inst;
+ int data;
+} cpu_cmmu_strategy[] = {
+ /* inst data */
+ { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS}, /* CPU 0 */
+ { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS}, /* CPU 1 */
+ { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS}, /* CPU 2 */
+ { CMMU_SPLIT_ADDRESS, CMMU_SPLIT_ADDRESS} /* CPU 3 */
+};
+
+unsigned int cmmu_shift;
+
+/* local prototypes */
+void m8820x_cmmu_set(int, unsigned, int, int, int, int, vaddr_t);
+void m8820x_cmmu_wait(int);
+void m8820x_cmmu_sync_cache(paddr_t, psize_t);
+void m8820x_cmmu_sync_inval_cache(paddr_t, psize_t);
+void m8820x_cmmu_inval_cache(paddr_t, psize_t);
+
+/* Flags passed to m8820x_cmmu_set() */
+#define MODE_VAL 0x01
+#define ACCESS_VAL 0x02
+#define ADDR_VAL 0x04
+
+#ifdef DEBUG
+void
+m8820x_show_apr(value)
+ unsigned value;
+{
+ printf("table @ 0x%x000", PG_PFNUM(value));
+ if (value & CACHE_WT)
+ printf(", writethrough");
+ if (value & CACHE_GLOBAL)
+ printf(", global");
+ if (value & CACHE_INH)
+ printf(", cache inhibit");
+ if (value & APR_V)
+ printf(", valid");
+ printf("\n");
+}
+#endif
+
+/*
+ * This routine sets up the CPU/CMMU configuration.
+ */
+void
+m8820x_setup_board_config()
+{
+ int num, cmmu_num;
+ unsigned *volatile cr;
+
+ master_cpu = 0; /* temp to get things going */
+ max_cpus = 4;
+ max_cmmus = 8;
+
+ cmmu_shift = ff1(max_cmmus / max_cpus);
+
+ /*
+ * Probe for available MMUs
+ */
+ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) {
+ cr = m8820x_cmmu[cmmu_num].cmmu_regs;
+ if (badwordaddr((vaddr_t)cr) == 0) {
+ int type;
+
+ type = CMMU_TYPE(cr[CMMU_IDR]);
+#ifdef DIAGNOSTIC
+ if (type != M88200_ID && type != M88204_ID) {
+ printf("WARNING: non M8820x circuit found "
+ "at CMMU address %p\n", cr);
+ continue; /* will probably die quickly */
+ }
+#endif
+ m8820x_cmmu[cmmu_num].cmmu_alive = CMMU_AVAILABLE;
+ dprintf(("m8820x_setup_cmmu_config: CMMU %d found at %p\n",
+ cmmu_num, cr));
+ }
+ }
+
+ /*
+ * Now that we know which CMMUs are there, let's report on which
+ * CPU/CMMU sets seem complete (hopefully all)
+ */
+ for (num = 0; num < max_cpus; num++) {
+ int i, type;
+
+ for (i = 0; i < (1 << cmmu_shift); i++) {
+ dprintf(("cmmu_init: testing CMMU %d for CPU %d\n",
+ (num << cmmu_shift) | i, num));
+#ifdef DIAGNOSTIC
+ if (m8820x_cmmu[(num << cmmu_shift) | i].cmmu_alive == CMMU_DEAD) {
+ printf("CMMU %d attached to CPU %d is not working\n",
+ (num << cmmu_shift) | i, num);
+ continue; /* will probably die quickly */
+ }
+#endif
+ }
+ cpu_sets[num] = 1; /* This cpu installed... */
+ type = CMMU_TYPE(m8820x_cmmu[num << cmmu_shift].
+ cmmu_regs[CMMU_IDR]);
+
+ printf("CPU%d is attached with %d MC%x CMMUs\n",
+ num, 1 << cmmu_shift, type == M88204_ID ? 0x88204 : 0x88200);
+ }
+
+ /*
+ * Calculate the CMMU<->CPU connections
+ */
+ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) {
+ m8820x_cmmu[cmmu_num].cmmu_cpu =
+ (cmmu_num * max_cpus) / max_cmmus;
+ dprintf(("m8820x_setup_cmmu_config: CMMU %d connected with CPU %d\n",
+ cmmu_num, m8820x_cmmu[cmmu_num].cmmu_cpu));
+ }
+
+ /*
+ * Now set m8820x_cmmu[].cmmu_access and addr
+ */
+ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) {
+ /*
+ * We don't set up anything for the hardwired configurations.
+ */
+ m8820x_cmmu[cmmu_num].cmmu_addr = 0;
+ m8820x_cmmu[cmmu_num].cmmu_addr_mask = 0;
+ m8820x_cmmu[cmmu_num].cmmu_addr_match = 1;
+ m8820x_cmmu[cmmu_num].cmmu_access = CMMU_ACS_BOTH;
+ }
+}
+
+#ifdef DDB
+
+const char *cmmu_strat_string[] = {
+ "address split ",
+ "user/spv split",
+ "spv SRAM split",
+ "all SRAM split"
+};
+
+void
+m8820x_cmmu_dump_config()
+{
+ int cmmu_num;
+
+ db_printf("Current CPU/CMMU configuration:\n");
+
+ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) {
+ db_printf("CMMU #%d: %s CMMU for CPU %d:\n Strategy: %s\n %s access addr 0x%08lx mask 0x%08lx match %s\n",
+ cmmu_num,
+ (m8820x_cmmu[cmmu_num].cmmu_type == INST_CMMU) ? "inst" : "data",
+ m8820x_cmmu[cmmu_num].cmmu_cpu,
+ cmmu_strat_string[(m8820x_cmmu[cmmu_num].cmmu_type == INST_CMMU) ?
+ cpu_cmmu_strategy[m8820x_cmmu[cmmu_num].cmmu_cpu].inst :
+ cpu_cmmu_strategy[m8820x_cmmu[cmmu_num].cmmu_cpu].data],
+ (m8820x_cmmu[cmmu_num].cmmu_access == CMMU_ACS_BOTH) ? "User and spv" :
+ ((m8820x_cmmu[cmmu_num].cmmu_access == CMMU_ACS_USER) ? "User " :
+ "Supervisor "),
+ m8820x_cmmu[cmmu_num].cmmu_addr,
+ m8820x_cmmu[cmmu_num].cmmu_addr_mask,
+ m8820x_cmmu[cmmu_num].cmmu_addr_match ? "TRUE" : "FALSE");
+ }
+}
+#endif /* DDB */
+
+/*
+ * This function is called by the MMU module and pokes values
+ * into the CMMU's registers.
+ */
+void
+m8820x_cmmu_set(reg, val, flags, num, mode, access, addr)
+ int reg;
+ unsigned val;
+ int flags, num, mode, access;
+ vaddr_t addr;
+{
+ int mmu;
+
+ /*
+ * We scan all CMMUs to find the matching ones and store the
+ * values there.
+ */
+ for (mmu = num << cmmu_shift;
+ mmu < (num + 1) << cmmu_shift; mmu++) {
+ if (((flags & MODE_VAL)) &&
+ (m8820x_cmmu[mmu].cmmu_type != mode))
+ continue;
+ if (((flags & ACCESS_VAL)) &&
+ (m8820x_cmmu[mmu].cmmu_access != access) &&
+ (m8820x_cmmu[mmu].cmmu_access != CMMU_ACS_BOTH))
+ continue;
+ if (flags & ADDR_VAL) {
+ if (((addr & m8820x_cmmu[mmu].cmmu_addr_mask) == m8820x_cmmu[mmu].cmmu_addr)
+ != m8820x_cmmu[mmu].cmmu_addr_match) {
+ continue;
+ }
+ }
+ m8820x_cmmu[mmu].cmmu_regs[reg] = val;
+ }
+}
+
+/*
+ * Force a read from the CMMU status register, thereby forcing execution to
+ * stop until all pending CMMU operations are finished.
+ * This is used by the various cache invalidation functions.
+ */
+void
+m8820x_cmmu_wait(int cpu)
+{
+ int mmu;
+
+ /*
+ * We scan all related CMMUs and read their status register.
+ */
+ for (mmu = cpu << cmmu_shift;
+ mmu < (cpu + 1) << cmmu_shift; mmu++) {
+#ifdef DEBUG
+ if (m8820x_cmmu[mmu].cmmu_regs[CMMU_SSR] & CMMU_SSR_BE) {
+ panic("cache flush failed!");
+ }
+#else
+ /* force the read access, but do not issue this statement... */
+ __asm__ __volatile__ ("|or r0, r0, %0" ::
+ "r" (m8820x_cmmu[mmu].cmmu_regs[CMMU_SSR]));
+#endif
+ }
+}
+
+const char *mmutypes[8] = {
+ "Unknown (0)",
+ "Unknown (1)",
+ "Unknown (2)",
+ "Unknown (3)",
+ "Unknown (4)",
+ "M88200 (16K)",
+ "M88204 (64K)",
+ "Unknown (7)"
+};
+
+/*
+ * Should only be called after the calling cpus knows its cpu
+ * number and master/slave status . Should be called first
+ * by the master, before the slaves are started.
+*/
+void
+m8820x_cpu_configuration_print(master)
+ int master;
+{
+ int pid = read_processor_identification_register();
+ int proctype = (pid & 0xff00) >> 8;
+ int procvers = (pid & 0xe) >> 1;
+ int mmu, cpu = cpu_number();
+ struct simplelock print_lock;
+
+ if (master)
+ simple_lock_init(&print_lock);
+
+ simple_lock(&print_lock);
+
+ printf("cpu%d: ", cpu);
+ if (proctype != 0) {
+ printf("unknown model arch 0x%x rev 0x%x\n",
+ proctype, procvers);
+ simple_unlock(&print_lock);
+ return;
+ }
+
+ printf("M88100 rev 0x%x", procvers);
+#if 0 /* not useful yet */
+#ifdef MVME188
+ if (brdtyp == BRD_188)
+ printf(", %s", master ? "master" : "slave");
+#endif
+#endif
+ printf(", %d CMMU", 1 << cmmu_shift);
+
+ for (mmu = cpu << cmmu_shift; mmu < (cpu + 1) << cmmu_shift;
+ mmu++) {
+ int idr = m8820x_cmmu[mmu].cmmu_regs[CMMU_IDR];
+ int mmuid = CMMU_TYPE(idr);
+ int access = m8820x_cmmu[mmu].cmmu_access;
+
+ if (mmu % 2 == 0)
+ printf("\ncpu%d: ", cpu);
+ else
+ printf(", ");
+
+ if (mmutypes[mmuid][0] == 'U')
+ printf("unknown model id 0x%x", mmuid);
+ else
+ printf("%s", mmutypes[mmuid]);
+ printf(" rev 0x%x, %s %scache",
+ CMMU_VERSION(idr),
+ access == CMMU_ACS_BOTH ? "global" :
+ (access == CMMU_ACS_USER ? "user" : "sup"),
+ m8820x_cmmu[mmu].cmmu_type == INST_CMMU ? "I" : "D");
+ }
+ printf("\n");
+
+#ifndef ERRATA__XXX_USR
+ {
+ static int errata_warn = 0;
+
+ if (proctype != 0 && procvers < 2) {
+ if (!errata_warn++)
+ printf("WARNING: M88100 bug workaround code "
+ "not enabled.\nPlease recompile the kernel "
+ "with option ERRATA__XXX_USR !\n");
+ }
+ }
+#endif
+
+ simple_unlock(&print_lock);
+}
+
+/*
+ * CMMU initialization routine
+ */
+void
+m8820x_cmmu_init()
+{
+ unsigned int line, cmmu_num;
+ int cssp, cpu, type;
+ u_int32_t apr;
+ unsigned *volatile cr;
+
+ for (cpu = 0; cpu < max_cpus; cpu++) {
+ cpu_cmmu[cpu].pair[INST_CMMU] = 0;
+ cpu_cmmu[cpu].pair[DATA_CMMU] = 0;
+ }
+
+ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++) {
+ if (m8820x_cmmu[cmmu_num].cmmu_alive != CMMU_DEAD) {
+ cr = m8820x_cmmu[cmmu_num].cmmu_regs;
+ type = CMMU_TYPE(cr[CMMU_IDR]);
+
+ cpu_cmmu[m8820x_cmmu[cmmu_num].cmmu_cpu].
+ pair[m8820x_cmmu[cmmu_num].cmmu_type] =
+ &m8820x_cmmu[cmmu_num];
+
+ /*
+ * Reset cache
+ */
+ for (cssp = type == M88204_ID ? 3 : 0;
+ cssp >= 0; cssp--)
+ for (line = 0; line <= 255; line++) {
+ cr[CMMU_SAR] =
+ line << MC88200_CACHE_SHIFT;
+ cr[CMMU_CSSP(cssp)] =
+ CMMU_CSSP_L5 | CMMU_CSSP_L4 |
+ CMMU_CSSP_L3 | CMMU_CSSP_L2 |
+ CMMU_CSSP_L1 | CMMU_CSSP_L0 |
+ CMMU_CSSP_VV(3, CMMU_VV_INVALID) |
+ CMMU_CSSP_VV(2, CMMU_VV_INVALID) |
+ CMMU_CSSP_VV(1, CMMU_VV_INVALID) |
+ CMMU_CSSP_VV(0, CMMU_VV_INVALID);
+ }
+
+ /*
+ * Set the SCTR, SAPR, and UAPR to some known state
+ */
+ cr[CMMU_SCTR] &=
+ ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR);
+ cr[CMMU_SAPR] = cr[CMMU_UAPR] =
+ ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL |
+ CACHE_INH) & ~APR_V;
+
+#ifdef SHADOW_BATC
+ m8820x_cmmu[cmmu_num].batc[0] =
+ m8820x_cmmu[cmmu_num].batc[1] =
+ m8820x_cmmu[cmmu_num].batc[2] =
+ m8820x_cmmu[cmmu_num].batc[3] =
+ m8820x_cmmu[cmmu_num].batc[4] =
+ m8820x_cmmu[cmmu_num].batc[5] =
+ m8820x_cmmu[cmmu_num].batc[6] =
+ m8820x_cmmu[cmmu_num].batc[7] = 0;
+#endif
+ cr[CMMU_BWP0] = cr[CMMU_BWP1] =
+ cr[CMMU_BWP2] = cr[CMMU_BWP3] =
+ cr[CMMU_BWP4] = cr[CMMU_BWP5] =
+ cr[CMMU_BWP6] = cr[CMMU_BWP7] = 0;
+ cr[CMMU_SCR] = CMMU_FLUSH_CACHE_INV_ALL;
+ __asm__ __volatile__ ("|or r0, r0, %0" ::
+ "r" (cr[CMMU_SSR]));
+ cr[CMMU_SCR] = CMMU_FLUSH_SUPER_ALL;
+ cr[CMMU_SCR] = CMMU_FLUSH_USER_ALL;
+ }
+ }
+
+ /*
+ * Enable snooping on MVME188 only.
+ * Snooping is enabled for instruction cmmus as well so that
+ * we can share breakpoints.
+ */
+
+ for (cpu = 0; cpu < max_cpus; cpu++) {
+ if (cpu_sets[cpu] == 0)
+ continue;
+
+ m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu,
+ DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCTR, CMMU_SCTR_SE, MODE_VAL, cpu,
+ INST_CMMU, 0, 0);
+
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL,
+ ACCESS_VAL, cpu, 0, CMMU_ACS_SUPER, 0);
+ m8820x_cmmu_wait(cpu);
+ /* Icache gets flushed just below */
+ }
+
+ /*
+ * Enable instruction cache.
+ * Data cache can not be enabled at this point, because some device
+ * addresses can never be cached, and the no-caching zones are not
+ * set up yet.
+ */
+ for (cpu = 0; cpu < max_cpus; cpu++) {
+ if (cpu_sets[cpu] == 0)
+ continue;
+
+ apr = ((0x00000 << PG_BITS) | CACHE_WT | CACHE_GLOBAL)
+ & ~(CACHE_INH | APR_V);
+
+ m8820x_cmmu_set(CMMU_SAPR, apr, MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_SUPER_ALL,
+ ACCESS_VAL, cpu, 0, CMMU_ACS_SUPER, 0);
+ m8820x_cmmu_wait(cpu);
+ }
+}
+
+/*
+ * Just before poweroff or reset....
+ */
+void
+m8820x_cmmu_shutdown_now()
+{
+ unsigned cmmu_num;
+ unsigned *volatile cr;
+
+ CMMU_LOCK;
+ for (cmmu_num = 0; cmmu_num < MAX_CMMUS; cmmu_num++)
+ if (m8820x_cmmu[cmmu_num].cmmu_alive != CMMU_DEAD) {
+ cr = m8820x_cmmu[cmmu_num].cmmu_regs;
+
+ cr[CMMU_SCTR] &=
+ ~(CMMU_SCTR_PE | CMMU_SCTR_SE | CMMU_SCTR_PR);
+ cr[CMMU_SAPR] = cr[CMMU_UAPR] =
+ ((0x00000 << PG_BITS) | CACHE_INH) &
+ ~(CACHE_WT | CACHE_GLOBAL | APR_V);
+ }
+ CMMU_UNLOCK;
+}
+
+/*
+ * enable parity
+ */
+void
+m8820x_cmmu_parity_enable()
+{
+ unsigned cmmu_num;
+ unsigned *volatile cr;
+
+ CMMU_LOCK;
+
+ for (cmmu_num = 0; cmmu_num < max_cmmus; cmmu_num++)
+ if (m8820x_cmmu[cmmu_num].cmmu_alive != CMMU_DEAD) {
+ cr = m8820x_cmmu[cmmu_num].cmmu_regs;
+ cr[CMMU_SCTR] |= CMMU_SCTR_PE;
+ }
+
+ CMMU_UNLOCK;
+}
+
+/*
+ * Find out the CPU number from accessing CMMU
+ * Better be at splhigh, or even better, with interrupts
+ * disabled.
+ */
+#define ILLADDRESS 0x3ffffff0 /* any faulty address for luna88k2 */
+
+unsigned
+m8820x_cmmu_cpu_number()
+{
+ unsigned cmmu_no;
+ int i, cpu;
+
+ CMMU_LOCK;
+
+ for (i = 0; i < 10; i++) {
+ /* clear CMMU p-bus status registers */
+ for (cmmu_no = 0; cmmu_no < MAX_CMMUS; cmmu_no++) {
+ if (m8820x_cmmu[cmmu_no].cmmu_alive == CMMU_AVAILABLE &&
+ m8820x_cmmu[cmmu_no].cmmu_type == DATA_CMMU)
+ m8820x_cmmu[cmmu_no].cmmu_regs[CMMU_PFSR] = 0;
+ }
+
+ /* access faulting address */
+ badwordaddr((vaddr_t)ILLADDRESS);
+
+ /* check which CMMU reporting the fault */
+ for (cmmu_no = 0; cmmu_no < MAX_CMMUS; cmmu_no++) {
+ if (m8820x_cmmu[cmmu_no].cmmu_alive == CMMU_AVAILABLE &&
+ m8820x_cmmu[cmmu_no].cmmu_type == DATA_CMMU &&
+ CMMU_PFSR_FAULT(m8820x_cmmu[cmmu_no].
+ cmmu_regs[CMMU_PFSR]) != CMMU_PFSR_SUCCESS) {
+ /* clean register, just in case... */
+ m8820x_cmmu[cmmu_no].cmmu_regs[CMMU_PFSR] = 0;
+ m8820x_cmmu[cmmu_no].cmmu_alive = CMMU_MARRIED;
+ cpu = m8820x_cmmu[cmmu_no].cmmu_cpu;
+ CMMU_UNLOCK;
+ return cpu;
+ }
+ }
+ }
+ CMMU_UNLOCK;
+
+ panic("m8820x_cmmu_cpu_number: could not determine my cpu number");
+}
+
+void
+m8820x_cmmu_set_sapr(cpu, ap)
+ unsigned cpu, ap;
+{
+ CMMU_LOCK;
+ m8820x_cmmu_set(CMMU_SAPR, ap, ACCESS_VAL, cpu, 0, CMMU_ACS_SUPER, 0);
+ CMMU_UNLOCK;
+}
+
+void
+m8820x_cmmu_set_uapr(ap)
+ unsigned ap;
+{
+ int s = splhigh();
+ int cpu = cpu_number();
+
+ CMMU_LOCK;
+ /* this functionality also mimiced in m8820x_cmmu_pmap_activate() */
+ m8820x_cmmu_set(CMMU_UAPR, ap, ACCESS_VAL, cpu, 0, CMMU_ACS_USER, 0);
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+/*
+ * Set batc entry number entry_no to value in
+ * the data and instruction cache for the named CPU.
+ *
+ * Except for the cmmu_init, this function and m8820x_cmmu_pmap_activate
+ * are the only functions which may set the batc values.
+ */
+void
+m8820x_cmmu_set_pair_batc_entry(cpu, entry_no, value)
+ unsigned cpu, entry_no;
+ unsigned value; /* the value to stuff into the batc */
+{
+ CMMU_LOCK;
+
+ m8820x_cmmu_set(CMMU_BWP(entry_no), value, MODE_VAL | ACCESS_VAL,
+ cpu, DATA_CMMU, CMMU_ACS_USER, 0);
+#ifdef SHADOW_BATC
+ CMMU(cpu,DATA_CMMU)->batc[entry_no] = value;
+#endif
+ m8820x_cmmu_set(CMMU_BWP(entry_no), value, MODE_VAL | ACCESS_VAL,
+ cpu, INST_CMMU, CMMU_ACS_USER, 0);
+#ifdef SHADOW_BATC
+ CMMU(cpu,INST_CMMU)->batc[entry_no] = value;
+#endif
+
+ CMMU_UNLOCK;
+}
+
+/*
+ * Functions that invalidate TLB entries.
+ */
+
+/*
+ * flush any tlb
+ * Some functionality mimiced in m8820x_cmmu_pmap_activate.
+ */
+void
+m8820x_cmmu_flush_tlb(unsigned cpu, unsigned kernel, vaddr_t vaddr,
+ vsize_t size)
+{
+ int s = splhigh();
+
+ CMMU_LOCK;
+
+ /*
+ * Since segment operations are horribly expensive, don't
+ * do any here. Invalidations of up to three pages are performed
+ * as page invalidations, otherwise the entire tlb is flushed.
+ *
+ * Note that this code relies upon size being a multiple of
+ * a page and vaddr being page-aligned.
+ */
+ if (size == PAGE_SIZE) { /* most frequent situation */
+ m8820x_cmmu_set(CMMU_SAR, vaddr,
+ ADDR_VAL | ACCESS_VAL, cpu, 0,
+ kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr);
+ m8820x_cmmu_set(CMMU_SCR,
+ kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE,
+ ADDR_VAL | ACCESS_VAL, cpu, 0,
+ kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr);
+ } else if (size > 3 * PAGE_SIZE) {
+ m8820x_cmmu_set(CMMU_SCR,
+ kernel ? CMMU_FLUSH_SUPER_ALL : CMMU_FLUSH_USER_ALL,
+ ACCESS_VAL, cpu, 0,
+ kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, 0);
+ } else
+ while (size != 0) {
+ m8820x_cmmu_set(CMMU_SAR, vaddr,
+ ADDR_VAL | ACCESS_VAL, cpu, 0,
+ kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr);
+ m8820x_cmmu_set(CMMU_SCR,
+ kernel ? CMMU_FLUSH_SUPER_PAGE : CMMU_FLUSH_USER_PAGE,
+ ADDR_VAL | ACCESS_VAL, cpu, 0,
+ kernel ? CMMU_ACS_SUPER : CMMU_ACS_USER, vaddr);
+
+ size -= PAGE_SIZE;
+ vaddr += PAGE_SIZE;
+ }
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+/*
+ * New fast stuff for pmap_activate.
+ * Does what a few calls used to do.
+ * Only called from pmap_activate().
+ */
+void
+m8820x_cmmu_pmap_activate(cpu, uapr, i_batc, d_batc)
+ unsigned cpu, uapr;
+ u_int32_t i_batc[BATC_MAX];
+ u_int32_t d_batc[BATC_MAX];
+{
+ int entry_no;
+
+ CMMU_LOCK;
+
+ /* the following is from m8820x_cmmu_set_uapr */
+ m8820x_cmmu_set(CMMU_UAPR, uapr, ACCESS_VAL,
+ cpu, 0, CMMU_ACS_USER, 0);
+
+ for (entry_no = 0; entry_no < BATC_MAX; entry_no++) {
+ m8820x_cmmu_set(CMMU_BWP(entry_no), i_batc[entry_no],
+ MODE_VAL | ACCESS_VAL, cpu, INST_CMMU, CMMU_ACS_USER, 0);
+ m8820x_cmmu_set(CMMU_BWP(entry_no), d_batc[entry_no],
+ MODE_VAL | ACCESS_VAL, cpu, DATA_CMMU, CMMU_ACS_USER, 0);
+#ifdef SHADOW_BATC
+ CMMU(cpu,INST_CMMU)->batc[entry_no] = i_batc[entry_no];
+ CMMU(cpu,DATA_CMMU)->batc[entry_no] = d_batc[entry_no];
+#endif
+ }
+
+ /*
+ * Flush the user TLB.
+ * IF THE KERNEL WILL EVER CARE ABOUT THE BATC ENTRIES,
+ * THE SUPERVISOR TLBs SHOULD BE FLUSHED AS WELL.
+ */
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_USER_ALL, ACCESS_VAL,
+ cpu, 0, CMMU_ACS_USER, 0);
+
+ CMMU_UNLOCK;
+}
+
+/*
+ * Functions that invalidate caches.
+ *
+ * Cache invalidates require physical addresses. Care must be exercised when
+ * using segment invalidates. This implies that the starting physical address
+ * plus the segment length should be invalidated. A typical mistake is to
+ * extract the first physical page of a segment from a virtual address, and
+ * then expecting to invalidate when the pages are not physically contiguous.
+ *
+ * We don't push Instruction Caches prior to invalidate because they are not
+ * snooped and never modified (I guess it doesn't matter then which form
+ * of the command we use then).
+ */
+
+/*
+ * flush both Instruction and Data caches
+ */
+void
+m8820x_cmmu_flush_cache(int cpu, paddr_t physaddr, psize_t size)
+{
+ int s = splhigh();
+ CMMU_LOCK;
+
+#if !defined(BROKEN_MMU_MASK)
+ if (size > NBSG) {
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0,
+ cpu, 0, 0, 0);
+ } else if (size <= MC88200_CACHE_LINE) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL,
+ cpu, 0, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE, ADDR_VAL,
+ cpu, 0, 0, (unsigned)physaddr);
+ } else if (size <= NBPG) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, ADDR_VAL,
+ cpu, 0, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE, ADDR_VAL,
+ cpu, 0, 0, (unsigned)physaddr);
+ } else {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr, 0,
+ cpu, 0, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT, 0,
+ cpu, 0, 0, 0);
+ }
+#else
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, 0,
+ cpu, 0, 0, 0);
+#endif /* !BROKEN_MMU_MASK */
+
+ m8820x_cmmu_wait(cpu);
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+/*
+ * flush Instruction caches
+ */
+void
+m8820x_cmmu_flush_inst_cache(int cpu, paddr_t physaddr, psize_t size)
+{
+ int s = splhigh();
+ CMMU_LOCK;
+
+#if !defined(BROKEN_MMU_MASK)
+ if (size > NBSG) {
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+ } else if (size <= MC88200_CACHE_LINE) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ } else if (size <= NBPG) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ } else {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ }
+#else
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+#endif /* !BROKEN_MMU_MASK */
+
+ m8820x_cmmu_wait(cpu);
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+void
+m8820x_cmmu_flush_data_cache(int cpu, paddr_t physaddr, psize_t size)
+{
+ int s = splhigh();
+ CMMU_LOCK;
+
+#if !defined(BROKEN_MMU_MASK)
+ if (size > NBSG) {
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ } else if (size <= MC88200_CACHE_LINE) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_LINE,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ } else if (size <= NBPG) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_PAGE,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ } else {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_SEGMENT,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ }
+#else
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+#endif /* !BROKEN_MMU_MASK */
+
+ m8820x_cmmu_wait(cpu);
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+/*
+ * sync dcache (and icache too)
+ */
+void
+m8820x_cmmu_sync_cache(paddr_t physaddr, psize_t size)
+{
+ int s = splhigh();
+ int cpu = cpu_number();
+
+ CMMU_LOCK;
+
+#if !defined(BROKEN_MMU_MASK)
+ if (size > NBSG) {
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+ } else if (size <= MC88200_CACHE_LINE) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_LINE,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_LINE,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ } else if (size <= NBPG) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_PAGE,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_PAGE,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ } else {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_SEGMENT,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CB_SEGMENT,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ }
+#else
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CB_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+#endif /* !BROKEN_MMU_MASK */
+
+ m8820x_cmmu_wait(cpu);
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+void
+m8820x_cmmu_sync_inval_cache(paddr_t physaddr, psize_t size)
+{
+ int s = splhigh();
+ int cpu = cpu_number();
+
+ CMMU_LOCK;
+
+#if !defined(BROKEN_MMU_MASK)
+ if (size > NBSG) {
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+ } else if (size <= MC88200_CACHE_LINE) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_LINE,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_LINE,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ } else if (size <= NBPG) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_PAGE,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_PAGE,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ } else {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_SEGMENT,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_CBI_SEGMENT,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ }
+#else
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_CBI_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+#endif /* !BROKEN_MMU_MASK */
+
+ m8820x_cmmu_wait(cpu);
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+void
+m8820x_cmmu_inval_cache(paddr_t physaddr, psize_t size)
+{
+ int s = splhigh();
+ int cpu = cpu_number();
+
+ CMMU_LOCK;
+
+#if !defined(BROKEN_MMU_MASK)
+ if (size > NBSG) {
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+ } else if (size <= MC88200_CACHE_LINE) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_LINE,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_LINE,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ } else if (size <= NBPG) {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_PAGE,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_PAGE,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ } else {
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, INST_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_SEGMENT,
+ MODE_VAL, cpu, INST_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SAR, (unsigned)physaddr,
+ MODE_VAL | ADDR_VAL, cpu, DATA_CMMU, 0, (unsigned)physaddr);
+ m8820x_cmmu_set(CMMU_SAR, CMMU_FLUSH_CACHE_INV_SEGMENT,
+ MODE_VAL, cpu, DATA_CMMU, 0, 0);
+ }
+#else
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL,
+ cpu, DATA_CMMU, 0, 0);
+ m8820x_cmmu_set(CMMU_SCR, CMMU_FLUSH_CACHE_INV_ALL, MODE_VAL,
+ cpu, INST_CMMU, 0, 0);
+#endif /* !BROKEN_MMU_MASK */
+
+ m8820x_cmmu_wait(cpu);
+
+ CMMU_UNLOCK;
+ splx(s);
+}
+
+void
+m8820x_dma_cachectl(vaddr_t va, vsize_t size, int op)
+{
+ paddr_t pa;
+#if !defined(BROKEN_MMU_MASK)
+ psize_t count;
+
+ while (size != 0) {
+ count = NBPG - (va & PGOFSET);
+
+ if (size < count)
+ count = size;
+
+ if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) {
+ switch (op) {
+ case DMA_CACHE_SYNC:
+ m8820x_cmmu_sync_cache(pa, count);
+ break;
+ case DMA_CACHE_SYNC_INVAL:
+ m8820x_cmmu_sync_inval_cache(pa, count);
+ break;
+ default:
+ m8820x_cmmu_inval_cache(pa, count);
+ break;
+ }
+ }
+
+ va += count;
+ size -= count;
+ }
+#else
+ /* XXX This assumes the space is also physically contiguous */
+ if (pmap_extract(pmap_kernel(), va, &pa) != FALSE) {
+ switch (op) {
+ case DMA_CACHE_SYNC:
+ m8820x_cmmu_sync_cache(pa, size);
+ break;
+ case DMA_CACHE_SYNC_INVAL:
+ m8820x_cmmu_sync_inval_cache(pa, size);
+ break;
+ default:
+ m8820x_cmmu_inval_cache(pa, size);
+ break;
+ }
+ }
+#endif /* !BROKEN_MMU_MASK */
+}
+
+#ifdef DDB
+union ssr {
+ unsigned bits;
+ struct {
+ unsigned :16,
+ ce:1,
+ be:1,
+ :4,
+ wt:1,
+ sp:1,
+ g:1,
+ ci:1,
+ :1,
+ m:1,
+ u:1,
+ wp:1,
+ bh:1,
+ v:1;
+ } field;
+};
+
+union cssp {
+ unsigned bits;
+ struct {
+ unsigned : 2,
+ l: 6,
+ d3: 1,
+ d2: 1,
+ d1: 1,
+ d0: 1,
+ vv3: 2,
+ vv2: 2,
+ vv1: 2,
+ vv0: 2,
+ :12;
+ } field;
+};
+
+union batcu {
+ unsigned bits;
+ struct { /* block address translation register */
+ unsigned int
+ lba:13, /* logical block address */
+ pba:13, /* physical block address */
+ s:1, /* supervisor */
+ wt:4, /* write through */
+ g:1, /* global */
+ ci:1, /* cache inhibit */
+ wp:1, /* write protect */
+ v:1; /* valid */
+ } field;
+};
+
+ #define VV_EX_UNMOD 0
+ #define VV_EX_MOD 1
+ #define VV_SHARED_UNMOD 2
+ #define VV_INVALID 3
+
+ #define D(UNION, LINE) \
+ ((LINE) == 3 ? (UNION).field.d3 : \
+ ((LINE) == 2 ? (UNION).field.d2 : \
+ ((LINE) == 1 ? (UNION).field.d1 : \
+ ((LINE) == 0 ? (UNION).field.d0 : ~0))))
+ #define VV(UNION, LINE) \
+ ((LINE) == 3 ? (UNION).field.vv3 : \
+ ((LINE) == 2 ? (UNION).field.vv2 : \
+ ((LINE) == 1 ? (UNION).field.vv1 : \
+ ((LINE) == 0 ? (UNION).field.vv0 : ~0))))
+
+ #undef VEQR_ADDR
+ #define VEQR_ADDR 0
+/*
+ * Show (for debugging) how the given CMMU translates the given ADDRESS.
+ * If cmmu == -1, the data cmmu for the current cpu is used.
+ */
+void
+m8820x_cmmu_show_translation(address, supervisor_flag, verbose_flag, cmmu_num)
+ unsigned address, supervisor_flag, verbose_flag;
+ int cmmu_num;
+{
+ /*
+ * A virtual address is split into three fields. Two are used as
+ * indicies into tables (segment and page), and one is an offset into
+ * a page of memory.
+ */
+ union {
+ unsigned bits;
+ struct {
+ unsigned segment_table_index:SDT_BITS,
+ page_table_index:PDT_BITS,
+ page_offset:PG_BITS;
+ } field;
+ } virtual_address;
+ u_int32_t value;
+
+ if (verbose_flag)
+ db_printf("-------------------------------------------\n");
+
+
+
+ /****** ACCESS PROPER CMMU or THREAD ***********/
+ if (cmmu_num == -1) {
+ int cpu = cpu_number();
+ if (cpu_cmmu[cpu].pair[DATA_CMMU] == 0) {
+ db_printf("ack! can't figure my own data cmmu number.\n");
+ return;
+ }
+ cmmu_num = cpu_cmmu[cpu].pair[DATA_CMMU] - m8820x_cmmu;
+ if (verbose_flag)
+ db_printf("The data cmmu for cpu#%d is cmmu#%d.\n",
+ 0, cmmu_num);
+ } else if (cmmu_num < 0 || cmmu_num >= MAX_CMMUS) {
+ db_printf("invalid cpu number [%d]... must be in range [0..%d]\n",
+ cmmu_num, MAX_CMMUS - 1);
+
+ return;
+ }
+
+ if (m8820x_cmmu[cmmu_num].cmmu_alive == CMMU_DEAD) {
+ db_printf("warning: cmmu %d is not alive.\n", cmmu_num);
+#if 0
+ return;
+#endif
+ }
+
+ if (!verbose_flag) {
+ if (!(m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE))
+ db_printf("WARNING: snooping not enabled for CMMU#%d.\n",
+ cmmu_num);
+ } else {
+ int i;
+ for (i = 0; i < MAX_CMMUS; i++)
+ if ((i == cmmu_num || m8820x_cmmu[i].cmmu_alive != CMMU_DEAD) &&
+ (verbose_flag > 1 || !(m8820x_cmmu[i].cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE))) {
+ db_printf("CMMU#%d (cpu %d %s) snooping %s\n", i,
+ m8820x_cmmu[i].cmmu_cpu, m8820x_cmmu[i].cmmu_type ? "data" : "inst",
+ (m8820x_cmmu[i].cmmu_regs[CMMU_SCTR] & CMMU_SCTR_SE) ? "on":"OFF");
+ }
+ }
+
+ if (supervisor_flag)
+ value = m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_SAPR];
+ else
+ value = m8820x_cmmu[cmmu_num].cmmu_regs[CMMU_UAPR];
+
+#ifdef SHADOW_BATC
+ {
+ int i;
+ union batcu batc;
+ for (i = 0; i < 8; i++) {
+ batc.bits = m8820x_cmmu[cmmu_num].batc[i];
+ if (batc.field.v == 0) {
+ if (verbose_flag>1)
+ db_printf("cmmu #%d batc[%d] invalid.\n", cmmu_num, i);
+ } else {
+ db_printf("cmmu#%d batc[%d] v%08x p%08x", cmmu_num, i,
+ batc.field.lba << 18, batc.field.pba);
+ if (batc.field.s) db_printf(", supervisor");
+ if (batc.field.wt) db_printf(", wt.th");
+ if (batc.field.g) db_printf(", global");
+ if (batc.field.ci) db_printf(", cache inhibit");
+ if (batc.field.wp) db_printf(", write protect");
+ }
+ }
+ }
+#endif /* SHADOW_BATC */
+
+ /******* SEE WHAT A PROBE SAYS (if not a thread) ***********/
+ {
+ union ssr ssr;
+ unsigned *volatile cmmu_regs = m8820x_cmmu[cmmu_num].cmmu_regs;
+ cmmu_regs[CMMU_SAR] = address;
+ cmmu_regs[CMMU_SCR] = supervisor_flag ? CMMU_PROBE_SUPER : CMMU_PROBE_USER;
+ ssr.bits = cmmu_regs[CMMU_SSR];
+ if (verbose_flag > 1)
+ db_printf("probe of 0x%08x returns ssr=0x%08x\n",
+ address, ssr.bits);
+ if (ssr.field.v)
+ db_printf("PROBE of 0x%08x returns phys=0x%x",
+ address, cmmu_regs[CMMU_SAR]);
+ else
+ db_printf("PROBE fault at 0x%x", cmmu_regs[CMMU_PFAR]);
+ if (ssr.field.ce) db_printf(", copyback err");
+ if (ssr.field.be) db_printf(", bus err");
+ if (ssr.field.wt) db_printf(", writethrough");
+ if (ssr.field.sp) db_printf(", sup prot");
+ if (ssr.field.g) db_printf(", global");
+ if (ssr.field.ci) db_printf(", cache inhibit");
+ if (ssr.field.m) db_printf(", modified");
+ if (ssr.field.u) db_printf(", used");
+ if (ssr.field.wp) db_printf(", write prot");
+ if (ssr.field.bh) db_printf(", BATC");
+ db_printf(".\n");
+ }
+
+ /******* INTERPRET AREA DESCRIPTOR *********/
+ {
+ if (verbose_flag > 1) {
+ db_printf("CMMU#%d", cmmu_num);
+ db_printf(" %cAPR is 0x%08x\n",
+ supervisor_flag ? 'S' : 'U', value);
+ }
+ db_printf("CMMU#%d", cmmu_num);
+ db_printf(" %cAPR: SegTbl: 0x%x000p",
+ supervisor_flag ? 'S' : 'U', PG_PFNUM(value));
+ if (value & CACHE_WT)
+ db_printf(", WTHRU");
+ if (value & CACHE_GLOBAL)
+ db_printf(", GLOBAL");
+ if (value & CACHE_INH)
+ db_printf(", INHIBIT");
+ if (value & APR_V)
+ db_printf(", VALID");
+ db_printf("\n");
+
+ /* if not valid, done now */
+ if ((value & APR_V) == 0) {
+ db_printf("<would report an error, valid bit not set>\n");
+
+ return;
+ }
+
+ value &= PG_FRAME; /* now point to seg page */
+ }
+
+ /* translate value from physical to virtual */
+ if (verbose_flag)
+ db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR);
+ value += VEQR_ADDR;
+
+ virtual_address.bits = address;
+
+ /****** ACCESS SEGMENT TABLE AND INTERPRET SEGMENT DESCRIPTOR *******/
+ {
+ sdt_entry_t sdt;
+ if (verbose_flag)
+ db_printf("will follow to entry %d of page at 0x%x...\n",
+ virtual_address.field.segment_table_index, value);
+ value |= virtual_address.field.segment_table_index *
+ sizeof(sdt_entry_t);
+
+ if (badwordaddr((vaddr_t)value)) {
+ db_printf("ERROR: unable to access page at 0x%08x.\n", value);
+ return;
+ }
+
+ sdt = *(sdt_entry_t *)value;
+ if (verbose_flag > 1)
+ db_printf("SEG DESC @0x%x is 0x%08x\n", value, sdt);
+ db_printf("SEG DESC @0x%x: PgTbl: 0x%x000",
+ value, PG_PFNUM(sdt));
+ if (sdt & CACHE_WT) db_printf(", WTHRU");
+ else db_printf(", !wthru");
+ if (sdt & SG_SO) db_printf(", S-PROT");
+ else db_printf(", UserOk");
+ if (sdt & CACHE_GLOBAL) db_printf(", GLOBAL");
+ else db_printf(", !global");
+ if (sdt & CACHE_INH) db_printf(", $INHIBIT");
+ else db_printf(", $ok");
+ if (sdt & SG_PROT) db_printf(", W-PROT");
+ else db_printf(", WriteOk");
+ if (sdt & SG_V) db_printf(", VALID");
+ else db_printf(", !valid");
+ db_printf(".\n");
+
+ /* if not valid, done now */
+ if (!(sdt & SG_V)) {
+ db_printf("<would report an error, STD entry not valid>\n");
+ return;
+ }
+
+ value = ptoa(PG_PFNUM(sdt));
+ }
+
+ /* translate value from physical to virtual */
+ if (verbose_flag)
+ db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR);
+ value += VEQR_ADDR;
+
+ /******* PAGE TABLE *********/
+ {
+ pt_entry_t pte;
+ if (verbose_flag)
+ db_printf("will follow to entry %d of page at 0x%x...\n",
+ virtual_address.field.page_table_index, value);
+ value |= virtual_address.field.page_table_index *
+ sizeof(pt_entry_t);
+
+ if (badwordaddr((vaddr_t)value)) {
+ db_printf("error: unable to access page at 0x%08x.\n", value);
+
+ return;
+ }
+
+ pte = *(pt_entry_t *)value;
+ if (verbose_flag > 1)
+ db_printf("PAGE DESC @0x%x is 0x%08x.\n", value, pte);
+ db_printf("PAGE DESC @0x%x: page @%x000",
+ value, PG_PFNUM(pte));
+ if (pte & PG_W) db_printf(", WIRE");
+ else db_printf(", !wire");
+ if (pte & CACHE_WT) db_printf(", WTHRU");
+ else db_printf(", !wthru");
+ if (pte & PG_SO) db_printf(", S-PROT");
+ else db_printf(", UserOk");
+ if (pte & CACHE_GLOBAL) db_printf(", GLOBAL");
+ else db_printf(", !global");
+ if (pte & CACHE_INH) db_printf(", $INHIBIT");
+ else db_printf(", $ok");
+ if (pte & PG_M) db_printf(", MOD");
+ else db_printf(", !mod");
+ if (pte & PG_U) db_printf(", USED");
+ else db_printf(", !used");
+ if (pte & PG_PROT) db_printf(", W-PROT");
+ else db_printf(", WriteOk");
+ if (pte & PG_V) db_printf(", VALID");
+ else db_printf(", !valid");
+ db_printf(".\n");
+
+ /* if not valid, done now */
+ if (!(pte & PG_V)) {
+ db_printf("<would report an error, PTE entry not valid>\n");
+ return;
+ }
+
+ value = ptoa(PG_PFNUM(pte));
+ if (verbose_flag)
+ db_printf("will follow to byte %d of page at 0x%x...\n",
+ virtual_address.field.page_offset, value);
+ value |= virtual_address.field.page_offset;
+
+ if (badwordaddr((vaddr_t)value)) {
+ db_printf("error: unable to access page at 0x%08x.\n", value);
+ return;
+ }
+ }
+
+ /* translate value from physical to virtual */
+ if (verbose_flag)
+ db_printf("[%x physical is %x virtual]\n", value, value + VEQR_ADDR);
+ value += VEQR_ADDR;
+
+ db_printf("WORD at 0x%x is 0x%08x.\n", value, *(unsigned *)value);
+
+}
+#endif /* DDB */
diff --git a/sys/arch/luna88k/luna88k/machdep.c b/sys/arch/luna88k/luna88k/machdep.c
new file mode 100644
index 00000000000..677d1f15a1b
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/machdep.c
@@ -0,0 +1,1840 @@
+/* $OpenBSD: machdep.c,v 1.1 2004/04/21 15:24:08 aoyama Exp $ */
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/buf.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/msgbuf.h>
+#include <sys/syscallargs.h>
+#ifdef SYSVMSG
+#include <sys/msg.h>
+#endif
+#include <sys/exec.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/extent.h>
+#include <sys/core.h>
+#include <sys/kcore.h>
+
+#include <net/netisr.h>
+
+#include <machine/asm_macro.h> /* enable/disable interrupts */
+#include <machine/mmu.h>
+#include <machine/board.h>
+#include <machine/cmmu.h> /* CMMU stuff */
+#include <machine/cpu.h>
+#include <machine/cpu_number.h>
+#include <machine/kcore.h>
+#include <machine/locore.h>
+#include <machine/reg.h>
+#include <machine/trap.h>
+#include <machine/m88100.h> /* DMT_VALID */
+
+#include <luna88k/luna88k/isr.h>
+
+#include <dev/cons.h>
+
+#include <uvm/uvm_extern.h>
+
+#include "ksyms.h"
+#if DDB
+#include <machine/db_machdep.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_output.h> /* db_printf() */
+#endif /* DDB */
+
+#if DDB
+#define DEBUG_MSG db_printf
+#else
+#define DEBUG_MSG printf
+#endif /* DDB */
+
+vaddr_t interrupt_stack[MAX_CPUS];
+
+/* machine dependent function pointers. */
+struct md_p md;
+
+/* prototypes */
+void regdump(struct trapframe *f);
+void dumpsys(void);
+void consinit(void);
+vaddr_t size_memory(void);
+int getcpuspeed(void);
+void identifycpu(void);
+void save_u_area(struct proc *, vaddr_t);
+void load_u_area(struct proc *);
+void dumpconf(void);
+void luna88k_ext_int(u_int v, struct trapframe *eframe);
+void powerdown(void);
+
+/*
+ * *int_mask_reg[CPU]
+ * Points to the hardware interrupt status register for each CPU.
+ */
+unsigned int *volatile int_mask_reg[MAX_CPUS] = {
+ (unsigned int *)INT_ST_MASK0,
+ (unsigned int *)INT_ST_MASK1,
+ (unsigned int *)INT_ST_MASK2,
+ (unsigned int *)INT_ST_MASK3
+};
+
+/*
+ * *clock_reg[CPU]
+ */
+unsigned int *volatile clock_reg[MAX_CPUS] = {
+ (unsigned int *)OBIO_CLOCK0,
+ (unsigned int *)OBIO_CLOCK1,
+ (unsigned int *)OBIO_CLOCK2,
+ (unsigned int *)OBIO_CLOCK3
+};
+
+volatile vaddr_t obiova;
+
+int ssir;
+int want_ast;
+int want_resched;
+
+int physmem; /* available physical memory, in pages */
+int longformat = 1; /* for regdump() */
+/*
+ * safepri is a safe priority for sleep to set for a spin-wait
+ * during autoconfiguration or after a panic.
+ */
+int safepri = IPL_NONE;
+
+struct vm_map *exec_map = NULL;
+struct vm_map *phys_map = NULL;
+
+/*
+ * iomap stuff is for managing chunks of virtual address space that
+ * can be allocated to IO devices.
+ * VMEbus drivers use this at this now. Only on-board IO devices' addresses
+ * are mapped so that pa == va. XXX smurph.
+ */
+
+vaddr_t iomapbase;
+
+struct extent *iomap_extent;
+struct vm_map *iomap_map;
+
+/*
+ * Declare these as initialized data so we can patch them.
+ */
+#ifdef NBUF
+int nbuf = NBUF;
+#else
+int nbuf = 0;
+#endif
+
+#ifndef BUFCACHEPERCENT
+#define BUFCACHEPERCENT 5
+#endif
+
+#ifdef BUFPAGES
+int bufpages = BUFPAGES;
+#else
+int bufpages = 0;
+#endif
+int bufcachepercent = BUFCACHEPERCENT;
+
+caddr_t allocsys(caddr_t);
+
+/*
+ * Info for CTL_HW
+ */
+char machine[] = MACHINE; /* cpu "architecture" */
+char cpu_model[120];
+
+#if defined(DDB) || NKSYMS > 0
+extern char *esym;
+#endif
+
+int machtype = LUNA_88K2; /* XXX: aoyama */
+int cputyp = CPU_88100; /* XXX: aoyama */
+int boothowto = RB_ASKNAME; /* XXX: should be set in boot loader and locore.S */
+int bootdev; /* XXX: should be set in boot loader and locore.S */
+int cpuspeed;
+double cycles_per_microsecond; /* used in locore.S:delay() */
+int sysconsole = 1; /* 0 = ttya, 1 = keyboard/mouse, used in dev/sio.c */
+u_int16_t dipswitch = 0; /* set in locore.S */
+int hwplanemask; /* set in luna88k_bootstrap() */
+
+int netisr;
+
+extern char *etext;
+extern char *edata;
+extern char *end;
+extern struct consdev syscons; /* in dev/siotty.c */
+
+extern void greeting(void); /* in dev/lcd.c */
+extern void syscnattach(int); /* in dev/siotty.c */
+extern int omfb_cnattach(void); /* in dev/lunafb.c */
+extern void ws_cnattach(void); /* in dev/lunaws.c */
+
+vaddr_t first_addr = 0;
+vaddr_t last_addr = 0;
+
+vaddr_t avail_start, avail_end;
+vaddr_t virtual_avail, virtual_end;
+
+extern struct pcb *curpcb;
+extern struct user *proc0paddr;
+
+/*
+ * This is to fake out the console routines, while booting.
+ * We could use directly the romtty console, but we want to be able to
+ * configure a kernel without romtty since we do not necessarily need a
+ * full-blown console driver.
+ */
+void romttycnprobe(struct consdev *);
+void romttycninit(struct consdev *);
+void romttycnputc(dev_t, int);
+int romttycngetc(dev_t);
+extern void nullcnpollc(dev_t, int);
+
+struct consdev romttycons = {
+ NULL,
+ NULL,
+ romttycngetc,
+ romttycnputc,
+ nullcnpollc,
+ NULL,
+ makedev(14,0),
+ CN_NORMAL,
+};
+
+/*
+ * Early console initialization: called early on from main, before vm init.
+ */
+void
+consinit()
+{
+#ifdef ROM_CONSOLE
+ extern struct consdev *cn_tab;
+#endif
+ /*
+ * Initialize the console before we print anything out.
+ */
+#ifdef ROM_CONSOLE
+ cn_tab = &romttycons;
+ /* cninit(); */
+#else /* from NetBSD/luna68k */
+ if (sysconsole == 0) {
+ syscnattach(0);
+ } else {
+ omfb_cnattach();
+ ws_cnattach();
+ }
+ /* cninit(); */ /* XXX: this should be later? */
+#endif
+
+#if defined(DDB)
+ db_machine_init();
+ ddb_init();
+ if (boothowto & RB_KDB)
+ Debugger();
+#endif
+}
+
+/*
+ * Figure out how much real memory is available.
+ * Start looking from the megabyte after the end of the kernel data,
+ * until we find non-memory.
+ */
+vaddr_t
+size_memory()
+{
+ unsigned int *volatile look;
+ unsigned int *max;
+#if 0
+ extern char *end;
+#endif
+#define PATTERN 0x5a5a5a5a
+#define STRIDE (4*1024) /* 4k at a time */
+#define Roundup(value, stride) (((unsigned)(value) + (stride) - 1) & ~((stride)-1))
+ /*
+ * count it up.
+ */
+ max = (void *)MAXPHYSMEM;
+#if 0
+ for (look = (void *)Roundup(end, STRIDE); look < max;
+#else
+ for (look = (void *)first_addr; look < max;
+#endif
+ look = (int *)((unsigned)look + STRIDE)) {
+ unsigned save;
+
+ /* if can't access, we've reached the end */
+ if (badwordaddr((vaddr_t)look)) {
+#if defined(DEBUG)
+ printf("%x\n", look);
+#endif
+ look = (int *)((int)look - STRIDE);
+ break;
+ }
+
+ /*
+ * If we write a value, we expect to read the same value back.
+ * We'll do this twice, the 2nd time with the opposite bit
+ * pattern from the first, to make sure we check all bits.
+ */
+ save = *look;
+ if (*look = PATTERN, *look != PATTERN)
+ break;
+ if (*look = ~PATTERN, *look != ~PATTERN)
+ break;
+ *look = save;
+ }
+
+ return (trunc_page((unsigned)look));
+}
+
+int
+getcpuspeed()
+{
+ double clock_mhz;
+
+ switch(machtype) {
+ case LUNA_88K:
+ clock_mhz = 25.0;
+ break;
+ case LUNA_88K2:
+ clock_mhz = 33.0;
+ break;
+ default:
+ panic("getcpuspeed: can not determine CPU speed");
+ break;
+ }
+
+ cycles_per_microsecond = clock_mhz;
+ return (int)clock_mhz;
+}
+
+void
+identifycpu()
+{
+ cpuspeed = getcpuspeed();
+ snprintf(cpu_model, sizeof cpu_model,
+ "OMRON LUNA-88K%s, %dMHz",
+ machtype == LUNA_88K2 ? "2" : "", cpuspeed);
+}
+
+/*
+ * Setup u area ptes for u area double mapping.
+ */
+
+void
+save_u_area(struct proc *p, vaddr_t va)
+{
+ int i;
+
+ for (i = 0; i < UPAGES; i++) {
+ p->p_md.md_upte[i] = *((pt_entry_t *)kvtopte(va));
+ va += NBPG;
+ }
+}
+
+void
+load_u_area(struct proc *p)
+{
+ int i;
+ vaddr_t va;
+ pt_entry_t *t;
+
+ for (i = 0, va = UADDR; i < UPAGES; i++) {
+ t = kvtopte(va);
+ *t = p->p_md.md_upte[i];
+ va += NBPG;
+ }
+ cmmu_flush_tlb(cpu_number(), 1, UADDR, USPACE);
+}
+
+void
+cpu_startup()
+{
+ caddr_t v;
+ int sz, i;
+ vsize_t size;
+ int base, residual;
+ vaddr_t minaddr, maxaddr, uarea_pages;
+
+ /*
+ * Initialize error message buffer (at end of core).
+ * avail_end was pre-decremented in mvme_bootstrap() to compensate.
+ */
+ for (i = 0; i < btoc(MSGBUFSIZE); i++)
+ pmap_kenter_pa((paddr_t)msgbufp + i * NBPG,
+ avail_end + i * NBPG, VM_PROT_READ | VM_PROT_WRITE);
+ pmap_update(pmap_kernel());
+ initmsgbuf((caddr_t)msgbufp, round_page(MSGBUFSIZE));
+
+ /*
+ * Good {morning,afternoon,evening,night}.
+ */
+ printf(version);
+ identifycpu();
+ printf("real mem = %d\n", ctob(physmem));
+
+ /*
+ * Check front DIP switch setting
+ */
+ printf("dipsw = 0x%x\n", dipswitch);
+
+ /* Check DIP switch 1 - 1 */
+ if ((0x8000 & dipswitch) == 0) {
+ boothowto |= RB_SINGLE;
+ }
+
+ /* Check DIP switch 1 - 3 */
+ if ((0x2000 & dipswitch) == 0) {
+ boothowto |= RB_ASKNAME;
+ }
+
+ /* Check DIP switch 1 - 4 */
+ if ((0x1000 & dipswitch) == 0) {
+ boothowto |= RB_CONFIG;
+ }
+
+ /*
+ * Get frame buffer depth from ROM work area.
+ */
+ {
+ int depth;
+
+ depth = *((volatile int *)0x00001114);
+ printf("frame buffer depth = %d\n", depth);
+ switch (depth) {
+ case 1:
+ hwplanemask = 0x01;
+ break;
+ case 4:
+ hwplanemask = 0x0f;
+ break;
+ case 8:
+ hwplanemask = 0xff;
+ break;
+ default:
+ hwplanemask = 0; /* No frame buffer */
+ break;
+ }
+ }
+
+#if 0 /* just for test */
+ /*
+ * Get boot arguments
+ */
+ {
+ char buf[256];
+ char **p = (volatile char **)0x00001120;
+
+ strncpy(buf, *p, 256);
+ if (buf[255] != '\0')
+ buf[255] = '\0';
+
+ printf("boot arg: (0x%x) %s\n", *p, buf);
+ }
+#endif
+
+ /*
+ * Find out how much space we need, allocate it,
+ * and then give everything true virtual addresses.
+ */
+ sz = (int)allocsys((caddr_t)0);
+
+ if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0)
+ panic("startup: no room for tables");
+ if (allocsys(v) - v != sz)
+ panic("startup: table size inconsistency");
+
+ /*
+ * Grab UADDR virtual address
+ */
+ uarea_pages = UADDR;
+ uvm_map(kernel_map, (vaddr_t *)&uarea_pages, USPACE,
+ NULL, UVM_UNKNOWN_OFFSET, 0,
+ UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
+ UVM_ADV_NORMAL, 0));
+ if (uarea_pages != UADDR)
+ panic("uarea_pages %lx: UADDR not free", uarea_pages);
+
+ /*
+ * Grab the OBIO space that we hardwired in pmap_bootstrap
+ */
+ obiova = OBIO_START;
+ uvm_map(kernel_map, (vaddr_t *)&obiova, OBIO_SIZE,
+ NULL, UVM_UNKNOWN_OFFSET, 0,
+ UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
+ UVM_ADV_NORMAL, 0));
+ if (obiova != OBIO_START)
+ panic("obiova %lx: OBIO not free", obiova);
+
+ /*
+ * Now allocate buffers proper. They are different than the above
+ * in that they usually occupy more virtual memory than physical.
+ */
+ size = MAXBSIZE * nbuf;
+ if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size),
+ NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_NONE,
+ UVM_PROT_NONE, UVM_INH_NONE, UVM_ADV_NORMAL, 0)))
+ panic("cpu_startup: cannot allocate VM for buffers");
+ minaddr = (vaddr_t)buffers;
+
+ if ((bufpages / nbuf) >= btoc(MAXBSIZE)) {
+ /* don't want to alloc more physical mem than needed */
+ bufpages = btoc(MAXBSIZE) * nbuf;
+ }
+ base = bufpages / nbuf;
+ residual = bufpages % nbuf;
+
+ for (i = 0; i < nbuf; i++) {
+ vsize_t curbufsize;
+ vaddr_t curbuf;
+ struct vm_page *pg;
+
+ /*
+ * Each buffer has MAXBSIZE bytes of VM space allocated. Of
+ * that MAXBSIZE space, we allocate and map (base+1) pages
+ * for the first "residual" buffers, and then we allocate
+ * "base" pages for the rest.
+ */
+ curbuf = (vaddr_t)buffers + (i * MAXBSIZE);
+ curbufsize = PAGE_SIZE * ((i < residual) ? (base+1) : base);
+
+ while (curbufsize) {
+ pg = uvm_pagealloc(NULL, 0, NULL, 0);
+ if (pg == NULL)
+ panic("cpu_startup: not enough memory for "
+ "buffer cache");
+ pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
+ VM_PROT_READ | VM_PROT_WRITE);
+ curbuf += PAGE_SIZE;
+ curbufsize -= PAGE_SIZE;
+ }
+ }
+ pmap_update(pmap_kernel());
+
+ /*
+ * Allocate a submap for exec arguments. This map effectively
+ * limits the number of processes exec'ing at any time.
+ */
+ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
+ 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
+
+ /*
+ * Allocate map for physio.
+ */
+ phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, 0, FALSE, NULL);
+
+ printf("avail mem = %ld (%d pages)\n", ptoa(uvmexp.free), uvmexp.free);
+ printf("using %d buffers containing %d bytes of memory\n", nbuf,
+ bufpages * PAGE_SIZE);
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ /*
+ * Initialize the autovectored interrupt list.
+ */
+ isrinit();
+
+ /*
+ * Configure the system.
+ */
+ if (boothowto & RB_CONFIG) {
+#ifdef BOOT_CONFIG
+ user_config();
+#else
+ printf("kernel does not support -c; continuing..\n");
+#endif
+ }
+
+ /*
+ * Say hello to the world on LCD.
+ */
+ greeting();
+}
+
+/*
+ * Allocate space for system data structures. We are given
+ * a starting virtual address and we return a final virtual
+ * address; along the way we set each data structure pointer.
+ *
+ * We call allocsys() with 0 to find out how much space we want,
+ * allocate that much and fill it with zeroes, and then call
+ * allocsys() again with the correct base virtual address.
+ */
+caddr_t
+allocsys(v)
+ caddr_t v;
+{
+
+#define valloc(name, type, num) \
+ v = (caddr_t)(((name) = (type *)v) + (num))
+
+#ifdef SYSVMSG
+ valloc(msgpool, char, msginfo.msgmax);
+ valloc(msgmaps, struct msgmap, msginfo.msgseg);
+ valloc(msghdrs, struct msg, msginfo.msgtql);
+ valloc(msqids, struct msqid_ds, msginfo.msgmni);
+#endif
+
+ /*
+ * Determine how many buffers to allocate. We use 10% of the
+ * first 2MB of memory, and 5% of the rest, with a minimum of 16
+ * buffers. We allocate 1/2 as many swap buffer headers as file
+ * i/o buffers.
+ */
+ if (bufpages == 0) {
+ if (physmem < btoc(2 * 1024 * 1024))
+ bufpages = physmem / 10;
+ else
+ bufpages = (btoc(2 * 1024 * 1024) + physmem) *
+ bufcachepercent / 100;
+ }
+ if (nbuf == 0) {
+ nbuf = bufpages;
+ if (nbuf < 16)
+ nbuf = 16;
+ }
+
+ /* Restrict to at most 70% filled kvm */
+ if (nbuf >
+ (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / MAXBSIZE * 7 / 10)
+ nbuf = (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) /
+ MAXBSIZE * 7 / 10;
+
+ /* More buffer pages than fits into the buffers is senseless. */
+ if (bufpages > nbuf * MAXBSIZE / PAGE_SIZE)
+ bufpages = nbuf * MAXBSIZE / PAGE_SIZE;
+
+ valloc(buf, struct buf, nbuf);
+
+ return v;
+}
+
+/*
+ * Set registers on exec.
+ * Clear all except sp and pc.
+ */
+void
+setregs(p, pack, stack, retval)
+ struct proc *p;
+ struct exec_package *pack;
+ u_long stack;
+ int retval[2];
+{
+ struct trapframe *tf = (struct trapframe *)USER_REGS(p);
+
+ /*
+ * The syscall will ``return'' to snip; set it.
+ * argc, argv, envp are placed on the stack by copyregs.
+ * Point r2 to the stack. crt0 should extract envp from
+ * argc & argv before calling user's main.
+ */
+#if 0
+ /*
+ * I don't think I need to mess with fpstate on 88k because
+ * we make sure the floating point pipeline is drained in
+ * the trap handlers. Should check on this later. XXX Nivas.
+ */
+
+ if ((fs = p->p_md.md_fpstate) != NULL) {
+ /*
+ * We hold an FPU state. If we own *the* FPU chip state
+ * we must get rid of it, and the only way to do that is
+ * to save it. In any case, get rid of our FPU state.
+ */
+ if (p == fpproc) {
+ savefpstate(fs);
+ fpproc = NULL;
+ }
+ free((void *)fs, M_SUBPROC);
+ p->p_md.md_fpstate = NULL;
+ }
+#endif /* 0 */
+ bzero((caddr_t)tf, sizeof *tf);
+
+ if (cputyp == CPU_88110) {
+ /*
+ * user mode, serialize mem, interrupts enabled,
+ * graphics unit, fp enabled
+ */
+ tf->tf_epsr = PSR_SRM | PSR_SFD;
+ /*
+ * XXX disable OoO for now...
+ */
+ tf->tf_epsr |= PSR_SER;
+ } else {
+ /*
+ * user mode, interrupts enabled,
+ * no graphics unit, fp enabled
+ */
+ tf->tf_epsr = PSR_SFD | PSR_SFD2;
+ }
+
+ /*
+ * We want to start executing at pack->ep_entry. The way to
+ * do this is force the processor to fetch from ep_entry. Set
+ * NIP to something bogus and invalid so that it will be a NOOP.
+ * And set sfip to ep_entry with valid bit on so that it will be
+ * fetched. mc88110 - just set exip to pack->ep_entry.
+ */
+ if (cputyp == CPU_88110) {
+ tf->tf_exip = pack->ep_entry & ~3;
+#ifdef DEBUG
+ printf("exec @ 0x%x\n", tf->tf_exip);
+#endif
+ } else {
+ tf->tf_snip = pack->ep_entry & ~3;
+ tf->tf_sfip = (pack->ep_entry & ~3) | FIP_V;
+ }
+ tf->tf_r[2] = stack;
+ tf->tf_r[31] = stack;
+ retval[1] = 0;
+}
+
+struct sigstate {
+ int ss_flags; /* which of the following are valid */
+ struct trapframe ss_frame; /* original exception frame */
+};
+
+/*
+ * WARNING: code in locore.s assumes the layout shown for sf_signo
+ * through sf_handler so... don't screw with them!
+ */
+struct sigframe {
+ int sf_signo; /* signo for handler */
+ siginfo_t * sf_sip;
+ struct sigcontext * sf_scp; /* context ptr for handler */
+ sig_t sf_handler; /* handler addr for u_sigc */
+ struct sigcontext sf_sc; /* actual context */
+ siginfo_t sf_si;
+};
+
+#ifdef DEBUG
+int sigdebug = 0;
+int sigpid = 0;
+ #define SDB_FOLLOW 0x01
+ #define SDB_KSTACK 0x02
+ #define SDB_FPSTATE 0x04
+#endif
+
+/*
+ * Send an interrupt to process.
+ */
+void
+sendsig(catcher, sig, mask, code, type, val)
+ sig_t catcher;
+ int sig, mask;
+ unsigned long code;
+ int type;
+ union sigval val;
+{
+ struct proc *p = curproc;
+ struct trapframe *tf;
+ struct sigacts *psp = p->p_sigacts;
+ struct sigframe *fp;
+ int oonstack, fsize;
+ struct sigframe sf;
+ int addr;
+
+ tf = p->p_md.md_tf;
+ oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
+ /*
+ * Allocate and validate space for the signal handler
+ * context. Note that if the stack is in data space, the
+ * call to grow() is a nop, and the copyout()
+ * will fail if the process has not already allocated
+ * the space with a `brk'.
+ */
+ fsize = sizeof(struct sigframe);
+ if ((psp->ps_flags & SAS_ALTSTACK) &&
+ (psp->ps_sigstk.ss_flags & SS_ONSTACK) == 0 &&
+ (psp->ps_sigonstack & sigmask(sig))) {
+ fp = (struct sigframe *)(psp->ps_sigstk.ss_sp +
+ psp->ps_sigstk.ss_size - fsize);
+ psp->ps_sigstk.ss_flags |= SS_ONSTACK;
+ } else
+ fp = (struct sigframe *)(tf->tf_r[31] - fsize);
+
+ /* make sure the frame is aligned on a 8 byte boundary */
+ if (((vaddr_t)fp & 0x07) != 0)
+ fp = (struct sigframe *)((vaddr_t)fp & ~0x07);
+
+ if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize))
+ (void)uvm_grow(p, (unsigned)fp);
+
+#ifdef DEBUG
+ if ((sigdebug & SDB_FOLLOW) ||
+ ((sigdebug & SDB_KSTACK) && (p->p_pid == sigpid)))
+ printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n",
+ p->p_pid, sig, &oonstack, fp, &fp->sf_sc);
+#endif
+ /*
+ * Build the signal context to be used by sigreturn.
+ */
+ sf.sf_signo = sig;
+ sf.sf_scp = &fp->sf_sc;
+ sf.sf_handler = catcher;
+ sf.sf_sc.sc_onstack = oonstack;
+ sf.sf_sc.sc_mask = mask;
+
+ if (psp->ps_siginfo & sigmask(sig)) {
+ sf.sf_sip = &fp->sf_si;
+ initsiginfo(&sf.sf_si, sig, code, type, val);
+ }
+
+ /*
+ * Copy the whole user context into signal context that we
+ * are building.
+ */
+ bcopy((const void *)&tf->tf_regs, (void *)&sf.sf_sc.sc_regs,
+ sizeof(sf.sf_sc.sc_regs));
+
+ if (copyout((caddr_t)&sf, (caddr_t)fp, sizeof sf)) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ sigexit(p, SIGILL);
+ /* NOTREACHED */
+ }
+ /*
+ * Build the argument list for the signal handler.
+ * Signal trampoline code is at base of user stack.
+ */
+ addr = p->p_sigcode;
+ if (cputyp != CPU_88110) {
+ /* mc88100 */
+ tf->tf_snip = (addr & ~3) | NIP_V;
+ tf->tf_sfip = (tf->tf_snip + 4) | FIP_V;
+ } else {
+ /* mc88110 */
+ tf->tf_exip = (addr & ~3);
+ tf->tf_enip = (tf->tf_exip + 4);
+ }
+ tf->tf_r[31] = (unsigned)fp;
+#ifdef DEBUG
+ if ((sigdebug & SDB_FOLLOW) ||
+ ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid))
+ printf("sendsig(%d): sig %d returns\n", p->p_pid, sig);
+#endif
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psl to gain improper privileges or to cause
+ * a machine fault.
+ */
+
+/* ARGSUSED */
+int
+sys_sigreturn(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct sys_sigreturn_args /* {
+ syscallarg(struct sigcontext *) sigcntxp;
+ } */ *uap = v;
+ struct sigcontext *scp;
+ struct trapframe *tf;
+ struct sigcontext ksc;
+
+ scp = (struct sigcontext *)SCARG(uap, sigcntxp);
+#ifdef DEBUG
+ if (sigdebug & SDB_FOLLOW)
+ printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
+#endif
+ if (((vaddr_t)scp & 3) != 0 ||
+ copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(struct sigcontext)))
+ return (EINVAL);
+
+ tf = p->p_md.md_tf;
+ scp = &ksc;
+
+ /*
+ * this can be improved by doing
+ * bcopy(sc_reg to tf, sizeof sigcontext - 2 words)
+ * XXX nivas
+ */
+ bcopy((const void *)&scp->sc_regs, (caddr_t)&tf->tf_regs,
+ sizeof(scp->sc_regs));
+
+ /*
+ * Restore the user supplied information
+ */
+ if (scp->sc_onstack & SS_ONSTACK)
+ p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
+ p->p_sigmask = scp->sc_mask & ~sigcantmask;
+
+ return (EJUSTRETURN);
+}
+
+__dead void
+boot(howto)
+ int howto;
+{
+ /* take a snapshot before clobbering any registers */
+ if (curproc && curproc->p_addr)
+ savectx(curpcb);
+
+ /* If system is cold, just halt. */
+ if (cold) {
+ /* (Unless the user explicitly asked for reboot.) */
+ if ((howto & RB_USERREQ) == 0)
+ howto |= RB_HALT;
+ goto haltsys;
+ }
+
+ boothowto = howto;
+ if ((howto & RB_NOSYNC) == 0) {
+ vfs_shutdown();
+ /*
+ * If we've been adjusting the clock, the todr
+ * will be out of synch; adjust it now unless
+ * the system was sitting in ddb.
+ */
+ if ((howto & RB_TIMEBAD) == 0)
+ resettodr();
+ else
+ printf("WARNING: not updating battery clock\n");
+ }
+
+ /* Disable interrupts. */
+ splhigh();
+
+ /* If rebooting and a dump is requested, do it. */
+ if (howto & RB_DUMP)
+ dumpsys();
+
+haltsys:
+ /* Run any shutdown hooks. */
+ doshutdownhooks();
+
+ /* Luna88k supports automatic powerdown */
+ if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
+ printf("attempting to power down...\n");
+ powerdown();
+ /* if failed, fall through. */
+ }
+
+ if (howto & RB_HALT) {
+ printf("halted\n\n");
+ } else {
+ /* Reset all cpus, which causes reboot */
+ *((volatile unsigned *)0x6d000010) = 0;
+ }
+
+ for (;;); /* to keep compiler happy, and me from going crazy */
+ /*NOTREACHED*/
+}
+
+unsigned dumpmag = 0x8fca0101; /* magic number for savecore */
+int dumpsize = 0; /* also for savecore */
+long dumplo = 0;
+cpu_kcore_hdr_t cpu_kcore_hdr;
+
+/*
+ * This is called by configure to set dumplo and dumpsize.
+ * Dumps always skip the first PAGE_SIZE of disk space
+ * in case there might be a disk label stored there.
+ * If there is extra space, put dump at the end to
+ * reduce the chance that swapping trashes it.
+ */
+void
+dumpconf()
+{
+ int nblks; /* size of dump area */
+ int maj;
+
+ if (dumpdev == NODEV)
+ return;
+ maj = major(dumpdev);
+ if (maj < 0 || maj >= nblkdev)
+ panic("dumpconf: bad dumpdev=0x%x", dumpdev);
+ if (bdevsw[maj].d_psize == NULL)
+ return;
+ nblks = (*bdevsw[maj].d_psize)(dumpdev);
+ if (nblks <= ctod(1))
+ return;
+
+ dumpsize = physmem;
+
+ /* luna88k only uses a single segment. */
+ cpu_kcore_hdr.ram_segs[0].start = 0;
+ cpu_kcore_hdr.ram_segs[0].size = ctob(physmem);
+ cpu_kcore_hdr.cputype = cputyp;
+
+ /*
+ * Don't dump on the first block
+ * in case the dump device includes a disk label.
+ */
+ if (dumplo < ctod(1))
+ dumplo = ctod(1);
+
+ /* Put dump at end of partition, and make it fit. */
+ if (dumpsize + 1 > dtoc(nblks - dumplo))
+ dumpsize = dtoc(nblks - dumplo) - 1;
+ if (dumplo < nblks - ctod(dumpsize) - 1)
+ dumplo = nblks - ctod(dumpsize) - 1;
+}
+
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+void
+dumpsys()
+{
+ int maj;
+ int psize;
+ daddr_t blkno; /* current block to write */
+ /* dump routine */
+ int (*dump)(dev_t, daddr_t, caddr_t, size_t);
+ int pg; /* page being dumped */
+ paddr_t maddr; /* PA being dumped */
+ int error; /* error code from (*dump)() */
+ kcore_seg_t *kseg_p;
+ cpu_kcore_hdr_t *chdr_p;
+ char dump_hdr[dbtob(1)]; /* XXX assume hdr fits in 1 block */
+
+ extern int msgbufmapped;
+
+ msgbufmapped = 0;
+
+ /* Make sure dump device is valid. */
+ if (dumpdev == NODEV)
+ return;
+ if (dumpsize == 0) {
+ dumpconf();
+ if (dumpsize == 0)
+ return;
+ }
+ maj = major(dumpdev);
+ if (dumplo < 0) {
+ printf("\ndump to dev %u,%u not possible\n", maj,
+ minor(dumpdev));
+ return;
+ }
+ dump = bdevsw[maj].d_dump;
+ blkno = dumplo;
+
+ printf("\ndumping to dev %u,%u offset %ld\n", maj,
+ minor(dumpdev), dumplo);
+
+ /* Setup the dump header */
+ kseg_p = (kcore_seg_t *)dump_hdr;
+ chdr_p = (cpu_kcore_hdr_t *)&dump_hdr[ALIGN(sizeof(*kseg_p))];
+ bzero(dump_hdr, sizeof(dump_hdr));
+
+ CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
+ kseg_p->c_size = dbtob(1) - ALIGN(sizeof(*kseg_p));
+ *chdr_p = cpu_kcore_hdr;
+
+ printf("dump ");
+ psize = (*bdevsw[maj].d_psize)(dumpdev);
+ if (psize == -1) {
+ printf("area unavailable\n");
+ return;
+ }
+
+ /* Dump the header. */
+ error = (*dump)(dumpdev, blkno++, (caddr_t)dump_hdr, dbtob(1));
+ if (error != 0)
+ goto abort;
+
+ maddr = (paddr_t)0;
+ for (pg = 0; pg < dumpsize; pg++) {
+#define NPGMB (1024 * 1024 / PAGE_SIZE)
+ /* print out how many MBs we have dumped */
+ if (pg != 0 && (pg % NPGMB) == 0)
+ printf("%d ", pg / NPGMB);
+#undef NPGMB
+ pmap_enter(pmap_kernel(), (vaddr_t)vmmap, maddr,
+ VM_PROT_READ, VM_PROT_READ|PMAP_WIRED);
+
+ error = (*dump)(dumpdev, blkno, vmmap, PAGE_SIZE);
+ if (error == 0) {
+ maddr += PAGE_SIZE;
+ blkno += btodb(PAGE_SIZE);
+ } else
+ break;
+ }
+abort:
+ switch (error) {
+ case 0:
+ printf("succeeded\n");
+ break;
+
+ case ENXIO:
+ printf("device bad\n");
+ break;
+
+ case EFAULT:
+ printf("device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("area improper\n");
+ break;
+
+ case EIO:
+ printf("i/o error\n");
+ break;
+
+ case EINTR:
+ printf("aborted from console\n");
+ break;
+
+ default:
+ printf("error %d\n", error);
+ break;
+ }
+}
+
+/* gets an interrupt stack for slave processors */
+vaddr_t
+get_slave_stack()
+{
+ vaddr_t addr;
+
+ addr = (vaddr_t)uvm_km_zalloc(kernel_map, INTSTACK_SIZE);
+
+ if (addr == NULL)
+ panic("Cannot allocate slave stack for cpu %d",
+ cpu_number());
+
+ interrupt_stack[cpu_number()] = addr;
+ return addr;
+}
+
+/*
+ * Slave CPU pre-main routine.
+ * Determine CPU number and set it.
+ *
+ * Running on an interrupt stack here; do nothing fancy.
+ *
+ * Called from "luna88k/locore.S"
+ */
+void
+slave_pre_main()
+{
+ set_cpu_number(cmmu_cpu_number()); /* Determine cpu number by CMMU */
+ splhigh();
+ enable_interrupt();
+}
+
+/* dummy main routine for slave processors */
+int
+slave_main()
+{
+ printf("slave CPU%d started\n", cpu_number());
+ while (1); /* spin forever */
+ return 0;
+}
+
+/*
+ * Device interrupt handler for LUNA88K
+ *
+ * when we enter, interrupts are disabled;
+ * when we leave, they should be disabled,
+ * but they need not be disabled throughout
+ * the routine.
+ */
+
+#define GET_MASK(cpu, val) *int_mask_reg[cpu] & (val)
+extern unsigned int luna88k_curspl[MAX_CPUS]; /* XXX sould be here? */
+extern unsigned int int_mask_val[INT_LEVEL]; /* XXX sould be here? */
+
+void
+luna88k_ext_int(u_int v, struct trapframe *eframe)
+{
+ int cpu = cpu_number();
+ unsigned int cur_mask, cur_int;
+ unsigned int level, old_spl;
+
+ cur_mask = *int_mask_reg[cpu];
+ old_spl = luna88k_curspl[cpu];
+ eframe->tf_mask = old_spl;
+
+ cur_int = cur_mask >> 29;
+
+ if (cur_int == 0) {
+ /*
+ * Spurious interrupts - may be caused by debug output clearing
+ * DUART interrupts.
+ */
+ printf("luna88k_ext_int(): Spurious interrupts?\n");
+ flush_pipeline();
+ goto out;
+ }
+
+ uvmexp.intrs++;
+
+ /*
+ * We want to service all interrupts marked in the IST register
+ * They are all valid because the mask would have prevented them
+ * from being generated otherwise. We will service them in order of
+ * priority.
+ */
+
+ /* XXX: This is very rough. Should be considered more. (aoyama) */
+ do {
+ level = (cur_int > old_spl ? cur_int : old_spl);
+ if (level >= 8) {
+ register int i;
+
+ printf("safe level %d <= old level %d\n", level, old_spl);
+ printf("cur_int = 0x%x\n", cur_int);
+
+ for (i = 0; i < 4; i++)
+ printf("IEN%d = 0x%x ", i, *int_mask_reg[i]);
+ printf("\nCPU0 spl %d CPU1 spl %d CPU2 spl %d CPU3 spl %d\n",
+ luna88k_curspl[0], luna88k_curspl[1],
+ luna88k_curspl[2], luna88k_curspl[3]);
+ for (i = 0; i < 8; i++)
+ printf("int_mask[%d] = 0x%08x\n", i, int_mask_val[i]);
+ printf("--CPU %d halted--\n", cpu_number());
+ spl7();
+ for(;;) ;
+ }
+
+ if (level > 7 || (char)level < 0) {
+ panic("int level (%x) is not between 0 and 7", level);
+ }
+
+ setipl(level);
+
+ enable_interrupt();
+
+ switch(cur_int) {
+ case CLOCK_INT_LEVEL:
+ /* increment intr counter */
+ intrcnt[M88K_CLK_IRQ]++;
+
+ *clock_reg[cpu] = 0xFFFFFFFFU; /* reset clock */
+
+ /*
+ if (clock_enabled[cpu])
+ sys_clock_interrupt(USERMODE(eframe[EF_EPSR]));
+ */
+ hardclock((void *)eframe);
+ break;
+ case 5:
+ case 4:
+ case 3:
+ isrdispatch_autovec(cur_int);
+ break;
+ default:
+ printf("luna88k_ext_int(): level %d interrupt.\n", cur_int);
+ break;
+ }
+ } while ((cur_int = (*int_mask_reg[cpu]) >> 29) != 0);
+
+ /*
+ * process any remaining data access exceptions before
+ * returning to assembler
+ */
+ disable_interrupt();
+out:
+ if (eframe->tf_dmt0 & DMT_VALID)
+ m88100_trap(T_DATAFLT, eframe);
+
+ /*
+ * Restore the mask level to what it was when the interrupt
+ * was taken.
+ */
+ setipl(eframe->tf_mask);
+ flush_pipeline(); /* XXX: need this? */
+}
+
+int
+cpu_exec_aout_makecmds(p, epp)
+ struct proc *p;
+ struct exec_package *epp;
+{
+
+ return (ENOEXEC);
+}
+
+int
+sys_sysarch(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+#if 0
+ struct sys_sysarch_args /* {
+ syscallarg(int) op;
+ syscallarg(char *) parm;
+ } */ *uap = v;
+#endif
+
+ return (ENOSYS);
+}
+
+/*
+ * machine dependent system variables.
+ */
+
+int
+cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
+ int *name;
+ u_int namelen;
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+ struct proc *p;
+{
+ dev_t consdev;
+
+ /* all sysctl names are this level are terminal */
+ if (namelen != 1)
+ return (ENOTDIR); /* overloaded */
+
+ switch (name[0]) {
+ case CPU_CONSDEV:
+ if (cn_tab != NULL)
+ consdev = cn_tab->cn_dev;
+ else
+ consdev = NODEV;
+ return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
+ sizeof consdev));
+ default:
+ return (EOPNOTSUPP);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * insert an element into a queue
+ */
+
+void
+_insque(velement, vhead)
+ void *velement, *vhead;
+{
+ struct prochd *element, *head;
+ element = velement;
+ head = vhead;
+ element->ph_link = head->ph_link;
+ head->ph_link = (struct proc *)element;
+ element->ph_rlink = (struct proc *)head;
+ ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+
+void
+_remque(velement)
+ void *velement;
+{
+ struct prochd *element;
+ element = velement;
+ ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
+ ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
+ element->ph_rlink = (struct proc *)0;
+}
+
+int
+copystr(fromaddr, toaddr, maxlength, lencopied)
+ const void *fromaddr;
+ void *toaddr;
+ size_t maxlength;
+ size_t *lencopied;
+{
+ u_int tally;
+
+ tally = 0;
+
+ while (maxlength--) {
+ *(u_char *)toaddr = *(u_char *)fromaddr++;
+ tally++;
+ if (*(u_char *)toaddr++ == 0) {
+ if (lencopied) *lencopied = tally;
+ return (0);
+ }
+ }
+
+ if (lencopied)
+ *lencopied = tally;
+
+ return (ENAMETOOLONG);
+}
+
+void
+setrunqueue(p)
+ struct proc *p;
+{
+ struct prochd *q;
+ struct proc *oldlast;
+ int which = p->p_priority >> 2;
+
+ if (p->p_back != NULL)
+ panic("setrunqueue %p", p);
+ q = &qs[which];
+ whichqs |= 1 << which;
+ p->p_forw = (struct proc *)q;
+ p->p_back = oldlast = q->ph_rlink;
+ q->ph_rlink = p;
+ oldlast->p_forw = p;
+}
+
+/*
+ * Remove process p from its run queue, which should be the one
+ * indicated by its priority. Calls should be made at splstatclock().
+ */
+void
+remrunqueue(vp)
+ struct proc *vp;
+{
+ struct proc *p = vp;
+ int which = p->p_priority >> 2;
+ struct prochd *q;
+
+ if ((whichqs & (1 << which)) == 0)
+ panic("remrq %p", p);
+ p->p_forw->p_back = p->p_back;
+ p->p_back->p_forw = p->p_forw;
+ p->p_back = NULL;
+ q = &qs[which];
+ if (q->ph_link == (struct proc *)q)
+ whichqs &= ~(1 << which);
+}
+
+/* dummys for now */
+
+void
+bugsyscall()
+{
+}
+
+void
+dosoftint()
+{
+ if (ssir & SIR_NET) {
+ siroff(SIR_NET);
+ uvmexp.softs++;
+#define DONETISR(bit, fn) \
+ do { \
+ if (netisr & (1 << bit)) { \
+ netisr &= ~(1 << bit); \
+ fn(); \
+ } \
+ } while (0)
+#include <net/netisr_dispatch.h>
+#undef DONETISR
+ }
+
+ if (ssir & SIR_CLOCK) {
+ siroff(SIR_CLOCK);
+ uvmexp.softs++;
+ softclock();
+ }
+}
+
+int
+spl0()
+{
+ int x;
+ x = splsoftclock();
+
+ if (ssir) {
+ dosoftint();
+ }
+
+ setipl(0);
+
+ return (x);
+}
+
+#ifdef EH_DEBUG
+
+void
+MY_info(f, p, flags, s)
+ struct trapframe *f;
+ caddr_t p;
+ int flags;
+ char *s;
+{
+ regdump(f);
+ printf("proc %x flags %x type %s\n", p, flags, s);
+}
+
+void
+MY_info_done(f, flags)
+ struct trapframe *f;
+ int flags;
+{
+ regdump(f);
+}
+
+#endif
+
+void
+nmihand(void *framep)
+{
+#if 0
+ struct trapframe *frame = framep;
+#endif
+
+#if DDB
+ DEBUG_MSG("Abort Pressed\n");
+ Debugger();
+#else
+ DEBUG_MSG("Spurious NMI?\n");
+#endif /* DDB */
+}
+
+void
+regdump(struct trapframe *f)
+{
+#define R(i) f->tf_r[i]
+ printf("R00-05: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(0),R(1),R(2),R(3),R(4),R(5));
+ printf("R06-11: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(6),R(7),R(8),R(9),R(10),R(11));
+ printf("R12-17: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(12),R(13),R(14),R(15),R(16),R(17));
+ printf("R18-23: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(18),R(19),R(20),R(21),R(22),R(23));
+ printf("R24-29: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(24),R(25),R(26),R(27),R(28),R(29));
+ printf("R30-31: 0x%08x 0x%08x\n",R(30),R(31));
+ if (cputyp == CPU_88110) {
+ printf("exip %x enip %x\n", f->tf_exip, f->tf_enip);
+ } else {
+ printf("sxip %x snip %x sfip %x\n",
+ f->tf_sxip, f->tf_snip, f->tf_sfip);
+ }
+#ifdef M88100
+ if (f->tf_vector == 0x3 && cputyp != CPU_88110) {
+ /* print dmt stuff for data access fault */
+ printf("dmt0 %x dmd0 %x dma0 %x\n",
+ f->tf_dmt0, f->tf_dmd0, f->tf_dma0);
+ printf("dmt1 %x dmd1 %x dma1 %x\n",
+ f->tf_dmt1, f->tf_dmd1, f->tf_dma1);
+ printf("dmt2 %x dmd2 %x dma2 %x\n",
+ f->tf_dmt2, f->tf_dmd2, f->tf_dma2);
+ printf("fault type %d\n", (f->tf_dpfsr >> 16) & 0x7);
+ dae_print((unsigned *)f);
+ }
+ if (longformat && cputyp != CPU_88110) {
+ printf("fpsr %x fpcr %x epsr %x ssbr %x\n",
+ f->tf_fpsr, f->tf_fpcr, f->tf_epsr, f->tf_ssbr);
+ printf("fpecr %x fphs1 %x fpls1 %x fphs2 %x fpls2 %x\n",
+ f->tf_fpecr, f->tf_fphs1, f->tf_fpls1,
+ f->tf_fphs2, f->tf_fpls2);
+ printf("fppt %x fprh %x fprl %x fpit %x\n",
+ f->tf_fppt, f->tf_fprh, f->tf_fprl, f->tf_fpit);
+ printf("vector %d mask %x mode %x scratch1 %x cpu %x\n",
+ f->tf_vector, f->tf_mask, f->tf_mode,
+ f->tf_scratch1, f->tf_cpu);
+ }
+#endif
+#ifdef M88110
+ if (longformat && cputyp == CPU_88110) {
+ printf("fpsr %x fpcr %x fpecr %x epsr %x\n",
+ f->tf_fpsr, f->tf_fpcr, f->tf_fpecr, f->tf_epsr);
+ printf("dsap %x duap %x dsr %x dlar %x dpar %x\n",
+ f->tf_dsap, f->tf_duap, f->tf_dsr, f->tf_dlar, f->tf_dpar);
+ printf("isap %x iuap %x isr %x ilar %x ipar %x\n",
+ f->tf_isap, f->tf_iuap, f->tf_isr, f->tf_ilar, f->tf_ipar);
+ printf("vector %d mask %x mode %x scratch1 %x cpu %x\n",
+ f->tf_vector, f->tf_mask, f->tf_mode,
+ f->tf_scratch1, f->tf_cpu);
+ }
+#endif
+#ifdef MVME188
+ if (brdtyp == BRD_188) {
+ unsigned int istr, cur_mask;
+
+ istr = *(int *volatile)IST_REG;
+ cur_mask = GET_MASK(0, istr);
+ printf("emask = 0x%b\n", f->tf_mask, IST_STRING);
+ printf("istr = 0x%b\n", istr, IST_STRING);
+ printf("cmask = 0x%b\n", cur_mask, IST_STRING);
+ }
+#endif
+}
+
+/*
+ * Called from locore.S during boot,
+ * this is the first C code that's run.
+ */
+
+void
+luna88k_bootstrap()
+{
+ extern int kernelstart;
+ extern struct consdev *cn_tab;
+ extern struct cmmu_p cmmu8820x;
+
+ /*
+ * Must initialize p_addr before autoconfig or
+ * the fault handler will get a NULL reference.
+ * Do this early so that we can take a data or
+ * instruction fault and survive it. XXX smurph
+ */
+ proc0.p_addr = proc0paddr;
+ curproc = &proc0;
+ curpcb = &proc0paddr->u_pcb;
+
+ /* zero out the machine dependant function pointers */
+ bzero(&md, sizeof(struct md_p));
+
+ /*
+ * set up interrupt and fp exception handlers
+ * based on the machine.
+ */
+ cmmu = &cmmu8820x;
+ md.interrupt_func = &luna88k_ext_int;
+ md.intr_mask = NULL;
+ md.intr_ipl = NULL;
+ md.intr_src = NULL;
+ /* clear and disable all interrupts */
+ *int_mask_reg[0] = 0;
+ *int_mask_reg[1] = 0;
+ *int_mask_reg[2] = 0;
+ *int_mask_reg[3] = 0;
+
+ /* startup fake console driver. It will be replaced by consinit() */
+ cn_tab = &romttycons;
+
+ uvmexp.pagesize = NBPG;
+ uvm_setpagesize();
+
+ first_addr = round_page((vaddr_t) &end); /* XXX: Is this OK? */
+ last_addr = size_memory();
+ physmem = btoc(last_addr);
+
+ cmmu_parity_enable();
+
+ setup_board_config();
+ cmmu_init();
+ master_cpu = cmmu_cpu_number();
+ set_cpu_number(master_cpu);
+
+ /*
+ * We may have more than one CPU, so mention which one is the master.
+ * We will also want to spin up slave CPUs on the long run...
+ */
+ printf("CPU%d is master CPU\n", master_cpu);
+
+#if 0
+ int i;
+ for (i = 0; i < MAX_CPUS; i++) {
+ if (!spin_cpu(i))
+ printf("CPU%d started\n", i);
+ }
+#endif
+
+ avail_start = first_addr;
+ avail_end = last_addr;
+ /*
+ * Steal MSGBUFSIZE at the top of physical memory for msgbuf
+ */
+ avail_end -= round_page(MSGBUFSIZE);
+
+#ifdef DEBUG
+ printf("LUNA88K boot: memory from 0x%x to 0x%x\n", avail_start, avail_end);
+#endif
+ pmap_bootstrap((vaddr_t)trunc_page((unsigned)&kernelstart) /* = loadpt */,
+ &avail_start, &avail_end, &virtual_avail,
+ &virtual_end);
+ /*
+ * Tell the VM system about available physical memory.
+ * luna88k only has one segment.
+ */
+ uvm_page_physload(atop(avail_start), atop(avail_end),
+ atop(avail_start), atop(avail_end),VM_FREELIST_DEFAULT);
+
+ /* Initialize cached PTEs for u-area mapping. */
+ save_u_area(&proc0, (vaddr_t)proc0paddr);
+
+ /*
+ * Map proc0's u-area at the standard address (UADDR).
+ */
+ load_u_area(&proc0);
+
+ /* Initialize the "u-area" pages. */
+ bzero((caddr_t)UADDR, UPAGES*NBPG);
+#ifdef DEBUG
+ printf("leaving luna88k_bootstrap()\n");
+#endif
+}
+
+/*
+ * Rom console routines:
+ * Enables printing of boot messages before consinit().
+ */
+
+#define __ROM_FUNC_TABLE ((int **)0x00001100)
+#define ROMGETC() (*(int (*)(void))__ROM_FUNC_TABLE[3])()
+#define ROMPUTC(x) (*(void (*)(int))__ROM_FUNC_TABLE[4])(x)
+
+void
+romttycnprobe(cp)
+ struct consdev *cp;
+{
+ cp->cn_dev = makedev(14, 0);
+ cp->cn_pri = CN_NORMAL;
+}
+
+void
+romttycninit(cp)
+ struct consdev *cp;
+{
+ /* Nothing to do */
+}
+
+int
+romttycngetc(dev)
+ dev_t dev;
+{
+ int s, c;
+
+ do {
+ s = splhigh();
+ c = ROMGETC();
+ splx(s);
+ } while (c == -1);
+ return c;
+}
+
+void
+romttycnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s;
+
+#if 0
+ if ((char)c == '\n')
+ ROMPUTC('\r');
+#endif
+ s = splhigh();
+ ROMPUTC(c);
+ splx(s);
+}
+
+/* taken from NetBSD/luna68k */
+void
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splclock();
+ static struct timeval lasttime;
+
+ *tvp = time;
+#ifdef notdef
+ tvp->tv_usec += clkread();
+ while (tvp->tv_usec >= 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+#endif
+ if (tvp->tv_sec == lasttime.tv_sec &&
+ tvp->tv_usec <= lasttime.tv_usec &&
+ (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ lasttime = *tvp;
+ splx(s);
+}
+
+/* powerdown */
+
+struct pio {
+ volatile u_int8_t portA;
+ volatile unsigned : 24;
+ volatile u_int8_t portB;
+ volatile unsigned : 24;
+ volatile u_int8_t portC;
+ volatile unsigned : 24;
+ volatile u_int8_t cntrl;
+ volatile unsigned : 24;
+};
+
+#define PIO1_POWER 0x04
+
+#define PIO1_ENABLE 0x01
+#define PIO1_DISABLE 0x00
+
+void
+powerdown(void)
+{
+ struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
+
+ DELAY(100000);
+ p1->cntrl = (PIO1_POWER << 1) | PIO1_DISABLE;
+ *(volatile u_int8_t *)&p1->portC;
+}
diff --git a/sys/arch/luna88k/luna88k/mainbus.c b/sys/arch/luna88k/luna88k/mainbus.c
new file mode 100644
index 00000000000..14a25832c1e
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/mainbus.c
@@ -0,0 +1,107 @@
+/* $OpenBSD: mainbus.c,v 1.1 2004/04/21 15:24:08 aoyama Exp $ */
+/* $NetBSD: mainbus.c,v 1.2 2000/01/07 05:13:08 nisimura Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tohru Nishimura.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+
+static const struct mainbus_attach_args devs[] = {
+ { "clock", 0x45000000, -1 }, /* Mostek/Dallas TimeKeeper */
+ { "le", 0xf1000000, 4 }, /* Am7990 */
+ { "sio", 0x51000000, 5 }, /* uPD7201A */
+ { "fb", 0xc1100000, -1 }, /* BrookTree RAMDAC */
+ { "spc", 0xe1000000, 3 }, /* MB89352 */
+ { "spc", 0xe1000040, 3 }, /* ditto */
+#if NPCM > 0
+ { "pcm", 0x91000000, 4 }, /* NEC-9801-86 Sound board (under testing) */
+#endif
+};
+
+void mainbus_attach(struct device *, struct device *, void *);
+int mainbus_match(struct device *, void *, void *);
+int mainbus_print(void *, const char *);
+
+const struct cfattach mainbus_ca = {
+ sizeof(struct device), mainbus_match, mainbus_attach
+};
+
+const struct cfdriver mainbus_cd = {
+ NULL, "mainbus", DV_DULL, 0
+};
+
+int
+mainbus_match(parent, cf, args)
+ struct device *parent;
+ void *cf, *args;
+{
+ static int mainbus_matched;
+
+ if (mainbus_matched)
+ return (0);
+
+ return ((mainbus_matched = 1));
+}
+
+void
+mainbus_attach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ int i;
+
+ printf("\n");
+ for (i = 0; i < sizeof(devs)/sizeof(devs[0]); i++)
+ config_found(self, (void *)&devs[i], mainbus_print);
+}
+
+int
+mainbus_print(aux, pnp)
+ void *aux;
+ const char *pnp;
+{
+ struct mainbus_attach_args *ma = aux;
+
+ if (pnp)
+ printf("%s at %s", ma->ma_name, pnp);
+
+ return (UNCONF);
+}
diff --git a/sys/arch/luna88k/luna88k/mem.c b/sys/arch/luna88k/luna88k/mem.c
new file mode 100644
index 00000000000..a0553547a0c
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/mem.c
@@ -0,0 +1,237 @@
+/* $OpenBSD: mem.c,v 1.1 2004/04/21 15:24:10 aoyama Exp $ */
+
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mem.c 8.3 (Berkeley) 1/12/94
+ */
+
+/*
+ * Memory special file
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+
+#include <machine/board.h>
+
+#include <uvm/uvm_extern.h>
+
+caddr_t zeropage;
+
+#define mmread mmrw
+#define mmwrite mmrw
+cdev_decl(mm);
+
+/*ARGSUSED*/
+int
+mmopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+
+ switch (minor(dev)) {
+ case 0:
+ case 1:
+ case 2:
+ case 12:
+ return (0);
+ default:
+ return (ENXIO);
+ }
+}
+
+/*ARGSUSED*/
+int
+mmclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ vaddr_t o, v;
+ int c;
+ struct iovec *iov;
+ int error = 0;
+ static int physlock = 0;
+ extern caddr_t vmmap;
+
+ if (minor(dev) == 0) {
+ /* lock against other uses of shared vmmap */
+ while (physlock > 0) {
+ physlock++;
+ error = tsleep((caddr_t)&physlock, PZERO | PCATCH,
+ "mmrw", 0);
+ if (error)
+ return (error);
+ }
+ physlock = 1;
+ }
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+/* minor device 0 is physical memory */
+ case 0:
+ /* move one page at a time */
+ v = uio->uio_offset;
+ if (v > MAXPHYSMEM) {
+ error = EFAULT;
+ goto unlock;
+ }
+ pmap_enter(pmap_kernel(), (vaddr_t)vmmap,
+ trunc_page(v),
+ uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
+ (uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE) | PMAP_WIRED);
+ pmap_update(pmap_kernel());
+ o = uio->uio_offset & PGOFSET;
+ c = min(uio->uio_resid, (int)(NBPG - o));
+ error = uiomove((caddr_t)vmmap + o, c, uio);
+ pmap_remove(pmap_kernel(), (vaddr_t)vmmap,
+ (vaddr_t)vmmap + NBPG);
+ pmap_update(pmap_kernel());
+ continue;
+
+/* minor device 1 is kernel memory */
+ case 1:
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (!uvm_kernacc((caddr_t)v, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return (EFAULT);
+ if (v < NBPG) {
+#ifdef DEBUG
+ /*
+ * For now, return zeros on read of page 0
+ * and EFAULT for writes.
+ */
+ if (uio->uio_rw == UIO_READ) {
+ if (zeropage == NULL) {
+ zeropage = (caddr_t)
+ malloc(PAGE_SIZE, M_TEMP,
+ M_WAITOK);
+ bzero(zeropage, PAGE_SIZE);
+ }
+ c = min(c, NBPG - (int)v);
+ v = (vaddr_t)zeropage;
+ } else
+#endif
+ return (EFAULT);
+ }
+ error = uiomove((caddr_t)v, c, uio);
+ continue;
+
+/* minor device 2 is EOF/RATHOLE */
+ case 2:
+ if (uio->uio_rw == UIO_WRITE)
+ uio->uio_resid = 0;
+ return (0);
+
+/* should add vme bus so that we can do user level probes */
+
+/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
+ case 12:
+ if (uio->uio_rw == UIO_WRITE) {
+ c = iov->iov_len;
+ break;
+ }
+ if (zeropage == NULL) {
+ zeropage = (caddr_t)
+ malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
+ bzero(zeropage, PAGE_SIZE);
+ }
+ c = min(iov->iov_len, PAGE_SIZE);
+ error = uiomove(zeropage, c, uio);
+ continue;
+
+ default:
+ return (ENXIO);
+ }
+ if (error)
+ break;
+ iov->iov_base += c;
+ iov->iov_len -= c;
+ uio->uio_offset += c;
+ uio->uio_resid -= c;
+ }
+ if (minor(dev) == 0) {
+unlock:
+ if (physlock > 1)
+ wakeup((caddr_t)&physlock);
+ physlock = 0;
+ }
+ return (error);
+}
+
+paddr_t
+mmmmap(dev, off, prot)
+ dev_t dev;
+ off_t off;
+ int prot;
+{
+ return (-1);
+}
+
+/*ARGSUSED*/
+int
+mmioctl(dev, cmd, data, flags, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flags;
+ struct proc *p;
+{
+ return (EOPNOTSUPP);
+}
diff --git a/sys/arch/luna88k/luna88k/pmap.c b/sys/arch/luna88k/luna88k/pmap.c
new file mode 100644
index 00000000000..48e56127dbf
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/pmap.c
@@ -0,0 +1,2834 @@
+/* $OpenBSD: pmap.c,v 1.1 2004/04/21 15:24:13 aoyama Exp $ */
+/*
+ * Copyright (c) 2001, 2002, 2003 Miodrag Vallat
+ * Copyright (c) 1998-2001 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/simplelock.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/msgbuf.h>
+#include <sys/user.h>
+
+#include <uvm/uvm.h>
+
+#include <machine/asm_macro.h>
+#include <machine/board.h>
+#include <machine/cmmu.h>
+#include <machine/cpu_number.h>
+#include <machine/pmap_table.h>
+
+/*
+ * VM externals
+ */
+extern vaddr_t avail_start, avail_end;
+extern vaddr_t virtual_avail, virtual_end;
+
+/*
+ * Macros to operate pm_cpus field
+ */
+#define SETBIT_CPUSET(cpu_number, cpuset) (*(cpuset)) |= (1 << (cpu_number));
+#define CLRBIT_CPUSET(cpu_number, cpuset) (*(cpuset)) &= ~(1 << (cpu_number));
+
+#ifdef DEBUG
+/*
+ * Static variables, functions and variables for debugging
+ */
+
+/*
+ * conditional debugging
+ */
+#define CD_FULL 0x02
+
+#define CD_ACTIVATE 0x0000004 /* pmap_activate */
+#define CD_KMAP 0x0000008 /* pmap_expand_kmap */
+#define CD_MAP 0x0000010 /* pmap_map */
+#define CD_CACHE 0x0000020 /* pmap_cache_ctrl */
+#define CD_BOOT 0x0000040 /* pmap_bootstrap */
+#define CD_INIT 0x0000080 /* pmap_init */
+#define CD_CREAT 0x0000100 /* pmap_create */
+#define CD_FREE 0x0000200 /* pmap_release */
+#define CD_DESTR 0x0000400 /* pmap_destroy */
+#define CD_RM 0x0000800 /* pmap_remove */
+#define CD_RMAL 0x0001000 /* pmap_remove_all */
+#define CD_PROT 0x0002000 /* pmap_protect */
+#define CD_EXP 0x0004000 /* pmap_expand */
+#define CD_ENT 0x0008000 /* pmap_enter */
+#define CD_UPD 0x0010000 /* pmap_update */
+#define CD_COL 0x0020000 /* pmap_collect */
+#define CD_CBIT 0x0040000 /* pmap_changebit */
+#define CD_TBIT 0x0080000 /* pmap_testbit */
+#define CD_USBIT 0x0100000 /* pmap_unsetbit */
+#define CD_PGMV 0x0200000 /* pagemove */
+#define CD_ALL 0x0FFFFFC
+
+int pmap_con_dbg = 0;
+
+/*
+ * Alignment checks for pages (must lie on page boundaries).
+ */
+#define PAGE_ALIGNED(ad) (((vaddr_t)(ad) & PAGE_MASK) == 0)
+#define CHECK_PAGE_ALIGN(ad, who) \
+ if (!PAGE_ALIGNED(ad)) \
+ printf("%s: addr %x not page aligned.\n", who, ad)
+
+#else /* DEBUG */
+
+#define CHECK_PAGE_ALIGN(ad, who)
+
+#endif /* DEBUG */
+
+struct pool pmappool, pvpool;
+
+caddr_t vmmap;
+pt_entry_t *vmpte, *msgbufmap;
+
+struct pmap kernel_pmap_store;
+pmap_t kernel_pmap = &kernel_pmap_store;
+
+typedef struct kpdt_entry *kpdt_entry_t;
+struct kpdt_entry {
+ kpdt_entry_t next;
+ paddr_t phys;
+};
+#define KPDT_ENTRY_NULL ((kpdt_entry_t)0)
+
+kpdt_entry_t kpdt_free;
+
+/*
+ * MAX_KERNEL_VA_SIZE must fit into the virtual address space between
+ * VM_MIN_KERNEL_ADDRESS and VM_MAX_KERNEL_ADDRESS.
+ */
+
+#define MAX_KERNEL_VA_SIZE (256*1024*1024) /* 256 Mb */
+
+/*
+ * Size of kernel page tables, which is enough to map MAX_KERNEL_VA_SIZE
+ */
+#define KERNEL_PDT_SIZE (atop(MAX_KERNEL_VA_SIZE) * sizeof(pt_entry_t))
+
+/*
+ * Size of kernel page tables for mapping onboard IO space.
+ */
+#define OBIO_PDT_SIZE (atop(OBIO_SIZE) * sizeof(pt_entry_t))
+
+#define MAX_KERNEL_PDT_SIZE (KERNEL_PDT_SIZE + OBIO_PDT_SIZE)
+
+/*
+ * Two pages of scratch space per cpu.
+ * Used in pmap_copy_page() and pmap_zero_page().
+ */
+vaddr_t phys_map_vaddr, phys_map_vaddr_end;
+
+#define PV_ENTRY_NULL ((pv_entry_t) 0)
+
+static pv_entry_t pg_to_pvh(struct vm_page *);
+
+static __inline pv_entry_t
+pg_to_pvh(struct vm_page *pg)
+{
+ return &pg->mdpage.pvent;
+}
+
+/*
+ * Locking primitives
+ */
+
+/*
+ * We raise the interrupt level to splvm, to block interprocessor
+ * interrupts during pmap operations.
+ */
+#define SPLVM(spl) spl = splvm()
+#define SPLX(spl) splx(spl)
+
+#define PMAP_LOCK(pmap,spl) \
+ do { \
+ SPLVM(spl); \
+ simple_lock(&(pmap)->pm_lock); \
+ } while (0)
+#define PMAP_UNLOCK(pmap, spl) \
+ do { \
+ simple_unlock(&(pmap)->pm_lock); \
+ SPLX(spl); \
+ } while (0)
+
+#define ETHERPAGES 16
+void *etherbuf = NULL;
+int etherlen;
+
+#ifdef PMAP_USE_BATC
+
+/*
+ * number of BATC entries used
+ */
+int batc_used;
+
+/*
+ * keep track BATC mapping
+ */
+batc_entry_t batc_entry[BATC_MAX];
+
+#endif /* PMAP_USE_BATC */
+
+vaddr_t kmapva = 0;
+
+/*
+ * Internal routines
+ */
+void flush_atc_entry(long, vaddr_t, boolean_t);
+pt_entry_t *pmap_expand_kmap(vaddr_t, vm_prot_t);
+void pmap_remove_pte(pmap_t, vaddr_t, pt_entry_t *);
+void pmap_remove_range(pmap_t, vaddr_t, vaddr_t);
+void pmap_expand(pmap_t, vaddr_t);
+void pmap_release(pmap_t);
+vaddr_t pmap_map(vaddr_t, paddr_t, paddr_t, vm_prot_t, u_int);
+pt_entry_t *pmap_pte(pmap_t, vaddr_t);
+void pmap_remove_all(struct vm_page *);
+void pmap_changebit(struct vm_page *, int, int);
+boolean_t pmap_unsetbit(struct vm_page *, int);
+boolean_t pmap_testbit(struct vm_page *, int);
+
+/*
+ * quick PTE field checking macros
+ */
+#define pmap_pte_w(pte) (*(pte) & PG_W)
+#define pmap_pte_prot(pte) (*(pte) & PG_PROT)
+
+#define pmap_pte_w_chg(pte, nw) ((nw) ^ pmap_pte_w(pte))
+#define pmap_pte_prot_chg(pte, np) ((np) ^ pmap_pte_prot(pte))
+
+/*
+ * Convert machine-independent protection code to M88K protection bits.
+ */
+static __inline u_int32_t
+m88k_protection(pmap_t pmap, vm_prot_t prot)
+{
+ pt_entry_t p;
+
+ p = (prot & VM_PROT_WRITE) ? PG_RW : PG_RO;
+ /*
+ * XXX this should not be necessary anymore now that pmap_enter
+ * does the correct thing... -- miod
+ */
+#ifdef M88110
+ if (cputyp == CPU_88110) {
+ p |= PG_U;
+ /* if the map is the kernel's map and since this
+ * is not a paged kernel, we go ahead and mark
+ * the page as modified to avoid an exception
+ * upon writing to the page the first time. XXX smurph
+ */
+ if (pmap == kernel_pmap) {
+ if ((p & PG_RO) == 0)
+ p |= PG_M;
+ }
+ }
+#endif
+ return p;
+}
+
+/*
+ * Routine: FLUSH_ATC_ENTRY
+ *
+ * Function:
+ * Flush atc(TLB) which maps given virtual address, in the CPUs which
+ * are specified by 'users', for the operating mode specified by
+ * 'kernel'.
+ *
+ * Parameters:
+ * users bit patterns of the CPUs which may hold the TLB, and
+ * should be flushed
+ * va virtual address that should be flushed
+ * kernel TRUE if supervisor mode, FALSE if user mode
+ */
+void
+flush_atc_entry(long users, vaddr_t va, boolean_t kernel)
+{
+ int cpu;
+ long tusers = users;
+
+#ifdef DEBUG
+ if ((tusers != 0) && (ff1(tusers) >= MAX_CPUS)) {
+ panic("flush_atc_entry: invalid ff1 users = %d", ff1(tusers));
+ }
+#endif
+
+ while ((cpu = ff1(tusers)) != 32) {
+ if (cpu_sets[cpu]) { /* just checking to make sure */
+ cmmu_flush_tlb(cpu, kernel, va, PAGE_SIZE);
+ }
+ tusers &= ~(1 << cpu);
+ }
+}
+
+/*
+ * Routine: PMAP_PTE
+ *
+ * Function:
+ * Given a map and a virtual address, compute a (virtual) pointer
+ * to the page table entry (PTE) which maps the address .
+ * If the page table associated with the address does not
+ * exist, PT_ENTRY_NULL is returned (and the map may need to grow).
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * virt virtual address for which page table entry is desired
+ *
+ * Otherwise the page table address is extracted from the segment table,
+ * the page table index is added, and the result is returned.
+ */
+pt_entry_t *
+pmap_pte(pmap_t pmap, vaddr_t virt)
+{
+ sdt_entry_t *sdt;
+
+#ifdef DEBUG
+ /*XXX will this change if physical memory is not contiguous? */
+ /* take a look at PDTIDX XXXnivas */
+ if (pmap == PMAP_NULL)
+ panic("pmap_pte: pmap is NULL");
+#endif
+
+ sdt = SDTENT(pmap, virt);
+ /*
+ * Check whether page table exists.
+ */
+ if (!SDT_VALID(sdt))
+ return (PT_ENTRY_NULL);
+
+ return (pt_entry_t *)(PG_PFNUM(*(sdt + SDT_ENTRIES)) << PDT_SHIFT) +
+ PDTIDX(virt);
+}
+
+/*
+ * Routine: PMAP_EXPAND_KMAP (internal)
+ *
+ * Function:
+ * Allocate a page descriptor table (pte_table) and validate associated
+ * segment table entry, returning pointer to page table entry. This is
+ * much like 'pmap_expand', except that table space is acquired
+ * from an area set up by pmap_bootstrap, instead of through
+ * uvm_km_zalloc. (Obviously, because uvm_km_zalloc uses the kernel map
+ * for allocation - which we can't do when trying to expand the
+ * kernel map!) Note that segment tables for the kernel map were
+ * all allocated at pmap_bootstrap time, so we only need to worry
+ * about the page table here.
+ *
+ * Parameters:
+ * virt VA for which translation tables are needed
+ * prot protection attributes for segment entries
+ *
+ * Extern/Global:
+ * kpdt_free kernel page table free queue
+ *
+ * Calls:
+ * m88k_protection
+ *
+ * This routine simply dequeues a table from the kpdt_free list,
+ * initializes all its entries (invalidates them), and sets the
+ * corresponding segment table entry to point to it. If the kpdt_free
+ * list is empty - we panic (no other places to get memory, sorry). (Such
+ * a panic indicates that pmap_bootstrap is not allocating enough table
+ * space for the kernel virtual address space).
+ *
+ */
+pt_entry_t *
+pmap_expand_kmap(vaddr_t virt, vm_prot_t prot)
+{
+ sdt_entry_t template, *sdt;
+ kpdt_entry_t kpdt_ent;
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_KMAP | CD_FULL)) == (CD_KMAP | CD_FULL))
+ printf("(pmap_expand_kmap: %x) v %x\n", curproc, virt);
+#endif
+
+ template = m88k_protection(kernel_pmap, prot) | SG_V;
+
+ /* segment table entry derivate from map and virt. */
+ sdt = SDTENT(kernel_pmap, virt);
+#ifdef DEBUG
+ if (SDT_VALID(sdt))
+ panic("pmap_expand_kmap: segment table entry VALID");
+#endif
+
+ kpdt_ent = kpdt_free;
+ if (kpdt_ent == KPDT_ENTRY_NULL)
+ panic("pmap_expand_kmap: Ran out of kernel pte tables");
+
+ kpdt_free = kpdt_free->next;
+ /* physical table */
+ *sdt = kpdt_ent->phys | template;
+ /* virtual table */
+ *(sdt + SDT_ENTRIES) = (vaddr_t)kpdt_ent | template;
+
+ /* Reinitialize this kpdt area to zero */
+ bzero((void *)kpdt_ent, PDT_SIZE);
+
+ return (pt_entry_t *)(kpdt_ent) + PDTIDX(virt);
+}
+
+/*
+ * Routine: PMAP_MAP
+ *
+ * Function:
+ * Map memory at initialization. The physical addresses being
+ * mapped are not managed and are never unmapped.
+ *
+ * Parameters:
+ * virt virtual address of range to map
+ * start physical address of range to map
+ * end physical address of end of range
+ * prot protection attributes
+ * cmode cache control attributes
+ *
+ * Calls:
+ * pmap_pte
+ * pmap_expand_kmap
+ *
+ * Special Assumptions
+ * For now, VM is already on, only need to map the specified
+ * memory. Used only by pmap_bootstrap() and vm_page_startup().
+ *
+ * For each page that needs mapping:
+ * pmap_pte is called to obtain the address of the page table
+ * table entry (PTE). If the page table does not exist,
+ * pmap_expand_kmap is called to allocate it. Finally, the page table
+ * entry is set to point to the physical page.
+ *
+ * initialize template with paddr, prot, dt
+ * look for number of phys pages in range
+ * {
+ * pmap_pte(virt) - expand if necessary
+ * stuff pte from template
+ * increment virt one page
+ * increment template paddr one page
+ * }
+ *
+ */
+vaddr_t
+pmap_map(vaddr_t virt, paddr_t start, paddr_t end, vm_prot_t prot, u_int cmode)
+{
+ u_int npages;
+ u_int num_phys_pages;
+ pt_entry_t template, *pte;
+ paddr_t page;
+#ifdef PMAP_USE_BATC
+ u_int32_t batctmp;
+ int i;
+#endif
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_MAP)
+ printf ("(pmap_map: %x) phys address from %x to %x mapped at virtual %x, prot %x cmode %x\n",
+ curproc, start, end, virt, prot, cmode);
+#endif
+
+#ifdef DEBUG
+ /* Check for zero if we map the very end of the address space... */
+ if (start > end && end != 0) {
+ panic("pmap_map: start greater than end address");
+ }
+#endif
+
+ template = m88k_protection(kernel_pmap, prot) | cmode | PG_V;
+
+#ifdef PMAP_USE_BATC
+ batctmp = BATC_SO | BATC_V;
+ if (template & CACHE_WT)
+ batctmp |= BATC_WT;
+ if (template & CACHE_GLOBAL)
+ batctmp |= BATC_GLOBAL;
+ if (template & CACHE_INH)
+ batctmp |= BATC_INH;
+ if (template & PG_PROT)
+ batctmp |= BATC_PROT;
+#endif
+
+ page = trunc_page(start);
+ npages = atop(round_page(end) - page);
+ for (num_phys_pages = npages; num_phys_pages != 0; num_phys_pages--) {
+#ifdef PMAP_USE_BATC
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_MAP | CD_FULL)) == (CD_MAP | CD_FULL))
+ printf("(pmap_map: %x) num_phys_pg=%x, virt=%x, "
+ "align V=%d, page=%x, align P=%d\n",
+ curproc, num_phys_pages, virt,
+ BATC_BLK_ALIGNED(virt), page,
+ BATC_BLK_ALIGNED(page));
+#endif
+
+ if (BATC_BLK_ALIGNED(virt) && BATC_BLK_ALIGNED(page) &&
+ num_phys_pages >= BATC_BLKBYTES/PAGE_SIZE &&
+ batc_used < BATC_MAX ) {
+ /*
+ * map by BATC
+ */
+ batctmp |= M88K_BTOBLK(virt) << BATC_VSHIFT;
+ batctmp |= M88K_BTOBLK(page) << BATC_PSHIFT;
+
+ for (i = 0; i < MAX_CPUS; i++)
+ if (cpu_sets[i])
+ cmmu_set_pair_batc_entry(i, batc_used,
+ batctmp);
+ batc_entry[batc_used] = batctmp;
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_MAP) {
+ printf("(pmap_map: %x) BATC used=%d, data=%x\n", curproc, batc_used, batctmp);
+ for (i = 0; i < BATC_BLKBYTES; i += PAGE_SIZE) {
+ pte = pmap_pte(kernel_pmap, virt + i);
+ if (PDT_VALID(pte))
+ printf("(pmap_map: %x) va %x is already mapped: pte %x\n",
+ curproc, virt + i, *pte);
+ }
+ }
+#endif
+ batc_used++;
+ virt += BATC_BLKBYTES;
+ page += BATC_BLKBYTES;
+ num_phys_pages -= BATC_BLKBYTES/PAGE_SIZE;
+ continue;
+ }
+#endif /* PMAP_USE_BATC */
+
+ if ((pte = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL)
+ pte = pmap_expand_kmap(virt,
+ VM_PROT_READ | VM_PROT_WRITE);
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_MAP | CD_FULL)) == (CD_MAP | CD_FULL))
+ if (PDT_VALID(pte))
+ printf("(pmap_map: %x) pte @ 0x%p already valid\n", curproc, pte);
+#endif
+
+ *pte = template | page;
+ virt += PAGE_SIZE;
+ page += PAGE_SIZE;
+ }
+ return virt;
+}
+
+/*
+ * Routine: PMAP_CACHE_CONTROL
+ *
+ * Function:
+ * Set the cache-control bits in the page table entries(PTE) which maps
+ * the specified virtual address range.
+ *
+ * Parameters:
+ * pmap_t pmap
+ * vaddr_t s
+ * vaddr_t e
+ * u_int mode
+ *
+ * Calls:
+ * pmap_pte
+ * invalidate_pte
+ * flush_atc_entry
+ *
+ * This routine sequences through the pages of the specified range.
+ * For each, it calls pmap_pte to acquire a pointer to the page table
+ * entry (PTE). If the PTE is invalid, or non-existent, nothing is done.
+ * Otherwise, the cache-control bits in the PTE's are adjusted as specified.
+ *
+ */
+void
+pmap_cache_ctrl(pmap_t pmap, vaddr_t s, vaddr_t e, u_int mode)
+{
+ int spl;
+ pt_entry_t *pte;
+ vaddr_t va;
+ paddr_t pa;
+ boolean_t kflush;
+ int cpu;
+ u_int users;
+
+#ifdef DEBUG
+ if ((mode & CACHE_MASK) != mode) {
+ printf("(cache_ctrl) illegal mode %x\n", mode);
+ return;
+ }
+ if (pmap_con_dbg & CD_CACHE) {
+ printf("(pmap_cache_ctrl: %x) pmap %x, va %x, mode %x\n", curproc, pmap, s, mode);
+ }
+
+ if (pmap == PMAP_NULL)
+ panic("pmap_cache_ctrl: pmap is NULL");
+#endif /* DEBUG */
+
+ PMAP_LOCK(pmap, spl);
+
+ users = pmap->pm_cpus;
+ kflush = pmap == kernel_pmap;
+
+ for (va = s; va < e; va += PAGE_SIZE) {
+ if ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL)
+ continue;
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_CACHE) {
+ printf("(cache_ctrl) pte@0x%p\n", pte);
+ }
+#endif /* DEBUG */
+ /*
+ * Invalidate pte temporarily to avoid being written back
+ * the modified bit and/or the reference bit by any other cpu.
+ * XXX
+ */
+ *pte = (invalidate_pte(pte) & ~CACHE_MASK) | mode;
+ flush_atc_entry(users, va, kflush);
+
+ /*
+ * Data cache should be copied back and invalidated.
+ */
+ pa = ptoa(PG_PFNUM(*pte));
+ for (cpu = 0; cpu < MAX_CPUS; cpu++)
+ if (cpu_sets[cpu])
+ cmmu_flush_cache(cpu, pa, PAGE_SIZE);
+ }
+ PMAP_UNLOCK(pmap, spl);
+}
+
+/*
+ * Routine: PMAP_BOOTSTRAP
+ *
+ * Function:
+ * Bootstrap the system enough to run with virtual memory.
+ * Map the kernel's code and data, allocate the kernel
+ * translation table space, and map control registers
+ * and other IO addresses.
+ *
+ * Parameters:
+ * load_start PA where kernel was loaded
+ * &phys_start PA of first available physical page
+ * &phys_end PA of last available physical page
+ * &virtual_avail VA of first available page (after kernel bss)
+ * &virtual_end VA of last available page (end of kernel address space)
+ *
+ * Extern/Global:
+ *
+ * PAGE_SIZE VM (software) page size
+ * kernelstart start symbol of kernel text
+ * etext end of kernel text
+ * phys_map_vaddr VA of page mapped arbitrarily for debug/IO
+ *
+ * Calls:
+ * simple_lock_init
+ * pmap_map
+ *
+ * The physical address 'load_start' is mapped at
+ * VM_MIN_KERNEL_ADDRESS, which maps the kernel code and data at the
+ * virtual address for which it was (presumably) linked. Immediately
+ * following the end of the kernel code/data, sufficient page of
+ * physical memory are reserved to hold translation tables for the kernel
+ * address space. The 'phys_start' parameter is adjusted upward to
+ * reflect this allocation. This space is mapped in virtual memory
+ * immediately following the kernel code/data map.
+ *
+ * A pair of virtual pages per cpu are reserved for debugging and
+ * IO purposes. They are arbitrarily mapped when needed. They are used,
+ * for example, by pmap_copy_page and pmap_zero_page.
+ *
+ * For luna88k, we have to map ROM work area also. This is a read only
+ * mapping for 0x20000 bytes. We will end up having load_start as
+ * 0 and VM_MIN_KERNEL_ADDRESS as 0 - yes sir, we have one-to-one
+ * mapping!!!
+ */
+
+void
+pmap_bootstrap(vaddr_t load_start, paddr_t *phys_start, paddr_t *phys_end,
+ vaddr_t *virt_start, vaddr_t *virt_end)
+{
+ kpdt_entry_t kpdt_virt;
+ sdt_entry_t *kmap;
+ vaddr_t vaddr, virt, kernel_pmap_size, pdt_size;
+ paddr_t s_text, e_text, kpdt_phys;
+ pt_entry_t *pte;
+ int i;
+ pmap_table_t ptable;
+ extern void *kernelstart, *etext;
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_BOOT) {
+ printf("pmap_bootstrap: \"load_start\" 0x%x\n", load_start);
+ }
+ if (!PAGE_ALIGNED(load_start))
+ panic("pmap_bootstrap: \"load_start\" not on the m88k page boundary: 0x%x", load_start);
+#endif
+
+ simple_lock_init(&kernel_pmap->pm_lock);
+
+ /*
+ * Allocate the kernel page table from the front of available
+ * physical memory, i.e. just after where the kernel image was loaded.
+ */
+ /*
+ * The calling sequence is
+ * ...
+ * pmap_bootstrap(&kernelstart, ...);
+ * kernelstart is the first symbol in the load image.
+ * We link the kernel such that &kernelstart == 0x20000
+ * The expression (&kernelstart - load_start) will end up as
+ * 0, making *virt_start == *phys_start, giving a 1-to-1 map)
+ */
+
+ *phys_start = round_page(*phys_start);
+ *virt_start = *phys_start +
+ (trunc_page((vaddr_t)&kernelstart) - load_start);
+
+ /*
+ * Initialize kernel_pmap structure
+ */
+ kernel_pmap->pm_count = 1;
+ kernel_pmap->pm_cpus = 0;
+ kmap = (sdt_entry_t *)(*phys_start);
+ kernel_pmap->pm_stab = (sdt_entry_t *)(*virt_start);
+ kmapva = *virt_start;
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("kernel_pmap->pm_stab = 0x%x (pa 0x%x)\n",
+ kernel_pmap->pm_stab, kmap);
+ }
+#endif
+
+ /*
+ * Reserve space for segment table entries.
+ * One for the regular segment table and one for the shadow table
+ * The shadow table keeps track of the virtual address of page
+ * tables. This is used in virtual-to-physical address translation
+ * functions. Remember, MMU cares only for physical addresses of
+ * segment and page table addresses. For kernel page tables, we
+ * really don't need this virtual stuff (since the kernel will
+ * be mapped 1-to-1) but for user page tables, this is required.
+ * Just to be consistent, we will maintain the shadow table for
+ * kernel pmap also.
+ */
+ kernel_pmap_size = 2 * SDT_SIZE;
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("kernel segment table size = 0x%x\n", kernel_pmap_size);
+ }
+#endif
+ /* init all segment descriptors to zero */
+ bzero(kernel_pmap->pm_stab, kernel_pmap_size);
+
+ *phys_start += kernel_pmap_size;
+ *virt_start += kernel_pmap_size;
+
+ /* make sure page tables are page aligned!! XXX smurph */
+ *phys_start = round_page(*phys_start);
+ *virt_start = round_page(*virt_start);
+
+ /* save pointers to where page table entries start in physical memory */
+ kpdt_phys = *phys_start;
+ kpdt_virt = (kpdt_entry_t)*virt_start;
+
+ /* might as well round up to a page - XXX smurph */
+ pdt_size = round_page(MAX_KERNEL_PDT_SIZE);
+ kernel_pmap_size += pdt_size;
+ *phys_start += pdt_size;
+ *virt_start += pdt_size;
+
+ /* init all page descriptors to zero */
+ bzero((void *)kpdt_phys, pdt_size);
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("--------------------------------------\n");
+ printf(" kernel page start = 0x%x\n", kpdt_phys);
+ printf(" kernel page table size = 0x%x\n", pdt_size);
+ printf(" kernel page end = 0x%x\n", *phys_start);
+ }
+#endif
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("kpdt_phys = 0x%x\n", kpdt_phys);
+ printf("kpdt_virt = 0x%x\n", kpdt_virt);
+ printf("end of kpdt at (virt)0x%08x, (phys)0x%08x\n",
+ *virt_start, *phys_start);
+ }
+#endif
+ /*
+ * init the kpdt queue
+ */
+ kpdt_free = kpdt_virt;
+ for (i = pdt_size / PDT_SIZE; i != 0; i--) {
+ kpdt_virt->next = (kpdt_entry_t)((vaddr_t)kpdt_virt + PDT_SIZE);
+ kpdt_virt->phys = kpdt_phys;
+ kpdt_virt = kpdt_virt->next;
+ kpdt_phys += PDT_SIZE;
+ }
+ kpdt_virt->next = KPDT_ENTRY_NULL; /* terminate the list */
+
+ /*
+ * Map the kernel image into virtual space
+ */
+
+ s_text = load_start; /* paddr of text */
+ e_text = load_start +
+ ((vaddr_t)&etext - trunc_page((vaddr_t)&kernelstart));
+ /* paddr of end of text section*/
+ e_text = round_page(e_text);
+
+#if 0
+ /* map the first 128k (PROM work) read only, cache inhibited (? XXX) */
+ vaddr = pmap_map(0, 0, 0x20000, VM_PROT_WRITE | VM_PROT_READ,
+ CACHE_INH);
+#endif
+
+ /* map the kernel text read only */
+ vaddr = pmap_map(trunc_page((vaddr_t)&kernelstart),
+ s_text, e_text, VM_PROT_WRITE | VM_PROT_READ,
+ CACHE_GLOBAL); /* shouldn't it be RO? XXX*/
+
+ vaddr = pmap_map(vaddr, e_text, (paddr_t)kmap,
+ VM_PROT_WRITE | VM_PROT_READ, CACHE_GLOBAL);
+
+ /*
+ * Map system segment & page tables - should be cache inhibited?
+ * 88200 manual says that CI bit is driven on the Mbus while accessing
+ * the translation tree. I don't think we need to map it CACHE_INH
+ * here...
+ */
+ if (kmapva != vaddr) {
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("(pmap_bootstrap) correcting vaddr\n");
+ }
+#endif
+ while (vaddr < (*virt_start - kernel_pmap_size))
+ vaddr = round_page(vaddr + 1);
+ }
+ vaddr = pmap_map(vaddr, (paddr_t)kmap, *phys_start,
+ VM_PROT_WRITE | VM_PROT_READ, CACHE_INH);
+
+#if defined (MVME187) || defined (MVME197)
+ /*
+ * Get ethernet buffer - need etherlen bytes physically contiguous.
+ * 1 to 1 mapped as well???. There is actually a bug in the macros
+ * used by the 1x7 ethernet driver. Remove this when that is fixed.
+ * XXX -nivas
+ */
+ if (brdtyp == BRD_187 || brdtyp == BRD_8120 || brdtyp == BRD_197) {
+ *phys_start = vaddr;
+ etherlen = ETHERPAGES * PAGE_SIZE;
+ etherbuf = (void *)vaddr;
+
+ vaddr = pmap_map(vaddr, *phys_start, *phys_start + etherlen,
+ VM_PROT_WRITE | VM_PROT_READ, CACHE_INH);
+
+ *virt_start += etherlen;
+ *phys_start += etherlen;
+
+ if (vaddr != *virt_start) {
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("2: vaddr %x *virt_start %x *phys_start %x\n", vaddr,
+ *virt_start, *phys_start);
+ }
+#endif
+ *virt_start = vaddr;
+ *phys_start = round_page(*phys_start);
+ }
+ }
+
+#endif /* defined (MVME187) || defined (MVME197) */
+
+ *virt_start = round_page(*virt_start);
+ *virt_end = VM_MAX_KERNEL_ADDRESS;
+
+ /*
+ * Map two pages per cpu for copying/zeroing.
+ */
+
+ phys_map_vaddr = *virt_start;
+ phys_map_vaddr_end = *virt_start + 2 * (max_cpus << PAGE_SHIFT);
+ *phys_start += 2 * (max_cpus << PAGE_SHIFT);
+ *virt_start += 2 * (max_cpus << PAGE_SHIFT);
+
+ /*
+ * Map all IO space 1-to-1. Ideally, I would like to not do this
+ * but have va for the given IO address dynamically allocated. But
+ * on the 88200, 2 of the BATCs are hardwired to map the IO space
+ * 1-to-1; I decided to map the rest of the IO space 1-to-1.
+ * And bug ROM & the SRAM need to be mapped 1-to-1 if we ever want to
+ * execute bug system calls after the MMU has been turned on.
+ * OBIO should be mapped cache inhibited.
+ */
+
+ ptable = pmap_table_build();
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("pmap_bootstrap: -> pmap_table_build\n");
+ }
+#endif
+
+ for (; ptable->size != (vsize_t)(-1); ptable++){
+ if (ptable->size) {
+ pmap_map(ptable->virt_start, ptable->phys_start,
+ ptable->phys_start + ptable->size,
+ ptable->prot, ptable->cacheability);
+ }
+ }
+
+ /*
+ * Allocate all the submaps we need. Note that SYSMAP just allocates
+ * kernel virtual address with no physical backing memory. The idea
+ * is physical memory will be mapped at this va before using that va.
+ * This means that if different physical pages are going to be mapped
+ * at different times, we better do a tlb flush before using it -
+ * else we will be referencing the wrong page.
+ */
+
+#define SYSMAP(c, p, v, n) \
+({ \
+ v = (c)virt; \
+ if ((p = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL) \
+ pmap_expand_kmap(virt, VM_PROT_READ | VM_PROT_WRITE); \
+ virt += ((n) * PAGE_SIZE); \
+})
+
+ virt = *virt_start;
+
+ SYSMAP(caddr_t, vmpte, vmmap, 1);
+ invalidate_pte(vmpte);
+
+ SYSMAP(struct msgbuf *, msgbufmap, msgbufp, btoc(MSGBUFSIZE));
+
+ *virt_start = virt;
+
+ /*
+ * Set translation for UPAGES at UADDR. The idea is we want to
+ * have translations set up for UADDR. Later on, the ptes for
+ * for this address will be set so that kstack will refer
+ * to the u area. Make sure pmap knows about this virtual
+ * address by doing vm_findspace on kernel_map.
+ */
+
+ for (i = 0, virt = UADDR; i < UPAGES; i++, virt += PAGE_SIZE) {
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("setting up mapping for Upage %d @ %x\n", i, virt);
+ }
+#endif
+ if ((pte = pmap_pte(kernel_pmap, virt)) == PT_ENTRY_NULL)
+ pmap_expand_kmap(virt, VM_PROT_READ | VM_PROT_WRITE);
+ }
+
+ /*
+ * Switch to using new page tables
+ */
+
+ kernel_pmap->pm_apr = (atop(kmap) << PG_SHIFT) |
+ CACHE_GLOBAL | CACHE_WT | APR_V;
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ show_apr(kernel_pmap->pm_apr);
+ }
+#endif
+ /* Invalidate entire kernel TLB and get ready for address translation */
+ for (i = 0; i < MAX_CPUS; i++)
+ if (cpu_sets[i]) {
+ cmmu_flush_tlb(i, TRUE, VM_MIN_KERNEL_ADDRESS,
+ VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS);
+ /* Load supervisor pointer to segment table. */
+ cmmu_set_sapr(i, kernel_pmap->pm_apr);
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("Processor %d running virtual.\n", i);
+ }
+#endif
+ SETBIT_CPUSET(i, &kernel_pmap->pm_cpus);
+ }
+
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_BOOT | CD_FULL)) == (CD_BOOT | CD_FULL)) {
+ printf("running virtual - avail_next 0x%x\n", *phys_start);
+ }
+#endif
+}
+
+/*
+ * Routine: PMAP_INIT
+ *
+ * Function:
+ * Initialize the pmap module. It is called by vm_init, to initialize
+ * any structures that the pmap system needs to map virtual memory.
+ *
+ * Calls:
+ * pool_init
+ *
+ * This routine does not really have much to do. It initializes
+ * pools for pmap structures and pv_entry structures.
+ */
+void
+pmap_init(void)
+{
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_INIT)
+ printf("pmap_init()\n");
+#endif
+
+ pool_init(&pmappool, sizeof(struct pmap), 0, 0, 0, "pmappl",
+ &pool_allocator_nointr);
+ pool_init(&pvpool, sizeof(pv_entry_t), 0, 0, 0, "pvpl", NULL);
+} /* pmap_init() */
+
+/*
+ * Routine: PMAP_ZERO_PAGE
+ *
+ * Function:
+ * Zeroes the specified page.
+ *
+ * Parameters:
+ * pg page to zero
+ *
+ * Extern/Global:
+ * phys_map_vaddr
+ *
+ * Calls:
+ * m88k_protection
+ *
+ * Special Assumptions:
+ * no locking required
+ *
+ * This routine maps the physical pages at the 'phys_map' virtual
+ * address set up in pmap_bootstrap. It flushes the TLB to make the new
+ * mappings effective, and zeros all the bits.
+ */
+void
+pmap_zero_page(struct vm_page *pg)
+{
+ paddr_t pa = VM_PAGE_TO_PHYS(pg);
+ vaddr_t va;
+ int spl;
+ int cpu = cpu_number();
+ pt_entry_t *pte;
+
+ CHECK_PAGE_ALIGN(pa, "pmap_zero_page");
+
+ va = (vaddr_t)(phys_map_vaddr + 2 * (cpu << PAGE_SHIFT));
+ pte = pmap_pte(kernel_pmap, va);
+
+ SPLVM(spl);
+
+ *pte = m88k_protection(kernel_pmap, VM_PROT_READ | VM_PROT_WRITE) |
+ CACHE_GLOBAL | PG_V | pa;
+
+ /*
+ * We don't need the flush_atc_entry() dance, as these pages are
+ * bound to only one cpu.
+ */
+ cmmu_flush_tlb(cpu, TRUE, va, PAGE_SIZE);
+
+ /*
+ * The page is likely to be a non-kernel mapping, and as
+ * such write back. Also, we might have split U/S caches!
+ * So be sure to have the pa flushed after the filling.
+ */
+ bzero((void *)va, PAGE_SIZE);
+ cmmu_flush_data_cache(cpu, pa, PAGE_SIZE);
+
+ SPLX(spl);
+}
+
+/*
+ * Routine: PMAP_CREATE
+ *
+ * Function:
+ * Create and return a physical map. If the size specified for the
+ * map is zero, the map is an actual physical map, and may be referenced
+ * by the hardware. If the size specified is non-zero, the map will be
+ * used in software only, and is bounded by that size.
+ *
+ * This routines allocates a pmap structure.
+ */
+pmap_t
+pmap_create(void)
+{
+ pmap_t pmap;
+ sdt_entry_t *segdt;
+ paddr_t stpa;
+ u_int s;
+#ifdef PMAP_USE_BATC
+ int i;
+#endif
+
+ pmap = pool_get(&pmappool, PR_WAITOK);
+ bzero(pmap, sizeof(*pmap));
+
+ /*
+ * Allocate memory for *actual* segment table and *shadow* table.
+ */
+ s = round_page(2 * SDT_SIZE);
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_CREAT) {
+ printf("(pmap_create: %x) need %d pages for sdt\n",
+ curproc, atop(s));
+ }
+#endif
+
+ segdt = (sdt_entry_t *)uvm_km_zalloc(kernel_map, s);
+ if (segdt == NULL)
+ panic("pmap_create: uvm_km_zalloc failure");
+
+ /*
+ * Initialize pointer to segment table both virtual and physical.
+ */
+ pmap->pm_stab = segdt;
+ if (pmap_extract(kernel_pmap, (vaddr_t)segdt,
+ (paddr_t *)&stpa) == FALSE)
+ panic("pmap_create: pmap_extract failed!");
+ pmap->pm_apr = (atop(stpa) << PG_SHIFT) |
+ CACHE_GLOBAL | APR_V;
+
+#ifdef DEBUG
+ if (!PAGE_ALIGNED(stpa))
+ panic("pmap_create: sdt_table 0x%x not aligned on page boundary",
+ (int)stpa);
+
+ if (pmap_con_dbg & CD_CREAT) {
+ printf("(pmap_create: %x) pmap=0x%p, pm_stab=0x%x (pa 0x%x)\n",
+ curproc, pmap, pmap->pm_stab, stpa);
+ }
+#endif
+
+ /* memory for page tables should not be writeback or local */
+ pmap_cache_ctrl(kernel_pmap,
+ (vaddr_t)segdt, (vaddr_t)segdt + s, CACHE_GLOBAL | CACHE_WT);
+
+ /*
+ * Initialize SDT_ENTRIES.
+ */
+ /*
+ * There is no need to clear segment table, since uvm_km_zalloc
+ * provides us clean pages.
+ */
+
+ /*
+ * Initialize pmap structure.
+ */
+ pmap->pm_count = 1;
+ simple_lock_init(&pmap->pm_lock);
+ pmap->pm_cpus = 0;
+
+#ifdef PMAP_USE_BATC
+ /* initialize block address translation cache */
+ for (i = 0; i < BATC_MAX; i++) {
+ pmap->pm_ibatc[i].bits = 0;
+ pmap->pm_dbatc[i].bits = 0;
+ }
+#endif
+
+ return pmap;
+}
+
+/*
+ * Routine: PMAP_RELEASE
+ *
+ * Internal procedure used by pmap_destroy() to actualy deallocate
+ * the tables.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ *
+ * Calls:
+ * pmap_pte
+ * uvm_km_free
+ *
+ * Special Assumptions:
+ * No locking is needed, since this is only called which the
+ * pm_count field of the pmap structure goes to zero.
+ *
+ * This routine sequences of through the user address space, releasing
+ * all translation table space back to the system using uvm_km_free.
+ * The loops are indexed by the virtual address space
+ * ranges represented by the table group sizes(PDT_VA_SPACE).
+ *
+ */
+void
+pmap_release(pmap_t pmap)
+{
+ unsigned long sdt_va; /* outer loop index */
+ sdt_entry_t *sdttbl; /* ptr to first entry in the segment table */
+ pt_entry_t *gdttbl; /* ptr to first entry in a page table */
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_FREE)
+ printf("(pmap_release: %x) pmap %x\n", curproc, pmap);
+#endif
+
+ /* Segment table Loop */
+ for (sdt_va = VM_MIN_ADDRESS; sdt_va < VM_MAX_ADDRESS;
+ sdt_va += PDT_VA_SPACE) {
+ if ((gdttbl = pmap_pte(pmap, (vaddr_t)sdt_va)) != PT_ENTRY_NULL) {
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_FREE | CD_FULL)) == (CD_FREE | CD_FULL))
+ printf("(pmap_release: %x) free page table = 0x%x\n",
+ curproc, gdttbl);
+#endif
+ uvm_km_free(kernel_map, (vaddr_t)gdttbl, PAGE_SIZE);
+ }
+ }
+
+ /*
+ * Freeing both *actual* and *shadow* segment tables
+ */
+ sdttbl = pmap->pm_stab; /* addr of segment table */
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_FREE | CD_FULL)) == (CD_FREE | CD_FULL))
+ printf("(pmap_release: %x) free segment table = 0x%x\n",
+ curproc, sdttbl);
+#endif
+ uvm_km_free(kernel_map, (vaddr_t)sdttbl, round_page(2 * SDT_SIZE));
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_FREE)
+ printf("(pmap_release: %x) pm_count = 0\n", curproc);
+#endif
+}
+
+/*
+ * Routine: PMAP_DESTROY
+ *
+ * Function:
+ * Retire the given physical map from service. Should only be called
+ * if the map contains no valid mappings.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ *
+ * Calls:
+ * pmap_release
+ * pool_put
+ *
+ * Special Assumptions:
+ * Map contains no valid mappings.
+ *
+ * This routine decrements the reference count in the pmap
+ * structure. If it goes to zero, pmap_release is called to release
+ * the memory space to the system. Then, call pool_put to free the
+ * pmap structure.
+ */
+void
+pmap_destroy(pmap_t pmap)
+{
+ int count;
+
+#ifdef DEBUG
+ if (pmap == kernel_pmap)
+ panic("pmap_destroy: Attempt to destroy kernel pmap");
+#endif
+
+ simple_lock(&pmap->pm_lock);
+ count = --pmap->pm_count;
+ simple_unlock(&pmap->pm_lock);
+ if (count == 0) {
+ pmap_release(pmap);
+ pool_put(&pmappool, pmap);
+ }
+}
+
+
+/*
+ * Routine: PMAP_REFERENCE
+ *
+ * Function:
+ * Add a reference to the specified pmap.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ *
+ * Under a pmap read lock, the pm_count field of the pmap structure
+ * is incremented. The function then returns.
+ */
+void
+pmap_reference(pmap_t pmap)
+{
+
+ simple_lock(&pmap->pm_lock);
+ pmap->pm_count++;
+ simple_unlock(&pmap->pm_lock);
+}
+
+/*
+ * Routine: PMAP_REMOVE_PTE (internal)
+ *
+ * Function:
+ * Invalidate a given page table entry associated with the
+ * given virtual address.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * va virtual address of page to remove
+ * pte existing pte
+ *
+ * External/Global:
+ * pv lists
+ *
+ * Calls:
+ * pool_put
+ * invalidate_pte
+ * flush_atc_entry
+ *
+ * Special Assumptions:
+ * The pmap must be locked.
+ *
+ * If the PTE is valid, the routine must invalidate the entry. The
+ * 'modified' bit, if on, is referenced to the VM, and into the appropriate
+ * entry in the PV list entry. Next, the function must find the PV
+ * list entry associated with this pmap/va (if it doesn't exist - the function
+ * panics). The PV list entry is unlinked from the list, and returned to
+ * its zone.
+ */
+void
+pmap_remove_pte(pmap_t pmap, vaddr_t va, pt_entry_t *pte)
+{
+ pt_entry_t opte;
+ pv_entry_t prev, cur, pvl;
+ struct vm_page *pg;
+ paddr_t pa;
+ u_int users;
+ boolean_t kflush;
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_RM) {
+ if (pmap == kernel_pmap)
+ printf("(pmap_remove_pte: %x) pmap kernel va %x\n", curproc, va);
+ else
+ printf("(pmap_remove: %x) pmap %x va %x\n", curproc, pmap, va);
+ }
+#endif
+
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ return; /* no page mapping, nothing to do! */
+ }
+
+ users = pmap->pm_cpus;
+ kflush = pmap == kernel_pmap;
+
+ /*
+ * Update statistics.
+ */
+ pmap->pm_stats.resident_count--;
+ if (pmap_pte_w(pte))
+ pmap->pm_stats.wired_count--;
+
+ pa = ptoa(PG_PFNUM(*pte));
+
+ /*
+ * Invalidate the pte.
+ */
+
+ opte = invalidate_pte(pte) & (PG_U | PG_M);
+ flush_atc_entry(users, va, kflush);
+
+ pg = PHYS_TO_VM_PAGE(pa);
+
+ /* If this isn't a managed page, just return. */
+ if (pg == NULL)
+ return;
+
+ /*
+ * Remove the mapping from the pvlist for
+ * this physical page.
+ */
+ pvl = pg_to_pvh(pg);
+
+#ifdef DIAGNOSTIC
+ if (pvl->pv_pmap == PMAP_NULL)
+ panic("pmap_remove_pte: null pv_list");
+#endif
+
+ prev = PV_ENTRY_NULL;
+ for (cur = pvl; cur != PV_ENTRY_NULL; cur = cur->pv_next) {
+ if (cur->pv_va == va && cur->pv_pmap == pmap)
+ break;
+ prev = cur;
+ }
+ if (cur == PV_ENTRY_NULL) {
+ panic("pmap_remove_pte: mapping for va "
+ "0x%lx (pa 0x%lx) not in pv list at 0x%p",
+ va, pa, pvl);
+ }
+
+ if (prev == PV_ENTRY_NULL) {
+ /*
+ * Hander is the pv_entry. Copy the next one
+ * to hander and free the next one (we can't
+ * free the hander)
+ */
+ cur = cur->pv_next;
+ if (cur != PV_ENTRY_NULL) {
+ cur->pv_flags = pvl->pv_flags;
+ *pvl = *cur;
+ pool_put(&pvpool, cur);
+ } else {
+ pvl->pv_pmap = PMAP_NULL;
+ }
+ } else {
+ prev->pv_next = cur->pv_next;
+ pool_put(&pvpool, cur);
+ }
+
+ /* Update saved attributes for managed page */
+ pvl->pv_flags |= opte;
+}
+
+/*
+ * Routine: PMAP_REMOVE_RANGE (internal)
+ *
+ * Function:
+ * Invalidate page table entries associated with the
+ * given virtual address range. The entries given are the first
+ * (inclusive) and last (exclusive) entries for the VM pages.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * s virtual address of start of range to remove
+ * e virtual address of end of range to remove
+ *
+ * External/Global:
+ * pv lists
+ *
+ * Calls:
+ * pmap_pte
+ * pmap_remove_pte
+ *
+ * Special Assumptions:
+ * The pmap must be locked.
+ *
+ * This routine sequences through the pages defined by the given
+ * range. For each page, the associated page table entry (PTE) is
+ * invalidated via pmap_remove_pte().
+ *
+ * Empty segments are skipped for performance.
+ */
+void
+pmap_remove_range(pmap_t pmap, vaddr_t s, vaddr_t e)
+{
+ vaddr_t va;
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_RM) {
+ if (pmap == kernel_pmap)
+ printf("(pmap_remove: %x) pmap kernel s %x e %x\n", curproc, s, e);
+ else
+ printf("(pmap_remove: %x) pmap %x s %x e %x\n", curproc, pmap, s, e);
+ }
+#endif
+
+ /*
+ * Loop through the range in vm_page_size increments.
+ */
+ for (va = s; va < e; va += PAGE_SIZE) {
+ sdt_entry_t *sdt;
+
+ sdt = SDTENT(pmap, va);
+
+ /* If no segment table, skip a whole segment */
+ if (!SDT_VALID(sdt)) {
+ va &= SDT_MASK;
+ va += (1 << SDT_SHIFT) - PAGE_SIZE;
+ continue;
+ }
+
+ pmap_remove_pte(pmap, va, pmap_pte(pmap, va));
+ }
+}
+
+/*
+ * Routine: PMAP_REMOVE
+ *
+ * Function:
+ * Remove the given range of addresses from the specified map.
+ * It is assumed that start and end are properly rounded to the VM page
+ * size.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * s
+ * e
+ *
+ * Special Assumptions:
+ * Assumes not all entries must be valid in specified range.
+ *
+ * Calls:
+ * pmap_remove_range
+ *
+ * After taking pmap read lock, pmap_remove_range is called to do the
+ * real work.
+ */
+void
+pmap_remove(pmap_t pmap, vaddr_t s, vaddr_t e)
+{
+ int spl;
+
+ if (pmap == PMAP_NULL)
+ return;
+
+#ifdef DEBUG
+ if (s >= e)
+ panic("pmap_remove: start greater than end address");
+#endif
+
+ PMAP_LOCK(pmap, spl);
+ pmap_remove_range(pmap, s, e);
+ PMAP_UNLOCK(pmap, spl);
+}
+
+/*
+ * Routine: PMAP_REMOVE_ALL
+ *
+ * Function:
+ * Removes this physical page from all physical maps in which it
+ * resides. Reflects back modify bits to the pager.
+ *
+ * Parameters:
+ * pg physical pages which is to
+ * be removed from all maps
+ *
+ * Extern/Global:
+ * pv lists
+ *
+ * Calls:
+ * simple_lock
+ * pmap_pte
+ * pool_put
+ *
+ * If the page specified by the given address is not a managed page,
+ * this routine simply returns. Otherwise, the PV list associated with
+ * that page is traversed. For each pmap/va pair pmap_pte is called to
+ * obtain a pointer to the page table entry (PTE) associated with the
+ * va (the PTE must exist and be valid, otherwise the routine panics).
+ * The hardware 'modified' bit in the PTE is examined. If it is on, the
+ * corresponding bit in the PV list entry corresponding
+ * to the physical page is set to 1.
+ * Then, the PTE is invalidated, and the PV list entry is unlinked and
+ * freed.
+ *
+ * At the end of this function, the PV list for the specified page
+ * will be null.
+ */
+void
+pmap_remove_all(struct vm_page *pg)
+{
+ pt_entry_t *pte;
+ pv_entry_t pvl;
+ vaddr_t va;
+ pmap_t pmap;
+ int spl;
+
+ if (pg == NULL) {
+ /* not a managed page. */
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_RMAL)
+ printf("(pmap_remove_all: %x) vm page 0x%x not a managed page\n", curproc, pg);
+#endif
+ return;
+ }
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_RMAL)
+ printf("(pmap_remove_all: %x) va %x\n", curproc, pg, pg_to_pvh(pg)->pv_va);
+#endif
+
+ SPLVM(spl);
+ /*
+ * Walk down PV list, removing all mappings.
+ * We don't have to lock the pv list, since we have the entire pmap
+ * system.
+ */
+remove_all_Retry:
+
+ pvl = pg_to_pvh(pg);
+
+ /*
+ * Loop for each entry on the pv list
+ */
+ while (pvl != PV_ENTRY_NULL && (pmap = pvl->pv_pmap) != PMAP_NULL) {
+ if (!simple_lock_try(&pmap->pm_lock))
+ goto remove_all_Retry;
+
+ va = pvl->pv_va;
+ pte = pmap_pte(pmap, va);
+
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ pvl = pvl->pv_next;
+ goto next; /* no page mapping */
+ }
+ if (pmap_pte_w(pte)) {
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_RMAL)
+ printf("pmap_remove_all: wired mapping for %lx not removed\n",
+ pg);
+#endif
+ pvl = pvl->pv_next;
+ goto next;
+ }
+
+ pmap_remove_pte(pmap, va, pte);
+
+ /*
+ * Do not free any page tables,
+ * leaves that for when VM calls pmap_collect().
+ */
+next:
+ simple_unlock(&pmap->pm_lock);
+ }
+ SPLX(spl);
+}
+
+/*
+ * Routine: PMAP_PROTECT
+ *
+ * Function:
+ * Sets the physical protection on the specified range of this map
+ * as requested.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * s start address of start of range
+ * e end address of end of range
+ * prot desired protection attributes
+ *
+ * Calls:
+ * PMAP_LOCK, PMAP_UNLOCK
+ * CHECK_PAGE_ALIGN
+ * pmap_pte
+ * PDT_VALID
+ *
+ * This routine sequences through the pages of the specified range.
+ * For each, it calls pmap_pte to acquire a pointer to the page table
+ * entry (PTE). If the PTE is invalid, or non-existent, nothing is done.
+ * Otherwise, the PTE's protection attributes are adjusted as specified.
+ */
+void
+pmap_protect(pmap_t pmap, vaddr_t s, vaddr_t e, vm_prot_t prot)
+{
+ int spl;
+ pt_entry_t *pte, ap;
+ vaddr_t va;
+ u_int users;
+ boolean_t kflush;
+
+#ifdef DEBUG
+ if (s >= e)
+ panic("pmap_protect: start grater than end address");
+#endif
+
+ if ((prot & VM_PROT_READ) == 0) {
+ pmap_remove(pmap, s, e);
+ return;
+ }
+
+ ap = m88k_protection(pmap, prot) & PG_PROT;
+
+ PMAP_LOCK(pmap, spl);
+
+ users = pmap->pm_cpus;
+ kflush = pmap == kernel_pmap;
+
+ CHECK_PAGE_ALIGN(s, "pmap_protect");
+
+ /*
+ * Loop through the range in vm_page_size increments.
+ */
+ for (va = s; va < e; va += PAGE_SIZE) {
+ sdt_entry_t *sdt;
+
+ sdt = SDTENT(pmap, va);
+
+ /* If no segment table, skip a whole segment */
+ if (!SDT_VALID(sdt)) {
+ va &= SDT_MASK;
+ va += (1 << SDT_SHIFT) - PAGE_SIZE;
+ continue;
+ }
+
+ pte = pmap_pte(pmap, va);
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ continue; /* no page mapping */
+ }
+
+ /*
+ * Invalidate pte temporarily to avoid the
+ * modified bit and/or the reference bit being
+ * written back by any other cpu.
+ */
+ *pte = (invalidate_pte(pte) & ~PG_PROT) | ap;
+ flush_atc_entry(users, va, kflush);
+ pte++;
+ }
+ PMAP_UNLOCK(pmap, spl);
+}
+
+/*
+ * Routine: PMAP_EXPAND
+ *
+ * Function:
+ * Expands a pmap to be able to map the specified virtual address.
+ * New kernel virtual memory is allocated for a page table.
+ *
+ * Must be called with the pmap system and the pmap unlocked, since
+ * these must be unlocked to use vm_allocate or vm_deallocate (via
+ * uvm_km_zalloc). Thus it must be called in a unlock/lock loop
+ * that checks whether the map has been expanded enough. (We won't loop
+ * forever, since page table aren't shrunk.)
+ *
+ * Parameters:
+ * pmap point to pmap structure
+ * v VA indicating which tables are needed
+ *
+ * Extern/Global:
+ * user_pt_map
+ * kernel_pmap
+ *
+ * Calls:
+ * pmap_pte
+ * uvm_km_free
+ * uvm_km_zalloc
+ * pmap_extract
+ *
+ * Special Assumptions
+ * no pmap locks held
+ * pmap != kernel_pmap
+ *
+ * 1: This routine immediately allocates space for a page table.
+ *
+ * 2: The page table entries (PTEs) are initialized (set invalid), and
+ * the corresponding segment table entry is set to point to the new
+ * page table.
+ */
+void
+pmap_expand(pmap_t pmap, vaddr_t v)
+{
+ int spl;
+ vaddr_t pdt_vaddr;
+ paddr_t pdt_paddr;
+ sdt_entry_t *sdt;
+ pt_entry_t *pte;
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_EXP)
+ printf ("(pmap_expand: %x) map %x v %x\n", curproc, pmap, v);
+#endif
+
+ CHECK_PAGE_ALIGN(v, "pmap_expand");
+
+ /* XXX */
+ pdt_vaddr = uvm_km_zalloc(kernel_map, PAGE_SIZE);
+ if (pmap_extract(kernel_pmap, pdt_vaddr, &pdt_paddr) == FALSE)
+ panic("pmap_expand: pmap_extract failed");
+
+ /* memory for page tables should not be writeback or local */
+ pmap_cache_ctrl(kernel_pmap,
+ pdt_vaddr, pdt_vaddr + PAGE_SIZE, CACHE_GLOBAL | CACHE_WT);
+
+ PMAP_LOCK(pmap, spl);
+
+ if ((pte = pmap_pte(pmap, v)) != PT_ENTRY_NULL) {
+ /*
+ * Someone else caused us to expand
+ * during our vm_allocate.
+ */
+ simple_unlock(&pmap->pm_lock);
+ uvm_km_free(kernel_map, pdt_vaddr, PAGE_SIZE);
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_EXP)
+ printf("(pmap_expand: %x) table has already been allocated\n", curproc);
+#endif
+ splx(spl);
+ return;
+ }
+ /*
+ * Apply a mask to V to obtain the vaddr of the beginning of
+ * its containing page 'table group', i.e. the group of
+ * page tables that fit eithin a single VM page.
+ * Using that, obtain the segment table pointer that references the
+ * first page table in the group, and initialize all the
+ * segment table descriptions for the page 'table group'.
+ */
+ v &= ~((1 << (PDT_BITS + PG_BITS)) - 1);
+
+ sdt = SDTENT(pmap, v);
+
+ /*
+ * Init each of the segment entries to point the freshly allocated
+ * page tables.
+ */
+ *((sdt_entry_t *)sdt) = pdt_paddr | SG_RW | SG_V;
+ *((sdt_entry_t *)(sdt + SDT_ENTRIES)) = pdt_vaddr | SG_RW | SG_V;
+
+ PMAP_UNLOCK(pmap, spl);
+}
+
+/*
+ * Routine: PMAP_ENTER
+ *
+ * Function:
+ * Insert the given physical page (p) at the specified virtual
+ * address (v) in the target phisical map with the protecton requested.
+ * If specified, the page will be wired down, meaning that the
+ * related pte can not be reclaimed.
+ *
+ * N.B.: This is the only routine which MAY NOT lazy-evaluation or lose
+ * information. That is, this routine must actually insert this page
+ * into the given map NOW.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * va VA of page to be mapped
+ * pa PA of page to be mapped
+ * prot protection attributes for page
+ * wired wired attribute for page
+ *
+ * Extern/Global:
+ * pv lists
+ *
+ * Calls:
+ * m88k_protection
+ * pmap_pte
+ * pmap_expand
+ * pmap_remove_pte
+ *
+ * This routine starts off by calling pmap_pte to obtain a (virtual)
+ * pointer to the page table entry corresponding to given virtual
+ * address. If the page table itself does not exist, pmap_expand is
+ * called to allocate it.
+ *
+ * If the page table entry (PTE) already maps the given physical page,
+ * all that is needed is to set the protection and wired attributes as
+ * given. TLB entries are flushed and pmap_enter returns.
+ *
+ * If the page table entry (PTE) maps a different physical page than
+ * that given, the old mapping is removed by a call to map_remove_range.
+ * And execution of pmap_enter continues.
+ *
+ * To map the new physical page, the routine first inserts a new
+ * entry in the PV list exhibiting the given pmap and virtual address.
+ * It then inserts the physical page address, protection attributes, and
+ * wired attributes into the page table entry (PTE).
+ *
+ *
+ * get machine-dependent prot code
+ * get the pte for this page
+ * if necessary pmap_expand(pmap, v)
+ * if (changing wired attribute or protection) {
+ * flush entry from TLB
+ * update template
+ * for (ptes per vm page)
+ * stuff pte
+ * } else if (mapped at wrong addr)
+ * flush entry from TLB
+ * pmap_remove_pte
+ * } else {
+ * enter mapping in pv_list
+ * setup template and stuff ptes
+ * }
+ *
+ */
+int
+pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
+{
+ int spl;
+ pt_entry_t *pte, template;
+ paddr_t old_pa;
+ pv_entry_t pv_e, pvl;
+ u_int users;
+ boolean_t kflush;
+ boolean_t wired = (flags & PMAP_WIRED) != 0;
+ struct vm_page *pg;
+
+ CHECK_PAGE_ALIGN(va, "pmap_entry - va");
+ CHECK_PAGE_ALIGN(pa, "pmap_entry - pa");
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_ENT) {
+ if (pmap == kernel_pmap)
+ printf("(pmap_enter: %x) pmap kernel va %x pa %x\n", curproc, va, pa);
+ else
+ printf("(pmap_enter: %x) pmap %x va %x pa %x\n", curproc, pmap, va, pa);
+ }
+
+ /* copying/zeroing pages are magic */
+ if (pmap == kernel_pmap &&
+ va >= phys_map_vaddr && va < phys_map_vaddr_end) {
+ return 0;
+ }
+#endif
+
+ template = m88k_protection(pmap, prot);
+
+ PMAP_LOCK(pmap, spl);
+ users = pmap->pm_cpus;
+ kflush = pmap == kernel_pmap;
+
+ /*
+ * Expand pmap to include this pte.
+ */
+ while ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL) {
+ if (pmap == kernel_pmap) {
+ pmap_expand_kmap(va, VM_PROT_READ | VM_PROT_WRITE);
+ } else {
+ /*
+ * Must unlock to expand the pmap.
+ */
+ simple_unlock(&pmap->pm_lock);
+ pmap_expand(pmap, va);
+ simple_lock(&pmap->pm_lock);
+ }
+ }
+ /*
+ * Special case if the physical page is already mapped at this address.
+ */
+ old_pa = ptoa(PG_PFNUM(*pte));
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_ENT)
+ printf("(pmap_enter) old_pa %x pte %x\n", old_pa, *pte);
+#endif
+ if (old_pa == pa) {
+ /* May be changing its wired attributes or protection */
+ if (wired && !(pmap_pte_w(pte)))
+ pmap->pm_stats.wired_count++;
+ else if (!wired && pmap_pte_w(pte))
+ pmap->pm_stats.wired_count--;
+
+ pvl = NULL;
+ } else { /* if (pa == old_pa) */
+ /* Remove old mapping from the PV list if necessary. */
+ pmap_remove_pte(pmap, va, pte);
+
+ pg = PHYS_TO_VM_PAGE(pa);
+ if (pg != NULL) {
+ /*
+ * Enter the mapping in the PV list for this
+ * physical page.
+ */
+ pvl = pg_to_pvh(pg);
+
+ if (pvl->pv_pmap == PMAP_NULL) {
+ /*
+ * No mappings yet
+ */
+ pvl->pv_va = va;
+ pvl->pv_pmap = pmap;
+ pvl->pv_next = PV_ENTRY_NULL;
+ pvl->pv_flags = 0;
+
+ } else {
+#ifdef DEBUG
+ /*
+ * Check that this mapping is not already there
+ */
+ for (pv_e = pvl; pv_e; pv_e = pv_e->pv_next)
+ if (pv_e->pv_pmap == pmap &&
+ pv_e->pv_va == va)
+ panic("pmap_enter: already in pv_list");
+#endif
+ /*
+ * Add new pv_entry after header.
+ */
+ pv_e = pool_get(&pvpool, PR_NOWAIT);
+ if (pv_e == NULL) {
+ if (flags & PMAP_CANFAIL) {
+ PMAP_UNLOCK(pmap, spl);
+ return (ENOMEM);
+ } else
+ panic("pmap_enter: "
+ "pvpool exhausted");
+ }
+ pv_e->pv_va = va;
+ pv_e->pv_pmap = pmap;
+ pv_e->pv_next = pvl->pv_next;
+ pv_e->pv_flags = 0;
+ pvl->pv_next = pv_e;
+ }
+ }
+
+ /*
+ * And count the mapping.
+ */
+ pmap->pm_stats.resident_count++;
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ } /* if (pa == old_pa) ... else */
+
+ template |= PG_V;
+ if (wired)
+ template |= PG_W;
+
+ if ((unsigned long)pa >= MAXPHYSMEM)
+ template |= CACHE_INH;
+ else
+ template |= CACHE_GLOBAL;
+
+ if (flags & VM_PROT_WRITE)
+ template |= PG_U | PG_M;
+ else if (flags & VM_PROT_ALL)
+ template |= PG_U;
+
+ /*
+ * Invalidate pte temporarily to avoid being written
+ * back the modified bit and/or the reference bit by
+ * any other cpu.
+ */
+ template |= invalidate_pte(pte) & (PG_U | PG_M);
+ *pte = template | pa;
+ flush_atc_entry(users, va, kflush);
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_ENT)
+ printf("(pmap_enter) set pte to %x\n", *pte);
+#endif
+
+ /*
+ * Cache attribute flags
+ */
+ if (pvl != NULL)
+ pvl->pv_flags |= (template & (PG_U | PG_M));
+
+ PMAP_UNLOCK(pmap, spl);
+
+ return 0;
+}
+
+/*
+ * Routine: pmap_unwire
+ *
+ * Function: Change the wiring attributes for a map/virtual-address pair.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * v virtual address of page to be unwired
+ *
+ * Calls:
+ * pmap_pte
+ *
+ * Special Assumptions:
+ * The mapping must already exist in the pmap.
+ */
+void
+pmap_unwire(pmap_t pmap, vaddr_t v)
+{
+ pt_entry_t *pte;
+ int spl;
+
+ PMAP_LOCK(pmap, spl);
+
+ if ((pte = pmap_pte(pmap, v)) == PT_ENTRY_NULL)
+ panic("pmap_unwire: pte missing");
+
+ if (pmap_pte_w(pte)) {
+ /* unwired mapping */
+ pmap->pm_stats.wired_count--;
+ *pte &= ~PG_W;
+ }
+
+ PMAP_UNLOCK(pmap, spl);
+}
+
+/*
+ * Routine: PMAP_EXTRACT
+ *
+ * Function:
+ * Extract the physical page address associoated
+ * with the given map/virtual_address pair.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ * va virtual address
+ * pap storage for result.
+ *
+ * Calls:
+ * PMAP_LOCK, PMAP_UNLOCK
+ * pmap_pte
+ *
+ * If BATC mapping is enabled and the specified pmap is kernel_pmap,
+ * batc_entry is scanned to find out the mapping.
+ *
+ * Then the routine calls pmap_pte to get a (virtual) pointer to
+ * the page table entry (PTE) associated with the given virtual
+ * address. If the page table does not exist, or if the PTE is not valid,
+ * then 0 address is returned. Otherwise, the physical page address from
+ * the PTE is returned.
+ */
+boolean_t
+pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap)
+{
+ pt_entry_t *pte;
+ paddr_t pa;
+ int spl;
+ boolean_t rv = FALSE;
+
+#ifdef PMAP_USE_BATC
+ int i;
+#endif
+
+#ifdef DIAGNOSTIC
+ if (pmap == PMAP_NULL)
+ panic("pmap_extract: pmap is NULL");
+#endif
+
+#ifdef PMAP_USE_BATC
+ /*
+ * check BATC first
+ */
+ if (pmap == kernel_pmap && batc_used != 0)
+ for (i = batc_used - 1; i != 0; i--)
+ if (batc_entry[i].lba == M88K_BTOBLK(va)) {
+ if (pap != NULL)
+ *pap = (batc_entry[i].pba << BATC_BLKSHIFT) |
+ (va & BATC_BLKMASK);
+ return TRUE;
+ }
+#endif
+
+ PMAP_LOCK(pmap, spl);
+
+ pte = pmap_pte(pmap, va);
+ if (pte != PT_ENTRY_NULL && PDT_VALID(pte)) {
+ rv = TRUE;
+ if (pap != NULL) {
+ pa = ptoa(PG_PFNUM(*pte));
+ pa |= (va & PAGE_MASK); /* offset within page */
+ *pap = pa;
+ }
+ }
+
+ PMAP_UNLOCK(pmap, spl);
+ return rv;
+}
+
+/*
+ * Routine: PMAP_COLLECT
+ *
+ * Runction:
+ * Garbage collects the physical map system for pages which are
+ * no longer used. there may well be pages which are not
+ * referenced, but others may be collected as well.
+ * Called by the pageout daemon when pages are scarce.
+ *
+ * Parameters:
+ * pmap pointer to pmap structure
+ *
+ * Calls:
+ * pmap_pte
+ * pmap_remove_range
+ * uvm_km_free
+ *
+ * The intent of this routine is to release memory pages being used
+ * by translation tables. They can be release only if they contain no
+ * valid mappings, and their parent table entry has been invalidated.
+ *
+ * The routine sequences through the entries user address space,
+ * inspecting page-sized groups of page tables for wired entries. If
+ * a full page of tables has no wired enties, any otherwise valid
+ * entries are invalidated (via pmap_remove_range). Then, the segment
+ * table entries corresponding to this group of page tables are
+ * invalidated. Finally, uvm_km_free is called to return the page to the
+ * system.
+ *
+ * If all entries in a segment table are invalidated, it too can
+ * be returned to the system.
+ */
+void
+pmap_collect(pmap_t pmap)
+{
+ vaddr_t sdt_va; /* outer loop index */
+ sdt_entry_t *sdtp; /* ptr to index into segment table */
+ pt_entry_t *gdttbl; /* ptr to first entry in a page table */
+ pt_entry_t *gdttblend; /* ptr to byte after last entry in
+ table group */
+ pt_entry_t *gdtp; /* ptr to index into a page table */
+ boolean_t found_gdt_wired; /* flag indicating a wired page exists
+ in a page table's address range */
+ int spl;
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_COL)
+ printf ("(pmap_collect: %x) pmap %x\n", curproc, pmap);
+#endif
+
+ PMAP_LOCK(pmap, spl);
+
+ sdtp = pmap->pm_stab; /* addr of segment table */
+
+ /* Segment table loop */
+ for (sdt_va = VM_MIN_ADDRESS; sdt_va < VM_MAX_ADDRESS;
+ sdt_va += PDT_VA_SPACE, sdtp++) {
+ gdttbl = pmap_pte(pmap, sdt_va);
+ if (gdttbl == PT_ENTRY_NULL)
+ continue; /* no maps in this range */
+
+ gdttblend = gdttbl + PDT_ENTRIES;
+
+ /* scan page maps for wired pages */
+ found_gdt_wired = FALSE;
+ for (gdtp = gdttbl; gdtp < gdttblend; gdtp++) {
+ if (pmap_pte_w(gdtp)) {
+ found_gdt_wired = TRUE;
+ break;
+ }
+ }
+
+ if (found_gdt_wired)
+ continue; /* can't free this range */
+
+ /* invalidate all maps in this range */
+ pmap_remove_range(pmap, sdt_va, sdt_va + PDT_VA_SPACE);
+
+ /*
+ * we can safely deallocate the page map(s)
+ */
+ *((sdt_entry_t *) sdtp) = 0;
+ *((sdt_entry_t *)(sdtp + SDT_ENTRIES)) = 0;
+
+ /*
+ * we have to unlock before freeing the table, since
+ * uvm_km_free will invoke another pmap routine
+ */
+ simple_unlock(&pmap->pm_lock);
+ uvm_km_free(kernel_map, (vaddr_t)gdttbl, PAGE_SIZE);
+ simple_lock(&pmap->pm_lock);
+ }
+
+ PMAP_UNLOCK(pmap, spl);
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_COL)
+ printf("(pmap_collect: %x) done\n", curproc);
+#endif
+}
+
+/*
+ * Routine: PMAP_ACTIVATE
+ *
+ * Function:
+ * Binds the pmap associated to the process to the current processor.
+ *
+ * Parameters:
+ * p pointer to proc structure
+ *
+ * Notes:
+ * If the specified pmap is not kernel_pmap, this routine stores its
+ * apr template into UAPR (user area pointer register) in the
+ * CMMUs connected to the specified CPU.
+ *
+ * Then it flushes the TLBs mapping user virtual space, in the CMMUs
+ * connected to the specified CPU.
+ */
+void
+pmap_activate(struct proc *p)
+{
+ pmap_t pmap = vm_map_pmap(&p->p_vmspace->vm_map);
+ int cpu = cpu_number();
+#ifdef PMAP_USE_BATC
+ int n;
+#endif
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_ACTIVATE)
+ printf("(pmap_activate: %x) pmap 0x%p\n", p, pmap);
+#endif
+
+ if (pmap != kernel_pmap) {
+ /*
+ * Lock the pmap to put this cpu in its active set.
+ */
+ simple_lock(&pmap->pm_lock);
+
+#ifdef PMAP_USE_BATC
+ /*
+ * cmmu_pmap_activate will set the uapr and the batc entries,
+ * then flush the *USER* TLB. IF THE KERNEL WILL EVER CARE
+ * ABOUT THE BATC ENTRIES, THE SUPERVISOR TLBs SHOULB BE
+ * FLUSHED AS WELL.
+ */
+ cmmu_pmap_activate(cpu, pmap->pm_apr,
+ pmap->pm_ibatc, pmap->pm_dbatc);
+ for (n = 0; n < BATC_MAX; n++)
+ *(register_t *)&batc_entry[n] = pmap->pm_ibatc[n].bits;
+#else
+ cmmu_set_uapr(pmap->pm_apr);
+ cmmu_flush_tlb(cpu, FALSE, VM_MIN_ADDRESS,
+ VM_MAX_ADDRESS - VM_MIN_ADDRESS);
+#endif /* PMAP_USE_BATC */
+
+ /*
+ * Mark that this cpu is using the pmap.
+ */
+ SETBIT_CPUSET(cpu, &(pmap->pm_cpus));
+ simple_unlock(&pmap->pm_lock);
+ }
+}
+
+/*
+ * Routine: PMAP_DEACTIVATE
+ *
+ * Function:
+ * Unbinds the pmap associated to the process from the current processor.
+ *
+ * Parameters:
+ * p pointer to proc structure
+ */
+void
+pmap_deactivate(struct proc *p)
+{
+ pmap_t pmap = vm_map_pmap(&p->p_vmspace->vm_map);
+ int cpu = cpu_number();
+
+ if (pmap != kernel_pmap) {
+ /*
+ * we expect the spl is already raised to sched level.
+ */
+ simple_lock(&pmap->pm_lock);
+ CLRBIT_CPUSET(cpu, &(pmap->pm_cpus));
+ simple_unlock(&pmap->pm_lock);
+ }
+}
+
+/*
+ * Routine: PMAP_COPY_PAGE
+ *
+ * Function:
+ * Copies the specified pages.
+ *
+ * Parameters:
+ * src PA of source page
+ * dst PA of destination page
+ *
+ * Extern/Global:
+ * phys_map_vaddr
+ *
+ * Calls:
+ * m88k_protection
+ *
+ * Special Assumptions:
+ * no locking required
+ *
+ * This routine maps the physical pages at the 'phys_map' virtual
+ * addresses set up in pmap_bootstrap. It flushes the TLB to make the
+ * new mappings effective, and performs the copy.
+ */
+void
+pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
+{
+ paddr_t src = VM_PAGE_TO_PHYS(srcpg);
+ paddr_t dst = VM_PAGE_TO_PHYS(dstpg);
+ vaddr_t dstva, srcva;
+ int spl;
+ pt_entry_t *dstpte, *srcpte;
+ int cpu = cpu_number();
+
+ CHECK_PAGE_ALIGN(src, "pmap_copy_page - src");
+ CHECK_PAGE_ALIGN(dst, "pmap_copy_page - dst");
+
+ dstva = (vaddr_t)(phys_map_vaddr + 2 * (cpu << PAGE_SHIFT));
+ srcva = dstva + PAGE_SIZE;
+ dstpte = pmap_pte(kernel_pmap, dstva);
+ srcpte = pmap_pte(kernel_pmap, srcva);
+
+ SPLVM(spl);
+
+ *dstpte = m88k_protection(kernel_pmap, VM_PROT_READ | VM_PROT_WRITE) |
+ CACHE_GLOBAL | PG_V | dst;
+ *srcpte = m88k_protection(kernel_pmap, VM_PROT_READ) |
+ CACHE_GLOBAL | PG_V | src;
+
+ /*
+ * We don't need the flush_atc_entry() dance, as these pages are
+ * bound to only one cpu.
+ */
+ cmmu_flush_tlb(cpu, TRUE, dstva, 2 * PAGE_SIZE);
+
+ /*
+ * The source page is likely to be a non-kernel mapping, and as
+ * such write back. Also, we might have split U/S caches!
+ * So be sure to have the source pa flushed before the copy is
+ * attempted, and the destination pa flushed afterwards.
+ */
+ cmmu_flush_data_cache(cpu, src, PAGE_SIZE);
+ bcopy((const void *)srcva, (void *)dstva, PAGE_SIZE);
+ cmmu_flush_data_cache(cpu, dst, PAGE_SIZE);
+
+ SPLX(spl);
+}
+
+/*
+ * Routine: PMAP_CHANGEBIT
+ *
+ * Function:
+ * Update the pte bits on the specified physical page.
+ *
+ * Parameters:
+ * pg physical page
+ * set bits to set
+ * mask bits to mask
+ *
+ * Extern/Global:
+ * pv_lists
+ *
+ * Calls:
+ * pmap_pte
+ *
+ * The pte bits corresponding to the page's frame index will be changed as
+ * requested. The PV list will be traversed.
+ * For each pmap/va the hardware the necessary bits in the page descriptor
+ * table entry will be altered as well if necessary. If any bits were changed,
+ * a TLB flush will be performed.
+ */
+void
+pmap_changebit(struct vm_page *pg, int set, int mask)
+{
+ pv_entry_t pvl, pvep;
+ pt_entry_t *pte, npte, opte;
+ pmap_t pmap;
+ int spl;
+ vaddr_t va;
+ u_int users;
+ boolean_t kflush;
+
+ SPLVM(spl);
+
+changebit_Retry:
+ pvl = pg_to_pvh(pg);
+
+ /*
+ * Clear saved attributes (modify, reference)
+ */
+ pvl->pv_flags &= mask;
+
+ if (pvl->pv_pmap == PMAP_NULL) {
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_CBIT)
+ printf("(pmap_changebit: %x) vm page 0x%x not mapped\n",
+ curproc, pg);
+#endif
+ SPLX(spl);
+ return;
+ }
+
+ /* for each listed pmap, update the affected bits */
+ for (pvep = pvl; pvep != PV_ENTRY_NULL; pvep = pvep->pv_next) {
+ pmap = pvep->pv_pmap;
+ if (!simple_lock_try(&pmap->pm_lock)) {
+ goto changebit_Retry;
+ }
+ users = pmap->pm_cpus;
+ kflush = pmap == kernel_pmap;
+
+ va = pvep->pv_va;
+ pte = pmap_pte(pmap, va);
+
+ /*
+ * Check for existing and valid pte
+ */
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ goto next; /* no page mapping */
+ }
+#ifdef DIAGNOSTIC
+ if (ptoa(PG_PFNUM(*pte)) != VM_PAGE_TO_PHYS(pg))
+ panic("pmap_changebit: pte %x in pmap %p %d doesn't point to page %p %lx",
+ *pte, pmap, kflush, pg, VM_PAGE_TO_PHYS(pg));
+#endif
+
+ /*
+ * Update bits
+ */
+ opte = *pte;
+ npte = (opte | set) & mask;
+
+ /*
+ * Flush TLB of which cpus using pmap.
+ *
+ * Invalidate pte temporarily to avoid the modified bit
+ * and/or the reference being written back by any other cpu.
+ */
+ if (npte != opte) {
+ invalidate_pte(pte);
+ *pte = npte;
+ flush_atc_entry(users, va, kflush);
+ }
+next:
+ simple_unlock(&pmap->pm_lock);
+ }
+ SPLX(spl);
+}
+
+/*
+ * Routine: PMAP_TESTBIT
+ *
+ * Function:
+ * Test the modified/referenced bits of a physical page.
+ *
+ * Parameters:
+ * pg physical page
+ * bit bit to test
+ *
+ * Extern/Global:
+ * pv lists
+ *
+ * Calls:
+ * simple_lock, simple_unlock
+ * pmap_pte
+ *
+ * If the attribute list for the given page has the bit, this routine
+ * returns TRUE.
+ *
+ * Otherwise, this routine walks the PV list corresponding to the
+ * given page. For each pmap/va pair, the page descriptor table entry is
+ * examined. If the selected bit is found on, the function returns TRUE
+ * immediately (doesn't need to walk remainder of list), and updates the
+ * attribute list.
+ */
+boolean_t
+pmap_testbit(struct vm_page *pg, int bit)
+{
+ pv_entry_t pvl, pvep;
+ pt_entry_t *pte;
+ int spl;
+
+ SPLVM(spl);
+
+testbit_Retry:
+ pvl = pg_to_pvh(pg);
+
+ if (pvl->pv_flags & bit) {
+ /* we've already cached this flag for this page,
+ no use looking further... */
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_TBIT)
+ printf("(pmap_testbit: %x) already cached a %x flag for this page\n",
+ curproc, bit);
+#endif
+ SPLX(spl);
+ return (TRUE);
+ }
+
+ if (pvl->pv_pmap == PMAP_NULL) {
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_TBIT)
+ printf("(pmap_testbit: %x) vm page 0x%x not mapped\n",
+ curproc, pg);
+#endif
+ SPLX(spl);
+ return (FALSE);
+ }
+
+ /* for each listed pmap, check modified bit for given page */
+ for (pvep = pvl; pvep != PV_ENTRY_NULL; pvep = pvep->pv_next) {
+ if (!simple_lock_try(&pvep->pv_pmap->pm_lock)) {
+ goto testbit_Retry;
+ }
+
+ pte = pmap_pte(pvep->pv_pmap, pvep->pv_va);
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ goto next;
+ }
+
+#ifdef DIAGNOSTIC
+ if (ptoa(PG_PFNUM(*pte)) != VM_PAGE_TO_PHYS(pg))
+ panic("pmap_testbit: pte %x in pmap %p %d doesn't point to page %p %lx",
+ *pte, pvep->pv_pmap, pvep->pv_pmap == kernel_pmap ? 1 : 0, pg, VM_PAGE_TO_PHYS(pg));
+#endif
+
+ if ((*pte & bit) != 0) {
+ simple_unlock(&pvep->pv_pmap->pm_lock);
+ pvl->pv_flags |= bit;
+#ifdef DEBUG
+ if ((pmap_con_dbg & (CD_TBIT | CD_FULL)) == (CD_TBIT | CD_FULL))
+ printf("(pmap_testbit: %x) true on page pte@0x%p\n", curproc, pte);
+#endif
+ SPLX(spl);
+ return (TRUE);
+ }
+next:
+ simple_unlock(&pvep->pv_pmap->pm_lock);
+ }
+
+ SPLX(spl);
+ return (FALSE);
+}
+
+/*
+ * Routine: PMAP_UNSETBIT
+ *
+ * Function:
+ * Clears a pte bit and returns its previous state, for the
+ * specified physical page.
+ * This is an optimized version of:
+ * rv = pmap_testbit(pg, bit);
+ * pmap_changebit(pg, 0, ~bit);
+ * return rv;
+ */
+boolean_t
+pmap_unsetbit(struct vm_page *pg, int bit)
+{
+ boolean_t rv = FALSE;
+ pv_entry_t pvl, pvep;
+ pt_entry_t *pte, opte;
+ pmap_t pmap;
+ int spl;
+ vaddr_t va;
+ u_int users;
+ boolean_t kflush;
+
+ SPLVM(spl);
+
+unsetbit_Retry:
+ pvl = pg_to_pvh(pg);
+
+ /*
+ * Clear saved attributes
+ */
+ pvl->pv_flags &= ~bit;
+
+ if (pvl->pv_pmap == PMAP_NULL) {
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_USBIT)
+ printf("(pmap_unsetbit: %x) vm page 0x%x not mapped\n",
+ curproc, pg);
+#endif
+ SPLX(spl);
+ return (FALSE);
+ }
+
+ /* for each listed pmap, update the specified bit */
+ for (pvep = pvl; pvep != PV_ENTRY_NULL; pvep = pvep->pv_next) {
+ pmap = pvep->pv_pmap;
+ if (!simple_lock_try(&pmap->pm_lock)) {
+ goto unsetbit_Retry;
+ }
+ users = pmap->pm_cpus;
+ kflush = pmap == kernel_pmap;
+
+ va = pvep->pv_va;
+ pte = pmap_pte(pmap, va);
+
+ /*
+ * Check for existing and valid pte
+ */
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ goto next; /* no page mapping */
+ }
+#ifdef DIAGNOSTIC
+ if (ptoa(PG_PFNUM(*pte)) != VM_PAGE_TO_PHYS(pg))
+ panic("pmap_unsetbit: pte %x in pmap %p %d doesn't point to page %p %lx",
+ *pte, pmap, kflush, pg, VM_PAGE_TO_PHYS(pg));
+#endif
+
+ /*
+ * Update bits
+ */
+ opte = *pte;
+ if (opte & bit) {
+ /*
+ * Flush TLB of which cpus using pmap.
+ *
+ * Invalidate pte temporarily to avoid the specified
+ * bit being written back by any other cpu.
+ */
+ invalidate_pte(pte);
+ *pte = opte ^ bit;
+ flush_atc_entry(users, va, kflush);
+ } else
+ rv = TRUE;
+next:
+ simple_unlock(&pmap->pm_lock);
+ }
+ SPLX(spl);
+
+ return (rv);
+}
+
+/*
+ * Routine: PMAP_IS_MODIFIED
+ *
+ * Function:
+ * Return whether or not the specified physical page is modified
+ * by any physical maps.
+ */
+boolean_t
+pmap_is_modified(struct vm_page *pg)
+{
+ return pmap_testbit(pg, PG_M);
+}
+
+/*
+ * Routine: PMAP_IS_REFERENCED
+ *
+ * Function:
+ * Return whether or not the specified physical page is referenced by
+ * any physical maps.
+ */
+boolean_t
+pmap_is_referenced(struct vm_page *pg)
+{
+ return pmap_testbit(pg, PG_U);
+}
+
+/*
+ * Routine: PMAP_PAGE_PROTECT
+ *
+ * Calls:
+ * pmap_changebit
+ * pmap_remove_all
+ *
+ * Lower the permission for all mappings to a given page.
+ */
+void
+pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
+{
+ if ((prot & VM_PROT_READ) == VM_PROT_NONE)
+ pmap_remove_all(pg);
+ else if ((prot & VM_PROT_WRITE) == VM_PROT_NONE)
+ pmap_changebit(pg, PG_RO, ~0);
+}
+
+void
+pmap_virtual_space(vaddr_t *startp, vaddr_t *endp)
+{
+ *startp = virtual_avail;
+ *endp = virtual_end;
+}
+
+void
+pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
+{
+ int spl;
+ pt_entry_t template, *pte;
+ u_int users;
+
+ CHECK_PAGE_ALIGN(va, "pmap_kenter_pa - VA");
+ CHECK_PAGE_ALIGN(pa, "pmap_kenter_pa - PA");
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_ENT) {
+ printf ("(pmap_kenter_pa: %x) va %x pa %x\n", curproc, va, pa);
+ }
+#endif
+
+ PMAP_LOCK(kernel_pmap, spl);
+ users = kernel_pmap->pm_cpus;
+
+ template = m88k_protection(kernel_pmap, prot);
+
+ /*
+ * Expand pmap to include this pte.
+ */
+ while ((pte = pmap_pte(kernel_pmap, va)) == PT_ENTRY_NULL)
+ pmap_expand_kmap(va, VM_PROT_READ | VM_PROT_WRITE);
+
+ /*
+ * And count the mapping.
+ */
+ kernel_pmap->pm_stats.resident_count++;
+ kernel_pmap->pm_stats.wired_count++;
+
+ invalidate_pte(pte);
+ if ((unsigned long)pa >= MAXPHYSMEM)
+ template |= CACHE_INH | PG_V | PG_W;
+ else
+ template |= CACHE_GLOBAL | PG_V | PG_W;
+ *pte = template | pa;
+ flush_atc_entry(users, va, TRUE);
+
+ PMAP_UNLOCK(kernel_pmap, spl);
+}
+
+void
+pmap_kremove(vaddr_t va, vsize_t len)
+{
+ int spl;
+ u_int users;
+ vaddr_t e;
+
+#ifdef DEBUG
+ if (pmap_con_dbg & CD_RM)
+ printf("(pmap_kremove: %x) va %x len %x\n", curproc, va, len);
+#endif
+
+ CHECK_PAGE_ALIGN(va, "pmap_kremove addr");
+ CHECK_PAGE_ALIGN(len, "pmap_kremove len");
+
+ PMAP_LOCK(kernel_pmap, spl);
+ users = kernel_pmap->pm_cpus;
+
+ e = va + len;
+ for (; va < e; va += PAGE_SIZE) {
+ sdt_entry_t *sdt;
+ pt_entry_t *pte;
+
+ sdt = SDTENT(kernel_pmap, va);
+
+ /* If no segment table, skip a whole segment */
+ if (!SDT_VALID(sdt)) {
+ va &= SDT_MASK;
+ va += (1 << SDT_SHIFT) - PAGE_SIZE;
+ continue;
+ }
+
+ pte = pmap_pte(kernel_pmap, va);
+ if (pte == PT_ENTRY_NULL || !PDT_VALID(pte)) {
+ continue; /* no page mapping */
+ }
+
+ /*
+ * Update the counts
+ */
+ kernel_pmap->pm_stats.resident_count--;
+ kernel_pmap->pm_stats.wired_count--;
+
+ invalidate_pte(pte);
+ flush_atc_entry(users, va, TRUE);
+ }
+ PMAP_UNLOCK(map, spl);
+}
diff --git a/sys/arch/luna88k/luna88k/pmap_table.c b/sys/arch/luna88k/luna88k/pmap_table.c
new file mode 100644
index 00000000000..9800edd714c
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/pmap_table.c
@@ -0,0 +1,89 @@
+/* $OpenBSD: pmap_table.c,v 1.1 2004/04/21 15:24:13 aoyama Exp $ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <machine/board.h>
+#include <machine/cmmu.h>
+#include <uvm/uvm_extern.h>
+#include <machine/pmap_table.h>
+
+#define R VM_PROT_READ
+#define RW (VM_PROT_READ | VM_PROT_WRITE)
+#define CW CACHE_WT
+#define CI CACHE_INH
+#define CG CACHE_GLOBAL
+
+/* phys_start, virt_start, size, prot, cacheability */
+const pmap_table_entry
+luna88k_board_table[] = {
+#if 0
+ { 0 , VEQR_ADDR , 48*1024*1024 /* XXX memory size */, RW, CG},
+#endif
+ { 0 , 0 , round_page(0x20000) /* XXX kernel start */, RW, CG},
+ { OBIO_START , OBIO_START , round_page(OBIO_SIZE), RW, CI },
+#if 0
+ { TRI_PORT_RAM, TRI_PORT_RAM, TRI_PORT_RAM_SPACE, RW, CI },
+ { 0 , VEQR_ADDR , 48*1024*1024 /* XXX memory size */, RW, CG},
+ { 0 , 0 , 0x20000 /* XXX kernel start */, RW, CG},
+ { PROM_ADDR , PROM_ADDR , PROM_SPACE , R, C },
+ { FUSE_ROM_ADDR, FUSE_ROM_ADDR, FUSE_ROM_SPACE, RW, CI },
+ { NVRAM_ADDR , NVRAM_ADDR , NVRAM_SPACE , RW, CI },
+ { OBIO_PIO0_BASE, OBIO_PIO0_BASE, PAGE, RW, CI },
+ { OBIO_PIO1_BASE, OBIO_PIO1_BASE, PAGE, RW, CI },
+ { OBIO_SIO , OBIO_SIO, PAGE, RW, CI },
+ { OBIO_TAS , OBIO_TAS, PAGE, RW, CI },
+ { OBIO_CLOCK0 , OBIO_CLOCK0, PAGE, RW, CI },
+ { INT_ST_MASK0 , INT_ST_MASK0, PAGE, RW, CI },
+ { SOFT_INT0 , SOFT_INT0, PAGE, W, CI },
+ { SOFT_INT_FLAG0, SOFT_INT_FLAG0, PAGE, RW, CI },
+ { RESET_CPU0 , RESET_CPU0, PAGE, RW, CI },
+#if 0
+ { EXT_A_ADDR , EXT_A_ADDR, EXT_A_SPACE, RW, CI },
+ { EXT_B_ADDR , EXT_B_ADDR, EXT_B_SPACE, RW, CI },
+ { PC_BASE , PC_BASE, PC_SPACE, RW, CI },
+#endif
+ { MROM_ADDR , MROM_ADDR, MROM_SPACE, R, CI },
+ { BMAP_START , BMAP_START, BMAP_SPACE, RW, CI },
+ { BMAP_PALLET0 , BMAP_PALLET0, PAGE, RW, CI },
+ { BMAP_PALLET1 , BMAP_PALLET1, PAGE, RW, CI },
+ { BMAP_PALLET2 , BMAP_PALLET2, PAGE, RW, CI },
+ { BOARD_CHECK_REG, BOARD_CHECK_REG,PAGE, RW, CI },
+ { BMAP_CRTC, BMAP_CRTC, PAGE, RW, CI },
+ { SCSI_ADDR, SCSI_ADDR, PAGE, RW, C},
+ { LANCE_ADDR, LANCE_ADDR, PAGE, RW, CI },
+#endif
+ { 0, 0, 0xffffffff, 0, 0 },
+};
+
+pmap_table_t
+pmap_table_build(void)
+{
+ return luna88k_board_table;
+}
diff --git a/sys/arch/luna88k/luna88k/process.S b/sys/arch/luna88k/luna88k/process.S
new file mode 100644
index 00000000000..5ffa2bf65e1
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/process.S
@@ -0,0 +1,332 @@
+/* $OpenBSD: process.S,v 1.1 2004/04/21 15:24:13 aoyama Exp $ */
+/*
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "assym.h"
+#include <machine/asm.h>
+#include <machine/psl.h>
+#include <machine/intr.h>
+
+ data
+ align 4
+ASLOCAL(swchanpanic)
+ string "switch wchan %x\0"
+ align 4
+ASLOCAL(swsrunpanic)
+ string "switch SRUN %x\0"
+#ifdef DEBUG
+ align 4
+ASLOCAL(boguspsr)
+ string "Invalid PSR in idle loop 0x%x\n\0"
+#endif
+
+ text
+ align 8
+ASLOCAL(Lswchanpanic)
+ or.u r2, r0, hi16(_ASM_LABEL(swchanpanic))
+ or r2, r2, lo16(_ASM_LABEL(swchanpanic))
+ bsr.n _C_LABEL(panic)
+ or r3, r0, r9
+
+ASLOCAL(Lswsrunpanic)
+ or.u r2, r0, hi16(_ASM_LABEL(swsrunpanic))
+ or r2, r2, lo16(_ASM_LABEL(swsrunpanic))
+ bsr.n _C_LABEL(panic)
+ or r3, r0, r9
+
+/*
+ * At exit of a process, do a cpu_switch for the last time.
+ * The mapping of the pcb at p->p_addr has already been deleted,
+ * and the memory for the pcb+stack has been freed.
+ * The ipl is high enough to prevent the memory from being reallocated.
+ * switch_exit(proc * p)
+ */
+
+ENTRY(switch_exit)
+ /*
+ * Change pcb to idle u. area, i.e., set r31 to top of stack
+ * and set curpcb to point to _idle_u. r2 contains proc *p.
+ */
+ or.u r30, r0, hi16(_C_LABEL(idle_u))
+ or r30, r30,lo16(_C_LABEL(idle_u))
+ addu r31, r30, USIZE /* now on idle_u stack */
+ or.u r10, r0, hi16(_C_LABEL(curpcb))
+ st r30, r10,lo16(_C_LABEL(curpcb)) /* curpcb = &idle_u */
+ or.u r10, r0, hi16(_C_LABEL(curproc))
+ st r0, r10, lo16(_C_LABEL(curproc)) /* curproc = NULL */
+
+ /* Schedule the vmspace and stack to be freed. */
+ bsr.n _C_LABEL(exit2)
+ subu r31, r31, 48 /* allocate stack */
+ addu r31, r31, 48 /* restore stack */
+ bsr _C_LABEL(cpu_switch) /* goto final switch */
+
+/*
+ * cpu_switch()
+ * XXX - Arg 1 is a proc pointer (curproc) but this doesn't use it.
+ * XXX - how about using stack for saving spl and last proc?
+ * XXX rewrite this whole mess in C nivas
+ */
+ENTRY(cpu_switch)
+
+ /*
+ * Save state of previous process in its pcb.
+ */
+ or.u r2, r0, hi16(_C_LABEL(curpcb))
+ ld r2, r2, lo16(_C_LABEL(curpcb))
+ st r1, r2, PCB_PC /* save return address */
+ bsr _ASM_LABEL(__savectx)
+ /* note that we don't need to recover r1 at this point */
+
+ or.u r11, r0, hi16(_C_LABEL(curproc))
+ ld r2, r11, lo16(_C_LABEL(curproc))
+ bcnd eq0, r2, 1f
+
+ bsr.n _C_LABEL(pmap_deactivate)
+ subu r31, r31,48
+ addu r31, r31,48
+ or.u r11, r0, hi16(_C_LABEL(curproc))
+
+1:
+ st r0, r11, lo16(_C_LABEL(curproc)) /* curproc = NULL */
+
+ASLOCAL(Lidleloop)
+
+ /*
+ * Find the highest-priority queue that isn't empty,
+ * then take the first proc from that queue.
+ */
+
+ or.u r7, r0, hi16(_C_LABEL(whichqs))
+ ld r7, r7, lo16(_C_LABEL(whichqs))
+
+ bcnd ne0, r7, _ASM_LABEL(Ldoneloop)
+
+ASLOCAL(Lloopchk) /* if whichqs is zero, keep checking */
+ bsr.n _C_LABEL(setipl) /* unmask all ints... */
+ or r2, r0, IPL_NONE
+
+ ldcr r2, PSR
+ bb0 PSR_INTERRUPT_DISABLE_BIT, r2, 1f
+#ifdef DEBUG
+ or r3, r2, r0
+ or.u r2, r0, hi16(_ASM_LABEL(boguspsr))
+ bsr.n _C_LABEL(printf)
+ or r2, r2, lo16(_ASM_LABEL(boguspsr))
+ ldcr r2, PSR
+#endif
+ clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* ...and enable them */
+ stcr r2, PSR
+ FLUSH_PIPELINE
+1:
+ br _ASM_LABEL(Lidleloop)
+
+ASLOCAL(Ldoneloop)
+
+ bsr.n _C_LABEL(setipl) /* disable ints */
+ or r2, r0, IPL_HIGH
+
+ or.u r7, r0, hi16(_C_LABEL(whichqs)) /* reload whichqs */
+ ld r7, r7, lo16(_C_LABEL(whichqs))
+
+ bcnd eq0, r7, _ASM_LABEL(Lloopchk) /* keep spinning for whichqs to be != 0 */
+
+ xor r6, r6, r6 /* set r6 to 0 */
+1: bb1 0, r7, 2f /* if rightmost bit set, done */
+ extu r7, r7, 0<1> /* else, right shift whichqs, */
+ br.n 1b /* increment r6, and repeat */
+ addu r6, r6, 1
+2:
+ or.u r7, r0, hi16(_qs)
+ or r7, r7, lo16(_qs)
+
+ /*
+ * Need to make
+ * p->p_forw->p_back = p->p_back and
+ * p->p_back->p_forw = p->p_forw where
+ * p is q->p_forw.
+ * Remember that q->p_forw == p and p->p_back == q.
+ */
+
+ lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */
+ ld r9, r8, P_FORW /* r8 is q, r9 is p */
+
+ ld r12, r9, P_FORW /* r12 = p->p_forw */
+ st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */
+ st r12, r8, P_FORW /* q->p_forw = p->p_forw */
+ lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */
+ ld r12, r8, P_FORW /* q->p_forw */
+ cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */
+ bb1 ne, r12, 3f /* yes, skip clearing bit in whichqs */
+
+ or r12, r0, 1 /* r12 is 1 now */
+1: bcnd eq0, r6, 2f
+ mak r12, r12, 0<1> /* shift left by 1 */
+ br.n 1b
+ subu r6, r6, 1 /* keep doing this while r6 != 0 */
+2:
+ /*
+ * NOTE: we could have just used "mak r12, r12, r6" instead of the
+ * loop above. But that will break if NQS is made > 32. I can use
+ * preprocessor to do the right thing, but that means I have to
+ * include sys/proc.h in this file. XXX nivas
+ */
+ or.u r7, r0, hi16(_C_LABEL(whichqs))
+ ld r8, r7, lo16(_C_LABEL(whichqs))
+ and.c r8, r8, r12 /* whichqs &= ~the bit */
+ st r8, r7, lo16(_C_LABEL(whichqs))
+3:
+ ld r2, r9, P_WCHAN
+ bcnd ne0, r2, _ASM_LABEL(Lswchanpanic)
+ ld.b r2, r9, P_STAT
+ cmp r2, r2, SRUN
+ bb1 ne, r2, _ASM_LABEL(Lswsrunpanic)
+
+ or.u r11, r0, hi16(_C_LABEL(want_resched))
+ st r0, r11, lo16(_C_LABEL(want_resched)) /* clear want_resched */
+
+ or.u r11, r0, hi16(_C_LABEL(curproc))
+ st r9, r11,lo16(_C_LABEL(curproc)) /* curproc = p */
+
+ /* r9 is curproc */
+ st r0, r9, P_BACK /* p->p_back = 0 */
+ ld r3, r9, P_ADDR
+ or.u r10, r0, hi16(_C_LABEL(curpcb))
+ st r3, r10, lo16(_C_LABEL(curpcb)) /* curpcb = p->p_addr */
+
+ /* pmap_activate() the process' pmap */
+ or r2, r0, r9 /* r2 = p */
+ or r14, r0, r9 /* save p in r14 */
+ bsr.n _C_LABEL(pmap_activate)
+ subu r31, r31,48
+ addu r31, r31,48
+ or r9, r0, r14 /* restore p saved in r14 */
+
+ or.u r31, r0, hi16(_ASM_LABEL(intstack_end))
+ or r31,r31, lo16(_ASM_LABEL(intstack_end))
+ subu r31, r31,48
+ bsr.n _C_LABEL(load_u_area)
+ or r2, r0, r9
+ addu r31, r31,48
+
+ or.u r10, r0, hi16(_C_LABEL(curpcb))
+ ld r10, r10, lo16(_C_LABEL(curpcb))
+ /* XXX Is this correct/necessary? */
+ st r10, r14, P_ADDR /* p->p_addr = curpcb; restore p_addr */
+
+ /* restore from the current context */
+ ld r2, r10, PCB_FCR62
+ ld r3, r10, PCB_FCR63
+ fstcr r2, fcr62
+ fstcr r3, fcr63
+ ld r1, r10, PCB_PC
+ ld r14,r10, PCB_R14
+ ld r15,r10, PCB_R15
+ ld r16,r10, PCB_R16
+ ld r17,r10, PCB_R17
+ ld r18,r10, PCB_R18
+ ld r19,r10, PCB_R19
+ ld r20,r10, PCB_R20
+ ld r21,r10, PCB_R21
+ ld r22,r10, PCB_R22
+ ld r23,r10, PCB_R23
+ ld r24,r10, PCB_R24
+ ld r25,r10, PCB_R25
+ ld r26,r10, PCB_R26
+ ld r27,r10, PCB_R27
+ ld r28,r10, PCB_R28
+ ld r29,r10, PCB_R29
+ ld r30,r10, PCB_R30 /* restore frame pointer & stack */
+ ld r31,r10, PCB_SP
+
+/* XXX
+ * Should we postpone restoring stack till after ipl is restored?
+ * The stack access could fault
+ */
+ subu r31,r31,48
+ st r1, r31,36 /* save r1 on stack */
+ bsr.n _C_LABEL(setipl)
+ ld r2, r10, PCB_IPL /* restore interrupt mask */
+ ld r1, r31,36 /* restore r1 from stack */
+ addu r31,r31,48
+ jmp.n r1
+ or r2, r0, 1 /* return 1 (for alternate returns) */
+
+/*
+ * savectx(pcb)
+ * Update pcb, saving current processor state.
+ */
+ENTRY(savectx)
+ /*
+ * Save preserved general register set.
+ */
+ st r1, r2, PCB_PC /* save return address */
+ASENTRY(__savectx)
+ st r14, r2, PCB_R14
+ st r15, r2, PCB_R15
+ st r16, r2, PCB_R16
+ st r17, r2, PCB_R17
+ st r18, r2, PCB_R18
+ st r19, r2, PCB_R19
+ st r20, r2, PCB_R20
+ st r21, r2, PCB_R21
+ st r22, r2, PCB_R22
+ st r23, r2, PCB_R23
+ st r24, r2, PCB_R24
+ st r25, r2, PCB_R25
+ st r26, r2, PCB_R26
+ st r27, r2, PCB_R27
+ st r28, r2, PCB_R28
+ st r29, r2, PCB_R29
+ st r30, r2, PCB_R30 /* save frame pointer & stack pointer */
+ st r31, r2, PCB_SP
+
+ /*
+ * Get the current spl.
+ * We need to save r1 on the stack because we don't know if we were
+ * called as savectx or __savectx.
+ */
+ subu r31, r31, 40 /* allocate stack for r1 and args */
+ st r1, r31, 32
+ bsr.n _C_LABEL(getipl) /* get the current interrupt mask */
+ or r14, r0, r2
+ st r2, r14, PCB_IPL /* save interrupt mask */
+ ld r1, r31, 32 /* recover return address */
+ addu r31, r31, 40 /* put stack pointer back */
+
+ /*
+ * Save FP state.
+ */
+ fldcr r2, fcr62
+ fldcr r3, fcr63
+ st r2, r14, PCB_FCR62
+ jmp.n r1
+ st r3, r14, PCB_FCR63
diff --git a/sys/arch/luna88k/luna88k/process_machdep.c b/sys/arch/luna88k/luna88k/process_machdep.c
new file mode 100644
index 00000000000..27bf49b45ed
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/process_machdep.c
@@ -0,0 +1,149 @@
+/* $OpenBSD: process_machdep.c,v 1.1 2004/04/21 15:24:14 aoyama Exp $ */
+
+/*
+ * Copyright (c) 1993 The Regents of the University of California.
+ * Copyright (c) 1993 Jan-Simon Pendry
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel
+ */
+
+/*
+ * This file may seem a bit stylized, but that so that it's easier to port.
+ * Functions to be implemented here are:
+ *
+ * process_read_regs(proc, regs)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_regs is called.
+ *
+ * process_write_regs(proc, regs)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_regs is called.
+ *
+ * process_sstep(proc)
+ * Arrange for the process to trap after executing a single instruction.
+ *
+ * process_set_pc(proc)
+ * Set the process's program counter.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+#include <machine/psl.h>
+#include <machine/reg.h>
+#include <machine/trap.h>
+#if 0
+#include <machine/frame.h>
+#endif
+#include <sys/ptrace.h>
+
+int
+process_read_regs(p, regs)
+ struct proc *p;
+ struct reg *regs;
+{
+ bcopy((caddr_t)USER_REGS(p), (caddr_t)regs, sizeof(struct reg));
+ return (0);
+}
+
+int
+process_read_fpregs(p, regs)
+ struct proc *p;
+ struct fpreg *regs;
+{
+#if 0
+ extern struct fpstate initfpstate;
+ struct fpstate *statep = &initfpstate;
+
+ /* NOTE: struct fpreg == struct fpstate */
+ if (p->p_md.md_fpstate)
+ statep = p->p_md.md_fpstate;
+ bcopy(statep, regs, sizeof(struct fpreg));
+#endif
+ return 0;
+}
+
+#ifdef PTRACE
+
+int
+process_write_regs(p, regs)
+ struct proc *p;
+ struct reg *regs;
+{
+ bcopy((caddr_t)regs, (caddr_t)USER_REGS(p), sizeof(struct reg));
+ return (0);
+}
+
+int
+process_sstep(p, sstep)
+ struct proc *p;
+ int sstep;
+{
+ if (sstep)
+ cpu_singlestep(p);
+ return (0);
+}
+
+int
+process_set_pc(p, addr)
+ struct proc *p;
+ caddr_t addr;
+{
+ struct reg *regs;
+
+ regs = USER_REGS(p);
+ regs->sxip = (u_int)addr;
+ regs->snip = (u_int)addr + 4;
+ return (0);
+}
+
+int
+process_write_fpregs(p, regs)
+ struct proc *p;
+ struct fpreg *regs;
+{
+#if 0
+ if (p->p_md.md_fpstate == NULL)
+ return EINVAL;
+
+ bcopy(regs, p->p_md.md_fpstate, sizeof(struct fpreg));
+#endif
+ return 0;
+}
+
+#endif /* PTRACE */
diff --git a/sys/arch/luna88k/luna88k/trap.c b/sys/arch/luna88k/luna88k/trap.c
new file mode 100644
index 00000000000..d7bee6ad47b
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/trap.c
@@ -0,0 +1,1797 @@
+/* $OpenBSD: trap.c,v 1.1 2004/04/21 15:24:14 aoyama Exp $ */
+/*
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Nivas Madhur.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/user.h>
+#include <sys/syscall.h>
+#include <sys/systm.h>
+#include <sys/ktrace.h>
+
+#include "systrace.h"
+#include <dev/systrace.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/asm_macro.h> /* enable/disable interrupts */
+#include <machine/cpu.h>
+#include <machine/locore.h>
+#ifdef M88100
+#include <machine/m88100.h> /* DMT_xxx */
+#include <machine/m8820x.h> /* CMMU_PFSR_xxx */
+#endif
+#ifdef M88110
+#include <machine/m88110.h>
+#endif
+#include <machine/pcb.h> /* FIP_E, etc. */
+#include <machine/psl.h> /* FIP_E, etc. */
+#include <machine/trap.h>
+
+#include <machine/db_machdep.h>
+#ifdef DDB
+#include <ddb/db_output.h> /* db_printf() */
+#endif /* DDB */
+#define SSBREAKPOINT (0xF000D1F8U) /* Single Step Breakpoint */
+
+#ifdef DDB
+#define DEBUG_MSG(x) db_printf x
+#else
+#define DEBUG_MSG(x)
+#endif /* DDB */
+
+#define USERMODE(PSR) (((PSR) & PSR_MODE) == 0)
+#define SYSTEMMODE(PSR) (((PSR) & PSR_MODE) != 0)
+
+/* sigh */
+extern int procfs_domem(struct proc *, struct proc *, void *, struct uio *);
+
+__dead void panictrap(int, struct trapframe *);
+__dead void error_fatal(struct trapframe *);
+
+extern void regdump(struct trapframe *f);
+
+const char *trap_type[] = {
+ "Reset",
+ "Interrupt Exception",
+ "Instruction Access",
+ "Data Access Exception",
+ "Misaligned Access",
+ "Unimplemented Opcode",
+ "Privilege Violation"
+ "Bounds Check Violation",
+ "Illegal Integer Divide",
+ "Integer Overflow",
+ "Error Exception",
+ "Non-Maskable Exception",
+};
+const int trap_types = sizeof trap_type / sizeof trap_type[0];
+
+const char *pbus_exception_type[] = {
+ "Success (No Fault)",
+ "unknown 1",
+ "unknown 2",
+ "Bus Error",
+ "Segment Fault",
+ "Page Fault",
+ "Supervisor Violation",
+ "Write Violation",
+};
+
+static inline void
+userret(struct proc *p, struct trapframe *frame, u_quad_t oticks)
+{
+ int sig;
+
+ /* take pending signals */
+ while ((sig = CURSIG(p)) != 0)
+ postsig(sig);
+ p->p_priority = p->p_usrpri;
+
+ if (want_resched) {
+ /*
+ * We're being preempted.
+ */
+ preempt(NULL);
+ while ((sig = CURSIG(p)) != 0)
+ postsig(sig);
+ }
+
+ /*
+ * If profiling, charge recent system time to the trapped pc.
+ */
+ if (p->p_flag & P_PROFIL) {
+ extern int psratio;
+
+ addupc_task(p, frame->tf_sxip & XIP_ADDR,
+ (int)(p->p_sticks - oticks) * psratio);
+ }
+ curpriority = p->p_priority;
+}
+
+__dead void
+panictrap(int type, struct trapframe *frame)
+{
+#ifdef DDB
+ static int panicing = 0;
+
+ if (panicing++ == 0) {
+ switch (cputyp) {
+#ifdef M88100
+ case CPU_88100:
+ if (type == 2) {
+ /* instruction exception */
+ db_printf("\nInstr access fault (%s) v = %x, "
+ "frame %p\n",
+ pbus_exception_type[
+ CMMU_PFSR_FAULT(frame->tf_ipfsr)],
+ frame->tf_sxip & XIP_ADDR, frame);
+ } else if (type == 3) {
+ /* data access exception */
+ db_printf("\nData access fault (%s) v = %x, "
+ "frame %p\n",
+ pbus_exception_type[
+ CMMU_PFSR_FAULT(frame->tf_dpfsr)],
+ frame->tf_sxip & XIP_ADDR, frame);
+ } else
+ db_printf("\nTrap type %d, v = %x, frame %p\n",
+ type, frame->tf_sxip & XIP_ADDR, frame);
+ break;
+#endif
+#ifdef M88110
+ case CPU_88110:
+ db_printf("\nTrap type %d, v = %x, frame %p\n",
+ type, frame->tf_exip, frame);
+ break;
+#endif
+ }
+ regdump(frame);
+ }
+#endif
+ if ((u_int)type < trap_types)
+ panic(trap_type[type]);
+ else
+ panic("trap %d", type);
+ /*NOTREACHED*/
+}
+
+#ifdef M88100
+void
+m88100_trap(unsigned type, struct trapframe *frame)
+{
+ struct proc *p;
+ u_quad_t sticks = 0;
+ struct vm_map *map;
+ vaddr_t va;
+ vm_prot_t ftype;
+ int fault_type, pbus_type;
+ u_long fault_code;
+ unsigned nss, fault_addr;
+ struct vmspace *vm;
+ union sigval sv;
+ int result;
+#ifdef DDB
+ int s;
+#endif
+ int sig = 0;
+
+ extern struct vm_map *kernel_map;
+ extern caddr_t guarded_access_start;
+ extern caddr_t guarded_access_end;
+ extern caddr_t guarded_access_bad;
+
+ uvmexp.traps++;
+ if ((p = curproc) == NULL)
+ p = &proc0;
+
+ if (USERMODE(frame->tf_epsr)) {
+ sticks = p->p_sticks;
+ type += T_USER;
+ p->p_md.md_tf = frame; /* for ptrace/signals */
+ }
+ fault_type = 0;
+ fault_code = 0;
+ fault_addr = frame->tf_sxip & XIP_ADDR;
+
+ switch (type) {
+ default:
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+
+#if defined(DDB)
+ case T_KDB_BREAK:
+ s = splhigh();
+ db_enable_interrupt();
+ ddb_break_trap(T_KDB_BREAK, (db_regs_t*)frame);
+ db_disable_interrupt();
+ splx(s);
+ return;
+ case T_KDB_ENTRY:
+ s = splhigh();
+ db_enable_interrupt();
+ ddb_entry_trap(T_KDB_ENTRY, (db_regs_t*)frame);
+ db_disable_interrupt();
+ splx(s);
+ return;
+#endif /* DDB */
+ case T_ILLFLT:
+ DEBUG_MSG(("Unimplemented opcode!\n"));
+ panictrap(frame->tf_vector, frame);
+ break;
+ case T_INT:
+ case T_INT+T_USER:
+ /* This function pointer is set in machdep.c
+ It calls m188_ext_int or sbc_ext_int depending
+ on the value of brdtyp - smurph */
+ (*md.interrupt_func)(T_INT, frame);
+ return;
+
+ case T_MISALGNFLT:
+ DEBUG_MSG(("kernel misaligned "
+ "access exception @ 0x%08x\n", frame->tf_sxip));
+ panictrap(frame->tf_vector, frame);
+ break;
+
+ case T_INSTFLT:
+ /* kernel mode instruction access fault.
+ * Should never, never happen for a non-paged kernel.
+ */
+#ifdef TRAPDEBUG
+ pbus_type = CMMU_PFSR_FAULT(frame->tf_ipfsr);
+ printf("Kernel Instruction fault #%d (%s) v = 0x%x, frame 0x%x cpu %d\n",
+ pbus_type, pbus_exception_type[pbus_type],
+ fault_addr, frame, frame->tf_cpu);
+#endif
+ panictrap(frame->tf_vector, frame);
+ break;
+
+ case T_DATAFLT:
+ /* kernel mode data fault */
+
+ /* data fault on the user address? */
+ if ((frame->tf_dmt0 & DMT_DAS) == 0) {
+ type = T_DATAFLT + T_USER;
+ goto user_fault;
+ }
+
+ fault_addr = frame->tf_dma0;
+ if (frame->tf_dmt0 & (DMT_WRITE|DMT_LOCKBAR)) {
+ ftype = VM_PROT_READ|VM_PROT_WRITE;
+ fault_code = VM_PROT_WRITE;
+ } else {
+ ftype = VM_PROT_READ;
+ fault_code = VM_PROT_READ;
+ }
+
+ va = trunc_page((vaddr_t)fault_addr);
+ if (va == 0) {
+ panic("trap: bad kernel access at %x", fault_addr);
+ }
+
+ vm = p->p_vmspace;
+ map = kernel_map;
+
+ pbus_type = CMMU_PFSR_FAULT(frame->tf_dpfsr);
+#ifdef TRAPDEBUG
+ printf("Kernel Data access fault #%d (%s) v = 0x%x, frame 0x%x cpu %d\n",
+ pbus_type, pbus_exception_type[pbus_type],
+ fault_addr, frame, frame->tf_cpu);
+#endif
+
+ switch (pbus_type) {
+ case CMMU_PFSR_BERROR:
+ /*
+ * If it is a guarded access, bus error is OK.
+ */
+ if ((frame->tf_sxip & XIP_ADDR) >=
+ (unsigned)&guarded_access_start &&
+ (frame->tf_sxip & XIP_ADDR) <=
+ (unsigned)&guarded_access_end) {
+ frame->tf_snip =
+ ((unsigned)&guarded_access_bad ) | NIP_V;
+ frame->tf_sfip =
+ ((unsigned)&guarded_access_bad + 4) | FIP_V;
+ frame->tf_sxip = 0;
+ /* We sort of resolved the fault ourselves
+ * because we know where it came from
+ * [guarded_access()]. But we must still think
+ * about the other possible transactions in
+ * dmt1 & dmt2. Mark dmt0 so that
+ * data_access_emulation skips it. XXX smurph
+ */
+ frame->tf_dmt0 |= DMT_SKIP;
+ data_access_emulation((unsigned *)frame);
+ frame->tf_dpfsr = 0;
+ frame->tf_dmt0 = 0;
+ return;
+ }
+ break;
+ case CMMU_PFSR_SUCCESS:
+ /*
+ * The fault was resolved. Call data_access_emulation
+ * to drain the data unit pipe line and reset dmt0
+ * so that trap won't get called again.
+ */
+ data_access_emulation((unsigned *)frame);
+ frame->tf_dpfsr = 0;
+ frame->tf_dmt0 = 0;
+ return;
+ case CMMU_PFSR_SFAULT:
+ case CMMU_PFSR_PFAULT:
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == 0) {
+ /*
+ * We could resolve the fault. Call
+ * data_access_emulation to drain the data
+ * unit pipe line and reset dmt0 so that trap
+ * won't get called again.
+ */
+ data_access_emulation((unsigned *)frame);
+ frame->tf_dpfsr = 0;
+ frame->tf_dmt0 = 0;
+ return;
+ }
+ break;
+ }
+#ifdef TRAPDEBUG
+ printf("PBUS Fault %d (%s) va = 0x%x\n", pbus_type,
+ pbus_exception_type[pbus_type], va);
+#endif
+ panictrap(frame->tf_vector, frame);
+ /* NOTREACHED */
+ case T_INSTFLT+T_USER:
+ /* User mode instruction access fault */
+ /* FALLTHROUGH */
+ case T_DATAFLT+T_USER:
+user_fault:
+ if (type == T_INSTFLT + T_USER) {
+ pbus_type = CMMU_PFSR_FAULT(frame->tf_ipfsr);
+#ifdef TRAPDEBUG
+ printf("User Instruction fault #%d (%s) v = 0x%x, frame 0x%x cpu %d\n",
+ pbus_type, pbus_exception_type[pbus_type],
+ fault_addr, frame, frame->tf_cpu);
+#endif
+ } else {
+ fault_addr = frame->tf_dma0;
+ pbus_type = CMMU_PFSR_FAULT(frame->tf_dpfsr);
+#ifdef TRAPDEBUG
+ printf("User Data access fault #%d (%s) v = 0x%x, frame 0x%x cpu %d\n",
+ pbus_type, pbus_exception_type[pbus_type],
+ fault_addr, frame, frame->tf_cpu);
+#endif
+ }
+
+ if (frame->tf_dmt0 & (DMT_WRITE | DMT_LOCKBAR)) {
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ fault_code = VM_PROT_WRITE;
+ } else {
+ ftype = VM_PROT_READ;
+ fault_code = VM_PROT_READ;
+ }
+
+ va = trunc_page((vaddr_t)fault_addr);
+
+ vm = p->p_vmspace;
+ map = &vm->vm_map;
+
+ /* Call uvm_fault() to resolve non-bus error faults */
+ switch (pbus_type) {
+ case CMMU_PFSR_SUCCESS:
+ result = 0;
+ break;
+ case CMMU_PFSR_BERROR:
+ result = EACCES;
+ break;
+ default:
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == EACCES)
+ result = EFAULT;
+ break;
+ }
+
+ if ((caddr_t)va >= vm->vm_maxsaddr) {
+ if (result == 0) {
+ nss = btoc(USRSTACK - va);/* XXX check this */
+ if (nss > vm->vm_ssize)
+ vm->vm_ssize = nss;
+ }
+ }
+
+ /*
+ * This could be a fault caused in copyin*()
+ * while accessing user space.
+ */
+ if (result != 0 && p->p_addr->u_pcb.pcb_onfault != NULL) {
+ frame->tf_snip = p->p_addr->u_pcb.pcb_onfault | NIP_V;
+ frame->tf_sfip = (p->p_addr->u_pcb.pcb_onfault + 4) | FIP_V;
+ frame->tf_sxip = 0;
+ /*
+ * Continue as if the fault had been resolved, but
+ * do not try to complete the faulting access.
+ */
+ frame->tf_dmt0 |= DMT_SKIP;
+ result = 0;
+ }
+
+ if (result == 0) {
+ if (type == T_DATAFLT+T_USER) {
+ /*
+ * We could resolve the fault. Call
+ * data_access_emulation to drain the data unit
+ * pipe line and reset dmt0 so that trap won't
+ * get called again.
+ */
+ data_access_emulation((unsigned *)frame);
+ frame->tf_dpfsr = 0;
+ frame->tf_dmt0 = 0;
+ } else {
+ /*
+ * back up SXIP, SNIP,
+ * clearing the Error bit
+ */
+ frame->tf_sfip = frame->tf_snip & ~FIP_E;
+ frame->tf_snip = frame->tf_sxip & ~NIP_E;
+ frame->tf_ipfsr = 0;
+ }
+ } else {
+ sig = result == EACCES ? SIGBUS : SIGSEGV;
+ fault_type = result == EACCES ?
+ BUS_ADRERR : SEGV_MAPERR;
+ }
+ break;
+ case T_MISALGNFLT+T_USER:
+ sig = SIGBUS;
+ fault_type = BUS_ADRALN;
+ break;
+ case T_PRIVINFLT+T_USER:
+ case T_ILLFLT+T_USER:
+#ifndef DDB
+ case T_KDB_BREAK:
+ case T_KDB_ENTRY:
+#endif
+ case T_KDB_BREAK+T_USER:
+ case T_KDB_ENTRY+T_USER:
+ case T_KDB_TRACE:
+ case T_KDB_TRACE+T_USER:
+ sig = SIGILL;
+ break;
+ case T_BNDFLT+T_USER:
+ sig = SIGFPE;
+ break;
+ case T_ZERODIV+T_USER:
+ sig = SIGFPE;
+ fault_type = FPE_INTDIV;
+ break;
+ case T_OVFFLT+T_USER:
+ sig = SIGFPE;
+ fault_type = FPE_INTOVF;
+ break;
+ case T_FPEPFLT+T_USER:
+ case T_FPEIFLT+T_USER:
+ sig = SIGFPE;
+ break;
+ case T_SIGSYS+T_USER:
+ sig = SIGSYS;
+ break;
+ case T_SIGTRAP+T_USER:
+ sig = SIGTRAP;
+ fault_type = TRAP_TRACE;
+ break;
+ case T_STEPBPT+T_USER:
+ /*
+ * This trap is used by the kernel to support single-step
+ * debugging (although any user could generate this trap
+ * which should probably be handled differently). When a
+ * process is continued by a debugger with the PT_STEP
+ * function of ptrace (single step), the kernel inserts
+ * one or two breakpoints in the user process so that only
+ * one instruction (or two in the case of a delayed branch)
+ * is executed. When this breakpoint is hit, we get the
+ * T_STEPBPT trap.
+ */
+ {
+ unsigned va;
+ unsigned instr;
+ struct uio uio;
+ struct iovec iov;
+ unsigned pc = PC_REGS(&frame->tf_regs);
+
+ /* read break instruction */
+ copyin((caddr_t)pc, &instr, sizeof(unsigned));
+#if 0
+ printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n",
+ p->p_comm, p->p_pid, instr, pc,
+ p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */
+#endif
+ /* check and see if we got here by accident */
+ if ((p->p_md.md_ss_addr != pc &&
+ p->p_md.md_ss_taken_addr != pc) ||
+ instr != SSBREAKPOINT) {
+ sig = SIGTRAP;
+ fault_type = TRAP_TRACE;
+ break;
+ }
+ /* restore original instruction and clear BP */
+ instr = p->p_md.md_ss_instr;
+ va = p->p_md.md_ss_addr;
+ if (va != 0) {
+ iov.iov_base = (caddr_t)&instr;
+ iov.iov_len = sizeof(int);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)va;
+ uio.uio_resid = sizeof(int);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = curproc;
+ procfs_domem(p, p, NULL, &uio);
+ }
+
+ /* branch taken instruction */
+ instr = p->p_md.md_ss_taken_instr;
+ va = p->p_md.md_ss_taken_addr;
+ if (instr != 0) {
+ iov.iov_base = (caddr_t)&instr;
+ iov.iov_len = sizeof(int);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)va;
+ uio.uio_resid = sizeof(int);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = curproc;
+ procfs_domem(p, p, NULL, &uio);
+ }
+#if 1
+ frame->tf_sfip = frame->tf_snip; /* set up next FIP */
+ frame->tf_snip = pc; /* set up next NIP */
+ frame->tf_snip |= 2; /* set valid bit */
+#endif
+ p->p_md.md_ss_addr = 0;
+ p->p_md.md_ss_instr = 0;
+ p->p_md.md_ss_taken_addr = 0;
+ p->p_md.md_ss_taken_instr = 0;
+ sig = SIGTRAP;
+ fault_type = TRAP_BRKPT;
+ }
+ break;
+
+ case T_USERBPT+T_USER:
+ /*
+ * This trap is meant to be used by debuggers to implement
+ * breakpoint debugging. When we get this trap, we just
+ * return a signal which gets caught by the debugger.
+ */
+ frame->tf_sfip = frame->tf_snip; /* set up the next FIP */
+ frame->tf_snip = frame->tf_sxip; /* set up the next NIP */
+ sig = SIGTRAP;
+ fault_type = TRAP_BRKPT;
+ break;
+
+ case T_ASTFLT+T_USER:
+ uvmexp.softs++;
+ want_ast = 0;
+ if (p->p_flag & P_OWEUPC) {
+ p->p_flag &= ~P_OWEUPC;
+ ADDUPROF(p);
+ }
+ break;
+ }
+
+ /*
+ * If trap from supervisor mode, just return
+ */
+ if (type < T_USER)
+ return;
+
+ if (sig) {
+ sv.sival_int = fault_addr;
+ trapsignal(p, sig, fault_code, fault_type, sv);
+ /*
+ * don't want multiple faults - we are going to
+ * deliver signal.
+ */
+ frame->tf_dmt0 = 0;
+ frame->tf_ipfsr = frame->tf_dpfsr = 0;
+ }
+
+ userret(p, frame, sticks);
+}
+#endif /* m88100 */
+
+#ifdef M88110
+void
+m88110_trap(unsigned type, struct trapframe *frame)
+{
+ struct proc *p;
+ u_quad_t sticks = 0;
+ struct vm_map *map;
+ vaddr_t va;
+ vm_prot_t ftype;
+ int fault_type;
+ u_long fault_code;
+ unsigned nss, fault_addr;
+ struct vmspace *vm;
+ union sigval sv;
+ int result;
+#ifdef DDB
+ int s; /* IPL */
+#endif
+ int sig = 0;
+ pt_entry_t *pte;
+
+ extern struct vm_map *kernel_map;
+ extern unsigned guarded_access_start;
+ extern unsigned guarded_access_end;
+ extern unsigned guarded_access_bad;
+ extern pt_entry_t *pmap_pte(pmap_t, vaddr_t);
+
+ uvmexp.traps++;
+ if ((p = curproc) == NULL)
+ p = &proc0;
+
+ if (USERMODE(frame->tf_epsr)) {
+ sticks = p->p_sticks;
+ type += T_USER;
+ p->p_md.md_tf = frame; /* for ptrace/signals */
+ }
+ fault_type = 0;
+ fault_code = 0;
+ fault_addr = frame->tf_exip & XIP_ADDR;
+
+ switch (type) {
+ default:
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+
+ case T_197_READ+T_USER:
+ case T_197_READ:
+ DEBUG_MSG(("DMMU read miss: Hardware Table Searches should be enabled!\n"));
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+ case T_197_WRITE+T_USER:
+ case T_197_WRITE:
+ DEBUG_MSG(("DMMU write miss: Hardware Table Searches should be enabled!\n"));
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+ case T_197_INST+T_USER:
+ case T_197_INST:
+ DEBUG_MSG(("IMMU miss: Hardware Table Searches should be enabled!\n"));
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+#ifdef DDB
+ case T_KDB_TRACE:
+ s = splhigh();
+ db_enable_interrupt();
+ ddb_break_trap(T_KDB_TRACE, (db_regs_t*)frame);
+ db_disable_interrupt();
+ splx(s);
+ return;
+ case T_KDB_BREAK:
+ s = splhigh();
+ db_enable_interrupt();
+ ddb_break_trap(T_KDB_BREAK, (db_regs_t*)frame);
+ db_disable_interrupt();
+ splx(s);
+ return;
+ case T_KDB_ENTRY:
+ s = splhigh();
+ db_enable_interrupt();
+ ddb_entry_trap(T_KDB_ENTRY, (db_regs_t*)frame);
+ db_disable_interrupt();
+ /* skip one instruction */
+ if (frame->tf_exip & 1)
+ frame->tf_exip = frame->tf_enip;
+ else
+ frame->tf_exip += 4;
+ frame->tf_enip = 0;
+ splx(s);
+ return;
+#if 0
+ case T_ILLFLT:
+ s = splhigh();
+ db_enable_interrupt();
+ ddb_error_trap(type == T_ILLFLT ? "unimplemented opcode" :
+ "error fault", (db_regs_t*)frame);
+ db_disable_interrupt();
+ splx(s);
+ return;
+#endif /* 0 */
+#endif /* DDB */
+ case T_ILLFLT:
+ DEBUG_MSG(("Unimplemented opcode!\n"));
+ panictrap(frame->tf_vector, frame);
+ break;
+ case T_NON_MASK:
+ case T_NON_MASK+T_USER:
+ /* This function pointer is set in machdep.c
+ It calls m197_ext_int - smurph */
+ (*md.interrupt_func)(T_NON_MASK, frame);
+ return;
+ case T_INT:
+ case T_INT+T_USER:
+ (*md.interrupt_func)(T_INT, frame);
+ return;
+ case T_MISALGNFLT:
+ DEBUG_MSG(("kernel mode misaligned "
+ "access exception @ 0x%08x\n", frame->tf_exip));
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+
+ case T_INSTFLT:
+ /* kernel mode instruction access fault.
+ * Should never, never happen for a non-paged kernel.
+ */
+#ifdef TRAPDEBUG
+ printf("Kernel Instruction fault exip %x isr %x ilar %x\n",
+ frame->tf_exip, frame->tf_isr, frame->tf_ilar);
+#endif
+ panictrap(frame->tf_vector, frame);
+ break;
+ /*NOTREACHED*/
+
+ case T_DATAFLT:
+ /* kernel mode data fault */
+
+ /* data fault on the user address? */
+ if ((frame->tf_dsr & CMMU_DSR_SU) == 0) {
+ type = T_DATAFLT + T_USER;
+ goto m88110_user_fault;
+ }
+
+#ifdef TRAPDEBUG
+ printf("Kernel Data access fault exip %x dsr %x dlar %x\n",
+ frame->tf_exip, frame->tf_dsr, frame->tf_dlar);
+#endif
+
+ fault_addr = frame->tf_dlar;
+ if (frame->tf_dsr & CMMU_DSR_RW) {
+ ftype = VM_PROT_READ;
+ fault_code = VM_PROT_READ;
+ } else {
+ ftype = VM_PROT_READ|VM_PROT_WRITE;
+ fault_code = VM_PROT_WRITE;
+ }
+
+ va = trunc_page((vaddr_t)fault_addr);
+ if (va == 0) {
+ panic("trap: bad kernel access at %x", fault_addr);
+ }
+
+ vm = p->p_vmspace;
+ map = kernel_map;
+
+ if (frame->tf_dsr & CMMU_DSR_BE) {
+ /*
+ * If it is a guarded access, bus error is OK.
+ */
+ if ((frame->tf_exip & XIP_ADDR) >=
+ (unsigned)&guarded_access_start &&
+ (frame->tf_exip & XIP_ADDR) <=
+ (unsigned)&guarded_access_end) {
+ frame->tf_exip = (unsigned)&guarded_access_bad;
+ frame->tf_enip = 0;
+ return;
+ }
+ }
+ if (frame->tf_dsr & (CMMU_DSR_SI | CMMU_DSR_PI)) {
+ frame->tf_dsr &= ~CMMU_DSR_WE; /* undefined */
+ /*
+ * On a segment or a page fault, call uvm_fault() to
+ * resolve the fault.
+ */
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == 0)
+ return;
+ }
+ if (frame->tf_dsr & CMMU_DSR_WE) { /* write fault */
+ /*
+ * This could be a write protection fault or an
+ * exception to set the used and modified bits
+ * in the pte. Basically, if we got a write error,
+ * then we already have a pte entry that faulted
+ * in from a previous seg fault or page fault.
+ * Get the pte and check the status of the
+ * modified and valid bits to determine if this
+ * indeed a real write fault. XXX smurph
+ */
+ pte = pmap_pte(map->pmap, va);
+ if (pte == PT_ENTRY_NULL)
+ panic("NULL pte on write fault??");
+ if (!(*pte & PG_M) && !(*pte & PG_RO)) {
+ /* Set modified bit and try the write again. */
+#ifdef TRAPDEBUG
+ printf("Corrected kernel write fault, map %x pte %x\n",
+ map->pmap, *pte);
+#endif
+ *pte |= PG_M;
+ return;
+#if 1 /* shouldn't happen */
+ } else {
+ /* must be a real wp fault */
+#ifdef TRAPDEBUG
+ printf("Uncorrected kernel write fault, map %x pte %x\n",
+ map->pmap, *pte);
+#endif
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == 0)
+ return;
+#endif
+ }
+ }
+ panictrap(frame->tf_vector, frame);
+ /* NOTREACHED */
+ case T_INSTFLT+T_USER:
+ /* User mode instruction access fault */
+ /* FALLTHROUGH */
+ case T_DATAFLT+T_USER:
+m88110_user_fault:
+ if (type == T_INSTFLT+T_USER) {
+ ftype = VM_PROT_READ;
+ fault_code = VM_PROT_READ;
+#ifdef TRAPDEBUG
+ printf("User Instruction fault exip %x isr %x ilar %x\n",
+ frame->tf_exip, frame->tf_isr, frame->tf_ilar);
+#endif
+ } else {
+ fault_addr = frame->tf_dlar;
+ if (frame->tf_dsr & CMMU_DSR_RW) {
+ ftype = VM_PROT_READ;
+ fault_code = VM_PROT_READ;
+ } else {
+ ftype = VM_PROT_READ|VM_PROT_WRITE;
+ fault_code = VM_PROT_WRITE;
+ }
+#ifdef TRAPDEBUG
+ printf("User Data access fault exip %x dsr %x dlar %x\n",
+ frame->tf_exip, frame->tf_dsr, frame->tf_dlar);
+#endif
+ }
+
+ va = trunc_page((vaddr_t)fault_addr);
+
+ vm = p->p_vmspace;
+ map = &vm->vm_map;
+
+ /*
+ * Call uvm_fault() to resolve non-bus error faults
+ * whenever possible.
+ */
+ if (type == T_DATAFLT+T_USER) {
+ /* data faults */
+ if (frame->tf_dsr & CMMU_DSR_BE) {
+ /* bus error */
+ result = EACCES;
+ } else
+ if (frame->tf_dsr & (CMMU_DSR_SI | CMMU_DSR_PI)) {
+ /* segment or page fault */
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == EACCES)
+ result = EFAULT;
+ } else
+ if (frame->tf_dsr & (CMMU_DSR_CP | CMMU_DSR_WA)) {
+ /* copyback or write allocate error */
+ result = 0;
+ } else
+ if (frame->tf_dsr & CMMU_DSR_WE) {
+ /* write fault */
+ /* This could be a write protection fault or an
+ * exception to set the used and modified bits
+ * in the pte. Basically, if we got a write
+ * error, then we already have a pte entry that
+ * faulted in from a previous seg fault or page
+ * fault.
+ * Get the pte and check the status of the
+ * modified and valid bits to determine if this
+ * indeed a real write fault. XXX smurph
+ */
+ pte = pmap_pte(vm_map_pmap(map), va);
+#ifdef DEBUG
+ if (pte == PT_ENTRY_NULL)
+ panic("NULL pte on write fault??");
+#endif
+ if (!(*pte & PG_M) && !(*pte & PG_RO)) {
+ /*
+ * Set modified bit and try the
+ * write again.
+ */
+#ifdef TRAPDEBUG
+ printf("Corrected userland write fault, map %x pte %x\n",
+ map->pmap, *pte);
+#endif
+ *pte |= PG_M;
+ /*
+ * invalidate ATCs to force
+ * table search
+ */
+ set_dcmd(CMMU_DCMD_INV_UATC);
+ return;
+ } else {
+ /* must be a real wp fault */
+#ifdef TRAPDEBUG
+ printf("Uncorrected userland write fault, map %x pte %x\n",
+ map->pmap, *pte);
+#endif
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == EACCES)
+ result = EFAULT;
+ }
+ } else {
+#ifdef TRAPDEBUG
+ printf("Unexpected Data access fault dsr %x\n",
+ frame->tf_dsr);
+#endif
+ panictrap(frame->tf_vector, frame);
+ }
+ } else {
+ /* instruction faults */
+ if (frame->tf_isr &
+ (CMMU_ISR_BE | CMMU_ISR_SP | CMMU_ISR_TBE)) {
+ /* bus error, supervisor protection */
+ result = EACCES;
+ } else
+ if (frame->tf_isr & (CMMU_ISR_SI | CMMU_ISR_PI)) {
+ /* segment or page fault */
+ result = uvm_fault(map, va, VM_FAULT_INVALID, ftype);
+ if (result == EACCES)
+ result = EFAULT;
+ } else {
+#ifdef TRAPDEBUG
+ printf("Unexpected Instruction fault isr %x\n",
+ frame->tf_isr);
+#endif
+ panictrap(frame->tf_vector, frame);
+ }
+ }
+
+ if ((caddr_t)va >= vm->vm_maxsaddr) {
+ if (result == 0) {
+ nss = btoc(USRSTACK - va);/* XXX check this */
+ if (nss > vm->vm_ssize)
+ vm->vm_ssize = nss;
+ }
+ }
+
+ /*
+ * This could be a fault caused in copyin*()
+ * while accessing user space.
+ */
+ if (result != 0 && p->p_addr->u_pcb.pcb_onfault != NULL) {
+ frame->tf_exip = p->p_addr->u_pcb.pcb_onfault;
+ frame->tf_enip = 0;
+ frame->tf_dsr = frame->tf_isr = 0;
+ /*
+ * Continue as if the fault had been resolved.
+ */
+ result = 0;
+ }
+
+ if (result != 0) {
+ sig = result == EACCES ? SIGBUS : SIGSEGV;
+ fault_type = result == EACCES ?
+ BUS_ADRERR : SEGV_MAPERR;
+ }
+ break;
+ case T_MISALGNFLT+T_USER:
+ sig = SIGBUS;
+ fault_type = BUS_ADRALN;
+ break;
+ case T_PRIVINFLT+T_USER:
+ case T_ILLFLT+T_USER:
+#ifndef DDB
+ case T_KDB_BREAK:
+ case T_KDB_ENTRY:
+ case T_KDB_TRACE:
+#endif
+ case T_KDB_BREAK+T_USER:
+ case T_KDB_ENTRY+T_USER:
+ case T_KDB_TRACE+T_USER:
+ sig = SIGILL;
+ break;
+ case T_BNDFLT+T_USER:
+ sig = SIGFPE;
+ break;
+ case T_ZERODIV+T_USER:
+ sig = SIGFPE;
+ fault_type = FPE_INTDIV;
+ break;
+ case T_OVFFLT+T_USER:
+ sig = SIGFPE;
+ fault_type = FPE_INTOVF;
+ break;
+ case T_FPEPFLT+T_USER:
+ case T_FPEIFLT+T_USER:
+ sig = SIGFPE;
+ break;
+ case T_SIGSYS+T_USER:
+ sig = SIGSYS;
+ break;
+ case T_SIGTRAP+T_USER:
+ sig = SIGTRAP;
+ fault_type = TRAP_TRACE;
+ break;
+ case T_STEPBPT+T_USER:
+ /*
+ * This trap is used by the kernel to support single-step
+ * debugging (although any user could generate this trap
+ * which should probably be handled differently). When a
+ * process is continued by a debugger with the PT_STEP
+ * function of ptrace (single step), the kernel inserts
+ * one or two breakpoints in the user process so that only
+ * one instruction (or two in the case of a delayed branch)
+ * is executed. When this breakpoint is hit, we get the
+ * T_STEPBPT trap.
+ */
+ {
+ unsigned instr;
+ struct uio uio;
+ struct iovec iov;
+ unsigned pc = PC_REGS(&frame->tf_regs);
+
+ /* read break instruction */
+ copyin((caddr_t)pc, &instr, sizeof(unsigned));
+#if 0
+ printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n",
+ p->p_comm, p->p_pid, instr, pc,
+ p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */
+#endif
+ /* check and see if we got here by accident */
+#ifdef notyet
+ if (p->p_md.md_ss_addr != pc || instr != SSBREAKPOINT) {
+ sig = SIGTRAP;
+ fault_type = TRAP_TRACE;
+ break;
+ }
+#endif
+ /* restore original instruction and clear BP */
+ /*sig = suiword((caddr_t)pc, p->p_md.md_ss_instr);*/
+ instr = p->p_md.md_ss_instr;
+ if (instr != 0) {
+ iov.iov_base = (caddr_t)&instr;
+ iov.iov_len = sizeof(int);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)pc;
+ uio.uio_resid = sizeof(int);
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = curproc;
+ }
+
+ p->p_md.md_ss_addr = 0;
+ sig = SIGTRAP;
+ fault_type = TRAP_BRKPT;
+ break;
+ }
+ case T_USERBPT+T_USER:
+ /*
+ * This trap is meant to be used by debuggers to implement
+ * breakpoint debugging. When we get this trap, we just
+ * return a signal which gets caught by the debugger.
+ */
+ sig = SIGTRAP;
+ fault_type = TRAP_BRKPT;
+ break;
+
+ case T_ASTFLT+T_USER:
+ uvmexp.softs++;
+ want_ast = 0;
+ if (p->p_flag & P_OWEUPC) {
+ p->p_flag &= ~P_OWEUPC;
+ ADDUPROF(p);
+ }
+ break;
+ }
+
+ /*
+ * If trap from supervisor mode, just return
+ */
+ if (type < T_USER)
+ return;
+
+ if (sig) {
+ sv.sival_int = fault_addr;
+ trapsignal(p, sig, fault_code, fault_type, sv);
+ /*
+ * don't want multiple faults - we are going to
+ * deliver signal.
+ */
+ frame->tf_dsr = frame->tf_isr = 0;
+ }
+
+ userret(p, frame, sticks);
+}
+#endif /* MVME197 */
+
+__dead void
+error_fatal(struct trapframe *frame)
+{
+#ifdef DDB
+ switch (frame->tf_vector) {
+ case 0:
+ db_printf("\n[RESET EXCEPTION (Really Bad News[tm]) frame %8p]\n", frame);
+ db_printf("This is usually caused by a branch to a NULL function pointer.\n");
+ db_printf("e.g. jump to address 0. Use the debugger trace command to track it down.\n");
+ break;
+ default:
+ db_printf("\n[ERROR EXCEPTION (Bad News[tm]) frame %p]\n", frame);
+ db_printf("This is usually an exception within an exception. The trap\n");
+ db_printf("frame shadow registers you are about to see are invalid.\n");
+ db_printf("(read totally useless) But R1 to R31 might be interesting.\n");
+ break;
+ }
+ regdump((struct trapframe*)frame);
+#endif /* DDB */
+ panic("unrecoverable exception %d", frame->tf_vector);
+}
+
+#ifdef M88100
+void
+m88100_syscall(register_t code, struct trapframe *tf)
+{
+ int i, nsys, nap;
+ struct sysent *callp;
+ struct proc *p;
+ int error;
+ register_t args[11], rval[2], *ap;
+ u_quad_t sticks;
+#ifdef DIAGNOSTIC
+ extern struct pcb *curpcb;
+#endif
+
+ uvmexp.syscalls++;
+
+ p = curproc;
+
+ callp = p->p_emul->e_sysent;
+ nsys = p->p_emul->e_nsysent;
+
+#ifdef DIAGNOSTIC
+ if (USERMODE(tf->tf_epsr) == 0)
+ panic("syscall");
+ if (curpcb != &p->p_addr->u_pcb)
+ panic("syscall curpcb/ppcb");
+ if (tf != (struct trapframe *)&curpcb->user_state)
+ panic("syscall trapframe");
+#endif
+
+ sticks = p->p_sticks;
+ p->p_md.md_tf = tf;
+
+ /*
+ * For 88k, all the arguments are passed in the registers (r2-r12)
+ * For syscall (and __syscall), r2 (and r3) has the actual code.
+ * __syscall takes a quad syscall number, so that other
+ * arguments are at their natural alignments.
+ */
+ ap = &tf->tf_r[2];
+ nap = 11; /* r2-r12 */
+
+ switch (code) {
+ case SYS_syscall:
+ code = *ap++;
+ nap--;
+ break;
+ case SYS___syscall:
+ if (callp != sysent)
+ break;
+ code = ap[_QUAD_LOWWORD];
+ ap += 2;
+ nap -= 2;
+ break;
+ }
+
+ /* Callp currently points to syscall, which returns ENOSYS. */
+ if (code < 0 || code >= nsys)
+ callp += p->p_emul->e_nosys;
+ else {
+ callp += code;
+ i = callp->sy_argsize / sizeof(register_t);
+ if (i > nap)
+ panic("syscall nargs");
+ /*
+ * just copy them; syscall stub made sure all the
+ * args are moved from user stack to registers.
+ */
+ bcopy((caddr_t)ap, (caddr_t)args, i * sizeof(register_t));
+ }
+
+#ifdef SYSCALL_DEBUG
+ scdebug_call(p, code, args);
+#endif
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p, code, callp->sy_argsize, args);
+#endif
+ rval[0] = 0;
+ rval[1] = 0;
+#if NSYSTRACE > 0
+ if (ISSET(p->p_flag, P_SYSTRACE))
+ error = systrace_redirect(code, p, args, rval);
+ else
+#endif
+ error = (*callp->sy_call)(p, args, rval);
+ /*
+ * system call will look like:
+ * ld r10, r31, 32; r10,r11,r12 might be garbage.
+ * ld r11, r31, 36
+ * ld r12, r31, 40
+ * or r13, r0, <code>
+ * tb0 0, r0, <128> <- sxip
+ * br err <- snip
+ * jmp r1 <- sfip
+ * err: or.u r3, r0, hi16(errno)
+ * st r2, r3, lo16(errno)
+ * subu r2, r0, 1
+ * jmp r1
+ *
+ * So, when we take syscall trap, sxip/snip/sfip will be as
+ * shown above.
+ * Given this,
+ * 1. If the system call returned 0, need to skip nip.
+ * nip = fip, fip += 4
+ * (doesn't matter what fip + 4 will be but we will never
+ * execute this since jmp r1 at nip will change the execution flow.)
+ * 2. If the system call returned an errno > 0, plug the value
+ * in r2, and leave nip and fip unchanged. This will have us
+ * executing "br err" on return to user space.
+ * 3. If the system call code returned ERESTART,
+ * we need to rexecute the trap instruction. Back up the pipe
+ * line.
+ * fip = nip, nip = xip
+ * 4. If the system call returned EJUSTRETURN, don't need to adjust
+ * any pointers.
+ */
+
+ switch (error) {
+ case 0:
+ /*
+ * If fork succeeded and we are the child, our stack
+ * has moved and the pointer tf is no longer valid,
+ * and p is wrong. Compute the new trapframe pointer.
+ * (The trap frame invariably resides at the
+ * tippity-top of the u. area.)
+ */
+ p = curproc;
+ tf = (struct trapframe *)USER_REGS(p);
+ tf->tf_r[2] = rval[0];
+ tf->tf_r[3] = rval[1];
+ tf->tf_epsr &= ~PSR_C;
+ tf->tf_snip = tf->tf_sfip & ~NIP_E;
+ tf->tf_sfip = tf->tf_snip + 4;
+ break;
+ case ERESTART:
+ /*
+ * If (error == ERESTART), back up the pipe line. This
+ * will end up reexecuting the trap.
+ */
+ tf->tf_epsr &= ~PSR_C;
+ tf->tf_sfip = tf->tf_snip & ~FIP_E;
+ tf->tf_snip = tf->tf_sxip & ~NIP_E;
+ break;
+ case EJUSTRETURN:
+ /* if (error == EJUSTRETURN), leave the ip's alone */
+ tf->tf_epsr &= ~PSR_C;
+ break;
+ default:
+ /* error != ERESTART && error != EJUSTRETURN*/
+ if (p->p_emul->e_errno)
+ error = p->p_emul->e_errno[error];
+ tf->tf_r[2] = error;
+ tf->tf_epsr |= PSR_C; /* fail */
+ tf->tf_snip = tf->tf_snip & ~NIP_E;
+ tf->tf_sfip = tf->tf_sfip & ~FIP_E;
+ break;
+ }
+#ifdef SYSCALL_DEBUG
+ scdebug_ret(p, code, error, rval);
+#endif
+ userret(p, tf, sticks);
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p, code, error, rval[0]);
+#endif
+}
+#endif /* M88100 */
+
+#ifdef M88110
+/* Instruction pointers operate differently on mc88110 */
+void
+m88110_syscall(register_t code, struct trapframe *tf)
+{
+ int i, nsys, nap;
+ struct sysent *callp;
+ struct proc *p;
+ int error;
+ register_t args[11], rval[2], *ap;
+ u_quad_t sticks;
+#ifdef DIAGNOSTIC
+ extern struct pcb *curpcb;
+#endif
+
+ uvmexp.syscalls++;
+
+ p = curproc;
+
+ callp = p->p_emul->e_sysent;
+ nsys = p->p_emul->e_nsysent;
+
+#ifdef DIAGNOSTIC
+ if (USERMODE(tf->tf_epsr) == 0)
+ panic("syscall");
+ if (curpcb != &p->p_addr->u_pcb)
+ panic("syscall curpcb/ppcb");
+ if (tf != (struct trapframe *)&curpcb->user_state)
+ panic("syscall trapframe");
+#endif
+
+ sticks = p->p_sticks;
+ p->p_md.md_tf = tf;
+
+ /*
+ * For 88k, all the arguments are passed in the registers (r2-r12)
+ * For syscall (and __syscall), r2 (and r3) has the actual code.
+ * __syscall takes a quad syscall number, so that other
+ * arguments are at their natural alignments.
+ */
+ ap = &tf->tf_r[2];
+ nap = 11; /* r2-r12 */
+
+ switch (code) {
+ case SYS_syscall:
+ code = *ap++;
+ nap--;
+ break;
+ case SYS___syscall:
+ if (callp != sysent)
+ break;
+ code = ap[_QUAD_LOWWORD];
+ ap += 2;
+ nap -= 2;
+ break;
+ }
+
+ /* Callp currently points to syscall, which returns ENOSYS. */
+ if (code < 0 || code >= nsys)
+ callp += p->p_emul->e_nosys;
+ else {
+ callp += code;
+ i = callp->sy_argsize / sizeof(register_t);
+ if (i > nap)
+ panic("syscall nargs");
+ /*
+ * just copy them; syscall stub made sure all the
+ * args are moved from user stack to registers.
+ */
+ bcopy((caddr_t)ap, (caddr_t)args, i * sizeof(register_t));
+ }
+#ifdef SYSCALL_DEBUG
+ scdebug_call(p, code, args);
+#endif
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p, code, callp->sy_argsize, args);
+#endif
+ rval[0] = 0;
+ rval[1] = 0;
+#if NSYSTRACE > 0
+ if (ISSET(p->p_flag, P_SYSTRACE))
+ error = systrace_redirect(code, p, args, rval);
+ else
+#endif
+ error = (*callp->sy_call)(p, args, rval);
+ /*
+ * system call will look like:
+ * ld r10, r31, 32; r10,r11,r12 might be garbage.
+ * ld r11, r31, 36
+ * ld r12, r31, 40
+ * or r13, r0, <code>
+ * tb0 0, r0, <128> <- exip
+ * br err <- enip
+ * jmp r1
+ * err: or.u r3, r0, hi16(errno)
+ * st r2, r3, lo16(errno)
+ * subu r2, r0, 1
+ * jmp r1
+ *
+ * So, when we take syscall trap, exip/enip will be as
+ * shown above.
+ * Given this,
+ * 1. If the system call returned 0, need to jmp r1.
+ * exip += 8
+ * 2. If the system call returned an errno > 0, increment
+ * exip += 4 and plug the value in r2. This will have us
+ * executing "br err" on return to user space.
+ * 3. If the system call code returned ERESTART,
+ * we need to rexecute the trap instruction. leave exip as is.
+ * 4. If the system call returned EJUSTRETURN, just return.
+ * exip += 4
+ */
+
+ switch (error) {
+ case 0:
+ /*
+ * If fork succeeded and we are the child, our stack
+ * has moved and the pointer tf is no longer valid,
+ * and p is wrong. Compute the new trapframe pointer.
+ * (The trap frame invariably resides at the
+ * tippity-top of the u. area.)
+ */
+ p = curproc;
+ tf = (struct trapframe *)USER_REGS(p);
+ tf->tf_r[2] = rval[0];
+ tf->tf_r[3] = rval[1];
+ tf->tf_epsr &= ~PSR_C;
+ /* skip two instructions */
+ if (tf->tf_exip & 1)
+ tf->tf_exip = tf->tf_enip + 4;
+ else
+ tf->tf_exip += 4 + 4;
+ tf->tf_enip = 0;
+ break;
+ case ERESTART:
+ /*
+ * Reexecute the trap.
+ * exip is already at the trap instruction, so
+ * there is nothing to do.
+ */
+ tf->tf_epsr &= ~PSR_C;
+ break;
+ case EJUSTRETURN:
+ tf->tf_epsr &= ~PSR_C;
+ /* skip one instruction */
+ if (tf->tf_exip & 1)
+ tf->tf_exip = tf->tf_enip;
+ else
+ tf->tf_exip += 4;
+ tf->tf_enip = 0;
+ break;
+ default:
+ if (p->p_emul->e_errno)
+ error = p->p_emul->e_errno[error];
+ tf->tf_r[2] = error;
+ tf->tf_epsr |= PSR_C; /* fail */
+ /* skip one instruction */
+ if (tf->tf_exip & 1)
+ tf->tf_exip = tf->tf_enip;
+ else
+ tf->tf_exip += 4;
+ tf->tf_enip = 0;
+ break;
+ }
+
+#ifdef SYSCALL_DEBUG
+ scdebug_ret(p, code, error, rval);
+#endif
+ userret(p, tf, sticks);
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p, code, error, rval[0]);
+#endif
+}
+#endif /* MVME197 */
+
+/*
+ * Set up return-value registers as fork() libc stub expects,
+ * and do normal return-to-user-mode stuff.
+ */
+void
+child_return(arg)
+ void *arg;
+{
+ struct proc *p = arg;
+ struct trapframe *tf;
+
+ tf = (struct trapframe *)USER_REGS(p);
+ tf->tf_r[2] = 0;
+ tf->tf_r[3] = 0;
+ tf->tf_epsr &= ~PSR_C;
+ if (cputyp != CPU_88110) {
+ tf->tf_snip = tf->tf_sfip & XIP_ADDR;
+ tf->tf_sfip = tf->tf_snip + 4;
+ } else {
+ /* skip two instructions */
+ if (tf->tf_exip & 1)
+ tf->tf_exip = tf->tf_enip + 4;
+ else
+ tf->tf_exip += 4 + 4;
+ tf->tf_enip = 0;
+ }
+
+ userret(p, tf, p->p_sticks);
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p, SYS_fork, 0, 0);
+#endif
+}
+
+#ifdef PTRACE
+
+/*
+ * User Single Step Debugging Support
+ */
+
+#include <sys/ptrace.h>
+
+unsigned ss_get_value(struct proc *, unsigned, int);
+int ss_put_value(struct proc *, unsigned, unsigned, int);
+unsigned ss_branch_taken(unsigned, unsigned,
+ unsigned (*func)(unsigned int, struct reg *), struct reg *);
+unsigned int ss_getreg_val(unsigned int, struct reg *);
+int ss_inst_branch(unsigned);
+int ss_inst_delayed(unsigned);
+unsigned ss_next_instr_address(struct proc *, unsigned, unsigned);
+
+unsigned
+ss_get_value(struct proc *p, unsigned addr, int size)
+{
+ struct uio uio;
+ struct iovec iov;
+ unsigned value;
+
+ iov.iov_base = (caddr_t)&value;
+ iov.iov_len = size;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)addr;
+ uio.uio_resid = size;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = curproc;
+ procfs_domem(curproc, p, NULL, &uio);
+ return value;
+}
+
+int
+ss_put_value(struct proc *p, unsigned addr, unsigned value, int size)
+{
+ struct uio uio;
+ struct iovec iov;
+
+ iov.iov_base = (caddr_t)&value;
+ iov.iov_len = size;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = (off_t)addr;
+ uio.uio_resid = size;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = curproc;
+ return procfs_domem(curproc, p, NULL, &uio);
+}
+
+/*
+ * ss_branch_taken(instruction, program counter, func, func_data)
+ *
+ * instruction will be a control flow instruction location at address pc.
+ * Branch taken is supposed to return the address to which the instruction
+ * would jump if the branch is taken. Func can be used to get the current
+ * register values when invoked with a register number and func_data as
+ * arguments.
+ *
+ * If the instruction is not a control flow instruction, panic.
+ */
+unsigned
+ss_branch_taken(unsigned inst, unsigned pc,
+ unsigned (*func)(unsigned int, struct reg *), struct reg *func_data)
+{
+ /* check if br/bsr */
+ if ((inst & 0xf0000000) == 0xc0000000) {
+ /* signed 26 bit pc relative displacement, shift left two bits */
+ inst = (inst & 0x03ffffff) << 2;
+ /* check if sign extension is needed */
+ if (inst & 0x08000000)
+ inst |= 0xf0000000;
+ return (pc + inst);
+ }
+
+ /* check if bb0/bb1/bcnd case */
+ switch (inst & 0xf8000000) {
+ case 0xd0000000: /* bb0 */
+ case 0xd8000000: /* bb1 */
+ case 0xe8000000: /* bcnd */
+ /* signed 16 bit pc relative displacement, shift left two bits */
+ inst = (inst & 0x0000ffff) << 2;
+ /* check if sign extension is needed */
+ if (inst & 0x00020000)
+ inst |= 0xfffc0000;
+ return (pc + inst);
+ }
+
+ /* check jmp/jsr case */
+ /* check bits 5-31, skipping 10 & 11 */
+ if ((inst & 0xfffff3e0) == 0xf400c000)
+ return (*func)(inst & 0x1f, func_data); /* the register value */
+
+ /* can't happen */
+ return (0);
+}
+
+/*
+ * ss_getreg_val - handed a register number and an exception frame.
+ * Returns the value of the register in the specified
+ * frame. Only makes sense for general registers.
+ */
+unsigned int
+ss_getreg_val(unsigned int regno, struct reg *regs)
+{
+ return (regno == 0 ? 0 : regs->r[regno]);
+}
+
+int
+ss_inst_branch(unsigned ins)
+{
+ /* check high five bits */
+
+ switch (ins >> (32 - 5)) {
+ case 0x18: /* br */
+ case 0x1a: /* bb0 */
+ case 0x1b: /* bb1 */
+ case 0x1d: /* bcnd */
+ return TRUE;
+ break;
+ case 0x1e: /* could be jmp */
+ if ((ins & 0xfffffbe0) == 0xf400c000)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* ss_inst_delayed - this instruction is followed by a delay slot. Could be
+ br.n, bsr.n bb0.n, bb1.n, bcnd.n or jmp.n or jsr.n */
+
+int
+ss_inst_delayed(unsigned ins)
+{
+ /* check the br, bsr, bb0, bb1, bcnd cases */
+ switch ((ins & 0xfc000000) >> (32 - 6)) {
+ case 0x31: /* br */
+ case 0x33: /* bsr */
+ case 0x35: /* bb0 */
+ case 0x37: /* bb1 */
+ case 0x3b: /* bcnd */
+ return TRUE;
+ }
+
+ /* check the jmp, jsr cases */
+ /* mask out bits 0-4, bit 11 */
+ return ((ins & 0xfffff7e0) == 0xf400c400) ? TRUE : FALSE;
+}
+
+unsigned
+ss_next_instr_address(struct proc *p, unsigned pc, unsigned delay_slot)
+{
+ if (delay_slot == 0)
+ return (pc + 4);
+ else {
+ if (ss_inst_delayed(ss_get_value(p, pc, sizeof(int))))
+ return (pc + 4);
+ else
+ return pc;
+ }
+}
+
+int
+cpu_singlestep(p)
+ struct proc *p;
+{
+ struct reg *sstf = USER_REGS(p);
+ unsigned pc, brpc;
+ int bpinstr = SSBREAKPOINT;
+ unsigned curinstr;
+
+ pc = PC_REGS(sstf);
+ /*
+ * User was stopped at pc, e.g. the instruction
+ * at pc was not executed.
+ * Fetch what's at the current location.
+ */
+ curinstr = ss_get_value(p, pc, sizeof(int));
+
+ /* compute next address after current location */
+ if (curinstr != 0) {
+ if (ss_inst_branch(curinstr) ||
+ inst_call(curinstr) || inst_return(curinstr)) {
+ brpc = ss_branch_taken(curinstr, pc, ss_getreg_val, sstf);
+ if (brpc != pc) { /* self-branches are hopeless */
+ p->p_md.md_ss_taken_addr = brpc;
+ p->p_md.md_ss_taken_instr =
+ ss_get_value(p, brpc, sizeof(int));
+ /* Store breakpoint instruction at the
+ "next" location now. */
+ if (ss_put_value(p, brpc, bpinstr,
+ sizeof(int)) != 0)
+ return (EFAULT);
+ }
+ }
+ pc = ss_next_instr_address(p, pc, 0);
+ } else {
+ pc = PC_REGS(sstf) + 4;
+ }
+
+ if (p->p_md.md_ss_addr != NULL) {
+ return (EFAULT);
+ }
+
+ p->p_md.md_ss_addr = pc;
+
+ /* Fetch what's at the "next" location. */
+ p->p_md.md_ss_instr = ss_get_value(p, pc, sizeof(int));
+
+ /* Store breakpoint instruction at the "next" location now. */
+ if (ss_put_value(p, pc, bpinstr, sizeof(int)) != 0)
+ return (EFAULT);
+
+ return (0);
+}
+
+#endif /* PTRACE */
+
+#ifdef DIAGNOSTIC
+void
+splassert_check(int wantipl, const char *func)
+{
+ int oldipl;
+
+ /*
+ * This will raise the spl if too low,
+ * in a feeble attempt to reduce further damage.
+ */
+ oldipl = raiseipl(wantipl);
+
+ if (oldipl < wantipl) {
+ splassert_fail(wantipl, oldipl, func);
+ }
+}
+#endif
diff --git a/sys/arch/luna88k/luna88k/vectors_88100.S b/sys/arch/luna88k/luna88k/vectors_88100.S
new file mode 100644
index 00000000000..e9e5a66734e
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/vectors_88100.S
@@ -0,0 +1,89 @@
+/* $OpenBSD: vectors_88100.S,v 1.1 2004/04/21 15:24:14 aoyama Exp $ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991, 1992 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/asm.h>
+
+#define UNDEFINED16 \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER; \
+ word UNKNOWN_HANDLER; word UNKNOWN_HANDLER;
+
+ data
+ .align 4096 /* VBR points to page aligned list */
+GLOBAL(vector_list)
+ VECTOR(reset_handler) /* 00 */
+ VECTOR(interrupt_handler) /* 01 */
+ VECTOR(instruction_access_handler) /* 02 */
+ VECTOR(data_exception_handler) /* 03 */
+ VECTOR(misaligned_handler) /* 04 */
+ VECTOR(unimplemented_handler) /* 05 */
+ VECTOR(privilege_handler) /* 06 */
+ VECTOR(bounds_handler) /* 07 */
+ VECTOR(divide_handler) /* 08 */
+ VECTOR(overflow_handler) /* 09 */
+ VECTOR(error_handler) /* 0a */
+ word UNKNOWN_HANDLER /* 0b */
+ word UNKNOWN_HANDLER /* 0c */
+ word UNKNOWN_HANDLER /* 0d */
+ word UNKNOWN_HANDLER /* 0e */
+ word UNKNOWN_HANDLER /* 0f */
+ UNDEFINED16 /* 1x */
+ UNDEFINED16 /* 2x */
+ UNDEFINED16 /* 3x */
+ UNDEFINED16 /* 4x */
+ UNDEFINED16 /* 5x */
+ UNDEFINED16 /* 6x */
+ word UNKNOWN_HANDLER /* 70 */
+ word UNKNOWN_HANDLER /* 71 */
+ VECTOR(fp_precise_handler) /* 72 */
+ VECTOR(fp_imprecise_handler) /* 73 */
+ VECTOR(unimplemented_handler) /* 74 */
+ word UNKNOWN_HANDLER /* 75 */
+ VECTOR(unimplemented_handler) /* 76 */
+ word UNKNOWN_HANDLER /* 77 */
+ VECTOR(unimplemented_handler) /* 78 */
+ word UNKNOWN_HANDLER /* 79 */
+ VECTOR(unimplemented_handler) /* 7a */
+ word UNKNOWN_HANDLER /* 7b */
+ VECTOR(unimplemented_handler) /* 7c */
+ word UNKNOWN_HANDLER /* 7d */
+ VECTOR(unimplemented_handler) /* 7e */
+ word UNKNOWN_HANDLER /* 7f */
+ VECTOR(syscall_handler) /* 80 */
+ VECTOR(syscall_handler) /* 81 */
+ VECTOR(break) /* 82 */
+ VECTOR(trace) /* 83 */
+ VECTOR(entry) /* 84 */
+GLOBAL(vector_list_end)
+ word END_OF_VECTOR_LIST
+
diff --git a/sys/arch/luna88k/luna88k/vm_machdep.c b/sys/arch/luna88k/luna88k/vm_machdep.c
new file mode 100644
index 00000000000..bcbdf7f61ec
--- /dev/null
+++ b/sys/arch/luna88k/luna88k/vm_machdep.c
@@ -0,0 +1,502 @@
+/* $OpenBSD: vm_machdep.c,v 1.1 2004/04/21 15:24:15 aoyama Exp $ */
+
+/*
+ * Copyright (c) 1998 Steve Murphree, Jr.
+ * Copyright (c) 1996 Nivas Madhur
+ * Copyright (c) 1993 Adam Glass
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: vm_machdep.c 1.21 91/04/06$
+ * from: @(#)vm_machdep.c 7.10 (Berkeley) 5/7/91
+ * vm_machdep.c,v 1.3 1993/07/07 07:09:32 cgd Exp
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+#include <sys/extent.h>
+#include <sys/core.h>
+#include <sys/exec.h>
+#include <sys/ptrace.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/mmu.h>
+#include <machine/board.h>
+#include <machine/cmmu.h>
+#include <machine/cpu.h>
+#include <machine/cpu_number.h>
+#include <machine/locore.h>
+#include <machine/trap.h>
+
+extern struct extent *iomap_extent;
+extern struct vm_map *iomap_map;
+
+vaddr_t iomap_mapin(paddr_t, psize_t, boolean_t);
+void iomap_mapout(vaddr_t, vsize_t);
+void *mapiodev(void *, int);
+void unmapiodev(void *, int);
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent. Returns 1 in the child process, 0 in the parent.
+ * We currently double-map the user area so that the stack is at the same
+ * address in each process; in the future we will probably relocate
+ * the frame pointers on the stack after copying.
+ */
+
+void
+cpu_fork(p1, p2, stack, stacksize, func, arg)
+ struct proc *p1, *p2;
+ void *stack;
+ size_t stacksize;
+ void (*func)(void *);
+ void *arg;
+{
+ struct switchframe *p2sf;
+ struct ksigframe {
+ void (*func)(void *);
+ void *proc;
+ } *ksfp;
+ extern struct pcb *curpcb;
+ extern void proc_trampoline(void);
+ extern void save_u_area(struct proc *, vaddr_t);
+
+ /* Copy pcb from p1 to p2. */
+ if (p1 == curproc) {
+ /* Sync the PCB before we copy it. */
+ savectx(curpcb);
+ }
+#ifdef DIAGNOSTIC
+ else if (p1 != &proc0)
+ panic("cpu_fork: curproc");
+#endif
+
+ bcopy(&p1->p_addr->u_pcb, &p2->p_addr->u_pcb, sizeof(struct pcb));
+ p2->p_addr->u_pcb.kernel_state.pcb_ipl = IPL_NONE; /* XXX */
+ p2->p_md.md_tf = (struct trapframe *)USER_REGS(p2);
+
+ /*XXX these may not be necessary nivas */
+ save_u_area(p2, (vaddr_t)p2->p_addr);
+
+ /*
+ * Create a switch frame for proc 2
+ */
+ p2sf = (struct switchframe *)((char *)p2->p_addr + USPACE - 8) - 1;
+
+ p2sf->sf_pc = (u_int)proc_do_uret;
+ p2sf->sf_proc = p2;
+ p2->p_addr->u_pcb.kernel_state.pcb_sp = (u_int)p2sf;
+
+ /*
+ * If specified, give the child a different stack.
+ */
+ if (stack != NULL)
+ USER_REGS(p2)->r[31] = (u_int)stack + stacksize;
+
+ ksfp = (struct ksigframe *)p2->p_addr->u_pcb.kernel_state.pcb_sp - 1;
+
+ ksfp->func = func;
+ ksfp->proc = arg;
+
+ /*
+ * When this process resumes, r31 will be ksfp and
+ * the process will be at the beginning of proc_trampoline().
+ * proc_trampoline will execute the function func, pop off
+ * ksfp frame, and call the function in the switchframe
+ * now exposed.
+ */
+
+ p2->p_addr->u_pcb.kernel_state.pcb_sp = (u_int)ksfp;
+ p2->p_addr->u_pcb.kernel_state.pcb_pc = (u_int)proc_trampoline;
+}
+
+/*
+ * cpu_exit is called as the last action during exit.
+ * We release the address space and machine-dependent resources,
+ * including the memory for the user structure and kernel stack.
+ * Once finished, we call switch_exit, which switches to a temporary
+ * pcb and stack and never returns. We block memory allocation
+ * until switch_exit has made things safe again.
+ */
+void
+cpu_exit(struct proc *p)
+{
+ pmap_deactivate(p);
+
+ splhigh();
+
+ uvmexp.swtch++;
+ switch_exit(p);
+ /* NOTREACHED */
+}
+
+/*
+ * Dump the machine specific header information at the start of a core dump.
+ */
+int
+cpu_coredump(p, vp, cred, chdr)
+ struct proc *p;
+ struct vnode *vp;
+ struct ucred *cred;
+ struct core *chdr;
+{
+ struct reg reg;
+ struct coreseg cseg;
+ int error;
+
+ CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0);
+ chdr->c_hdrsize = ALIGN(sizeof(*chdr));
+ chdr->c_seghdrsize = ALIGN(sizeof(cseg));
+ chdr->c_cpusize = sizeof(reg);
+
+ /* Save registers. */
+ error = process_read_regs(p, &reg);
+ if (error)
+ return error;
+
+ CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU);
+ cseg.c_addr = 0;
+ cseg.c_size = chdr->c_cpusize;
+
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
+ (off_t)chdr->c_hdrsize, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred,
+ NULL, p);
+ if (error)
+ return error;
+
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&reg, sizeof(reg),
+ (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
+ IO_NODELOCKED|IO_UNIT, cred, NULL, p);
+ if (error)
+ return error;
+
+ chdr->c_nseg++;
+ return 0;
+}
+
+/*
+ * Finish a swapin operation.
+ * We neded to update the cached PTEs for the user area in the
+ * machine dependent part of the proc structure.
+ */
+
+void
+cpu_swapin(struct proc *p)
+{
+ extern void save_u_area(struct proc *, vaddr_t);
+
+ save_u_area(p, (vaddr_t)p->p_addr);
+}
+
+/*
+ * Map an IO request into kernel virtual address space. Requests fall into
+ * one of five catagories:
+ *
+ * B_PHYS|B_UAREA: User u-area swap.
+ * Address is relative to start of u-area (p_addr).
+ * B_PHYS|B_PAGET: User page table swap.
+ * Address is a kernel VA in usrpt (Usrptmap).
+ * B_PHYS|B_DIRTY: Dirty page push.
+ * Address is a VA in proc2's address space.
+ * B_PHYS|B_PGIN: Kernel pagein of user pages.
+ * Address is VA in user's address space.
+ * B_PHYS: User "raw" IO request.
+ * Address is VA in user's address space.
+ *
+ * All requests are (re)mapped into kernel VA space via phys_map
+ *
+ * XXX we allocate KVA space by using kmem_alloc_wait which we know
+ * allocates space without backing physical memory. This implementation
+ * is a total crock, the multiple mappings of these physical pages should
+ * be reflected in the higher-level VM structures to avoid problems.
+ */
+void
+vmapbuf(bp, len)
+ struct buf *bp;
+ vsize_t len;
+{
+ caddr_t addr;
+ vaddr_t kva, off;
+ paddr_t pa;
+ struct pmap *pmap;
+
+#ifdef DIAGNOSTIC
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vmapbuf");
+#endif
+
+ addr = (caddr_t)trunc_page((vaddr_t)(bp->b_saveaddr = bp->b_data));
+ off = (vaddr_t)bp->b_saveaddr & PGOFSET;
+ len = round_page(off + len);
+ pmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
+
+ /*
+ * You may ask: Why phys_map? kernel_map should be OK - after all,
+ * we are mapping user va to kernel va or remapping some
+ * kernel va to another kernel va. The answer is TLB flushing
+ * when the address gets a new mapping.
+ */
+
+ kva = uvm_km_valloc_wait(phys_map, len);
+
+ /*
+ * Flush the TLB for the range [kva, kva + off]. Strictly speaking,
+ * we should do this in vunmapbuf(), but we do it lazily here, when
+ * new pages get mapped in.
+ */
+
+ cmmu_flush_tlb(cpu_number(), 1, kva, len);
+
+ bp->b_data = (caddr_t)(kva + off);
+ while (len > 0) {
+ if (pmap_extract(pmap, (vaddr_t)addr, &pa) == FALSE)
+ panic("vmapbuf: null page frame");
+ pmap_enter(vm_map_pmap(phys_map), kva, pa,
+ VM_PROT_READ | VM_PROT_WRITE,
+ VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
+ /* make sure snooping will be possible... */
+ pmap_cache_ctrl(pmap_kernel(), kva, kva + PAGE_SIZE,
+ CACHE_GLOBAL);
+ addr += PAGE_SIZE;
+ kva += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+}
+
+/*
+ * Free the io map PTEs associated with this IO operation.
+ * We also restore the original b_addr.
+ */
+void
+vunmapbuf(bp, len)
+ struct buf *bp;
+ vsize_t len;
+{
+ vaddr_t addr, off;
+
+#ifdef DIAGNOSTIC
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+#endif
+
+ addr = trunc_page((vaddr_t)bp->b_data);
+ off = (vaddr_t)bp->b_data & PGOFSET;
+ len = round_page(off + len);
+ uvm_km_free_wakeup(phys_map, addr, len);
+ bp->b_data = bp->b_saveaddr;
+ bp->b_saveaddr = 0;
+}
+
+
+/*
+ * Map a range [pa, pa+len] in the given map to a kernel address
+ * in iomap space.
+ *
+ * Note: To be flexible, I did not put a restriction on the alignment
+ * of pa. However, it is advisable to have pa page aligned since otherwise,
+ * we might have several mappings for a given chunk of the IO page.
+ */
+vaddr_t
+iomap_mapin(paddr_t pa, psize_t len, boolean_t canwait)
+{
+ vaddr_t iova, tva, off;
+ paddr_t ppa;
+ int s, error;
+
+ if (len == 0)
+ return NULL;
+
+ ppa = pa;
+ off = (u_long)ppa & PGOFSET;
+
+ len = round_page(off + len);
+
+ s = splhigh();
+ error = extent_alloc(iomap_extent, len, PAGE_SIZE, 0, EX_NOBOUNDARY,
+ canwait ? EX_WAITSPACE : EX_NOWAIT, &iova);
+ splx(s);
+
+ if (error != 0)
+ return NULL;
+
+ cmmu_flush_tlb(cpu_number(), 1, iova, len); /* necessary? */
+
+ ppa = trunc_page(ppa);
+
+#ifndef NEW_MAPPING
+ tva = iova;
+#else
+ tva = ppa;
+#endif
+
+ while (len>0) {
+ pmap_enter(vm_map_pmap(iomap_map), tva, ppa,
+ VM_PROT_WRITE | VM_PROT_READ,
+ VM_PROT_WRITE | VM_PROT_READ | PMAP_WIRED);
+ len -= PAGE_SIZE;
+ tva += PAGE_SIZE;
+ ppa += PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+#ifndef NEW_MAPPING
+ return (iova + off);
+#else
+ return (pa + off);
+#endif
+
+}
+
+/*
+ * Free up the mapping in iomap.
+ */
+void
+iomap_mapout(vaddr_t kva, vsize_t len)
+{
+ vaddr_t off;
+ int s, error;
+
+ off = kva & PGOFSET;
+ kva = trunc_page(kva);
+ len = round_page(off + len);
+
+ pmap_remove(vm_map_pmap(iomap_map), kva, kva + len);
+ pmap_update(vm_map_pmap(iomap_map));
+
+ s = splhigh();
+ error = extent_free(iomap_extent, kva, len, EX_NOWAIT);
+ splx(s);
+
+ if (error != 0)
+ printf("iomap_mapout: extent_free failed\n");
+}
+
+/*
+ * Allocate/deallocate a cache-inhibited range of kernel virtual address
+ * space mapping the indicated physical address range [pa - pa+size)
+ */
+void *
+mapiodev(pa, size)
+ void *pa;
+ int size;
+{
+ paddr_t ppa;
+ ppa = (paddr_t)pa;
+ return ((void *)iomap_mapin(ppa, size, 0));
+}
+
+void
+unmapiodev(kva, size)
+ void *kva;
+ int size;
+{
+ vaddr_t va;
+ va = (vaddr_t)kva;
+ iomap_mapout(va, size);
+}
+
+int
+badvaddr(vaddr_t va, int size)
+{
+ volatile int x;
+
+ if (badaddr(va, size)) {
+ return -1;
+ }
+
+ switch (size) {
+ case 1:
+ x = *(unsigned char *volatile)va;
+ break;
+ case 2:
+ x = *(unsigned short *volatile)va;
+ break;
+ case 4:
+ x = *(unsigned long *volatile)va;
+ break;
+ default:
+ return -1;
+ }
+ return (0);
+}
+
+/*
+ * Move pages from one kernel virtual address to another.
+ */
+void
+pagemove(from, to, size)
+ caddr_t from, to;
+ size_t size;
+{
+ paddr_t pa;
+ boolean_t rv;
+
+#ifdef DEBUG
+ if ((size & PAGE_MASK) != 0)
+ panic("pagemove");
+#endif
+ while (size > 0) {
+ rv = pmap_extract(pmap_kernel(), (vaddr_t)from, &pa);
+#ifdef DEBUG
+ if (rv == FALSE)
+ panic("pagemove 2");
+ if (pmap_extract(pmap_kernel(), (vaddr_t)to, NULL) == TRUE)
+ panic("pagemove 3");
+#endif
+ pmap_kremove((vaddr_t)from, PAGE_SIZE);
+ pmap_kenter_pa((vaddr_t)to, pa, VM_PROT_READ|VM_PROT_WRITE);
+ from += PAGE_SIZE;
+ to += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+}
+
+u_int
+kvtop(va)
+ vaddr_t va;
+{
+ paddr_t pa;
+
+ pmap_extract(pmap_kernel(), va, &pa);
+ /* XXX check for failure */
+ return ((u_int)pa);
+}