diff options
author | Per Fogelstrom <pefo@cvs.openbsd.org> | 1997-02-06 16:02:48 +0000 |
---|---|---|
committer | Per Fogelstrom <pefo@cvs.openbsd.org> | 1997-02-06 16:02:48 +0000 |
commit | 8a091f472ca262aca4d0e922a0e313259359681d (patch) | |
tree | b4d26db683b405c63989ccecc3840da916abe1d4 | |
parent | e9cbad18615f2e1fe42a5075063877f29370c0f8 (diff) |
Import of WGRISC port. (Willowglen R3081 board)
94 files changed, 29974 insertions, 0 deletions
diff --git a/sys/arch/wgrisc/Makefile b/sys/arch/wgrisc/Makefile new file mode 100644 index 00000000000..79473e5afc1 --- /dev/null +++ b/sys/arch/wgrisc/Makefile @@ -0,0 +1,28 @@ +# from: @(#)Makefile 8.1 (Berkeley) 6/16/93 +# $Id: Makefile,v 1.1 1997/02/06 16:02:41 pefo Exp $ + +# Makefile for pica links, tags file + +.include "../../kern/Make.tags.inc" + +all: + @echo "make links or tags only" + +DIRS= conf dev dist include pica + +links:: + -for i in ${DIRS}; do \ + (cd $$i && { rm -f tags; ln -s ${SYSTAGS} tags; }) done + +PICA= /sys/pica/dev/*.[ch] /sys/pica/include/*.[ch] \ + /sys/pica/pica/*.[ch] /sys/pica/ultrix/*.[ch] +APICA= /sys/pica/pica/*.s + +tags:: + -ctags -wdtif ${COMM} ${PICA} + egrep "^LEAF(.*)|^[AN]LEAF(.*)|^NON_LEAF(.*)" ${APICA} | \ + sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \ + >> tags + sort -o tags tags + +.include <bsd.prog.mk> diff --git a/sys/arch/wgrisc/compile/.cvsignore b/sys/arch/wgrisc/compile/.cvsignore new file mode 100644 index 00000000000..db5b0e04a3a --- /dev/null +++ b/sys/arch/wgrisc/compile/.cvsignore @@ -0,0 +1 @@ +GENERIC diff --git a/sys/arch/wgrisc/compile/.keep_me b/sys/arch/wgrisc/compile/.keep_me new file mode 100644 index 00000000000..75270197a54 --- /dev/null +++ b/sys/arch/wgrisc/compile/.keep_me @@ -0,0 +1 @@ +This file must remain so that 'cvs checkout' makes the compile directory. diff --git a/sys/arch/wgrisc/conf/DISKLESS b/sys/arch/wgrisc/conf/DISKLESS new file mode 100644 index 00000000000..744607c9c24 --- /dev/null +++ b/sys/arch/wgrisc/conf/DISKLESS @@ -0,0 +1,77 @@ +# +# Generic configuration file for MIPS R4400 PICA system +# + +machine riscpc + +maxusers 8 + +# does not really do anything anymore, but this replaces "ident GENERIC" +#options GENERIC + +# Need to set locally +options TIMEZONE="8*60" # minutes west of GMT (for) +options DST=1 # use daylight savings rules + +# Standard system options +options SWAPPAGER # swap pager (anonymous and swap space) +options VNODEPAGER # vnode pager (mapped files) +options DEVPAGER # device pager (mapped devices) +options DIAGNOSTIC # extra kernel debugging checks +options DEBUG # extra kernel debugging support +options "COMPAT_43" # compatibility with 4.3BSD binaries +#options KTRACE # system call tracing support +options "NKMEMCLUSTERS=1024" # 4K pages in kernel malloc pool +#options KGDB # support for kernel gdb +#options "KGDBRATE=19200" # kernel gdb port rate (default 9600) +#options "KGDBDEV=15*256+0" # device for kernel gdb + +# System V options +options SYSVMSG # System V-like message queues +options SYSVSEM # System V-like semaphores +options SYSVSHM # System V-like memory sharing +options SHMMAXPGS=1024 # 1024 pages is the default +options NATIVE_ELF + +# Filesystem options +options FIFO # POSIX fifo support (in all filesystems) +options FFS,QUOTA # fast filesystem with user and group quotas +options MFS # memory-based filesystem +options NFSCLIENT # Sun NFS-compatible filesystem (client) +options NFSSERVER # Sun NFS-compatible filesystem (server) +options KERNFS # kernel data-structure filesystem +#options MSDOSFS # Ability to read write MS-Dos filsystem +#options CD9660 # ISO 9660 + Rock Ridge file system +options FDESC # user file descriptor filesystem +#options UMAPFS # uid/gid remapping filesystem +#options NULLFS # null layer filesystem +#options LFS # Log-based filesystem (still experimental) +#options PORTAL # portal filesystem (still experimental) + +# Networking options +options INET # Internet protocols +options "TCP_COMPAT_42" # compatibility with 4.2BSD TCP/IP +options GATEWAY # IP packet forwarding +#options MULTICAST # Multicast support +#options MROUTING # Multicast routing support +#options ISO # OSI networking +#options TPIP +#options EON + +config bsd root on nfs swap on nfs + +mainbus0 at root +cpu* at mainbus0 + +pica* at mainbus0 +clock0 at pica? +com0 at pica? +com1 at pica? +sn0 at pica? + +pseudo-device sl 2 # serial-line IP ports +pseudo-device ppp 2 # serial-line PPP ports +pseudo-device pty 64 # pseudo ptys +pseudo-device bpfilter 16 # packet filter ports +pseudo-device loop +pseudo-device vnd 4 # virtual disk diff --git a/sys/arch/wgrisc/conf/GENERIC b/sys/arch/wgrisc/conf/GENERIC new file mode 100644 index 00000000000..ca3772e008b --- /dev/null +++ b/sys/arch/wgrisc/conf/GENERIC @@ -0,0 +1,124 @@ +# $OpenBSD: GENERIC,v 1.1 1997/02/06 16:02:45 pefo Exp $ +# +# Generic configuration file for Willowglen RISC-PC 9100 +# + +machine wgrisc + +maxusers 8 + +# Need to set locally +options TIMEZONE=0 # minutes west of GMT (for) +options DST=0 # use daylight savings rules + +# Standard system options +options SWAPPAGER # swap pager (anonymous and swap space) +options DEVPAGER # device pager (mapped devices) + +options DIAGNOSTIC # extra kernel debugging checks +options KTRACE # system call tracing support +options DEBUG # extra kernel debugging support +options COMPAT_43 # compatibility with 4.3BSD binaries + +# System V options +#options SYSVMSG # System V-like message queues +#options SYSVSEM # System V-like semaphores +#options SYSVSHM # System V-like memory sharing +options SHMMAXPGS=1024 # 1024 pages is the default +options NATIVE_ELF # Arc systems uses ELF as native format + +# Filesystem options +#options CD9660 # ISO 9660 + Rock Ridge file system +#options FDESC # user file descriptor filesystem (/dev/fd) +options FIFO # POSIX fifo support (in all filesystems) +options FFS,QUOTA # fast filesystem with user and group quotas +#options KERNFS # kernel data-structure filesystem +#options LFS # Log-based filesystem (still experimental) +#options MFS # memory-based filesystem +#options MSDOSFS # Ability to read write MS-Dos filsystem +options NFSCLIENT # Sun NFS-compatible filesystem (client) +#options NFSSERVER # Sun NFS-compatible filesystem (server) +#options NULLFS # null layer filesystem +#options PORTAL # portal filesystem (still experimental) +#options PROCFS # /proc +#options UMAPFS # uid/gid remapping filesystem +#options UNION # union file system + + +# Networking options +#options GATEWAY # IP packet forwarding +options INET # Internet protocols +#options NS # XNS +#options IPX # IPX+SPX +#options ISO,TPIP # OSI networking +#options EON # OSI tunneling over IP +#options CCITT,LLC,HDLC # X.25 +#options IPFILTER # IP packet filter for security + +#options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP +#options MULTICAST # Multicast support +#options MROUTING # Multicast routing support + +# Special options +options MACHINE_NONCONTIG # Support noncontigous memory. +options CONADDR=0xae400000 # serial console I/O address. + +# Specify storage configuration (its a joke..) +config bsd swap generic + +# +# Definition of system +# +mainbus0 at root +cpu* at mainbus0 + +riscbus* at mainbus0 +isabr* at mainbus0 + +clock0 at riscbus? +com0 at riscbus? +com1 at riscbus? +com2 at riscbus? +com3 at riscbus? +#sn0 at riscbus? + +asc0 at riscbus? +scsibus* at asc? + +# +# ISA Bus. +# + +isa* at isabr? + +com4 at isa? port 0x3e8 irq 4 +com5 at isa? port 0x2e8 irq 3 + +ep0 at isa? port ? irq ? # 3C509 ethernet cards +#ed0 at isa? port 0x280 iomem 0xd0000 irq 9 # WD/SMC, 3C503, and NE[12]000 +#ed1 at isa? port 0x250 iomem 0xd8000 irq 9 # ethernet cards +#ed2 at isa? port 0x300 iomem 0xcc000 irq 10 # + +# +# SCSI Bus 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 ? + +# +pseudo-device loop 1 # network loopback +pseudo-device bpfilter 8 # packet filter ports +#pseudo-device sl 2 # serial-line IP ports +#pseudo-device ppp 2 # serial-line PPP ports +#pseudo-device tun 2 # network tunneling over tty + +pseudo-device pty 64 # pseudo ptys +pseudo-device tb 1 # tablet line discipline +pseudo-device vnd 4 # paging to files +#pseudo-device ccd 4 # concatenated disk devices + diff --git a/sys/arch/wgrisc/conf/Makefile.wgrisc b/sys/arch/wgrisc/conf/Makefile.wgrisc new file mode 100644 index 00000000000..ba4cb657c57 --- /dev/null +++ b/sys/arch/wgrisc/conf/Makefile.wgrisc @@ -0,0 +1,183 @@ +# $OpenBSD: Makefile.wgrisc,v 1.1 1997/02/06 16:02:45 pefo Exp $ + +# @(#)Makefile.wgrisc 8.2 (Berkeley) 2/16/94 +# +# Makefile for 4.4 BSD +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/arch/MACHINE/conf/``machineid'' +# after which you should do +# config machineid +# Machine generic makefile changes should be made in +# /sys/arch/MACHINE/conf/Makefile.``machinetype'' +# 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). +AS?= as +CC?= cc +CPP?= cpp +LD?= ld +STRIP?= strip -d +TOUCH?= touch -f -c + +# source tree is located via $S relative to the compilation directory +S= ../../../.. +WGRISC= ../.. + +INCLUDES= -I. -I$S/arch -I$S +CPPFLAGS= ${INCLUDES} ${IDENT} -D_KERNEL -Dwgrisc +CFLAGS= ${DEBUG} -O2 -Werror -mno-abicalls -mips1 -mcpu=r3000 +AFLAGS= -x assembler-with-cpp -traditional-cpp -D_LOCORE + +### 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. + +USRLAND_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +USRLAND_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +NORMAL_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +DRIVER_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +DRIVER_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $< +NORMAL_S_C= ${AS} ${COPTS} ${PARAM} $< -o $@ + +%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} + +SYSTEM_OBJ= locore.o fp.o ${OBJS} param.o ioconf.o ${LIBKERN} \ + ${LIBCOMPAT} +# +SYSTEM_DEP= Makefile ${SYSTEM_OBJ} +SYSTEM_LD_HEAD= rm -f $@ +SYSTEM_LD= -@if [ X${DEBUG} = X-g ]; \ + then strip=-X; \ + else strip=-x; \ + fi; \ + echo ${LD} $$strip -o $@ -e start -T ../../conf/ld.script \ + '$${SYSTEM_OBJ}' vers.o; \ + ${LD} $$strip -o $@ -e start -T ../../conf/ld.script \ + ${SYSTEM_OBJ} vers.o +# +SYSTEM_LD_TAIL= chmod 755 $@; \ + elf2ecoff $@ $@.ecoff; \ + size $@ + +%LOAD + +newvers: + sh $S/conf/newvers.sh + ${CC} $(CFLAGS) -c vers.c + +clean:: + rm -f eddep bsd bsd.gdb bsd.ecoff tags *.o locore.i [a-z]*.s \ + Errs errs linterrs makelinks genassym + +lint: /tmp param.c + @lint -hbxn -DGENERIC -Dvolatile= ${COPTS} ${PARAM} -UKGDB \ + ${WGRISC}/wgrisc/Locore.c ${CFILES} \ + ioconf.c param.c + +symbols.sort: ${WGRISC}/wgrisc/symbols.raw + grep -v '^#' ${WGRISC}/wgrisc/symbols.raw \ + | sed 's/^ //' | sort -u > symbols.sort + +locore.o: ${WGRISC}/wgrisc/locore.S ${WGRISC}/include/asm.h \ + ${WGRISC}/include/cpu.h ${WGRISC}/include/reg.h assym.h + ${NORMAL_S} -mips1 ${WGRISC}/wgrisc/locore.S + +fp.o: ${WGRISC}/wgrisc/fp.S ${WGRISC}/include/asm.h \ + ${WGRISC}/include/cpu.h ${WGRISC}/include/reg.h assym.h + ${NORMAL_S} -mips1 ${WGRISC}/wgrisc/fp.S + +# the following are necessary because the files depend on the types of +# cpu's included in the system configuration +clock.o machdep.o autoconf.o conf.o: Makefile + +# depend on network 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 + +assym.h: genassym + ./genassym >assym.h + +genassym: genassym.o + ${HOSTCC} -o $@ genassym.o + +genassym.o: ${WGRISC}/wgrisc/genassym.c + ${HOSTCC} ${INCLUDES} ${IDENT} -D_KERNEL -Dwgrisc -c $< + +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 + +tags: + @echo "see $S/kern/Makefile for tags" + +ioconf.o: ioconf.c + ${NORMAL_C} + +param.c: $S/conf/param.c + rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${NORMAL_C_C} + +newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP} + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c + +depend:: .depend +.depend: ${SRCS} assym.h param.c + mkdep ${AFLAGS} ${CPPFLAGS} ${WGRISC}/wgrisc/locore.s + mkdep -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES} + mkdep -a ${AFLAGS} ${CPPFLAGS} ${SFILES} + mkdep -a ${CFLAGS} ${CPPFLAGS} ${PARAM} ${WGRISC}/wgrisc/genassym.c + +%RULES + diff --git a/sys/arch/wgrisc/conf/files.wgrisc b/sys/arch/wgrisc/conf/files.wgrisc new file mode 100644 index 00000000000..ad6fed82a90 --- /dev/null +++ b/sys/arch/wgrisc/conf/files.wgrisc @@ -0,0 +1,106 @@ +# $OpenBSD: files.wgrisc,v 1.1 1997/02/06 16:02:45 pefo Exp $ +# +# maxpartitions must be first item in files.${ARCH} +# +maxpartitions 8 + +maxusers 2 8 64 + +# Required files + + +file arch/wgrisc/wgrisc/autoconf.c +file arch/wgrisc/wgrisc/conf.c +file arch/wgrisc/wgrisc/cpu_exec.c +file arch/wgrisc/wgrisc/disksubr.c +file arch/wgrisc/wgrisc/machdep.c +file arch/wgrisc/wgrisc/minidebug.c +file arch/wgrisc/wgrisc/mem.c +file arch/wgrisc/wgrisc/pmap.c +file arch/wgrisc/wgrisc/process_machdep.c +file arch/wgrisc/wgrisc/sys_machdep.c +file arch/wgrisc/wgrisc/trap.c +file arch/wgrisc/wgrisc/vm_machdep.c + +# +# Machine-independent ATAPI drivers +# + +include "../../../dev/atapi/files.atapi" + + +# +# System BUS types +# + +define mainbus {} +device mainbus +attach mainbus at root +file arch/wgrisc/wgrisc/mainbus.c mainbus + +# Our CPU configurator +device cpu +attach cpu at mainbus # not optional +file arch/wgrisc/wgrisc/cpu.c cpu + +# +# LOCALBUS bus autoconfiguration devices +# +device riscbus {} +attach riscbus at mainbus # { slot = -1, offset = -1 } +file arch/wgrisc/riscbus/riscbus.c riscbus + +# Real time clock, must have one.. +device clock +attach clock at riscbus +file arch/wgrisc/wgrisc/clock.c clock +file arch/wgrisc/wgrisc/clock_dp.c clock + +# Ethernet chip +device sn +attach sn at riscbus: ifnet, ether +file arch/wgrisc/dev/if_sn.c sn needs-count + +# Use machine independent SCSI driver routines +include "../../../scsi/files.scsi" +major {sd = 0} +major {cd = 3} + +# Machine dependent SCSI interface driver +device asc: scsi +attach asc at riscbus +file arch/wgrisc/dev/asc.c asc needs-count + +# +# ISA +# +device isabr {} : isabus +attach isabr at mainbus +file arch/wgrisc/isa/isabus.c isabr + +# +# Stock isa bus support +# +define pcmcia {} # XXX dummy decl... + +include "../../../dev/isa/files.isa" + +# National Semiconductor DS8390/WD83C690-based boards +# (WD/SMC 80x3 family, SMC Ultra [8216], 3Com 3C503, NE[12]000, and clones) +# XXX conflicts with other ports; can't be in files.isa +device ed: ether, ifnet +attach ed at isa with ed_isa +attach ed at pcmcia with ed_pcmcia +file dev/isa/if_ed.c ed & (ed_isa | ed_pcmcia) needs-flag + +# 8250/16[45]50-based "com" ports +attach com at riscbus with com_risc +file arch/wgrisc/dev/com_risc.c com_risc + +# + +file dev/cons.c +file dev/cninit.c +file netinet/in_cksum.c +file netns/ns_cksum.c ns + diff --git a/sys/arch/wgrisc/conf/ld.script b/sys/arch/wgrisc/conf/ld.script new file mode 100644 index 00000000000..3c59f13f80b --- /dev/null +++ b/sys/arch/wgrisc/conf/ld.script @@ -0,0 +1,74 @@ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x80100000 + SIZEOF_HEADERS; + .text : + { + _ftext = . ; + *(.text) + *(.rodata) + *(.rodata1) + *(.reginfo) + *(.init) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0 + .data : + { + _fdata = . ; + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + _gp = ALIGN(16) + 0x7ff0; + .got : + { + *(.got.plt) *(.got) + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff --git a/sys/arch/wgrisc/dev/ace.c b/sys/arch/wgrisc/dev/ace.c new file mode 100644 index 00000000000..d577033f2c7 --- /dev/null +++ b/sys/arch/wgrisc/dev/ace.c @@ -0,0 +1,1653 @@ +/* $OpenBSD: ace.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995, 1996 + * Charles M. Hannum. All rights reserved. + * 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. 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. + * + * @(#)com.c 7.5 (Berkeley) 5/16/91 + */ + +/* + * ACE driver, based on HP dca driver + * uses National Semiconductor NS16450/NS16550AF UART + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/types.h> +#include <sys/device.h> + +#include <wgrisc/wgrisc/wgrisctype.h> +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/isa/isavar.h> +#include <dev/ic/comreg.h> +#include <dev/ic/comvar.h> +#include <dev/ic/ns16550reg.h> +#ifdef COM_HAYESP +#include <dev/ic/hayespreg.h> +#endif +#define com_lcr com_cfcr + +#include "ace.h" + + +#define COM_IBUFSIZE (2 * 512) +#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4) + +struct com_softc { + struct device sc_dev; + void *sc_ih; + bus_chipset_tag_t sc_bc; + struct tty *sc_tty; + + int sc_overflows; + int sc_floods; + int sc_errors; + + int sc_halt; + + int sc_iobase; +#ifdef COM_HAYESP + int sc_hayespbase; +#endif + + bus_io_handle_t sc_ioh; + bus_io_handle_t sc_hayespioh; + + u_char sc_hwflags; +#define COM_HW_NOIEN 0x01 +#define COM_HW_FIFO 0x02 +#define COM_HW_HAYESP 0x04 +#define COM_HW_ABSENT_PENDING 0x08 /* reattached, awaiting close/reopen */ +#define COM_HW_ABSENT 0x10 /* configure actually failed, or removed */ +#define COM_HW_REATTACH 0x20 /* reattaching */ +#define COM_HW_CONSOLE 0x40 + u_char sc_swflags; +#define COM_SW_SOFTCAR 0x01 +#define COM_SW_CLOCAL 0x02 +#define COM_SW_CRTSCTS 0x04 +#define COM_SW_MDMBUF 0x08 + u_char sc_msr, sc_mcr, sc_lcr, sc_ier; + u_char sc_dtr; + + u_char sc_cua; + + u_char sc_initialize; /* force initialization */ + + u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; + u_char sc_ibufs[2][COM_IBUFSIZE]; +}; + +#ifdef COM_HAYESP +int comprobeHAYESP __P((bus_io_handle_t hayespioh, struct com_softc *sc)); +#endif +void comdiag __P((void *)); +int comspeed __P((long)); +int comparam __P((struct tty *, struct termios *)); +void comstart __P((struct tty *)); +void compoll __P((void *)); + +/* XXX: These belong elsewhere */ +cdev_decl(com); +bdev_decl(com); + +struct consdev; +void acecnprobe __P((struct consdev *)); +void acecninit __P((struct consdev *)); +int acecngetc __P((dev_t)); +void acecnputc __P((dev_t, int)); +void acecnpollc __P((dev_t, int)); + +static u_char tiocm_xxx2mcr __P((int)); + +/* + * XXX the following two cfattach structs should be different, and possibly + * XXX elsewhere. + */ +int comprobe __P((struct device *, void *, void *)); +void comattach __P((struct device *, struct device *, void *)); +void com_absent_notify __P((struct com_softc *sc)); +void comstart_pending __P((void *)); + +#if NACE_ISA +struct cfattach ace_isa_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif + +#if NACE_COMMULTI +struct cfattach ace_commulti_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif + +#if NACE_RISCBUS +#undef CONADDR /* This is stupid but using devs before config .. */ +#define CONADDR 0xae400000 + +struct cfattach ace_riscbus_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif + + +struct cfdriver ace_cd = { + NULL, "ace", DV_TTY +}; + +void cominit __P((bus_chipset_tag_t, bus_io_handle_t, int)); + +#ifndef CONSPEED +#define CONSPEED B9600 +#endif + +#ifdef COMCONSOLE +int comdefaultrate = CONSPEED; /* XXX why set default? */ +#else +int comdefaultrate = TTYDEF_SPEED; +#endif +int comconsaddr; +int comconsinit; +int comconsattached; +bus_chipset_tag_t comconsbc; +bus_io_handle_t comconsioh; +tcflag_t comconscflag = TTYDEF_CFLAG; + +int commajor; +int comsopen = 0; +int comevents = 0; + +#ifdef KGDB +#include <machine/remote-sl.h> +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + +#define DEVUNIT(x) (minor(x) & 0x7f) +#define DEVCUA(x) (minor(x) & 0x80) + +/* Macros to clear/set/test flags. */ +#define SET(t, f) (t) |= (f) +#define CLR(t, f) (t) &= ~(f) +#define ISSET(t, f) ((t) & (f)) + +/* + * must be called at spltty() or higher. + */ +void +com_absent_notify(sc) + struct com_softc *sc; +{ + struct tty *tp = sc->sc_tty; + + if (tp) { + CLR(tp->t_state, TS_CARR_ON|TS_BUSY); + ttyflush(tp, FREAD|FWRITE); + } +} + +int +comspeed(speed) + long speed; +{ +#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ + + int x, err; + + if (speed == 0) + return 0; + if (speed < 0) + return -1; + x = divrnd((COM_FREQ / 16), speed); + if (x <= 0) + return -1; + err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000; + if (err < 0) + err = -err; + if (err > COM_TOLERANCE) + return -1; + return x; + +#undef divrnd(n, q) +} + +int +comprobe1(bc, ioh, iobase) + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + int iobase; +{ + int i, k; + + /* force access to id reg */ + bus_io_write_1(bc, ioh, com_lcr, 0); + bus_io_write_1(bc, ioh, com_iir, 0); + for (i = 0; i < 32; i++) { + k = bus_io_read_1(bc, ioh, com_iir); + if (k & 0x38) { + bus_io_read_1(bc, ioh, com_data); /* cleanup */ + } else + break; + } + if (i >= 32) + return 0; + + return 1; +} + +#ifdef COM_HAYESP +int +comprobeHAYESP(hayespioh, sc) + bus_io_handle_t hayespioh; + struct com_softc *sc; +{ + char val, dips; + int combaselist[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; + bus_chipset_tag_t bc = sc->sc_bc; + + /* + * Hayes ESP cards have two iobases. One is for compatibility with + * 16550 serial chips, and at the same ISA PC base addresses. The + * other is for ESP-specific enhanced features, and lies at a + * different addressing range entirely (0x140, 0x180, 0x280, or 0x300). + */ + + /* Test for ESP signature */ + if ((bus_io_read_1(bc, hayespioh, 0) & 0xf3) == 0) + return 0; + + /* + * ESP is present at ESP enhanced base address; unknown com port + */ + + /* Get the dip-switch configurations */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_GETDIPS); + dips = bus_io_read_1(bc, hayespioh, HAYESP_STATUS1); + + /* Determine which com port this ESP card services: bits 0,1 of */ + /* dips is the port # (0-3); combaselist[val] is the com_iobase */ + if (sc->sc_iobase != combaselist[dips & 0x03]) + return 0; + + printf(": ESP"); + + /* Check ESP Self Test bits. */ + /* Check for ESP version 2.0: bits 4,5,6 == 010 */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_GETTEST); + val = bus_io_read_1(bc, hayespioh, HAYESP_STATUS1); /* Clear reg 1 */ + val = bus_io_read_1(bc, hayespioh, HAYESP_STATUS2); + if ((val & 0x70) < 0x20) { + printf("-old (%o)", val & 0x70); + /* we do not support the necessary features */ + return 0; + } + + /* Check for ability to emulate 16550: bit 8 == 1 */ + if ((dips & 0x80) == 0) { + printf(" slave"); + /* XXX Does slave really mean no 16550 support?? */ + return 0; + } + + /* + * If we made it this far, we are a full-featured ESP v2.0 (or + * better), at the correct com port address. + */ + + SET(sc->sc_hwflags, COM_HW_HAYESP); + printf(", 1024 byte fifo\n"); + return 1; +} +#endif + +int +comprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + int iobase, needioh; + int rv = 1; + +#if NACE_ISA +#define IS_ISA(parent) \ + (!strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") || \ + !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pcmcia")) +#elif NACE_ISA +#define IS_ISA(parent) \ + !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "isa") +#endif +#if NACE_RISCBUS +#define IS_RISCBUS(parent) \ + !strcmp((parent)->dv_cfdata->cf_driver->cd_name, "riscbus") +#endif + /* + * XXX should be broken out into functions for isa probe and + * XXX for commulti probe, with a helper function that contains + * XXX most of the interesting stuff. + */ +#if NACE_ISA + if (IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + bc = ia->ia_bc; + iobase = ia->ia_iobase; + needioh = 1; + } else +#endif +#if NACE_RISCBUS + if(IS_RISCBUS(parent)) { + struct confargs *ca = aux; + if(!BUS_MATCHNAME(ca, "com")) + return(0); + iobase = (long)BUS_CVTADDR(ca); + bc = 0; + needioh = 1; + } else +#endif +#if NACE_COMMULTI + if (1) { + struct cfdata *cf = match; + struct commulti_attach_args *ca = aux; + + if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ca->ca_slave) + return (0); + + bc = ca->ca_bc; + iobase = ca->ca_iobase; + ioh = ca->ca_ioh; + needioh = 0; + } else +#endif + return(0); /* This cannot happen */ + + /* if it's in use as console, it's there. */ + if (iobase == comconsaddr && !comconsattached) + goto out; + + if (needioh && bus_io_map(bc, iobase, COM_NPORTS, &ioh)) { + rv = 0; + goto out; + } + rv = comprobe1(bc, ioh, iobase); + if (needioh) + bus_io_unmap(bc, ioh, COM_NPORTS); + +out: +#if NACE_ISA + if (rv && IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + ia->ia_iosize = COM_NPORTS; + ia->ia_msize = 0; + } +#endif + return (rv); +} + +void +comattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct com_softc *sc = (void *)self; + int iobase, irq; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; +#ifdef COM_HAYESP + int hayesp_ports[] = { 0x140, 0x180, 0x280, 0x300, 0 }; + int *hayespp; +#endif + + /* + * XXX should be broken out into functions for isa attach and + * XXX for commulti attach, with a helper function that contains + * XXX most of the interesting stuff. + */ + if (ISSET(sc->sc_hwflags, COM_HW_REATTACH)) { + int s; + s = spltty(); + com_absent_notify(sc); + splx(s); + } else + sc->sc_hwflags = 0; + sc->sc_swflags = 0; +#if NACE_ISA + if (IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + /* + * We're living on an isa. + */ + iobase = ia->ia_iobase; + bc = ia->ia_bc; + if (iobase != comconsaddr) { + if (bus_io_map(bc, iobase, COM_NPORTS, &ioh)) + panic("comattach: io mapping failed"); + } else + ioh = comconsioh; + irq = ia->ia_irq; + } else +#endif +#if NACE_RISCBUS + if(IS_RISCBUS(parent)) { + struct confargs *ca = aux; + iobase = (long)BUS_CVTADDR(ca); + bc = 0; + irq = 0; + ioh = iobase; + } else +#endif +#if NACE_COMMULTI + if (1) { + struct commulti_attach_args *ca = aux; + + /* + * We're living on a commulti. + */ + iobase = ca->ca_iobase; + bc = ca->ca_bc; + ioh = ca->ca_ioh; + irq = IRQUNK; + + if (ca->ca_noien) + SET(sc->sc_hwflags, COM_HW_NOIEN); + } else +#endif + panic("comattach: impossible"); + + sc->sc_bc = bc; + sc->sc_ioh = ioh; + sc->sc_iobase = iobase; + + if (iobase == comconsaddr) { + comconsattached = 1; + + /* + * Need to reset baud rate, etc. of next print so reset + * comconsinit. Also make sure console is always "hardwired". + */ + delay(1000); /* wait for output to finish */ + comconsinit = 0; + SET(sc->sc_hwflags, COM_HW_CONSOLE); + SET(sc->sc_swflags, COM_SW_SOFTCAR); + } + +#ifdef COM_HAYESP + /* Look for a Hayes ESP board. */ + for (hayespp = hayesp_ports; *hayespp != 0; hayespp++) { + bus_io_handle_t hayespioh; + +#define HAYESP_NPORTS 8 /* XXX XXX XXX ??? ??? ??? */ + if (bus_io_map(bc, *hayespp, HAYESP_NPORTS, &hayespioh)) + continue; + if (comprobeHAYESP(hayespioh, sc)) { + sc->sc_hayespbase = *hayespp; + sc->sc_hayespioh = hayespioh; + break; + } + bus_io_unmap(bc, hayespioh, HAYESP_NPORTS); + } + /* No ESP; look for other things. */ + if (*hayespp == 0) { +#endif + + /* look for a NS 16550AF UART with FIFOs */ + bus_io_write_1(bc, ioh, com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + delay(100); + if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_FIFO_MASK) == + IIR_FIFO_MASK) + if (ISSET(bus_io_read_1(bc, ioh, com_fifo), FIFO_TRIGGER_14) == + FIFO_TRIGGER_14) { + SET(sc->sc_hwflags, COM_HW_FIFO); + printf(": ns16550a, working fifo\n"); + } else + printf(": ns16550, broken fifo\n"); + else + printf(": ns8250 or ns16450, no fifo\n"); + bus_io_write_1(bc, ioh, com_fifo, 0); +#ifdef COM_HAYESP + } +#endif + + /* disable interrupts */ + bus_io_write_1(bc, ioh, com_ier, 0); + bus_io_write_1(bc, ioh, com_mcr, 0); + + if (irq != IRQUNK) { +#if NACE_ISA + if (IS_ISA(parent)) { + struct isa_attach_args *ia = aux; + + sc->sc_ih = isa_intr_establish(ia->ia_ic, irq, + IST_EDGE, IPL_TTY, comintr, sc, + sc->sc_dev.dv_xname); + } else +#endif +#if NACE_RISCBUS + if (IS_RISCBUS(parent)) { + struct confargs *ca = aux; + BUS_INTR_ESTABLISH(ca, comintr, (void *)(long)sc); + } else +#endif + panic("comattach: IRQ but can't have one"); + } + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + kgdb_dev = -1; /* can't debug over console port */ + else { + cominit(bc, ioh, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("%s: ", sc->sc_dev.dv_xname); + kgdb_connect(1); + } else + printf("%s: kgdb enabled\n", + sc->sc_dev.dv_xname); + } + } +#endif + + /* XXX maybe move up some? */ + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + printf("%s: console\n", sc->sc_dev.dv_xname); +} + +int +aceopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = DEVUNIT(dev); + struct com_softc *sc; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + struct tty *tp; + int s; + int error = 0; + + if (unit >= ace_cd.cd_ndevs) + return ENXIO; + sc = ace_cd.cd_devs[unit]; + if (!sc || ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) + return ENXIO; + + s = spltty(); + if (!sc->sc_tty) { + tp = sc->sc_tty = ttymalloc(); + tty_attach(tp); + } else + tp = sc->sc_tty; + splx(s); + + tp->t_oproc = comstart; + tp->t_param = comparam; + tp->t_dev = dev; + if (!ISSET(tp->t_state, TS_ISOPEN)) { + SET(tp->t_state, TS_WOPEN); + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + tp->t_cflag = comconscflag; + else + tp->t_cflag = TTYDEF_CFLAG; + if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) + SET(tp->t_cflag, CLOCAL); + if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) + SET(tp->t_cflag, CRTSCTS); + if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) + SET(tp->t_cflag, MDMBUF); + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = comdefaultrate; + + s = spltty(); + + sc->sc_initialize = 1; + comparam(tp, &tp->t_termios); + ttsetwater(tp); + + if (comsopen++ == 0) + timeout(compoll, NULL, 1); + + sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; + sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER; + sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE; + + bc = sc->sc_bc; + ioh = sc->sc_ioh; +#ifdef COM_HAYESP + /* Setup the ESP board */ + if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) { + bus_io_handle_t hayespioh = sc->sc_hayespioh; + + bus_io_write_1(bc, ioh, com_fifo, + FIFO_DMA_MODE|FIFO_ENABLE| + FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_8); + + /* Set 16550 compatibility mode */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETMODE); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_MODE_FIFO|HAYESP_MODE_RTS| + HAYESP_MODE_SCALE); + + /* Set RTS/CTS flow control */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETFLOWTYPE); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, HAYESP_FLOW_RTS); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, HAYESP_FLOW_CTS); + + /* Set flow control levels */ + bus_io_write_1(bc, hayespioh, HAYESP_CMD1, HAYESP_SETRXFLOW); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_HIBYTE(HAYESP_RXHIWMARK)); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_LOBYTE(HAYESP_RXHIWMARK)); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_HIBYTE(HAYESP_RXLOWMARK)); + bus_io_write_1(bc, hayespioh, HAYESP_CMD2, + HAYESP_LOBYTE(HAYESP_RXLOWMARK)); + } else +#endif + if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) { + /* + * (Re)enable and drain FIFOs. + * + * Certain SMC chips cause problems if the FIFOs are + * enabled while input is ready. Turn off the FIFO + * if necessary to clear the input. Test the input + * ready bit after enabling the FIFOs to handle races + * between enabling and fresh input. + * + * Set the FIFO threshold based on the receive speed. + */ + for (;;) { + bus_io_write_1(bc, ioh, com_fifo, 0); + delay(100); + (void) bus_io_read_1(bc, ioh, com_data); + bus_io_write_1(bc, ioh, com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | + (tp->t_ispeed <= 1200 ? + FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); + delay(100); + if(!ISSET(bus_io_read_1(bc, ioh, + com_lsr), LSR_RXRDY)) + break; + } + } + + /* flush any pending I/O */ + while (ISSET(bus_io_read_1(bc, ioh, com_lsr), LSR_RXRDY)) + (void) bus_io_read_1(bc, ioh, com_data); + /* you turn me on, baby */ + sc->sc_mcr = MCR_DTR | MCR_RTS; + if (!ISSET(sc->sc_hwflags, COM_HW_NOIEN)) + SET(sc->sc_mcr, MCR_IENABLE); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + sc->sc_ier = IER_ERXRDY | IER_ERLS | IER_EMSC; + bus_io_write_1(bc, ioh, com_ier, sc->sc_ier); + + sc->sc_msr = bus_io_read_1(bc, ioh, com_msr); + if (ISSET(sc->sc_swflags, COM_SW_SOFTCAR) || DEVCUA(dev) || + ISSET(sc->sc_msr, MSR_DCD) || ISSET(tp->t_cflag, MDMBUF)) + SET(tp->t_state, TS_CARR_ON); + else + CLR(tp->t_state, TS_CARR_ON); + } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) + return EBUSY; + else + s = spltty(); + + if (DEVCUA(dev)) { + if (ISSET(tp->t_state, TS_ISOPEN)) { + /* Ah, but someone already is dialed in... */ + splx(s); + return EBUSY; + } + sc->sc_cua = 1; /* We go into CUA mode */ + } + + /* wait for carrier if necessary */ + if (ISSET(flag, O_NONBLOCK)) { + if (!DEVCUA(dev) && sc->sc_cua) { + /* Opening TTY non-blocking... but the CUA is busy */ + splx(s); + return EBUSY; + } + } else { + while (!(DEVCUA(dev) && sc->sc_cua) && + !ISSET(tp->t_cflag, CLOCAL) && + !ISSET(tp->t_state, TS_CARR_ON)) { + SET(tp->t_state, TS_WOPEN); + error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, + ttopen, 0); + if (error) { + /* XXX should turn off chip if we're the + only waiter */ + if (DEVCUA(dev)) + sc->sc_cua = 0; + splx(s); + return error; + } + } + } + splx(s); + + return (*linesw[tp->t_line].l_open)(dev, tp); +} + +int +aceclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = DEVUNIT(dev); + struct com_softc *sc = ace_cd.cd_devs[unit]; + struct tty *tp = sc->sc_tty; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int s; + + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return 0; + + (*linesw[tp->t_line].l_close)(tp, flag); + s = spltty(); + if (!ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + /* can't do any of this stuff .... */ + CLR(sc->sc_lcr, LCR_SBREAK); + bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr); + bus_io_write_1(bc, ioh, com_ier, 0); + if (ISSET(tp->t_cflag, HUPCL) && + !ISSET(sc->sc_swflags, COM_SW_SOFTCAR)) { + /* XXX perhaps only clear DTR */ + bus_io_write_1(bc, ioh, com_mcr, 0); + } + } + CLR(tp->t_state, TS_BUSY | TS_FLUSH); + if (--comsopen == 0) + untimeout(compoll, NULL); + sc->sc_cua = 0; + splx(s); + ttyclose(tp); +#ifdef COM_DEBUG + /* mark it ready for more use if reattached earlier */ + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT_PENDING)) { + printf("aceclose pending cleared\n"); + } +#endif + CLR(sc->sc_hwflags, COM_HW_ABSENT_PENDING); + +#ifdef notyet /* XXXX */ + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { + ttyfree(tp); + sc->sc_tty = 0; + } +#endif + return 0; +} + +int +aceread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +acewrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +struct tty * +acetty(dev) + dev_t dev; +{ + struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return (tp); +} + +static u_char +tiocm_xxx2mcr(data) + int data; +{ + u_char m = 0; + + if (ISSET(data, TIOCM_DTR)) + SET(m, MCR_DTR); + if (ISSET(data, TIOCM_RTS)) + SET(m, MCR_RTS); + return m; +} + +int +aceioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int unit = DEVUNIT(dev); + struct com_softc *sc = ace_cd.cd_devs[unit]; + struct tty *tp = sc->sc_tty; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int error; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + 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; + + switch (cmd) { + case TIOCSBRK: + SET(sc->sc_lcr, LCR_SBREAK); + bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr); + break; + case TIOCCBRK: + CLR(sc->sc_lcr, LCR_SBREAK); + bus_io_write_1(bc, ioh, com_lcr, sc->sc_lcr); + break; + case TIOCSDTR: + SET(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCCDTR: + CLR(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCMSET: + CLR(sc->sc_mcr, MCR_DTR | MCR_RTS); + case TIOCMBIS: + SET(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data)); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCMBIC: + CLR(sc->sc_mcr, tiocm_xxx2mcr(*(int *)data)); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + break; + case TIOCMGET: { + u_char m; + int bits = 0; + + m = sc->sc_mcr; + if (ISSET(m, MCR_DTR)) + SET(bits, TIOCM_DTR); + if (ISSET(m, MCR_RTS)) + SET(bits, TIOCM_RTS); + m = sc->sc_msr; + if (ISSET(m, MSR_DCD)) + SET(bits, TIOCM_CD); + if (ISSET(m, MSR_CTS)) + SET(bits, TIOCM_CTS); + if (ISSET(m, MSR_DSR)) + SET(bits, TIOCM_DSR); + if (ISSET(m, MSR_RI | MSR_TERI)) + SET(bits, TIOCM_RI); + if (bus_io_read_1(bc, ioh, com_ier)) + SET(bits, TIOCM_LE); + *(int *)data = bits; + break; + } + case TIOCGFLAGS: { + int driverbits, userbits = 0; + + driverbits = sc->sc_swflags; + if (ISSET(driverbits, COM_SW_SOFTCAR)) + SET(userbits, TIOCFLAG_SOFTCAR); + if (ISSET(driverbits, COM_SW_CLOCAL)) + SET(userbits, TIOCFLAG_CLOCAL); + if (ISSET(driverbits, COM_SW_CRTSCTS)) + SET(userbits, TIOCFLAG_CRTSCTS); + if (ISSET(driverbits, COM_SW_MDMBUF)) + SET(userbits, TIOCFLAG_MDMBUF); + + *(int *)data = userbits; + break; + } + case TIOCSFLAGS: { + int userbits, driverbits = 0; + + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return(EPERM); + + userbits = *(int *)data; + if (ISSET(userbits, TIOCFLAG_SOFTCAR) || + ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + SET(driverbits, COM_SW_SOFTCAR); + if (ISSET(userbits, TIOCFLAG_CLOCAL)) + SET(driverbits, COM_SW_CLOCAL); + if (ISSET(userbits, TIOCFLAG_CRTSCTS)) + SET(driverbits, COM_SW_CRTSCTS); + if (ISSET(userbits, TIOCFLAG_MDMBUF)) + SET(driverbits, COM_SW_MDMBUF); + + sc->sc_swflags = driverbits; + break; + } + default: + return ENOTTY; + } + + return 0; +} + +int +comparam(tp, t) + struct tty *tp; + struct termios *t; +{ + struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(tp->t_dev)]; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int ospeed = comspeed(t->c_ospeed); + u_char lcr; + tcflag_t oldcflag; + int s; + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + int s = spltty(); + com_absent_notify(sc); + splx(s); + return EIO; + } + + /* check requested parameters */ + if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) + return EINVAL; + + lcr = ISSET(sc->sc_lcr, LCR_SBREAK); + + switch (ISSET(t->c_cflag, CSIZE)) { + case CS5: + SET(lcr, LCR_5BITS); + break; + case CS6: + SET(lcr, LCR_6BITS); + break; + case CS7: + SET(lcr, LCR_7BITS); + break; + case CS8: + SET(lcr, LCR_8BITS); + break; + } + if (ISSET(t->c_cflag, PARENB)) { + SET(lcr, LCR_PENAB); + if (!ISSET(t->c_cflag, PARODD)) + SET(lcr, LCR_PEVEN); + } + if (ISSET(t->c_cflag, CSTOPB)) + SET(lcr, LCR_STOPB); + + sc->sc_lcr = lcr; + + s = spltty(); + + if (ospeed == 0) { + CLR(sc->sc_mcr, MCR_DTR); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + + /* + * Set the FIFO threshold based on the receive speed, if we are + * changing it. + */ + if (sc->sc_initialize || (tp->t_ispeed != t->c_ispeed)) { + sc->sc_initialize = 0; + + if (ospeed != 0) { + /* + * Make sure the transmit FIFO is empty before + * proceeding. If we don't do this, some revisions + * of the UART will hang. Interestingly enough, + * even if we do this will the last character is + * still being pushed out, they don't hang. This + * seems good enough. + */ + while (ISSET(tp->t_state, TS_BUSY)) { + int error; + + ++sc->sc_halt; + error = ttysleep(tp, &tp->t_outq, + TTOPRI | PCATCH, "comprm", 0); + --sc->sc_halt; + if (error) { + splx(s); + comstart(tp); + return (error); + } + } + + bus_io_write_1(bc, ioh, com_lcr, lcr | LCR_DLAB); + bus_io_write_1(bc, ioh, com_dlbl, ospeed); + bus_io_write_1(bc, ioh, com_dlbh, ospeed >> 8); + bus_io_write_1(bc, ioh, com_lcr, lcr); + SET(sc->sc_mcr, MCR_DTR); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } else + bus_io_write_1(bc, ioh, com_lcr, lcr); + + if (!ISSET(sc->sc_hwflags, COM_HW_HAYESP) && + ISSET(sc->sc_hwflags, COM_HW_FIFO)) + bus_io_write_1(bc, ioh, com_fifo, + FIFO_ENABLE | + (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); + } else + bus_io_write_1(bc, ioh, com_lcr, lcr); + + /* When not using CRTSCTS, RTS follows DTR. */ + if (!ISSET(t->c_cflag, CRTSCTS)) { + if (ISSET(sc->sc_mcr, MCR_DTR)) { + if (!ISSET(sc->sc_mcr, MCR_RTS)) { + SET(sc->sc_mcr, MCR_RTS); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + } else { + if (ISSET(sc->sc_mcr, MCR_RTS)) { + CLR(sc->sc_mcr, MCR_RTS); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + } + sc->sc_dtr = MCR_DTR | MCR_RTS; + } else + sc->sc_dtr = MCR_DTR; + + /* and copy to tty */ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + oldcflag = tp->t_cflag; + tp->t_cflag = t->c_cflag; + + /* + * If DCD is off and MDMBUF is changed, ask the tty layer if we should + * stop the device. + */ + if (!ISSET(sc->sc_msr, MSR_DCD) && + !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) && + ISSET(oldcflag, MDMBUF) != ISSET(tp->t_cflag, MDMBUF) && + (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { + CLR(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + + /* Just to be sure... */ + splx(s); + comstart(tp); + return 0; +} + +void +comstart_pending(arg) + void *arg; +{ + struct com_softc *sc = arg; + int s; + + s = spltty(); + com_absent_notify(sc); + splx(s); +} + +void +comstart(tp) + struct tty *tp; +{ + struct com_softc *sc = ace_cd.cd_devs[DEVUNIT(tp->t_dev)]; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + int s; + + s = spltty(); + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT|COM_HW_ABSENT_PENDING)) { + /* + * not quite good enough: if caller is ttywait() it will + * go to sleep immediately, so hang out a bit and then + * prod caller again. + */ + com_absent_notify(sc); + timeout(comstart_pending, sc, 1); + goto out; + } + if (ISSET(tp->t_state, TS_BUSY)) + goto out; + if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || + sc->sc_halt > 0) + goto stopped; + if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, MSR_CTS)) + goto stopped; + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup(&tp->t_outq); + } + if (tp->t_outq.c_cc == 0) + goto stopped; + selwakeup(&tp->t_wsel); + } + SET(tp->t_state, TS_BUSY); + + if (!ISSET(sc->sc_ier, IER_ETXRDY)) { + SET(sc->sc_ier, IER_ETXRDY); + bus_io_write_1(bc, ioh, com_ier, sc->sc_ier); + } +#ifdef COM_HAYESP + if (ISSET(sc->sc_hwflags, COM_HW_HAYESP)) { + u_char buffer[1024], *cp = buffer; + int n = q_to_b(&tp->t_outq, cp, sizeof buffer); + do + bus_io_write_1(bc, ioh, com_data, *cp++); + while (--n); + } + else +#endif + if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) { + u_char buffer[16], *cp = buffer; + int n = q_to_b(&tp->t_outq, cp, sizeof buffer); + do { + bus_io_write_1(bc, ioh, com_data, *cp++); + } while (--n); + } else + bus_io_write_1(bc, ioh, com_data, getc(&tp->t_outq)); +out: + splx(s); + return; +stopped: + if (ISSET(sc->sc_ier, IER_ETXRDY)) { + CLR(sc->sc_ier, IER_ETXRDY); + bus_io_write_1(bc, ioh, com_ier, sc->sc_ier); + } + splx(s); +} + +/* + * Stop output on a line. + */ +int +acestop(tp, flag) + struct tty *tp; + int flag; +{ + int s; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY)) + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + splx(s); + return 0; +} + +void +comdiag(arg) + void *arg; +{ + struct com_softc *sc = arg; + int overflows, floods; + int s; + + s = spltty(); + sc->sc_errors = 0; + overflows = sc->sc_overflows; + sc->sc_overflows = 0; + floods = sc->sc_floods; + sc->sc_floods = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", + sc->sc_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +void +compoll(arg) + void *arg; +{ + int unit; + struct com_softc *sc; + struct tty *tp; + register u_char *ibufp; + u_char *ibufend; + register int c; + int s; + static int lsrmap[8] = { + 0, TTY_PE, + TTY_FE, TTY_PE|TTY_FE, + TTY_FE, TTY_PE|TTY_FE, + TTY_FE, TTY_PE|TTY_FE + }; + + s = spltty(); + if (comevents == 0) { + splx(s); + goto out; + } + comevents = 0; + splx(s); + + for (unit = 0; unit < ace_cd.cd_ndevs; unit++) { + sc = ace_cd.cd_devs[unit]; + if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf) + continue; + + tp = sc->sc_tty; + + s = spltty(); + + ibufp = sc->sc_ibuf; + ibufend = sc->sc_ibufp; + + if (ibufp == ibufend) { + splx(s); + continue; + } + + sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? + sc->sc_ibufs[1] : sc->sc_ibufs[0]; + sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER; + sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE; + + if (tp == 0 || !ISSET(tp->t_state, TS_ISOPEN)) { + splx(s); + continue; + } + + if (ISSET(tp->t_cflag, CRTSCTS) && + !ISSET(sc->sc_mcr, MCR_RTS)) { + /* XXX */ + SET(sc->sc_mcr, MCR_RTS); + bus_io_write_1(sc->sc_bc, sc->sc_ioh, com_mcr, + sc->sc_mcr); + } + + splx(s); + + while (ibufp < ibufend) { + c = *ibufp++; + if (*ibufp & LSR_OE) { + sc->sc_overflows++; + if (sc->sc_errors++ == 0) + timeout(comdiag, sc, 60 * hz); + } + /* This is ugly, but fast. */ + c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2]; + (*linesw[tp->t_line].l_rint)(c, tp); + } + } + +out: + timeout(compoll, NULL, 1); +} + +int +comintr(arg) + void *arg; +{ + struct com_softc *sc = arg; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh = sc->sc_ioh; + struct tty *tp; + u_char lsr, data, msr, delta; +#ifdef COM_DEBUG + int n; + struct { + u_char iir, lsr, msr; + } iter[32]; +#endif + + if (ISSET(sc->sc_hwflags, COM_HW_ABSENT) || !sc->sc_tty) + return 0; /* can't do squat. */ + +#ifdef COM_DEBUG + n = 0; + if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (0); +#else + if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (0); +#endif + + tp = sc->sc_tty; + + for (;;) { +#ifdef COM_DEBUG + iter[n].lsr = +#endif + lsr = bus_io_read_1(bc, ioh, com_lsr); + + if (ISSET(lsr, LSR_RXRDY)) { + register u_char *p = sc->sc_ibufp; + + comevents = 1; + do { + data = bus_io_read_1(bc, ioh, com_data); + if (ISSET(lsr, LSR_BI)) { +#ifdef notdef + printf("break %02x %02x %02x %02x\n", + sc->sc_msr, sc->sc_mcr, sc->sc_lcr, + sc->sc_dtr); +#endif +#ifdef DDB + if (ISSET(sc->sc_hwflags, + COM_HW_CONSOLE)) { + Debugger(); + goto next; + } +#endif + } + if (p >= sc->sc_ibufend) { + sc->sc_floods++; + if (sc->sc_errors++ == 0) + timeout(comdiag, sc, 60 * hz); + } else { + *p++ = data; + *p++ = lsr; + if (p == sc->sc_ibufhigh && + ISSET(tp->t_cflag, CRTSCTS)) { + /* XXX */ + CLR(sc->sc_mcr, MCR_RTS); + bus_io_write_1(bc, ioh, com_mcr, + sc->sc_mcr); + } + } +#ifdef DDB + next: +#endif +#ifdef COM_DEBUG + if (++n >= 32) + goto ohfudge; + iter[n].lsr = +#endif + lsr = bus_io_read_1(bc, ioh, com_lsr); + } while (ISSET(lsr, LSR_RXRDY)); + + sc->sc_ibufp = p; + } +#ifdef COM_DEBUG + else if (ISSET(lsr, LSR_BI|LSR_FE|LSR_PE|LSR_OE)) + printf("weird lsr %02x\n", lsr); +#endif + +#ifdef COM_DEBUG + iter[n].msr = +#endif + msr = bus_io_read_1(bc, ioh, com_msr); + + if (msr != sc->sc_msr) { + delta = msr ^ sc->sc_msr; + sc->sc_msr = msr; + if (ISSET(delta, MSR_DCD) && + !ISSET(sc->sc_swflags, COM_SW_SOFTCAR) && + (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD)) == 0) { + CLR(sc->sc_mcr, sc->sc_dtr); + bus_io_write_1(bc, ioh, com_mcr, sc->sc_mcr); + } + if (ISSET(delta & msr, MSR_CTS) && + ISSET(tp->t_cflag, CRTSCTS)) { + /* the line is up and we want to do rts/cts flow control */ + (*linesw[tp->t_line].l_start)(tp); + } + } + + if (ISSET(lsr, LSR_TXRDY) && ISSET(tp->t_state, TS_BUSY)) { + CLR(tp->t_state, TS_BUSY | TS_FLUSH); + if (sc->sc_halt > 0) + wakeup(&tp->t_outq); + (*linesw[tp->t_line].l_start)(tp); + } + +#ifdef COM_DEBUG + if (++n >= 32) + goto ohfudge; + if (ISSET(iter[n].iir = bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (1); +#else + if (ISSET(bus_io_read_1(bc, ioh, com_iir), IIR_NOPEND)) + return (1); +#endif + } +#ifdef COM_DEBUG +ohfudge: + printf("comintr: too many iterations"); + for (n = 0; n < 32; n++) { + if ((n % 4) == 0) + printf("\ncomintr: iter[%02d]", n); + printf(" %02x %02x %02x", iter[n].iir, iter[n].lsr, iter[n].msr); + } + printf("\n"); + printf("comintr: msr %02x mcr %02x lcr %02x ier %02x\n", + sc->sc_msr, sc->sc_mcr, sc->sc_lcr, sc->sc_ier); + printf("comintr: state %08x cc %d\n", sc->sc_tty->t_state, + sc->sc_tty->t_outq.c_cc); +#endif +} + +/* + * Following are all routines needed for COM to act as console + */ +#include <dev/cons.h> + +void +acecnprobe(cp) + struct consdev *cp; +{ + /* XXX NEEDS TO BE FIXED XXX */ + extern int cputype; + bus_chipset_tag_t bc = 0; + bus_io_handle_t ioh; + int found; + + cp->cn_pri = CN_DEAD; + + if (bus_io_map(bc, CONADDR, COM_NPORTS, &ioh)) { + cp->cn_pri = CN_DEAD; + return; + } + ioh = CONADDR; + found = comprobe1(bc, ioh, CONADDR); + if (!found) { + return; + } + + /* locate the major number */ + for (commajor = 0; commajor < nchrdev; commajor++) + if (cdevsw[commajor].d_open == aceopen) + break; + + /* initialize required fields */ + cp->cn_dev = makedev(commajor, CONUNIT); +#ifdef COMCONSOLE + cp->cn_pri = CN_REMOTE; /* Force a serial port console */ +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +acecninit(cp) + struct consdev *cp; +{ + +#if 0 + XXX NEEDS TO BE FIXED XXX + comconsbc = ???; +#endif + if (bus_io_map(comconsbc, CONADDR, COM_NPORTS, &comconsioh)) + panic("acecninit: mapping failed"); + + cominit(comconsbc, comconsioh, comdefaultrate); + comconsaddr = CONADDR; + comconsinit = 0; +} + +void +cominit(bc, ioh, rate) + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + int rate; +{ + int s = splhigh(); + u_char stat; + + bus_io_write_1(bc, ioh, com_lcr, LCR_DLAB); + rate = comspeed(comdefaultrate); + bus_io_write_1(bc, ioh, com_dlbl, rate); + bus_io_write_1(bc, ioh, com_dlbh, rate >> 8); + bus_io_write_1(bc, ioh, com_lcr, LCR_8BITS); + bus_io_write_1(bc, ioh, com_ier, IER_ERXRDY | IER_ETXRDY); + bus_io_write_1(bc, ioh, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4); + stat = bus_io_read_1(bc, ioh, com_iir); + splx(s); +} + +int +acecngetc(dev) + dev_t dev; +{ + int s = splhigh(); + bus_chipset_tag_t bc = comconsbc; + bus_io_handle_t ioh = comconsioh; + u_char stat, c; + + while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_RXRDY)) + ; + c = bus_io_read_1(bc, ioh, com_data); + stat = bus_io_read_1(bc, ioh, com_iir); + splx(s); + return c; +} + +/* + * Console kernel output character routine. + */ +void +acecnputc(dev, c) + dev_t dev; + int c; +{ + int s = splhigh(); + bus_chipset_tag_t bc = comconsbc; + bus_io_handle_t ioh = comconsioh; + u_char stat; + register int timo; + +#ifdef KGDB + if (dev != kgdb_dev) +#endif + if (comconsinit == 0) { + cominit(bc, ioh, comdefaultrate); + comconsinit = 1; + } + /* wait for any pending transmission to finish */ + timo = 50000; + while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_TXRDY) && --timo) + ; + bus_io_write_1(bc, ioh, com_data, c); + /* wait for this transmission to complete */ + timo = 1500000; + while (!ISSET(stat = bus_io_read_1(bc, ioh, com_lsr), LSR_TXRDY) && --timo) + ; + /* clear any interrupts generated by this transmission */ + stat = bus_io_read_1(bc, ioh, com_iir); + splx(s); +} + +void +acecnpollc(dev, on) + dev_t dev; + int on; +{ + +} diff --git a/sys/arch/wgrisc/dev/asc.c b/sys/arch/wgrisc/dev/asc.c new file mode 100644 index 00000000000..13785ab9c0f --- /dev/null +++ b/sys/arch/wgrisc/dev/asc.c @@ -0,0 +1,2096 @@ +/* $OpenBSD: asc.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* $NetBSD: asc.c,v 1.10 1994/12/05 19:11:12 dean Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * @(#)asc.c 8.3 (Berkeley) 7/3/94 + */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 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 + * 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 the + * rights to redistribute these changes. + */ + +/* + * HISTORY + * Log: scsi_53C94_hdw.c,v + * Revision 2.5 91/02/05 17:45:07 mrt + * Added author notices + * [91/02/04 11:18:43 mrt] + * + * Changed to use new Mach copyright + * [91/02/02 12:17:20 mrt] + * + * Revision 2.4 91/01/08 15:48:24 rpd + * Added continuation argument to thread_block. + * [90/12/27 rpd] + * + * Revision 2.3 90/12/05 23:34:48 af + * Recovered from pmax merge.. and from the destruction of a disk. + * [90/12/03 23:40:40 af] + * + * Revision 2.1.1.1 90/11/01 03:39:09 af + * Created, from the DEC specs: + * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" + * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. + * And from the NCR data sheets + * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" + * [90/09/03 af] + */ + +/* + * File: scsi_53C94_hdw.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Bottom layer of the SCSI driver: chip-dependent functions + * + * This file contains the code that is specific to the NCR 53C94 + * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start + * operation, and interrupt routine. + */ + +/* + * This layer works based on small simple 'scripts' that are installed + * at the start of the command and drive the chip to completion. + * The idea comes from the specs of the NCR 53C700 'script' processor. + * + * There are various reasons for this, mainly + * - Performance: identify the common (successful) path, and follow it; + * at interrupt time no code is needed to find the current status + * - Code size: it should be easy to compact common operations + * - Adaptability: the code skeleton should adapt to different chips without + * terrible complications. + * - Error handling: and it is easy to modify the actions performed + * by the scripts to cope with strange but well identified sequences + * + */ + +#include <asc.h> +#if NASC > 0 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/dkstat.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/errno.h> +#include <sys/device.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> +#include <machine/pio.h> + +#include <wgrisc/dev/scsi.h> +#include <wgrisc/dev/ascreg.h> +#include <wgrisc/dev/dma.h> + +#include <wgrisc/riscbus/riscbus.h> +#include <wgrisc/wgrisc/wgrisctype.h> + +#define readback(a) { register int foo; foo = (a); } +extern int cputype; + +/* + * In 4ns ticks. + */ +int asc_to_scsi_period[] = { + 32, + 33, + 34, + 35, + 5, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, +}; + +/* + * Internal forward declarations. + */ +static void asc_reset(); +static void asc_startcmd(); + +#ifdef DEBUG +int asc_debug = 1; +int asc_debug_cmd; +int asc_debug_bn; +int asc_debug_sz; +#define NLOG 16 +struct asc_log { + u_int status; + u_char state; + u_char msg; + int target; + int resid; +} asc_log[NLOG], *asc_logp = asc_log; +#define PACK(unit, status, ss, ir) \ + ((unit << 24) | (status << 16) | (ss << 8) | ir) +#endif + +/* + * Scripts are entries in a state machine table. + * A script has four parts: a pre-condition, an action, a command to the chip, + * and an index into asc_scripts for the next state. The first triggers error + * handling if not satisfied and in our case it is formed by the + * values of the interrupt register and status register, this + * basically captures the phase of the bus and the TC and BS + * bits. The action part is just a function pointer, and the + * command is what the 53C94 should be told to do at the end + * of the action processing. This command is only issued and the + * script proceeds if the action routine returns TRUE. + * See asc_intr() for how and where this is all done. + */ +typedef struct script { + int condition; /* expected state at interrupt time */ + int (*action)(); /* extra operations */ + int command; /* command to the chip */ + struct script *next; /* index into asc_scripts for next state */ +} script_t; + +/* Matching on the condition value */ +#define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8)) + +/* forward decls of script actions */ +static int script_nop(); /* when nothing needed */ +static int asc_end(); /* all come to an end */ +static int asc_get_status(); /* get status from target */ +static int asc_dma_in(); /* start reading data from target */ +static int asc_last_dma_in(); /* cleanup after all data is read */ +static int asc_resume_in(); /* resume data in after a message */ +static int asc_resume_dma_in(); /* resume DMA after a disconnect */ +static int asc_dma_out(); /* send data to target via dma */ +static int asc_last_dma_out(); /* cleanup after all data is written */ +static int asc_resume_out(); /* resume data out after a message */ +static int asc_resume_dma_out(); /* resume DMA after a disconnect */ +static int asc_sendsync(); /* negotiate sync xfer */ +static int asc_replysync(); /* negotiate sync xfer */ +static int asc_msg_in(); /* process a message byte */ +static int asc_disconnect(); /* process an expected disconnect */ + +/* Define the index into asc_scripts for various state transitions */ +#define SCRIPT_DATA_IN 0 +#define SCRIPT_CONTINUE_IN 2 +#define SCRIPT_DATA_OUT 3 +#define SCRIPT_CONTINUE_OUT 5 +#define SCRIPT_SIMPLE 6 +#define SCRIPT_GET_STATUS 7 +#define SCRIPT_DONE 8 +#define SCRIPT_MSG_IN 9 +#define SCRIPT_REPLY_SYNC 11 +#define SCRIPT_TRY_SYNC 12 +#define SCRIPT_DISCONNECT 15 +#define SCRIPT_RESEL 16 +#define SCRIPT_RESUME_IN 17 +#define SCRIPT_RESUME_DMA_IN 18 +#define SCRIPT_RESUME_OUT 19 +#define SCRIPT_RESUME_DMA_OUT 20 +#define SCRIPT_RESUME_NO_DATA 21 + +/* + * Scripts + */ +script_t asc_scripts[] = { + /* start data in */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ + asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ + asc_last_dma_in, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, + + /* continue data in after a chunk is finished */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ + asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + + /* start data out */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ + asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ + asc_last_dma_out, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, + + /* continue data out after a chunk is finished */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ + asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + + /* simple command with no data transfer */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ + script_nop, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, + + /* get status and finish command */ + {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ + asc_get_status, ASC_CMD_MSG_ACPT, + &asc_scripts[SCRIPT_DONE]}, + {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ + asc_end, ASC_CMD_NOP, + &asc_scripts[SCRIPT_DONE]}, + + /* message in */ + {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ + asc_msg_in, ASC_CMD_MSG_ACPT, + &asc_scripts[SCRIPT_MSG_IN + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ + script_nop, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_MSG_IN]}, + + /* send synchonous negotiation reply */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ + asc_replysync, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_REPLY_SYNC]}, + + /* try to negotiate synchonous transfer parameters */ + {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ + asc_sendsync, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_TRY_SYNC + 1]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ + script_nop, ASC_CMD_XFER_INFO, + &asc_scripts[SCRIPT_MSG_IN]}, + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ + script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_RESUME_NO_DATA]}, + + /* handle a disconnect */ + {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ + asc_disconnect, ASC_CMD_ENABLE_SEL, + &asc_scripts[SCRIPT_RESEL]}, + + /* reselect sequence: this is just a placeholder so match fails */ + {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ + script_nop, ASC_CMD_MSG_ACPT, + &asc_scripts[SCRIPT_RESEL]}, + + /* resume data in after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ + asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + + /* resume partial DMA data in after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ + asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_IN + 1]}, + + /* resume data out after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ + asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + + /* resume partial DMA data out after a message */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ + asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, + &asc_scripts[SCRIPT_DATA_OUT + 1]}, + + /* resume after a message when there is no more data */ + {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ + script_nop, ASC_CMD_I_COMPLETE, + &asc_scripts[SCRIPT_GET_STATUS]}, +}; + +/* + * State kept for each active SCSI device. + */ +typedef struct scsi_state { + script_t *script; /* saved script while processing error */ + struct scsi_generic cmd;/* storage for scsi command */ + int statusByte; /* status byte returned during STATUS_PHASE */ + u_int dmaBufSize; /* DMA buffer size */ + int dmalen; /* amount to transfer in this chunk */ + int dmaresid; /* amount not transfered if chunk suspended */ + int cmdlen; /* length of command in cmd */ + int buflen; /* total remaining amount of data to transfer */ + vm_offset_t buf; /* current pointer within scsicmd->buf */ + int flags; /* see below */ + int msglen; /* number of message bytes to read */ + int msgcnt; /* number of message bytes received */ + u_char sync_period; /* DMA synchronous period */ + u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ + u_char msg_out; /* next MSG_OUT byte to send */ + u_char msg_in[16]; /* buffer for multibyte messages */ +} State; + +/* state flags */ +#define DISCONN 0x001 /* true if currently disconnected from bus */ +#define DMA_IN_PROGRESS 0x002 /* true if data DMA started */ +#define DMA_IN 0x004 /* true if reading from SCSI device */ +#define DMA_OUT 0x010 /* true if writing to SCSI device */ +#define DID_SYNC 0x020 /* true if synchronous offset was negotiated */ +#define TRY_SYNC 0x040 /* true if try neg. synchronous offset */ +#define PARITY_ERR 0x080 /* true if parity error seen */ +#define CHECK_SENSE 0x100 /* true if doing sense command */ + +struct dma_softc_t; +/* + * State kept for each active SCSI host interface (53C94). + */ +struct asc_softc { + struct device sc_dev; /* use as a device */ + asc_regmap_t *regs; /* chip address */ + dma_softc_t dma; /* dma control structure */ + int sc_id; /* SCSI ID of this interface */ + int myidmask; /* ~(1 << myid) */ + int state; /* current SCSI connection state */ + int target; /* target SCSI ID if busy */ + script_t *script; /* next expected interrupt & action */ + struct scsi_xfer *cmdq[ASC_NCMD];/* Pointer to queued commands */ + struct scsi_xfer *cmd[ASC_NCMD];/* Pointer to current active command */ + State st[ASC_NCMD]; /* state info for each active command */ + int min_period; /* Min transfer period clk/byte */ + int max_period; /* Max transfer period clk/byte */ + int ccf; /* CCF, whatever that really is? */ + int timeout_250; /* 250ms timeout */ + int tb_ticks; /* 4ns. ticks/tb channel ticks */ + struct scsi_link sc_link; /* scsi link struct */ +}; + +#define ASC_STATE_IDLE 0 /* idle state */ +#define ASC_STATE_BUSY 1 /* selecting or currently connected */ +#define ASC_STATE_TARGET 2 /* currently selected as target */ +#define ASC_STATE_RESEL 3 /* currently waiting for reselect */ + +typedef struct asc_softc *asc_softc_t; + +static char dma_buffer[MAXPHYS]; /*yieek*/ /*XXX*/ + +/* + * Autoconfiguration data for config. + */ +int ascmatch __P((struct device *, void *, void *)); +void ascattach __P((struct device *, struct device *, void *)); +int ascprint(void *, const char *); + +struct cfattach asc_ca = { + sizeof(struct asc_softc), ascmatch, ascattach +}; +struct cfdriver asc_cd = { + NULL, "asc", DV_DULL, NULL, 0 +}; + +/* + * Glue to the machine dependent scsi + */ +int asc_scsi_cmd __P((struct scsi_xfer *)); +void asc_minphys __P((struct buf *)); + +struct scsi_adapter asc_switch = { + asc_scsi_cmd, + asc_minphys, + NULL, + NULL, +}; + +struct scsi_device asc_dev = { +/*XXX*/ NULL, /* Use default error handler */ +/*XXX*/ NULL, /* have a queue, served by this */ +/*XXX*/ NULL, /* have no async handler */ +/*XXX*/ NULL, /* Use default 'done' routine */ +}; + +static void asc_start(); +static int asc_intr(); + +/* + * Match driver based on name + */ +int +ascmatch(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + struct cfdata *cf = match; + struct confargs *ca = aux; + + if(!BUS_MATCHNAME(ca, "asc")) + return(0); + return(1); +} + +void +ascattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + register struct confargs *ca = aux; + register asc_softc_t asc = (void *)self; + register asc_regmap_t *regs; + int id, s, i; + int bufsiz; + + /* + * Initialize hw descriptor, cache some pointers + */ + asc->regs = (asc_regmap_t *)BUS_CVTADDR(ca); + + /* + * Set up machine dependencies. + * 1) how to do dma + * 2) timing based on chip clock frequency + */ + switch (cputype) { + case WGRISC9100: + bufsiz = MAXPHYS; /* Scatter gather in software */ + break; + default: + bufsiz = 64 * 1024; + }; + /* + * Now for timing. WGRISC has a 20Mhz + */ + switch (cputype) { + case WGRISC9100: + asc->min_period = ASC_MIN_PERIOD20; + asc->max_period = ASC_MAX_PERIOD20; + asc->ccf = ASC_CCF(20); + asc->timeout_250 = ASC_TIMEOUT_250(20, asc->ccf); + asc->tb_ticks = 10; + asc->dma.dma_ch = DMA_CH0; + break; + default: + asc->min_period = ASC_MIN_PERIOD12; + asc->max_period = ASC_MAX_PERIOD12; + asc->ccf = ASC_CCF(13); + asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf); + asc->tb_ticks = 20; + break; + }; + + asc->state = ASC_STATE_IDLE; + asc->target = -1; + + regs = asc->regs; + + /* + * Reset chip, fully. Note that interrupts are already enabled. + */ + s = splbio(); + + /* preserve our ID for now */ +#if 0 + asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; +#else + asc->sc_id = 7; /* XXX Until boot roms set up scsi id */ +#endif + asc->myidmask = ~(1 << asc->sc_id); + + asc_reset(asc, regs); + + /* + * Our SCSI id on the bus. + * The user can set this via the prom on 3maxen/picaen. + * If this changes it is easy to fix: make a default that + * can be changed as boot arg. + */ +#ifdef unneeded + regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | + (scsi_initiator_id[unit] & 0x7); + asc->sc_id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; +#endif + id = asc->sc_id; + splx(s); + + /* + * Give each target its DMA buffer region. + * The buffer address is the same for all targets, + * the allocated dma viritual scatter/gather space. + */ + for (i = 0; i < ASC_NCMD; i++) { + asc->st[i].dmaBufSize = bufsiz; + } + + /* + * Set up interrupt handler. + */ + BUS_INTR_ESTABLISH(ca, asc_intr, (void *)asc); + + printf(": NCR53C94, target %d\n", id); + + /* + * Fill in the prototype scsi link. + */ + asc->sc_link.adapter_softc = asc; + asc->sc_link.adapter_target = asc->sc_id; + asc->sc_link.adapter = &asc_switch; + asc->sc_link.device = &asc_dev; + asc->sc_link.openings = 2; + + /* + * Now try to attach all the sub devices. + */ + config_found(self, &asc->sc_link, ascprint); +} + +int +ascprint(aux, name) + void *aux; + const char *name; +{ +} + +/* + * Driver breaks down request transfer size. + */ +void +asc_minphys(bp) + struct buf *bp; +{ + minphys(bp); +} + +/* + * Start activity on a SCSI device. + * We maintain information on each device separately since devices can + * connect/disconnect during an operation. + */ +int +asc_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct asc_softc *asc = sc_link->adapter_softc; + State *state = &asc->st[sc_link->target]; + + int flags, s; + + flags = xs->flags; + + /* + * Flush caches for any data buffer + */ + if(xs->datalen != 0) { +#ifdef R4K + R4K_HitFlushDCache(xs->data, xs->datalen); +#else + R3K_FlushDCache(); +#endif + } + /* + * The hack on the next few lines are to avoid buffers + * mapped to UADDR. Realloc to the kva uarea address. + */ + if((u_int)(xs->data) >= UADDR) { + xs->data = ((u_int)(xs->data) & ~UADDR) + (u_char *)(curproc->p_addr); + } + + /* + * Check if another command is already in progress. + * We may have to change this if we allow SCSI devices with + * separate LUNs. + */ + s = splbio(); + if (asc->cmd[sc_link->target]) { + if (asc->cmdq[sc_link->target]) { + splx(s); + printf("asc_scsi_cmd: called when target busy"); + xs->error = XS_DRIVER_STUFFUP; + return TRY_AGAIN_LATER; + } + asc->cmdq[sc_link->target] = xs; + splx(s); + return SUCCESSFULLY_QUEUED; + } + asc->cmd[sc_link->target] = xs; + + /* + * Going to launch. + * Make a local copy of the command and some pointers. + */ + asc_startcmd(asc, sc_link->target); + + /* + * If in startup, interrupts not usable yet. + */ + if(flags & SCSI_POLL) { + return(asc_poll(asc,sc_link->target)); + } + splx(s); + return SUCCESSFULLY_QUEUED; +} + +int +asc_poll(asc, target) + struct asc_softc *asc; + int target; +{ + struct scsi_xfer *scsicmd = asc->cmd[target]; + int count = scsicmd->timeout * 10; + + while(count) { + if(asc->regs->asc_status &ASC_CSR_INT) { + asc_intr(asc); + } + if(scsicmd->flags & ITSDONE) + break; + DELAY(5); + count--; + } + if(count == 0) { + scsicmd->error = XS_TIMEOUT; + asc_end(asc, 0, 0, 0); + } + return COMPLETE; +} + +static void +asc_reset(asc, regs) + asc_softc_t asc; + asc_regmap_t *regs; +{ + int i; + + /* + * Reset chip and SCSI bus. Put everything in a known state. + */ + regs->asc_cmd = ASC_CMD_RESET; + wbflush(); DELAY(25); + regs->asc_cmd = ASC_CMD_NOP; + wbflush(); DELAY(25); + regs->asc_cmd = ASC_CMD_BUS_RESET; + wbflush(); + while(!(regs->asc_status & ASC_CSR_INT)) { + /*void*/ + } + regs->asc_cmd = ASC_CMD_RESET; + wbflush(); DELAY(25); + regs->asc_cmd = ASC_CMD_NOP; + wbflush(); DELAY(25); + + /* + * Set up various chip parameters + */ + regs->asc_ccf = asc->ccf; + wbflush(); DELAY(25); + regs->asc_sel_timo = asc->timeout_250; + /* restore our ID */ + regs->asc_cnfg1 = asc->sc_id | ASC_CNFG1_P_CHECK; + /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */ + regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL; + regs->asc_cnfg3 = 0; + /* zero anything else */ + ASC_TC_PUT(regs, 0); + regs->asc_syn_p = asc->min_period; + regs->asc_syn_o = 0; /* async for now */ + wbflush(); +} + +/* + * Start a SCSI command on a target. + */ +static void +asc_startcmd(asc, target) + asc_softc_t asc; + int target; +{ + asc_regmap_t *regs; + State *state; + struct scsi_xfer *scsicmd; + int i, len; + + /* + * See if another target is currently selected on this SCSI bus. + */ + if (asc->target >= 0) + return; + + regs = asc->regs; + + /* + * If a reselection is in progress, it is Ok to ignore it since + * the ASC will automatically cancel the command and flush + * the FIFO if the ASC is reselected before the command starts. + * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if + * a reselect occurs before starting the command. + */ + + asc->state = ASC_STATE_BUSY; + asc->target = target; + + /* cache some pointers */ + scsicmd = asc->cmd[target]; + state = &asc->st[target]; + + /* + * Init the chip and target state. + */ + state->flags = state->flags & (DID_SYNC | CHECK_SENSE); + state->script = (script_t *)0; + state->msg_out = SCSI_NO_OP; + + /* + * Set up for DMA of command output. Also need to flush cache. + */ + if(!(state->flags & CHECK_SENSE)) { + bcopy(scsicmd->cmd, &state->cmd, scsicmd->cmdlen); + state->cmdlen = scsicmd->cmdlen; + state->buf = (vm_offset_t)scsicmd->data; + state->buflen = scsicmd->datalen; + } + len = state->cmdlen; + state->dmalen = len; + +#ifdef DEBUG + if (asc_debug > 1) { + printf("asc_startcmd: %s target %d cmd %x len %d\n", + asc->sc_dev.dv_xname, target, + state->cmd.opcode, state->buflen); + } +#endif + + /* check for simple SCSI command with no data transfer */ + if(state->flags & CHECK_SENSE) { + asc->script = &asc_scripts[SCRIPT_DATA_IN]; + state->flags |= DMA_IN; + } + else if (scsicmd->flags & SCSI_DATA_OUT) { + asc->script = &asc_scripts[SCRIPT_DATA_OUT]; + state->flags |= DMA_OUT; + } + else if (scsicmd->flags & SCSI_DATA_IN) { + asc->script = &asc_scripts[SCRIPT_DATA_IN]; + state->flags |= DMA_IN; + } + else if (state->buflen == 0) { + /* check for sync negotiation */ + if ((scsicmd->flags & /* SCSICMD_USE_SYNC */ 0) && + !(state->flags & DID_SYNC)) { + asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; + state->flags |= TRY_SYNC; + } else + asc->script = &asc_scripts[SCRIPT_SIMPLE]; + state->buf = (vm_offset_t)0; + } + +#ifdef DEBUG + asc_debug_cmd = state->cmd.opcode; + if (state->cmd.opcode == SCSI_READ_EXT) { + asc_debug_bn = (state->cmd.bytes[1] << 24) | + (state->cmd.bytes[2] << 16) | + (state->cmd.bytes[3] << 8) | + state->cmd.bytes[4]; + asc_debug_sz = (state->cmd.bytes[6] << 8) | state->cmd.bytes[7]; + } + asc_logp->status = PACK(asc->sc_dev.dv_unit, 0, 0, asc_debug_cmd); + asc_logp->target = asc->target; + asc_logp->state = asc->script - asc_scripts; + asc_logp->msg = SCSI_DIS_REC_IDENTIFY; + asc_logp->resid = scsicmd->datalen; + if (++asc_logp >= &asc_log[NLOG]) + asc_logp = asc_log; +#endif + + /* preload the FIFO with the message and command to be sent */ + regs->asc_fifo = SCSI_DIS_REC_IDENTIFY | (scsicmd->sc_link->lun & 0x07); + + for( i = 0; i < len; i++ ) { + regs->asc_fifo = ((caddr_t)&state->cmd)[i]; + } + ASC_TC_PUT(regs, 0); + readback(regs->asc_cmd); + regs->asc_cmd = ASC_CMD_DMA; + readback(regs->asc_cmd); + + regs->asc_dbus_id = target; + readback(regs->asc_dbus_id); + regs->asc_syn_p = state->sync_period; + readback(regs->asc_syn_p); + regs->asc_syn_o = state->sync_offset; + readback(regs->asc_syn_o); + +/*XXX PEFO */ +/* we are not using sync transfer now, need to check this if we will */ + + if (state->flags & TRY_SYNC) + regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; + else + regs->asc_cmd = ASC_CMD_SEL_ATN; + readback(regs->asc_cmd); +} + +/* + * Interrupt routine + * Take interrupts from the chip + * + * Implementation: + * Move along the current command's script if + * all is well, invoke error handler if not. + */ +int +asc_intr(sc) + void *sc; +{ + asc_softc_t asc = sc; + asc_regmap_t *regs = asc->regs; + State *state; + script_t *scpt; + int ss, ir, status; + + /* collect ephemeral information */ + status = regs->asc_status; + ss = regs->asc_ss; + + if ((status & ASC_CSR_INT) == 0) /* Make sure it's a real interrupt */ + return; + + ir = regs->asc_intr; /* this resets the previous two */ + scpt = asc->script; + +#ifdef DEBUG + asc_logp->status = PACK(asc->sc_dev.dv_unit, status, ss, ir); + asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; + asc_logp->state = scpt - asc_scripts; + asc_logp->msg = -1; + asc_logp->resid = 0; + if (++asc_logp >= &asc_log[NLOG]) + asc_logp = asc_log; + if (asc_debug > 2) + printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", + status, ss, ir, scpt - asc_scripts, scpt->condition); +#endif + + /* check the expected state */ + if (SCRIPT_MATCH(ir, status) == scpt->condition) { + /* + * Perform the appropriate operation, then proceed. + */ + if ((*scpt->action)(asc, status, ss, ir)) { + regs->asc_cmd = scpt->command; + readback(regs->asc_cmd); + asc->script = scpt->next; + } + goto done; + } + + /* + * Check for parity error. + * Hardware will automatically set ATN + * to request the device for a MSG_OUT phase. + */ + if (status & ASC_CSR_PE) { + printf("%s: SCSI device %d: incomming parity error seen\n", + asc->sc_dev.dv_xname, asc->target); + asc->st[asc->target].flags |= PARITY_ERR; + } + + /* + * Check for gross error. + * Probably a bug in a device driver. + */ + if (status & ASC_CSR_GE) { + printf("%s: SCSI device %d: gross error\n", + asc->sc_dev.dv_xname, asc->target); + goto abort; + } + + /* check for message in or out */ + if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { + register int len, fifo; + + state = &asc->st[asc->target]; + switch (ASC_PHASE(status)) { + case ASC_PHASE_DATAI: + case ASC_PHASE_DATAO: + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); + goto abort; + + case ASC_PHASE_MSG_IN: + break; + + case ASC_PHASE_MSG_OUT: + /* + * Check for parity error. + * Hardware will automatically set ATN + * to request the device for a MSG_OUT phase. + */ + if (state->flags & PARITY_ERR) { + state->flags &= ~PARITY_ERR; + state->msg_out = SCSI_MESSAGE_PARITY_ERROR; + /* reset message in counter */ + state->msglen = 0; + } else + state->msg_out = SCSI_NO_OP; + regs->asc_fifo = state->msg_out; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + goto done; + + case ASC_PHASE_STATUS: + /* probably an error in the SCSI command */ + asc->script = &asc_scripts[SCRIPT_GET_STATUS]; + regs->asc_cmd = ASC_CMD_I_COMPLETE; + readback(regs->asc_cmd); + goto done; + + default: + goto abort; + } + + if (state->script) + goto abort; + + /* + * OK, message coming in clean up whatever is going on. + * Get number of bytes left to transfered from byte counter + * counter decrements when data is trf on the SCSI bus + */ + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + /* flush any data in the FIFO */ + if (fifo && !(state->flags & DMA_IN_PROGRESS)) { +printf("asc_intr: fifo flush %d len %d fifo %x\n", fifo, len, regs->asc_fifo); + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + DELAY(2); + } + else if (fifo && state->flags & DMA_IN_PROGRESS) { + if (state->flags & DMA_OUT) { + len += fifo; /* Bytes dma'ed but not sent */ + } + else if (state->flags & DMA_IN) { + u_char *cp; + + printf("asc_intr: IN: dmalen %d len %d fifo %d\n", + state->dmalen, len, fifo); /* XXX */ + } + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + DELAY(2); + } + if (len && (state->flags & DMA_IN_PROGRESS)) { + /* save number of bytes still to be sent or received */ + state->dmaresid = len; + state->flags &= ~DMA_IN_PROGRESS; + ASC_TC_PUT(regs, 0); +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + /* setup state to resume to */ + if (state->flags & DMA_IN) { + /* + * Since the ASC_CNFG3_SRB bit of the + * cnfg3 register bit is not set, + * we just transferred an extra byte. + * Since we can't resume on an odd byte + * boundary, we copy the valid data out + * and resume DMA at the start address. + */ + if (len & 1) { + printf("asc_intr: msg in len %d (fifo %d)\n", + len, fifo); /* XXX */ + len = state->dmalen - len; + goto do_in; + } + state->script = + &asc_scripts[SCRIPT_RESUME_DMA_IN]; + } else if (state->flags & DMA_OUT) + state->script = + &asc_scripts[SCRIPT_RESUME_DMA_OUT]; + else + state->script = asc->script; + } else if (state->flags & DMA_IN) { + if (len) { +#ifdef DEBUG + printf("asc_intr: 1: bn %d len %d (fifo %d)\n", + asc_debug_bn, len, fifo); /* XXX */ +#endif + goto abort; + } + /* setup state to resume to */ + if (state->flags & DMA_IN_PROGRESS) { + len = state->dmalen; + state->flags &= ~DMA_IN_PROGRESS; + do_in: + DMA_END(&asc->dma); + state->buf += len; + state->buflen -= len; + } + if (state->buflen) + state->script = + &asc_scripts[SCRIPT_RESUME_IN]; + else + state->script = + &asc_scripts[SCRIPT_RESUME_NO_DATA]; + } else if (state->flags & DMA_OUT) { + if (len) { + printf("asc_intr: 2: len %d (fifo %d)\n", len, + fifo); /* XXX */ +/* XXX THEO */ +#if 1 + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + DELAY(2); + len = 0; +#else + goto abort; +#endif + } + /* + * If this is the last chunk, the next expected + * state is to get status. + */ + if (state->flags & DMA_IN_PROGRESS) { + state->flags &= ~DMA_IN_PROGRESS; + DMA_END(&asc->dma); + len = state->dmalen; + state->buf += len; + state->buflen -= len; + } + if (state->buflen) + state->script = + &asc_scripts[SCRIPT_RESUME_OUT]; + else + state->script = + &asc_scripts[SCRIPT_RESUME_NO_DATA]; + } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) + state->script = &asc_scripts[SCRIPT_RESUME_NO_DATA]; + else + state->script = asc->script; + + /* setup to receive a message */ + asc->script = &asc_scripts[SCRIPT_MSG_IN]; + state->msglen = 0; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + goto done; + } + + /* check for SCSI bus reset */ + if (ir & ASC_INT_RESET) { + register int i; + + printf("%s: SCSI bus reset!!\n", asc->sc_dev.dv_xname); + /* need to flush any pending commands */ + for (i = 0; i < ASC_NCMD; i++) { + if (!asc->cmd[i]) + continue; + asc->cmd[i]->error = XS_DRIVER_STUFFUP; + asc_end(asc, 0, 0, 0); + } + /* rearbitrate synchronous offset */ + for (i = 0; i < ASC_NCMD; i++) { + asc->st[i].sync_offset = 0; + asc->st[i].flags = 0; + } + asc->target = -1; + return; + } + + /* check for command errors */ + if (ir & ASC_INT_ILL) + goto abort; + + /* check for disconnect */ + if (ir & ASC_INT_DISC) { + state = &asc->st[asc->target]; + switch (asc->script - asc_scripts) { + case SCRIPT_DONE: + case SCRIPT_DISCONNECT: + /* + * Disconnects can happen normally when the + * command is complete with the phase being + * either ASC_PHASE_DATAO or ASC_PHASE_MSG_IN. + * The SCRIPT_MATCH() only checks for one phase + * so we can wind up here. + * Perform the appropriate operation, then proceed. + */ + if ((*scpt->action)(asc, status, ss, ir)) { + regs->asc_cmd = scpt->command; + readback(regs->asc_cmd); + asc->script = scpt->next; + } + goto done; + + case SCRIPT_TRY_SYNC: + case SCRIPT_SIMPLE: + case SCRIPT_DATA_IN: + case SCRIPT_DATA_OUT: /* one of the starting scripts */ + if (ASC_SS(ss) == 0) { + /* device did not respond */ + if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + } + asc->cmd[asc->target]->error = XS_DRIVER_STUFFUP; + asc_end(asc, status, ss, ir); + return; + } + /* FALLTHROUGH */ + + default: + printf("%s: SCSI device %d: unexpected disconnect\n", + asc->sc_dev.dv_xname, asc->target); +#ifdef DEBUG + asc_DumpLog("asc_disc"); +#endif + /* + * On rare occasions my RZ24 does a disconnect during + * data in phase and the following seems to keep it + * happy. + * XXX Should a scsi disk ever do this?? + */ + asc->script = &asc_scripts[SCRIPT_RESEL]; + asc->state = ASC_STATE_RESEL; + state->flags |= DISCONN; + regs->asc_cmd = ASC_CMD_ENABLE_SEL; + readback(regs->asc_cmd); + return; + } + } + + /* check for reselect */ + if (ir & ASC_INT_RESEL) { + unsigned fifo, id, msg; + + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + if (fifo < 2) + goto abort; + /* read unencoded SCSI ID and convert to binary */ + msg = regs->asc_fifo & asc->myidmask; + for (id = 0; (msg & 1) == 0; id++) + msg >>= 1; + /* read identify message */ + msg = regs->asc_fifo; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].msg = msg; + else + asc_logp[-1].msg = msg; +#endif + asc->state = ASC_STATE_BUSY; + asc->target = id; + state = &asc->st[id]; + asc->script = state->script; + state->script = (script_t *)0; + if (!(state->flags & DISCONN)) + goto abort; + state->flags &= ~DISCONN; + regs->asc_syn_p = state->sync_period; + regs->asc_syn_o = state->sync_offset; + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + goto done; + } + + /* check if we are being selected as a target */ + if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) + goto abort; + + /* + * 'ir' must be just ASC_INT_FC. + * This is normal if canceling an ASC_ENABLE_SEL. + */ + +done: + wbflush(); + /* + * If the next interrupt comes in immediatly the interrupt + * dispatcher (which we are returning to) will catch it + * before returning to the interrupted code. + */ + return; + +abort: +#ifdef DEBUG + asc_DumpLog("asc_intr"); +#endif +#if 0 + panic("asc_intr"); +#else + boot(4); /* XXX */ +#endif +} + +/* + * All the many little things that the interrupt + * routine might switch to. + */ + +/* ARGSUSED */ +static int +script_nop(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + return (1); +} + +/* ARGSUSED */ +static int +asc_get_status(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register int data; + + /* + * Get the last two bytes in the FIFO. + */ + if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { + printf("asc_get_status: cmdreg %x, fifo cnt %d\n", + regs->asc_cmd, data); /* XXX */ +#ifdef DEBUG + asc_DumpLog("get_status"); /* XXX */ +#endif + if (data < 2) { + asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(asc->regs->asc_cmd); + return (0); + } + do { + data = regs->asc_fifo; + } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); + } + + /* save the status byte */ + asc->st[asc->target].statusByte = data = regs->asc_fifo; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].msg = data; + else + asc_logp[-1].msg = data; +#endif + + /* get the (presumed) command_complete message */ + if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) + return (1); + +#ifdef DEBUG + printf("asc_get_status: status %x cmd %x\n", + asc->st[asc->target].statusByte, data); + asc_DumpLog("asc_get_status"); +#endif + return (0); +} + +/* ARGSUSED */ +static int +asc_end(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + struct scsi_xfer *scsicmd; + struct scsi_link *sc_link; + State *state; + int i, target; + + asc->state = ASC_STATE_IDLE; + target = asc->target; + asc->target = -1; + scsicmd = asc->cmd[target]; + sc_link = scsicmd->sc_link; + asc->cmd[target] = (struct scsi_xfer *)0; + state = &asc->st[target]; + +#ifdef DEBUG + if (asc_debug > 1) { + printf("asc_end: %s target %d cmd %x err %d resid %d\n", + asc->sc_dev.dv_xname, target, + state->cmd.opcode, scsicmd->error, state->buflen); + } +#endif +#ifdef DIAGNOSTIC + if (target < 0 || !scsicmd) + panic("asc_end"); +#endif + + /* look for disconnected devices */ + for (i = 0; i < ASC_NCMD; i++) { + if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) + continue; + asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; + readback(asc->regs->asc_cmd); + asc->state = ASC_STATE_RESEL; + asc->script = &asc_scripts[SCRIPT_RESEL]; + break; + } + + if(scsicmd->error == XS_NOERROR && !(state->flags & CHECK_SENSE)) { + if((state->statusByte & ST_MASK) == SCSI_CHECK) { + struct scsi_sense *ss = (void *)&state->cmd; + /* Save return values */ + scsicmd->resid = state->buflen; + scsicmd->status = state->statusByte; + /* Set up sense request command */ + bzero(ss, sizeof(*ss)); + ss->opcode = REQUEST_SENSE; + ss->byte2 = sc_link->lun << 5; + ss->length = sizeof(struct scsi_sense_data); + state->cmdlen = sizeof(*ss); + state->buf = (vm_offset_t)&scsicmd->sense; + state->buflen = sizeof(struct scsi_sense_data); + state->flags |= CHECK_SENSE; +#ifdef R4K + R4K_HitFlushDCache(state->buf, state->buflen); +#else + R3K_FlushDCache(); +#endif + asc->cmd[target] = scsicmd; + asc_startcmd(asc, target); + return(0); + } + } + + if(scsicmd->error == XS_NOERROR && (state->flags & CHECK_SENSE)) { + scsicmd->error = XS_SENSE; + } + else { + scsicmd->resid = state->buflen; + } + state->flags &= ~CHECK_SENSE; + + /* + * Look for another device that is ready. + * May want to keep last one started and increment for fairness + * rather than always starting at zero. + */ + for (i = 0; i < ASC_NCMD; i++) { + if (asc->cmd[i] == 0 && asc->cmdq[i] != 0) { + asc->cmd[i] = asc->cmdq[i]; + asc->cmdq[i] = 0; + } + } + for (i = 0; i < ASC_NCMD; i++) { + /* don't restart a disconnected command */ + if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) + continue; + asc_startcmd(asc, i); + break; + } + + /* signal device driver that the command is done */ + scsicmd->flags |= ITSDONE; + scsi_done(scsicmd); + + return (0); +} + +/* ARGSUSED */ +static int +asc_dma_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len; + + /* check for previous chunk in buffer */ + if (state->flags & DMA_IN_PROGRESS) { + /* + * Only count bytes that have been copied to memory. + * There may be some bytes in the FIFO if synchonous transfers + * are in progress. + */ + DMA_END(&asc->dma); + ASC_TC_GET(regs, len); + len = state->dmalen - len; + state->buf += len; + state->buflen -= len; + } + + /* setup to start reading the next chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; + DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_last_dma_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, fifo; + + DMA_END(&asc->dma); + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); +#endif + if (fifo) { + /* device must be trying to send more than we expect */ + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + } + state->flags &= ~DMA_IN_PROGRESS; + len = state->dmalen - len; + state->buflen -= len; + + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len; + + /* setup to start reading the next chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_FROM_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_in: buflen %d, len %d\n", state->buflen, + len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_dma_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, off; + + /* setup to finish reading the current chunk */ + len = state->dmaresid; + off = state->dmalen - len; + if ((off & 1) && state->sync_offset) { + printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", + state->dmalen, len, off); /* XXX */ + regs->asc_res_fifo = ((u_char *)state->buf)[off]; +/*XXX Need to flush cache ? */ + } + DMA_START(&asc->dma, (caddr_t)state->buf + off, len, DMA_FROM_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", + state->dmalen, state->buflen, len, off); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (state->dmalen != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_dma_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, fifo; + + if (state->flags & DMA_IN_PROGRESS) { + /* check to be sure previous chunk was finished */ + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; + if (len || fifo) + printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); /* XXX */ + len += fifo; + len = state->dmalen - len; + state->buf += len; + state->buflen -= len; + } + + /* setup for this chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; + DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_last_dma_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, fifo; + + ASC_TC_GET(regs, len); + fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", + state->buflen, state->dmalen, len, fifo); +#endif + if (fifo) { + len += fifo; + regs->asc_cmd = ASC_CMD_FLUSH; + readback(regs->asc_cmd); + } + state->flags &= ~DMA_IN_PROGRESS; + len = state->dmalen - len; + state->buflen -= len; + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len; + + /* setup for this chunk */ + len = state->buflen; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + if (len > state->dmaBufSize) + len = state->dmaBufSize; + state->dmalen = len; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].resid = len; + else + asc_logp[-1].resid = len; +#endif + DMA_START(&asc->dma, (caddr_t)state->buf, len, DMA_TO_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_out: buflen %d, len %d\n", state->buflen, + len); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (len != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_resume_dma_out(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int len, off; + + /* setup to finish writing this chunk */ + len = state->dmaresid; + off = state->dmalen - len; + if (off & 1) { + printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", + state->dmalen, len, off); /* XXX */ + regs->asc_fifo = ((u_char *)state->buf)[off]; +/*XXX Need to flush Cache ? */ + off++; + len--; + } + DMA_START(&asc->dma, (caddr_t)state->buf + off, len, DMA_TO_DEV); + ASC_TC_PUT(regs, len); +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", + state->dmalen, state->buflen, len, off); +#endif + + /* check for next chunk */ + state->flags |= DMA_IN_PROGRESS; + if (state->dmalen != state->buflen) { + regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; + return (0); + } + return (1); +} + +/* ARGSUSED */ +static int +asc_sendsync(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + + /* send the extended synchronous negotiation message */ + regs->asc_fifo = SCSI_EXTENDED_MSG; + wbflush(); + regs->asc_fifo = 3; + wbflush(); + regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; + wbflush(); + regs->asc_fifo = SCSI_MIN_PERIOD; + wbflush(); + regs->asc_fifo = ASC_MAX_OFFSET; + /* state to resume after we see the sync reply message */ + state->script = asc->script + 2; + state->msglen = 0; + return (1); +} + +/* ARGSUSED */ +static int +asc_replysync(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_replysync: %x %x\n", + asc_to_scsi_period[state->sync_period] * asc->tb_ticks, + state->sync_offset); +#endif + /* send synchronous transfer in response to a request */ + regs->asc_fifo = SCSI_EXTENDED_MSG; + wbflush(); + regs->asc_fifo = 3; + wbflush(); + regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; + wbflush(); + regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; + wbflush(); + regs->asc_fifo = state->sync_offset; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + + /* return to the appropriate script */ + if (!state->script) { +#ifdef DEBUG + asc_DumpLog("asc_replsync"); +#endif + panic("asc_replysync"); + } + asc->script = state->script; + state->script = (script_t *)0; + return (0); +} + +/* ARGSUSED */ +static int +asc_msg_in(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register asc_regmap_t *regs = asc->regs; + register State *state = &asc->st[asc->target]; + register int msg; + int i; + + /* read one message byte */ + msg = regs->asc_fifo; +#ifdef DEBUG + if (asc_logp == asc_log) + asc_log[NLOG - 1].msg = msg; + else + asc_logp[-1].msg = msg; +#endif + + /* check for multi-byte message */ + if (state->msglen != 0) { + /* first byte is the message length */ + if (state->msglen < 0) { + state->msglen = msg; + return (1); + } + if (state->msgcnt >= state->msglen) + goto abort; + state->msg_in[state->msgcnt++] = msg; + + /* did we just read the last byte of the message? */ + if (state->msgcnt != state->msglen) + return (1); + + /* process an extended message */ +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_msg_in: msg %x %x %x\n", + state->msg_in[0], + state->msg_in[1], + state->msg_in[2]); +#endif + switch (state->msg_in[0]) { + case SCSI_SYNCHRONOUS_XFER: + state->flags |= DID_SYNC; + state->sync_offset = state->msg_in[2]; + + /* convert SCSI period to ASC period */ + i = state->msg_in[1] / asc->tb_ticks; + if (i < asc->min_period) + i = asc->min_period; + else if (i >= asc->max_period) { + /* can't do sync transfer, period too long */ + printf("%s: SCSI device %d: sync xfer period too long (%d)\n", + asc->sc_dev.dv_xname, asc->target, i); + i = asc->max_period; + state->sync_offset = 0; + } + if ((i * asc->tb_ticks) != state->msg_in[1]) + i++; + state->sync_period = i & 0x1F; + + /* + * If this is a request, check minimums and + * send back an acknowledge. + */ + if (!(state->flags & TRY_SYNC)) { + regs->asc_cmd = ASC_CMD_SET_ATN; + readback(regs->asc_cmd); + + if (state->sync_period < asc->min_period) + state->sync_period = + asc->min_period; + if (state->sync_offset > ASC_MAX_OFFSET) + state->sync_offset = + ASC_MAX_OFFSET; + asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; + regs->asc_syn_p = state->sync_period; + readback(regs->asc_syn_p); + regs->asc_syn_o = state->sync_offset; + readback(regs->asc_syn_o); + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + return (0); + } + + regs->asc_syn_p = state->sync_period; + readback(regs->asc_syn_p); + regs->asc_syn_o = state->sync_offset; + readback(regs->asc_syn_o); + goto done; + + default: + printf("%s: SCSI device %d: rejecting extended message 0x%x\n", + asc->sc_dev.dv_xname, asc->target, + state->msg_in[0]); + goto reject; + } + } + + /* process first byte of a message */ +#ifdef DEBUG + if (asc_debug > 2) + printf("asc_msg_in: msg %x\n", msg); +#endif + switch (msg) { +#if 0 + case SCSI_MESSAGE_REJECT: + printf(" did not like SYNCH xfer "); /* XXX */ + state->flags |= DID_SYNC; + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + status = asc_wait(regs, ASC_CSR_INT); + ir = regs->asc_intr; + /* some just break out here, some dont */ + if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { + regs->asc_fifo = SCSI_ABORT; + regs->asc_cmd = ASC_CMD_XFER_INFO; + readback(regs->asc_cmd); + status = asc_wait(regs, ASC_CSR_INT); + ir = regs->asc_intr; + } + if (ir & ASC_INT_DISC) { + asc_end(asc, status, 0, ir); + return (0); + } + goto status; +#endif /* 0 */ + + case SCSI_EXTENDED_MSG: /* read an extended message */ + /* setup to read message length next */ + state->msglen = -1; + state->msgcnt = 0; + return (1); + + case SCSI_NO_OP: + break; + + case SCSI_SAVE_DATA_POINTER: + /* expect another message */ + return (1); + + case SCSI_RESTORE_POINTERS: + /* + * Need to do the following if resuming synchonous data in + * on an odd byte boundary. + regs->asc_cnfg2 |= ASC_CNFG2_RFB; + */ + break; + + case SCSI_DISCONNECT: + if (state->flags & DISCONN) + goto abort; + state->flags |= DISCONN; + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + asc->script = &asc_scripts[SCRIPT_DISCONNECT]; + return (0); + + default: + printf("%s: SCSI device %d: rejecting message 0x%x\n", + asc->sc_dev.dv_xname, asc->target, msg); + reject: + /* request a message out before acknowledging this message */ + state->msg_out = SCSI_MESSAGE_REJECT; + regs->asc_cmd = ASC_CMD_SET_ATN; + readback(regs->asc_cmd); + } + +done: + /* return to original script */ + regs->asc_cmd = ASC_CMD_MSG_ACPT; + readback(regs->asc_cmd); + if (!state->script) { + abort: +#ifdef DEBUG + asc_DumpLog("asc_msg_in"); +#endif + panic("asc_msg_in"); + } + asc->script = state->script; + state->script = (script_t *)0; + return (0); +} + +/* ARGSUSED */ +static int +asc_disconnect(asc, status, ss, ir) + register asc_softc_t asc; + register int status, ss, ir; +{ + register State *state = &asc->st[asc->target]; + +#ifdef DIAGNOSTIC + if (!(state->flags & DISCONN)) { + printf("asc_disconnect: device %d: DISCONN not set!\n", + asc->target); + } +#endif /* DIAGNOSTIC */ + asc->target = -1; + asc->state = ASC_STATE_RESEL; + return (1); +} + +#ifdef DEBUG +/* + * Dump the log buffer. + */ +asc_DumpLog(str) + char *str; +{ + register struct asc_log *lp; + register u_int status; + + printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, + asc_debug_bn, asc_debug_sz); + lp = asc_logp; + do { + status = lp->status; + printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", + status >> 24, + lp->target, + (status >> 16) & 0xFF, + (status >> 8) & 0xFF, + status & 0XFF, + lp->state, + asc_scripts[lp->state].condition, + lp->msg, lp->resid); + if (++lp >= &asc_log[NLOG]) + lp = asc_log; + } while (lp != asc_logp); +} +#endif /* DEBUG */ + +#endif /* NASC > 0 */ diff --git a/sys/arch/wgrisc/dev/ascreg.h b/sys/arch/wgrisc/dev/ascreg.h new file mode 100644 index 00000000000..3a5a213ba36 --- /dev/null +++ b/sys/arch/wgrisc/dev/ascreg.h @@ -0,0 +1,326 @@ +/* $OpenBSD: ascreg.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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: @(#)ascreg.h 8.1 (Berkeley) 6/10/93 + * $Id: ascreg.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ + */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 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 + * 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 the + * rights to redistribute these changes. + */ + +/* + * HISTORY + * Log: scsi_53C94.h,v + * Revision 2.4 91/02/05 17:44:59 mrt + * Added author notices + * [91/02/04 11:18:32 mrt] + * + * Changed to use new Mach copyright + * [91/02/02 12:17:11 mrt] + * + * Revision 2.3 90/12/05 23:34:46 af + * Documented max DMA xfer size. + * [90/12/03 23:39:36 af] + * + * Revision 2.1.1.1 90/11/01 03:38:54 af + * Created, from the DEC specs: + * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" + * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. + * And from the NCR data sheets + * "NCR 53C94, 53C95, 53C96 Advanced SCSI Controller" + * [90/09/03 af] + */ + +/* + * File: scsi_53C94.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Defines for the NCR 53C94 ASC (SCSI interface) + * Some gotcha came from the "86C01/53C94 DMA lab work" written + * by Ken Stewart (NCR MED Logic Products Applications Engineer) + * courtesy of NCR. Thanks Ken ! + */ + +#define ASC_OFFSET_53C94 0x0 /* from module base */ + +#define ASC_NCMD 7 /* Number of simultaneous cmds */ + +/* + * Synch xfer parameters, and timing conversions + */ +#define SCSI_MIN_PERIOD 50 /* in 4 nsecs units */ +#define ASC_MIN_PERIOD40 8 /* in CLKS/BYTE, 1 CLK = 25nsecs */ +#define ASC_MIN_PERIOD25 5 /* in CLKS/BYTE, 1 CLK = 40nsecs */ +#define ASC_MIN_PERIOD20 4 /* in CLKS/BYTE, 1 CLK = 50nsecs */ +#define ASC_MIN_PERIOD12 3 /* in CLKS/BYTE, 1 CLK = 80nsecs */ +#define ASC_MAX_PERIOD40 56 /* in CLKS/BYTE, 1 CLK = 25nsecs */ +#define ASC_MAX_PERIOD25 35 /* in CLKS/BYTE, 1 CLK = 40nsecs */ +#define ASC_MAX_PERIOD20 28 /* in CLKS/BYTE, 1 CLK = 50nsecs */ +#define ASC_MAX_PERIOD12 18 /* in CLKS/BYTE, 1 CLK = 80nsecs */ +#define ASC_MAX_OFFSET 15 /* pure number */ +/* + * Register map, padded as needed + */ + +typedef volatile struct { + u_char asc_tc_lsb; /* 00 rw: Transfer Counter LSB */ + u_char asc_tc_msb; /* 01 rw: Transfer Counter MSB */ + u_char asc_fifo; /* 02 rw: FIFO top */ + u_char asc_cmd; /* 03 rw: Command */ + u_char asc_status; /* 04 r: Status */ +#define asc_dbus_id asc_status /* 04 w: Destination Bus ID */ + u_char asc_intr; /* 05 r: Interrupt */ +#define asc_sel_timo asc_intr /* 05 w: (re)select timeout */ + u_char asc_ss; /* 06 r: Sequence Step */ +#define asc_syn_p asc_ss /* 06 w: synchronous period */ + u_char asc_flags; /* 07 r: FIFO flags + seq step */ +#define asc_syn_o asc_flags /* 07 w: synchronous offset */ + u_char asc_cnfg1; /* 08 rw: Configuration 1 */ + u_char asc_ccf; /* 09 w: Clock Conv. Factor */ + u_char asc_test; /* 0a w: Test Mode */ + u_char asc_cnfg2; /* 0b rw: Configuration 2 */ + u_char asc_cnfg3; /* 0c rw: Configuration 3 */ + u_char asc_res_fifo; /* 0d w: Reserve FIFO byte */ + u_char asc_tc_xsb; /* 0e rw: Transfer Counter Xtended */ +} asc_regmap_t; + +/* + * Transfer Count: access macros + * That a NOP is required after loading the dma counter + * I learned on the NCR test code. Sic. + */ + +#define ASC_TC_MAX 0x10000 + +#define ASC_TC_GET(ptr, val) \ + val = (ptr)->asc_tc_lsb | ((ptr)->asc_tc_msb << 8) | ((ptr)->asc_tc_xsb << 16) +#define ASC_TC_PUT(ptr, val) \ + (ptr)->asc_tc_lsb = (val); \ + (ptr)->asc_tc_msb = (val) >> 8; \ + (ptr)->asc_tc_xsb = (val) >> 16; \ + (ptr)->asc_cmd = ASC_CMD_NOP | ASC_CMD_DMA; + +/* + * Command register (command codes) + */ + +#define ASC_CMD_DMA 0x80 + /* Miscellaneous */ +#define ASC_CMD_NOP 0x00 +#define ASC_CMD_FLUSH 0x01 +#define ASC_CMD_RESET 0x02 +#define ASC_CMD_BUS_RESET 0x03 + /* Initiator state */ +#define ASC_CMD_XFER_INFO 0x10 +#define ASC_CMD_I_COMPLETE 0x11 +#define ASC_CMD_MSG_ACPT 0x12 +#define ASC_CMD_XFER_PAD 0x18 +#define ASC_CMD_SET_ATN 0x1a +#define ASC_CMD_CLR_ATN 0x1b + /* Target state */ +#define ASC_CMD_SND_MSG 0x20 +#define ASC_CMD_SND_STATUS 0x21 +#define ASC_CMD_SND_DATA 0x22 +#define ASC_CMD_DISC_SEQ 0x23 +#define ASC_CMD_TERM 0x24 +#define ASC_CMD_T_COMPLETE 0x25 +#define ASC_CMD_DISC 0x27 +#define ASC_CMD_RCV_MSG 0x28 +#define ASC_CMD_RCV_CDB 0x29 +#define ASC_CMD_RCV_DATA 0x2a +#define ASC_CMD_RCV_CMD 0x2b +#define ASC_CMD_ABRT_DMA 0x04 + /* Disconnected state */ +#define ASC_CMD_RESELECT 0x40 +#define ASC_CMD_SEL 0x41 +#define ASC_CMD_SEL_ATN 0x42 +#define ASC_CMD_SEL_ATN_STOP 0x43 +#define ASC_CMD_ENABLE_SEL 0x44 +#define ASC_CMD_DISABLE_SEL 0x45 +#define ASC_CMD_SEL_ATN3 0x46 + +/* + * Status register, and phase encoding + */ + +#define ASC_CSR_INT 0x80 +#define ASC_CSR_GE 0x40 +#define ASC_CSR_PE 0x20 +#define ASC_CSR_TC 0x10 +#define ASC_CSR_VGC 0x08 +#define ASC_CSR_MSG 0x04 +#define ASC_CSR_CD 0x02 +#define ASC_CSR_IO 0x01 + +#define ASC_PHASE(csr) ((csr) & 0x7) +#define ASC_PHASE_DATAO 0x0 +#define ASC_PHASE_DATAI 0x1 +#define ASC_PHASE_COMMAND 0x2 +#define ASC_PHASE_STATUS 0x3 + /* 4..5 ANSI reserved */ +#define ASC_PHASE_MSG_OUT 0x6 +#define ASC_PHASE_MSG_IN 0x7 + +/* + * Destination Bus ID + */ + +#define ASC_DEST_ID_MASK 0x07 + +/* + * Interrupt register + */ + +#define ASC_INT_RESET 0x80 +#define ASC_INT_ILL 0x40 +#define ASC_INT_DISC 0x20 +#define ASC_INT_BS 0x10 +#define ASC_INT_FC 0x08 +#define ASC_INT_RESEL 0x04 +#define ASC_INT_SEL_ATN 0x02 +#define ASC_INT_SEL 0x01 + +/* + * Timeout register: + * + * val = (timeout * CLK_freq) / (8192 * CCF); + */ + +#define ASC_TIMEOUT_250(clk, ccf) (((clk) * 31) / (ccf)) + +/* + * Sequence Step register + */ + +#define ASC_SS_RESERVED 0xf0 +#define ASC_SS_SOM 0x08 +#define ASC_SS_MASK 0x07 +#define ASC_SS(ss) ((ss) & ASC_SS_MASK) + +/* + * Synchronous Transfer Period + */ + +#define ASC_STP_MASK 0x1f +#define ASC_STP_MIN 0x05 /* 5 clk per byte */ +#define ASC_STP_MAX 0x04 /* after ovfl, 35 clk/byte */ + +/* + * FIFO flags + */ + +#define ASC_FLAGS_SEQ_STEP 0xe0 +#define ASC_FLAGS_FIFO_CNT 0x1f + +/* + * Synchronous offset + */ + +#define ASC_SYNO_MASK 0x0f /* 0 -> asyn */ + +/* + * Configuration 1 + */ + +#define ASC_CNFG1_SLOW 0x80 +#define ASC_CNFG1_SRD 0x40 +#define ASC_CNFG1_P_TEST 0x20 +#define ASC_CNFG1_P_CHECK 0x10 +#define ASC_CNFG1_TEST 0x08 +#define ASC_CNFG1_MY_BUS_ID 0x07 + +/* + * CCF register + */ + +#define ASC_CCF(clk) ((((clk) - 1) / 5) + 1) + +/* + * Test register + */ + +#define ASC_TEST_XXXX 0xf8 +#define ASC_TEST_HI_Z 0x04 +#define ASC_TEST_I 0x02 +#define ASC_TEST_T 0x01 + +/* + * Configuration 2 + */ + +#define ASC_CNFG2_RFB 0x80 +#define ASC_CNFG2_EPL 0x40 +#define ASC_CNFG2_EBC 0x20 +#define ASC_CNFG2_DREQ_HIZ 0x10 +#define ASC_CNFG2_SCSI2 0x08 +#define ASC_CNFG2_BPA 0x04 +#define ASC_CNFG2_RPE 0x02 +#define ASC_CNFG2_DPE 0x01 + +/* + * Configuration 3 + */ + +#define ASC_CNFG3_RESERVED 0xf8 +#define ASC_CNFG3_SRB 0x04 +#define ASC_CNFG3_ALT_DMA 0x02 +#define ASC_CNFG3_T8 0x01 + +#define ST_MASK 0x3e diff --git a/sys/arch/wgrisc/dev/com_risc.c b/sys/arch/wgrisc/dev/com_risc.c new file mode 100644 index 00000000000..557179e6642 --- /dev/null +++ b/sys/arch/wgrisc/dev/com_risc.c @@ -0,0 +1,195 @@ +/* $OpenBSD: com_risc.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ + +/* + * Copyright (c) 1993, 1994 Charles Hannum. + * Copyright (c) 1990 William F. Jolitz, TeleMuse + * 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 software is a component of "386BSD" developed by + * William F. Jolitz, TeleMuse. + * 4. Neither the name of the developer nor the name "386BSD" + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ + * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS + * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. + * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT + * NOT MAKE USE OF THIS WORK. + * + * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED + * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN + * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES + * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING + * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND + * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE + * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS + * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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. + */ + +/* + * Device Driver for AT parallel printer port + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/tty.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/isa/isavar.h> /* XXX for isa_chipset_tag_t in com_softc */ + +#include <dev/ic/comreg.h> +#include <dev/ic/comvar.h> +#include <dev/ic/ns16550reg.h> + +/* Macros to clear/set/test flags. */ +#define SET(t, f) (t) |= (f) +#define CLR(t, f) (t) &= ~(f) +#define ISSET(t, f) ((t) & (f)) + +#undef CONADDR /* This is stupid but using devs before config .. */ +#define CONADDR 0xae400000 + +int com_risc_probe __P((struct device *, void *, void *)); +void com_risc_attach __P((struct device *, struct device *, void *)); + +struct cfattach com_risc_ca = { + sizeof(struct com_softc), com_risc_probe, com_risc_attach +}; + +int +com_risc_probe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + bus_space_tag_t iot; + bus_space_handle_t ioh; + int iobase, needioh; + int rv = 1; + struct confargs *ca = aux; + + if(!BUS_MATCHNAME(ca, "com")) + return(0); + iobase = (long)BUS_CVTADDR(ca); + iot = 0; + needioh = 1; + + /* if it's in use as console, it's there. */ + if (iobase == comconsaddr && !comconsattached) + goto out; + + if (needioh && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { + rv = 0; + goto out; + } + rv = comprobe1(iot, ioh, iobase); + if (needioh) + bus_space_unmap(iot, ioh, COM_NPORTS); + +out: + return (rv); +} + +void +com_risc_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct com_softc *sc = (void *)self; + int iobase; + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct confargs *ca = aux; + + sc->sc_hwflags = 0; + sc->sc_swflags = 0; + sc->sc_iobase = iobase = (bus_addr_t)BUS_CVTADDR(ca); + sc->sc_ioh = ioh = (bus_space_handle_t)iobase; + sc->sc_iot = iot = 0; + + if (iobase == comconsaddr) { + comconsattached = 1; + + /* + * Need to reset baud rate, etc. of next print so reset + * comconsinit. Also make sure console is always "hardwired". + */ + delay(1000); /* wait for output to finish */ + comconsinit = 0; + SET(sc->sc_hwflags, COM_HW_CONSOLE); + SET(sc->sc_swflags, COM_SW_SOFTCAR); + } + + + /* look for a NS 16550AF UART with FIFOs */ + bus_space_write_1(iot, ioh, com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + delay(100); + if (ISSET(bus_space_read_1(iot, ioh, com_iir), IIR_FIFO_MASK) == + IIR_FIFO_MASK) + if (ISSET(bus_space_read_1(iot, ioh, com_fifo), + FIFO_TRIGGER_14) == FIFO_TRIGGER_14) { + SET(sc->sc_hwflags, COM_HW_FIFO); + printf(": ns16550a, working fifo\n"); + } else + printf(": ns16550, broken fifo\n"); + else + printf(": ns8250 or ns16450, no fifo\n"); + bus_space_write_1(iot, ioh, com_fifo, 0); + + /* disable interrupts */ + bus_space_write_1(iot, ioh, com_ier, 0); + bus_space_write_1(iot, ioh, com_mcr, 0); + + BUS_INTR_ESTABLISH(ca, comintr, (void *)(long)sc); + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + kgdb_dev = -1; /* can't debug over console port */ + else { + cominit(iot, ioh, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("%s: ", sc->sc_dev.dv_xname); + kgdb_connect(1); + } else + printf("%s: kgdb enabled\n", + sc->sc_dev.dv_xname); + } + } +#endif + + /* XXX maybe move up some? */ + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + printf("%s: console\n", sc->sc_dev.dv_xname); +} diff --git a/sys/arch/wgrisc/dev/dma.h b/sys/arch/wgrisc/dev/dma.h new file mode 100644 index 00000000000..dd5fb4c51b2 --- /dev/null +++ b/sys/arch/wgrisc/dev/dma.h @@ -0,0 +1,147 @@ +/* $OpenBSD: dma.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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. + * + */ + +extern vm_map_t phys_map; + +/* + * Structure used to control dma. + */ + +typedef struct dma_softc { + struct device sc_dev; /* use as a device */ + struct esp_softc *sc_esp; + int dma_ch; + vm_offset_t dma_va; /* Viritual address for transfer */ + vm_offset_t req_va; /* Original request va */ + int req_size; /* Request size */ + int mode; /* Mode register value and direction */ + int sc_active; /* Active flag */ + char **sc_dmaaddr; /* Pointer to dma address in dev */ + int *sc_dmalen; /* Pointer to len counter in dev */ +} dma_softc_t; + +#define DMA_TO_DEV 0 +#define DMA_FROM_DEV 1 + +#define DMA_CH0 0 +#define DMA_CH1 1 + +#define DMA_RESET(r) +#if 0 +#define DMA_START(a, b, c, d) \ + { \ + int dcmd; \ + int xcmd; \ + int pa; \ + int sz; \ + if((vm_offset_t)(b) < VM_MIN_KERNEL_ADDRESS) { \ + pa = CACHED_TO_PHYS(b); \ + } \ + else { \ + pa = pmap_extract(vm_map_pmap(phys_map), (vm_offset_t)(b));\ + } \ + sz = c; \ + if(sz + (pa & (NBPG - 1)) > NBPG) { \ + sz = NBPG - (pa & (NBPG - 1)); \ + } \ + dcmd = ((d) == DMA_FROM_DEV) ? 0x30 : 0x10; \ + if((a)->dma_ch == DMA_CH0) { \ + out32(R3715_DMA_ADR0, pa); \ + out32(R3715_DMA_CNT0, sz - 1); \ + xcmd = ~0x30; \ + } \ + else { \ + out32(R3715_DMA_ADR1, pa); \ + out32(R3715_DMA_CNT1, sz - 1); \ + dcmd = dcmd << 6; \ + xcmd = ~(0x30 << 6); \ + } \ + dcmd |= (1 << 26); \ + out32(R3715_IO_TIMING, (in32(R3715_IO_TIMING) & xcmd) | dcmd);\ + } +#else +#define DMA_START(a, b, c, d) \ + { \ + int dcmd; \ + int xcmd; \ + int pa; \ + int sz; \ + pa = CACHED_TO_PHYS(dma_buffer); \ + (a)->req_va = (vm_offset_t)(b); \ + (a)->req_size = c; \ + (a)->mode = d; \ + sz = c; \ + if((d) == DMA_TO_DEV) { \ + int *_p = (int *)PHYS_TO_UNCACHED(pa); \ + int *_v = (int *)b; \ + int _n = sz; \ + while(_n > 0) { \ + *_p = htonl(*_v); \ + _p++; _v++; _n -= 4; \ + } \ + } \ + dcmd = ((d) == DMA_FROM_DEV) ? 0x30 : 0x10; \ + if((a)->dma_ch == DMA_CH0) { \ + out32(R3715_DMA_ADR0, pa); \ + out32(R3715_DMA_CNT0, sz - 1); \ + xcmd = ~0x30; \ + } \ + else { \ + out32(R3715_DMA_ADR1, pa); \ + out32(R3715_DMA_CNT1, sz - 1); \ + dcmd = dcmd << 6; \ + xcmd = ~(0x30 << 6); \ + } \ + dcmd |= (1 << 26); \ + out32(R3715_IO_TIMING, (in32(R3715_IO_TIMING) & xcmd) | dcmd);\ + } +#endif +#define DMA_MAP(a, b, c, d) +#define DMA_INTR(r) +#define DMA_DRAIN(r) +#define DMA_END(c) \ + { \ + int dcmd; \ + dcmd = ((c)->dma_ch == DMA_CH0) ? 0x10 : 0x10000; \ + out32(R3715_IO_TIMING, in32(R3715_IO_TIMING) & ~dcmd); \ + if((c)->mode == DMA_FROM_DEV) { \ + int *_v = (int *)(c)->req_va; \ + int *_p = (int *)PHYS_TO_UNCACHED(CACHED_TO_PHYS(dma_buffer)); \ + int _n = (c)->req_size; \ + while(_n > 0) { \ + *_v = htonl(*_p); \ + _p++; _v++; _n -= 4; \ + } \ + } \ + } diff --git a/sys/arch/wgrisc/dev/if_sn.c b/sys/arch/wgrisc/dev/if_sn.c new file mode 100644 index 00000000000..b31ed2e0911 --- /dev/null +++ b/sys/arch/wgrisc/dev/if_sn.c @@ -0,0 +1,1288 @@ +/* $OpenBSD: if_sn.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* + * National Semiconductor SONIC Driver + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + * + * This driver has been substantially modified since Algorithmics donated + * it. + */ + +#include "sn.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/buf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <machine/autoconf.h> + +#include <net/if.h> +#include <net/netisr.h> +#include <net/route.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#endif + +#include <vm/vm.h> + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#define SONICDW 32 +typedef unsigned char uchar; + +#include <wgrisc/dev/if_sn.h> +#define SWR(a, x) (a) = (x) +#define SRD(a) ((a) & 0xffff) + +#include <machine/cpu.h> +#include <wgrisc/riscbus/riscbus.h> + +/* + * Statistics collected over time + */ +struct sn_stats { + int ls_opacks; /* packets transmitted */ + int ls_ipacks; /* packets received */ + int ls_tdr; /* contents of tdr after collision */ + int ls_tdef; /* packets where had to wait */ + int ls_tone; /* packets with one retry */ + int ls_tmore; /* packets with more than one retry */ + int ls_tbuff; /* transmit buff errors */ + int ls_tuflo; /* " uflo " */ + int ls_tlcol; + int ls_tlcar; + int ls_trtry; + int ls_rbuff; /* receive buff errors */ + int ls_rfram; /* framing */ + int ls_roflo; /* overflow */ + int ls_rcrc; + int ls_rrng; /* rx ring sequence error */ + int ls_babl; /* chip babl error */ + int ls_cerr; /* collision error */ + int ls_miss; /* missed packet */ + int ls_merr; /* memory error */ + int ls_copies; /* copies due to out of range mbufs */ + int ls_maxmbufs; /* max mbufs on transmit */ + int ls_maxslots; /* max ring slots on transmit */ +}; + +struct sn_softc { + struct device sc_dev; + struct arpcom sc_ac; +#define sc_if sc_ac.ac_if /* network visible interface */ +#define sc_enaddr sc_ac.ac_enaddr /* hardware ethernet address */ + + struct sonic_reg *sc_csr; /* hardware pointer */ + int sc_rxmark; /* position in rx ring for reading buffs */ + + int sc_rramark; /* index into rra of wp */ + + int sc_txhead; /* index of first TDA passed to chip */ + int sc_missed; /* missed packet counter */ + struct RXpkt *sc_lrxp; /* last RDA available to chip */ + struct sn_stats sc_sum; + short sc_iflags; +} sn_softc; + +int snmatch __P((struct device *, void *, void *)); +void snattach __P((struct device *, struct device *, void *)); + +struct cfattach sn_ca = { + sizeof(struct sn_softc), snmatch, snattach +}; +struct cfdriver sn_cd = { + NULL, "sn", DV_IFNET, NULL, 0 +}; + +#undef assert +#undef _assert + +#ifdef NDEBUG +#define assert(e) ((void)0) +#define _assert(e) ((void)0) +#else +#define _assert(e) assert(e) +#ifdef __STDC__ +#define assert(e) ((e) ? (void)0 : __assert("sn ", __FILE__, __LINE__, #e)) +#else /* PCC */ +#define assert(e) ((e) ? (void)0 : __assert("sn "__FILE__, __LINE__, "e")) +#endif +#endif + +void +m_check(m) + struct mbuf *m; +{ + if (m->m_flags & M_EXT) { + assert(m->m_len >= 0); + assert(m->m_len <= m->m_ext.ext_size); + assert(m->m_data >= &m->m_ext.ext_buf[0]); + assert(m->m_data <= &m->m_ext.ext_buf[m->m_ext.ext_size]); + assert(m->m_data + m->m_len <= &m->m_ext.ext_buf[m->m_ext.ext_size]); + } else if (m->m_flags & M_PKTHDR) { + assert(m->m_len >= 0); + assert(m->m_len <= MHLEN); + assert(m->m_data >= m->m_pktdat); + assert(m->m_data <= &m->m_pktdat[MHLEN]); + assert(m->m_data + m->m_len <= &m->m_pktdat[MHLEN]); + } else { + assert(m->m_len >= 0); + assert(m->m_len <= MLEN); + assert(m->m_data >= m->m_dat); + assert(m->m_data <= &m->m_dat[MLEN]); + assert(m->m_data + m->m_len <= &m->m_dat[MLEN]); + } +} + +void +m_checkm(m) + struct mbuf *m; +{ + while (m) { + m_check(m); + m = m->m_next; + } +} + +int ethdebug = 0; + +int snintr __P((struct sn_softc *)); +int snioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data)); +void snstart __P((struct ifnet *ifp)); +void snwatchdog __P((struct ifnet *ifp)); +void snreset __P((struct sn_softc *sc)); + +/* + * SONIC buffers need to be aligned 16 or 32 bit aligned. + * These macros calculate and verify alignment. + */ +#if SONICDW == 32 +#define SONICALIGN 4 +#else +#define SONICALIGN 2 +#endif +#define SOALIGN(array) (((int)array+SONICALIGN-1) & ~(SONICALIGN-1)) +#define SOALIGNED(p) (!(((uint)p)&(SONICALIGN-1))) + +#define UPPER(x) ((unsigned)(x) >> 16) +#define LOWER(x) ((unsigned)(x) & 0xffff) + +#define NRRA 32 /* # receive resource descriptors */ +#define RRAMASK 0x1f /* why it must be poer of two */ + +#define NRBA 16 /* # receive buffers < NRRA */ +#define NRDA NRBA /* # receive descriptors */ +#define NTDA 4 /* # transmit descriptors */ + +#define CDASIZE sizeof(struct CDA) +#define RRASIZE (NRRA*sizeof(struct RXrsrc)) +#define RDASIZE (NRDA*sizeof(struct RXpkt)) +#define TDASIZE (NTDA*sizeof(struct TXpkt)) + +#define FCSSIZE 4 /* size of FCS append te received packets */ + +/* + * maximum recieve packet size plus 2 byte pad to make each + * one aligned. 4 byte slop (required for eobc) + */ +#define RBASIZE (sizeof(struct ether_header) + ETHERMTU + FCSSIZE + 2 + 4) + +/* + * space requiered for descriptors + */ +#define DESC_SIZE (RRASIZE + CDASIZE + RDASIZE + TDASIZE + SONICALIGN - 1) + +/* + * Nicely aligned pointers into the sonicbuffers + * p_ points at physical (K1_SEG) addresses. + * v_ is sonic local address used by sonic. + */ +struct RXrsrc *p_rra; /* receiver resource descriptors */ +struct RXrsrc *v_rra; +struct RXpkt *p_rda; /* receiver desriptors */ +struct RXpkt *v_rda; +struct TXpkt *p_tda; /* transmitter descriptors */ +struct TXpkt *v_tda; +struct CDA *p_cda; /* CAM descriptors */ +struct CDA *v_cda; +char *p_rba; /* receive buffer area base */ +char *v_rba; + +/* Meta transmit descriptors */ +struct mtd { + struct mtd *mtd_link; + struct TXpkt *mtd_txp; + struct mbuf *mtd_mbuf; +} mtda[NTDA]; + +struct mtd *mtdfree; /* list of free meta transmit descriptors */ +struct mtd *mtdhead; /* head of descriptors assigned to chip */ +struct mtd *mtdtail; /* tail of descriptors assigned to chip */ +struct mtd *mtdnext; /* next descriptor to give to chip */ + +void mtd_free __P((struct mtd *)); +struct mtd *mtd_alloc __P((void)); + +int sngetaddr __P((struct sn_softc *sc)); +int sninit __P((struct sn_softc *sc)); +int snstop __P((struct sn_softc *sc)); +int sonicput __P((struct sn_softc *sc, struct mbuf *m0)); + +void camdump __P((struct sn_softc *sc)); + +int +snmatch(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct cfdata *cf = match; + struct confargs *ca = aux; + + /* XXX CHECK BUS */ + /* make sure that we're looking for this type of device. */ + if (!BUS_MATCHNAME(ca, "sonic")) + return (0); + + return (1); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +void +snattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct sn_softc *sc = (void *)self; + struct confargs *ca = aux; + struct ifnet *ifp = &sc->sc_if; + struct cfdata *cf = sc->sc_dev.dv_cfdata; + int p, pp; + + sc->sc_csr = (struct sonic_reg *)BUS_CVTADDR(ca); + +/* + * because the sonic is basicly 16bit device it 'concatenates' + * a higher buffer address to a 16 bit offset this will cause wrap + * around problems near the end of 64k !! + */ + p = RISC_SONIC_SRAM; + pp = RISC_SONIC_SRAM - (FRAGMAX * NTDA * 4096); + + if ((p ^ (p + TDASIZE)) & 0x10000) + p = (p + 0x10000) & ~0xffff; + p_tda = (struct TXpkt *) p; + v_tda = (struct TXpkt *)(p - pp); + p += TDASIZE; + + if ((p ^ (p + RRASIZE + CDASIZE)) & 0x10000) + p = (p + 0x10000) & ~0xffff; + p_rra = (struct RXrsrc *) p; + v_rra = (struct RXrsrc *)(p - pp); + p += RRASIZE; + + if ((p ^ (p + RDASIZE)) & 0x10000) + p = (p + 0x10000) & ~0xffff; + p_rda = (struct RXpkt *) p; + v_rda = (struct RXpkt *)(p - pp); + p += RDASIZE; + + p_cda = (struct CDA *) p; + v_cda = (struct CDA *)(p - pp); + p += CDASIZE; + + p += 4096 - (p & (4095)); + p_rba = (char *)p; + v_rba = (char *)(p - pp); + p += NRBA * RBASIZE; + + printf(": bufsize %d",p - RISC_SONIC_SRAM); + +#if 0 + camdump(sc); +#endif + sngetaddr(sc); + printf(" address %s\n", ether_sprintf(sc->sc_enaddr)); + +#if 0 +printf("\nsonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n", + p_rra, p_cda, p_rda, p_tda, p_rba); +printf("sonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n", + v_rra, v_cda, v_rda, v_tda, v_rba); +printf("mapped to offset 0x%x size 0x%x\n", SONICBUF - pp, p - SONICBUF); +#endif + + BUS_INTR_ESTABLISH(ca, (intr_handler_t)snintr, (void *)sc); + + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_ioctl = snioctl; + ifp->if_start = snstart; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_watchdog = snwatchdog; +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + if_attach(ifp); + ether_ifattach(ifp); +} + +int +snioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct ifaddr *ifa; + struct sn_softc *sc = ifp->if_softc; + int s = splnet(), err = 0; + int temp; + int error; + + if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) { + splx(s); + return error; + } + + switch (cmd) { + + case SIOCSIFADDR: + ifa = (struct ifaddr *)data; + ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + (void)sninit(ifp->if_softc); + arp_ifinit(&sc->sc_ac, ifa); + break; +#endif + default: + (void)sninit(ifp->if_softc); + break; + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + ifp->if_flags & IFF_RUNNING) { + snstop(ifp->if_softc); + ifp->if_flags &= ~IFF_RUNNING; + } else if (ifp->if_flags & IFF_UP && + (ifp->if_flags & IFF_RUNNING) == 0) + (void)sninit(ifp->if_softc); + /* + * If the state of the promiscuous bit changes, the interface + * must be reset to effect the change. + */ + if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) && + (ifp->if_flags & IFF_RUNNING)) { + sc->sc_iflags = ifp->if_flags; + printf("change in flags\n"); + temp = sc->sc_if.if_flags & IFF_UP; + snreset(sc); + sc->sc_if.if_flags |= temp; + snstart(ifp); + } + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if(cmd == SIOCADDMULTI) + err = ether_addmulti((struct ifreq *)data, &sc->sc_ac); + else + err = ether_delmulti((struct ifreq *)data, &sc->sc_ac); + + if (err == ENETRESET) { + /* + * Multicast list has changed; set the hardware + * filter accordingly. But remember UP flag! + */ + temp = sc->sc_if.if_flags & IFF_UP; + snreset(sc); + sc->sc_if.if_flags |= temp; + err = 0; + } + break; + default: + err = EINVAL; + } + splx(s); + return (err); +} + +/* + * Encapsulate a packet of type family for the local net. + * Use trailer local net encapsulation if enough data in first + * packet leaves a multiple of 512 bytes of data in remainder. + */ +void +snstart(ifp) + struct ifnet *ifp; +{ + struct sn_softc *sc = ifp->if_softc; + struct mbuf *m; + int len; + + if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) + return; + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if (m == 0) + return; + + /* + * If there is nothing in the o/p queue, and there is room in + * the Tx ring, then send the packet directly. Otherwise append + * it to the o/p queue. + */ + if (!sonicput(sc, m)) { /* not enough space */ + IF_PREPEND(&sc->sc_if.if_snd, m); + } +#if NBPFILTER > 0 + /* + * If bpf is listening on this interface, let it + * see the packet before we commit it to the wire. + */ + if (sc->sc_if.if_bpf) + bpf_mtap(sc->sc_if.if_bpf, m); +#endif + + sc->sc_if.if_opackets++; /* # of pkts */ + sc->sc_sum.ls_opacks++; /* # of pkts */ +} + +/* + * This is called from sonicioctl() when /etc/ifconfig is run to set + * the address or switch the i/f on. + */ +void caminitialise __P((void)); +void camentry __P((int, u_char *ea)); +void camprogram __P((struct sn_softc *)); +void initialise_tda __P((struct sn_softc *)); +void initialise_rda __P((struct sn_softc *)); +void initialise_rra __P((struct sn_softc *)); + +/* + * reset and restart the SONIC. Called in case of fatal + * hardware/software errors. + */ +void +snreset(sc) + struct sn_softc *sc; +{ + snstop(sc); + sninit(sc); +} + +int +sninit(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + int s, error; + + if (sc->sc_if.if_flags & IFF_RUNNING) + /* already running */ + return (0); + + s = splnet(); + + csr->s_cr = CR_RST; /* s_dcr only accessable reset mode! */ + + /* config it */ + csr->s_dcr = DCR_LBR | DCR_SYNC | DCR_WAIT0 | DCR_DW32 | DCR_DMABLOCK | + DCR_RFT16 | DCR_TFT16; + csr->s_rcr = RCR_BRD | RCR_LBNONE; + csr->s_imr = IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_HBLEN | IMR_LCDEN; + + /* clear pending interrupts */ + csr->s_isr = 0x7fff; + + /* clear tally counters */ + csr->s_crct = -1; + csr->s_faet = -1; + csr->s_mpt = -1; + + initialise_tda(sc); + initialise_rda(sc); + initialise_rra(sc); + + /* enable the chip */ + csr->s_cr = 0; + wbflush(); + + /* program the CAM with our address */ + caminitialise(); + camentry(0, sc->sc_enaddr); + camprogram(sc); + + /* get it to read resource descriptors */ + csr->s_cr = CR_RRRA; + wbflush(); + while (csr->s_cr & CR_RRRA) + continue; + + /* enable rx */ + csr->s_cr = CR_RXEN; + wbflush(); + + /* flag interface as "running" */ + sc->sc_if.if_flags |= IFF_RUNNING; + + splx(s); + return (0); + +bad: + snstop(sc); + return (error); +} + +/* + * close down an interface and free its buffers + * Called on final close of device, or if sninit() fails + * part way through. + */ +int +snstop(sc) + struct sn_softc *sc; +{ + struct mtd *mtd; + int s = splnet(); + + /* stick chip in reset */ + sc->sc_csr->s_cr = CR_RST; + wbflush(); + + /* free all receive buffers (currently static so nothing to do) */ + + /* free all pending transmit mbufs */ + while (mtd = mtdhead) { + mtdhead = mtdhead->mtd_link; + if (mtd->mtd_mbuf) + m_freem(mtd->mtd_mbuf); + mtd->mtd_mbuf = 0; + mtd_free(mtd); + } + mtdnext = mtd_alloc(); + + sc->sc_if.if_timer = 0; + sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP); + + splx(s); + return (0); +} + +/* + * Called if any Tx packets remain unsent after 5 seconds, + * In all cases we just reset the chip, and any retransmission + * will be handled by higher level protocol timeouts. + */ +void +snwatchdog(ifp) + struct ifnet *ifp; +{ + struct sn_softc *sc = ifp->if_softc; + int temp; + + if (mtdhead && mtdhead->mtd_mbuf) { + /* something still pending for transmit */ + if (mtdhead->mtd_txp->status == 0) + log(LOG_ERR, "%s: Tx - timeout\n", + sc->sc_if.if_xname); + else + log(LOG_ERR, "%s: Tx - lost interrupt\n", + sc->sc_if.if_xname); + temp = sc->sc_if.if_flags & IFF_UP; + snreset(sc); + sc->sc_if.if_flags |= temp; + } +} +/* + * stuff packet into sonic (at splnet) +*/ +int +sonicput(sc, m0) + struct sn_softc *sc; + struct mbuf *m0; +{ + struct sonic_reg *csr = sc->sc_csr; + struct TXpkt *txp; + struct mtd *mtdnew; + struct mbuf *m; + int len = 0, fr = 0; + int i; + int fragoffset; /* Offset in viritual dma space for fragment */ + + /* grab the replacement mtd */ + if ((mtdnew = mtd_alloc()) == 0) + return (0); + + /* this packet goes to mdtnext fill in the TDA */ + mtdnext->mtd_mbuf = m0; + txp = mtdnext->mtd_txp; + SWR(txp->config, 0); + fragoffset = (txp - p_tda) * FRAGMAX * 4096; + + /* + * Now fill in the fragments. Each fragment maps to it's + * own dma page. Fragments crossing a dma page boundary + * are split up in two fragments. This is somewhat stupid + * because the dma mapper can do the work, but it helps + * keeping the fragments in order. (read lazy programmer). + */ + for (m = m0; m; m = m->m_next) { + unsigned va = (unsigned) mtod(m, caddr_t); + int resid = m->m_len; + +#if has_to_be_fixed + if(resid != 0) { + R4K_HitFlushDCache(va, resid); + } +#endif + len += resid; + + while (resid) { + unsigned pa; + unsigned n; + + pa = (va & PGOFSET) + fragoffset; + n = resid; + if (n > NBPG - (va & PGOFSET)) { + n = NBPG - (va & PGOFSET); + } + if (fr < FRAGMAX) { + SWR(txp->u[fr].frag_ptrlo, LOWER(pa)); + SWR(txp->u[fr].frag_ptrhi, UPPER(pa)); + SWR(txp->u[fr].frag_size, n); + } + fr++; + va += n; + resid -= n; + fragoffset += 4096; + } + } + /* + * pad out last fragment for minimum size + */ + if (len < ETHERMIN + sizeof(struct ether_header) && fr < FRAGMAX) { + int pad = ETHERMIN + sizeof(struct ether_header) - len; + static char zeros[64]; + unsigned pa; + + pa = ((unsigned)zeros & PGOFSET) + fragoffset; + SWR(txp->u[fr].frag_ptrlo, LOWER(pa)); + SWR(txp->u[fr].frag_ptrhi, UPPER(pa)); + SWR(txp->u[fr].frag_size, pad); + fr++; + len = ETHERMIN + sizeof(struct ether_header); + } + + if (fr > FRAGMAX) { + mtd_free(mtdnew); + m_freem(m0); + log(LOG_ERR, "%s: tx too many fragments %d\n", + sc->sc_if.if_xname, fr); + sc->sc_if.if_oerrors++; + return (len); + } + + SWR(txp->frag_count, fr); + SWR(txp->pkt_size, len); + + /* link onto the next mtd that will be used */ + SWR(txp->u[fr].tlink, LOWER(v_tda + (mtdnew->mtd_txp - p_tda)) | EOL); + + if (mtdhead == 0) { + /* no current transmit list start with this one */ + mtdtail = mtdhead = mtdnext; + csr->s_ctda = LOWER(v_tda + (txp - p_tda)); + } else { + /* + * have a transmit list append it to end note + * mtdnext is already physicaly linked to mtdtail in + * mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink + */ + SWR(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink, + SRD(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink) & ~EOL); + mtdtail = mtdnext; + } + mtdnext->mtd_link = mtdnew; + mtdnext = mtdnew; + + /* make sure chip is running */ + wbflush(); + csr->s_cr = CR_TXP; + wbflush(); + sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */ + return (len); +} + +/* + * Read out the ethernet address from the cam. It is stored + * there by the boot when doing a loopback test. Thus we don't + * have to fetch it from nv ram. + */ +int +sngetaddr(sc) + struct sn_softc *sc; +{ + unsigned i, x, y; + char *cp, *ea; + +#if 0 + sc->sc_csr->s_cr = CR_RST; + wbflush(); + sc->sc_csr->s_cep = 0; + i = sc->sc_csr->s_cap2; + wbflush(); + sc->sc_enaddr[5] = i >> 8; + sc->sc_enaddr[4] = i; + i = sc->sc_csr->s_cap1; + wbflush(); + sc->sc_enaddr[3] = i >> 8; + sc->sc_enaddr[2] = i; + i = sc->sc_csr->s_cap0; + wbflush(); + sc->sc_enaddr[1] = i >> 8; + sc->sc_enaddr[0] = i; + + sc->sc_csr->s_cr = 0; + wbflush(); +#else + sc->sc_enaddr[0] = 0x08; + sc->sc_enaddr[1] = 0x00; + sc->sc_enaddr[2] = 0x20; + sc->sc_enaddr[3] = 0xa0; + sc->sc_enaddr[4] = 0x66; + sc->sc_enaddr[5] = 0x54; +#endif + return (0); +} + +void sonictxint __P((struct sn_softc *)); +void sonicrxint __P((struct sn_softc *)); + +int sonic_read __P((struct sn_softc *, struct RXpkt *)); +struct mbuf *sonic_get __P((struct sn_softc *, struct ether_header *, int)); + +void +mtd_free(mtd) + struct mtd *mtd; +{ + mtd->mtd_link = mtdfree; + mtdfree = mtd; +} + +struct mtd * +mtd_alloc() +{ + struct mtd *mtd = mtdfree; + + if (mtd) { + mtdfree = mtd->mtd_link; + mtd->mtd_link = 0; + } + return (mtd); +} + +/* + * CAM support + */ +void +caminitialise() +{ + int i; + + for (i = 0; i < MAXCAM; i++) + SWR(p_cda->desc[i].cam_ep, i); + SWR(p_cda->enable, 0); +} + +void +camentry(entry, ea) + int entry; + u_char *ea; +{ + SWR(p_cda->desc[entry].cam_ep, entry); + SWR(p_cda->desc[entry].cam_ap2, (ea[5] << 8) | ea[4]); + SWR(p_cda->desc[entry].cam_ap1, (ea[3] << 8) | ea[2]); + SWR(p_cda->desc[entry].cam_ap0, (ea[1] << 8) | ea[0]); + SWR(p_cda->enable, SRD(p_cda->enable) | (1 << entry)); +} + +void +camprogram(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + int timeout; + int i; + + csr = sc->sc_csr; + csr->s_cdp = LOWER(v_cda); + csr->s_cdc = MAXCAM; + csr->s_cr = CR_LCAM; + wbflush(); + + timeout = 10000; + while (csr->s_cr & CR_LCAM && timeout--) + continue; + if (timeout == 0) { + /* XXX */ + panic("sonic: CAM initialisation failed\n"); + } + timeout = 10000; + while ((csr->s_isr & ISR_LCD) == 0 && timeout--) + continue; + + if (csr->s_isr & ISR_LCD) + csr->s_isr = ISR_LCD; + else + printf("sonic: CAM initialisation without interrupt\n"); +} + +#if 0 +void +camdump(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + int i; + + printf("CAM entries:\n"); + csr->s_cr = CR_RST; + wbflush(); + + for (i = 0; i < 16; i++) { + ushort ap2, ap1, ap0; + csr->s_cep = i; + wbflush(); + ap2 = csr->s_cap2; + ap1 = csr->s_cap1; + ap0 = csr->s_cap0; + printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0); + } + printf("CAM enable 0x%x\n", csr->s_cep); + + csr->s_cr = 0; + wbflush(); +} +#endif + +void +initialise_tda(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + struct mtd *mtd; + int i; + + csr = sc->sc_csr; + + mtdfree = mtdhead = mtdtail = (struct mtd *) 0; + + for (i = 0; i < NTDA; i++) { + mtd = &mtda[i]; + mtd->mtd_txp = &p_tda[i]; + mtd->mtd_mbuf = (struct mbuf *) 0; + mtd_free(mtd); + } + mtdnext = mtd_alloc(); + + csr->s_utda = UPPER(v_tda); +} + +void +initialise_rda(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + int i; + + csr = sc->sc_csr; + + /* link the RDA's together into a circular list */ + for (i = 0; i < (NRDA - 1); i++) { + SWR(p_rda[i].rlink, LOWER(&v_rda[i + 1])); + SWR(p_rda[i].in_use, 1); + } + SWR(p_rda[NRDA - 1].rlink, LOWER(&v_rda[0]) | EOL); + SWR(p_rda[NRDA - 1].in_use, 1); + + /* mark end of receive descriptor list */ + sc->sc_lrxp = &p_rda[NRDA - 1]; + + sc->sc_rxmark = 0; + + csr->s_urda = UPPER(&v_rda[0]); + csr->s_crda = LOWER(&v_rda[0]); + wbflush(); +} + +void +initialise_rra(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr; + int i; + + csr = sc->sc_csr; + + csr->s_eobc = RBASIZE / 2 - 2; /* must be >= MAXETHERPKT */ + csr->s_urra = UPPER(v_rra); + csr->s_rsa = LOWER(v_rra); + csr->s_rea = LOWER(&v_rra[NRRA]); + csr->s_rrp = LOWER(v_rra); + csr->s_rsc = 0; + + /* fill up SOME of the rra with buffers */ + for (i = 0; i < NRBA; i++) { + SWR(p_rra[i].buff_ptrhi, UPPER(&v_rba[i * RBASIZE])); + SWR(p_rra[i].buff_ptrlo, LOWER(&v_rba[i * RBASIZE])); + SWR(p_rra[i].buff_wchi, UPPER(RBASIZE / 2)); + SWR(p_rra[i].buff_wclo, LOWER(RBASIZE / 2)); + } + sc->sc_rramark = NRBA; + csr->s_rwp = LOWER(&v_rra[sc->sc_rramark]); + wbflush(); +} + +int +snintr(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + int isr; + + while (isr = (csr->s_isr & ISR_ALL)) { + /* scrub the interrupts that we are going to service */ + csr->s_isr = isr; + wbflush(); + + if (isr & (ISR_BR | ISR_LCD | ISR_PINT | ISR_TC)) + printf("sonic: unexpected interrupt status 0x%x\n", isr); + + if (isr & (ISR_TXDN | ISR_TXER)) + sonictxint(sc); + + if (isr & ISR_PKTRX) + sonicrxint(sc); + + if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) { + if (isr & ISR_HBL) + printf("sonic: no heartbeat\n"); + if (isr & ISR_RDE) + printf("sonic: receive descriptors exhausted\n"); + if (isr & ISR_RBE) + printf("sonic: receive buffers exhausted\n"); + if (isr & ISR_RBAE) + printf("sonic: receive buffer area exhausted\n"); + if (isr & ISR_RFO) + printf("sonic: receive FIFO overrun\n"); + } + if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) { +#ifdef notdef + if (isr & ISR_CRC) + sc->sc_crctally++; + if (isr & ISR_FAE) + sc->sc_faetally++; + if (isr & ISR_MP) + sc->sc_mptally++; +#endif + } + } + return (1); +} + +/* + * Transmit interrupt routine + */ +void +sonictxint(sc) + struct sn_softc *sc; +{ + struct TXpkt *txp; + struct sonic_reg *csr; + struct mtd *mtd; + + if (mtdhead == (struct mtd *) 0) + return; + + csr = sc->sc_csr; + + while (mtd = mtdhead) { + struct mbuf *m = mtd->mtd_mbuf; + + if (m == 0) + break; + + txp = mtd->mtd_txp; + + if (SRD(txp->status) == 0) /* it hasn't really gone yet */ + return; + + if (ethdebug) { + struct ether_header *eh = mtod(m, struct ether_header *); + printf("xmit status=0x%x len=%d type=0x%x from %s", + txp->status, + txp->pkt_size, + htons(eh->ether_type), + ether_sprintf(eh->ether_shost)); + printf(" (to %s)\n", ether_sprintf(eh->ether_dhost)); + } + m_freem(m); + mtd->mtd_mbuf = 0; + mtdhead = mtd->mtd_link; + + mtd_free(mtd); + + if ((SRD(txp->status) & TCR_PTX) == 0) { + printf("sonic: Tx packet status=0x%x\n", txp->status); + + if (mtdhead != mtdnext) { + printf("resubmitting remaining packets\n"); + csr->s_ctda = LOWER(v_tda + (mtdhead->mtd_txp - p_tda)); + csr->s_cr = CR_TXP; + wbflush(); + return; + } + } + } + /* mtdhead should be at mtdnext (go) */ + assert(mtdhead == mtdnext); + assert(mtdhead->mtd_link == 0); + mtdhead = 0; + + /* and start feeding any queued packets to chip */ + while (1) { + struct mbuf *m; + + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if (m == 0) /* nothing left to send */ + break; + if (!sonicput(sc, m)) { /* not enough space */ + IF_PREPEND(&sc->sc_if.if_snd, m); + break; + } + } +} + +/* + * Receive interrupt routine + */ +void +sonicrxint(sc) + struct sn_softc *sc; +{ + struct sonic_reg *csr = sc->sc_csr; + struct RXpkt *rxp; + u_long addr; + int orra; + + rxp = &p_rda[sc->sc_rxmark]; + + while (SRD(rxp->in_use) == 0) { + unsigned status = SRD(rxp->status); + if ((status & RCR_LPKT) == 0) + printf("sonic: more than one packet in RBA!\n"); + assert(PSNSEQ(SRD(rxp->seq_no)) == 0); + + if (status & RCR_PRX) { + if (sonic_read(sc, rxp)) { + sc->sc_if.if_ipackets++; + sc->sc_sum.ls_ipacks++; + sc->sc_missed = 0; + } + } else + sc->sc_if.if_ierrors++; + + /* + * give receive buffer area back to chip XXX what buffer + * did the sonic use for this descriptor answer look at + * the rba sequence number !! + */ + orra = RBASEQ(SRD(rxp->seq_no)) & RRAMASK; + + assert(SRD(rxp->pkt_ptrhi) == SRD(p_rra[orra].buff_ptrhi)); + assert(SRD(rxp->pkt_ptrlo) == SRD(p_rra[orra].buff_ptrlo)); +if(SRD(rxp->pkt_ptrlo) != SRD(p_rra[orra].buff_ptrlo)) +printf("%x,%x\n",SRD(rxp->pkt_ptrlo),SRD(p_rra[orra].buff_ptrlo)); + assert(SRD(p_rra[orra].buff_wclo)); + + /* + * orra is now empty of packets and can be freed if + * sonic read didnt copy it out then we would have to + * wait !! + * (dont bother add it back in again straight away) + */ + p_rra[sc->sc_rramark] = p_rra[orra]; + + /* zap old rra for fun */ + p_rra[orra].buff_wchi = 0; + p_rra[orra].buff_wclo = 0; + + sc->sc_rramark = (sc->sc_rramark + 1) & RRAMASK; + csr->s_rwp = LOWER(&v_rra[sc->sc_rramark]); + wbflush(); + + /* + * give recieve descriptor back to chip simple + * list is circular + */ + SWR(rxp->in_use, 1); + SWR(rxp->rlink, SRD(rxp->rlink) | EOL); + SWR(sc->sc_lrxp->rlink, SRD(sc->sc_lrxp->rlink) & ~EOL); + sc->sc_lrxp = rxp; + + if (++sc->sc_rxmark >= NRDA) + sc->sc_rxmark = 0; + rxp = &p_rda[sc->sc_rxmark]; + } +} + +/* + * sonic_read -- pull packet off interface and forward to + * appropriate protocol handler + */ +int +sonic_read(sc, rxp) + struct sn_softc *sc; + struct RXpkt *rxp; +{ + struct ifnet *ifp = &sc->sc_if; + /*extern char *ether_sprintf();*/ + struct ether_header *et; + struct mbuf *m; + int len, off, i; + caddr_t pkt; + + /* + * Get input data length. + * Get pointer to ethernet header (in input buffer). + * Deal with trailer protocol: if type is PUP trailer + * get true type from first 16-bit word past data. + * Remember that type was trailer by setting off. + */ + + len = SRD(rxp->byte_count) - sizeof(struct ether_header) - FCSSIZE; + pkt = (caddr_t)((SRD(rxp->pkt_ptrhi) << 16) | SRD(rxp->pkt_ptrlo)); + pkt = pkt - v_rba + p_rba; + et = (struct ether_header *)pkt; + + if (ethdebug) { + printf("rcvd 0x%x status=0x%x, len=%d type=0x%x from %s", + et, rxp->status, len, htons(et->ether_type), + ether_sprintf(et->ether_shost)); + printf(" (to %s)\n", ether_sprintf(et->ether_dhost)); + } + if (len < ETHERMIN || len > ETHERMTU) { + printf("sonic: invalid packet length %d bytes\n", len); + return (0); + } + +#if NBPFILTER > 0 + /* + * Check if there's a bpf filter listening on this interface. + * If so, hand off the raw packet to enet, then discard things + * not destined for us (but be sure to keep broadcast/multicast). + */ + if (sc->sc_if.if_bpf) { + bpf_tap(sc->sc_if.if_bpf, pkt, + len + sizeof(struct ether_header)); + if ((ifp->if_flags & IFF_PROMISC) != 0 && + (et->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ + bcmp(et->ether_dhost, sc->sc_enaddr, + sizeof(et->ether_dhost)) != 0) + return; + } +#endif + m = sonic_get(sc, et, len); + if (m == NULL) + return (0); + ether_input(ifp, et, m); + return(1); +} + +#define sonicdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) + +/* + * munge the recieved packet into an mbuf chain + * because we are using stupif buffer management this + * is slow. +*/ +struct mbuf * +sonic_get(sc, eh, datalen) + struct sn_softc *sc; + struct ether_header *eh; + int datalen; +{ + struct mbuf *m; + struct mbuf *top = 0, **mp = ⊤ + int len; + char *spkt = sonicdataaddr(eh, 0, caddr_t); + char *epkt = spkt + datalen; + char *cp = spkt; + + epkt = cp + datalen; + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = &sc->sc_if; + m->m_pkthdr.len = datalen; + m->m_len = MHLEN; + + while (datalen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + m->m_len = MLEN; + } + len = min(datalen, epkt - cp); + if (len >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = len = min(len, MCLBYTES); + else + len = m->m_len; + } else { + /* + * Place initial small packet/header at end of mbuf. + */ + if (len < m->m_len) { + if (top == 0 && len + max_linkhdr <= m->m_len) + m->m_data += max_linkhdr; + m->m_len = len; + } else + len = m->m_len; + } + bcopy(cp, mtod(m, caddr_t), (unsigned) len); + cp += len; + *mp = m; + mp = &m->m_next; + datalen -= len; + if (cp == epkt) + cp = spkt; + } + return (top); +} diff --git a/sys/arch/wgrisc/dev/if_sn.h b/sys/arch/wgrisc/dev/if_sn.h new file mode 100644 index 00000000000..4139a1c7850 --- /dev/null +++ b/sys/arch/wgrisc/dev/if_sn.h @@ -0,0 +1,347 @@ +/* $OpenBSD: if_sn.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + */ + +/* + * if_sonic.h -- National Semiconductor DP83932BVF (SONIC) + */ + +/* + * Accessing SONIC data structures and registers as 32 bit values + * makes code endianess independent. The SONIC is however always in + * bigendian mode so it is necessary to ensure that data structures shared + * between the CPU and the SONIC are always in bigendian order. + */ + +/* + * Receive Resource Descriptor + * This structure describes the buffers into which packets + * will be received. Note that more than one packet may be + * packed into a single buffer if constraints permit. + */ +#if SONICDW == 32 +struct RXrsrc { + u_long buff_ptrlo; /* buffer address LO */ + u_long buff_ptrhi; /* buffer address HI */ + u_long buff_wclo; /* buffer size (16bit words) LO */ + u_long buff_wchi; /* buffer size (16bit words) HI */ +}; +#endif + +/* + * Receive Descriptor + * This structure holds information about packets received. + */ +#if SONICDW == 32 +struct RXpkt { + u_long status; /* + receive status */ + u_long byte_count; /* + packet byte count (including FCS) */ + u_long pkt_ptrlo; /* + packet data LO (in RBA) */ + u_long pkt_ptrhi; /* + packet data HI (in RBA) */ + u_long seq_no; /* + RBA sequence numbers */ + u_long rlink; /* link to next receive descriptor */ + u_long in_use; /* + packet available to SONIC */ + u_long pad; /* pad to multiple of 16 bytes */ +}; +#endif +#define RBASEQ(x) (((x)>>8)&0xff) +#define PSNSEQ(x) ((x) & 0xff) + +/* + * Transmit Descriptor + * This structure holds information about packets to be transmitted. + */ +#define FRAGMAX 31 /* maximum number of fragments in a packet */ +#if SONICDW == 32 +struct TXpkt { + u_long status; /* + transmitted packet status */ + u_long config; /* transmission configuration */ + u_long pkt_size; /* entire packet size in bytes */ + u_long frag_count; /* # fragments in packet */ + union { + struct { + u_long _frag_ptrlo; /* pointer to packet fragment LO */ + u_long _frag_ptrhi; /* pointer to packet fragment HI */ + u_long _frag_size; /* fragment size */ + } u_frag; + struct { + u_long _tlink; /* link to next transmit descriptor */ + } u_link; + } u[FRAGMAX+1]; /* +1 makes tcp->u[FRAGMAX].u_link.link valid! */ +}; +#endif + +#define frag_ptrlo u_frag._frag_ptrlo +#define frag_ptrhi u_frag._frag_ptrhi +#define frag_size u_frag._frag_size +#define tlink u_link._tlink + +#define EOL 0x0001 /* end of list marker for link fields */ + +#define MAXCAM 16 /* number of user entries in CAM */ +#if SONICDW == 32 +struct CDA { + struct { + u_long cam_ep; /* CAM Entry Pointer */ + u_long cam_ap0; /* CAM Address Port 0 xx-xx-xx-xx-YY-YY */ + u_long cam_ap1; /* CAM Address Port 1 xx-xx-YY-YY-xxxx */ + u_long cam_ap2; /* CAM Address Port 2 YY-YY-xx-xx-xx-xx */ + } desc[MAXCAM]; + u_long enable; /* mask enabling CAM entries */ +}; +#endif + +/* + * SONIC registers as seen by the processor + */ +struct sonic_reg { + volatile u_long s_cr; /* 00: Command */ + volatile u_long s_dcr; /* 01: Data Configuration */ + volatile u_long s_rcr; /* 02: Receive Control */ + volatile u_long s_tcr; /* 03: Transmit Control */ + volatile u_long s_imr; /* 04: Interrupt Mask */ + volatile u_long s_isr; /* 05: Interrupt Status */ + volatile u_long s_utda; /* 06: Upper Transmit Descriptor Address */ + volatile u_long s_ctda; /* 07: Current Transmit Descriptor Address */ + volatile u_long _s_tps; /* 08* Transmit Packet Size */ + volatile u_long _s_tfc; /* 09* Transmit Fragment Count */ + volatile u_long _s_tsa0; /* 0a* Transmit Start Address 0 */ + volatile u_long _s_tsa1; /* 0b* Transmit Start Address 1 */ + volatile u_long _s_tfs; /* 0c* Transmit Fragment Size */ + volatile u_long s_urda; /* 0d: Upper Receive Descriptor Address */ + volatile u_long s_crda; /* 0e: Current Receive Descriptor Address */ + volatile u_long _s_crba0; /* 0f* Current Receive Buffer Address 0 */ + volatile u_long _s_crba1; /* 10* Current Receive Buffer Address 1 */ + volatile u_long _s_rbwc0; /* 11* Remaining Buffer Word Count 0 */ + volatile u_long _s_rbwc1; /* 12* Remaining Buffer Word Count 1 */ + volatile u_long s_eobc; /* 13: End Of Buffer Word Count */ + volatile u_long s_urra; /* 14: Upper Receive Resource Address */ + volatile u_long s_rsa; /* 15: Resource Start Address */ + volatile u_long s_rea; /* 16: Resource End Address */ + volatile u_long s_rrp; /* 17: Resource Read Pointer */ + volatile u_long s_rwp; /* 18: Resource Write Pointer */ + volatile u_long _s_trba0; /* 19* Temporary Receive Buffer Address 0 */ + volatile u_long _s_trba1; /* 1a* Temporary Receive Buffer Address 1 */ + volatile u_long _s_tbwc0; /* 1b* Temporary Buffer Word Count 0 */ + volatile u_long _s_tbwc1; /* 1c* Temporary Buffer Word Count 1 */ + volatile u_long _s_addr0; /* 1d* Address Generator 0 */ + volatile u_long _s_addr1; /* 1e* Address Generator 1 */ + volatile u_long _s_llfa; /* 1f* Last Link Field Address */ + volatile u_long _s_ttda; /* 20* Temp Transmit Descriptor Address */ + volatile u_long s_cep; /* 21: CAM Entry Pointer */ + volatile u_long s_cap2; /* 22: CAM Address Port 2 */ + volatile u_long s_cap1; /* 23: CAM Address Port 1 */ + volatile u_long s_cap0; /* 24: CAM Address Port 0 */ + volatile u_long s_ce; /* 25: CAM Enable */ + volatile u_long s_cdp; /* 26: CAM Descriptor Pointer */ + volatile u_long s_cdc; /* 27: CAM Descriptor Count */ + volatile u_long s_sr; /* 28: Silicon Revision */ + volatile u_long s_wt0; /* 29: Watchdog Timer 0 */ + volatile u_long s_wt1; /* 2a: Watchdog Timer 1 */ + volatile u_long s_rsc; /* 2b: Receive Sequence Counter */ + volatile u_long s_crct; /* 2c: CRC Error Tally */ + volatile u_long s_faet; /* 2d: FAE Tally */ + volatile u_long s_mpt; /* 2e: Missed Packet Tally */ + volatile u_long _s_mdt; /* 2f* Maximum Deferral Timer */ + volatile u_long _s_rtc; /* 30* Receive Test Control */ + volatile u_long _s_ttc; /* 31* Transmit Test Control */ + volatile u_long _s_dtc; /* 32* DMA Test Control */ + volatile u_long _s_cc0; /* 33* CAM Comparison 0 */ + volatile u_long _s_cc1; /* 34* CAM Comparison 1 */ + volatile u_long _s_cc2; /* 35* CAM Comparison 2 */ + volatile u_long _s_cm; /* 36* CAM Match */ + volatile u_long :32; /* 37* reserved */ + volatile u_long :32; /* 38* reserved */ + volatile u_long _s_rbc; /* 39* Receiver Byte Count */ + volatile u_long :32; /* 3a* reserved */ + volatile u_long _s_tbo; /* 3b* Transmitter Backoff Counter */ + volatile u_long _s_trc; /* 3c* Transmitter Random Counter */ + volatile u_long _s_tbm; /* 3d* Transmitter Backoff Mask */ + volatile u_long :32; /* 3e* Reserved */ + volatile u_long s_dcr2; /* 3f Data Configuration 2 (AVF) */ +}; + +/* + * Register Interpretations + */ + +/* + * The command register is used for issuing commands to the SONIC. + * With the exception of CR_RST, the bit is reset when the operation + * completes. + */ +#define CR_LCAM 0x0200 /* load CAM with descriptor at s_cdp */ +#define CR_RRRA 0x0100 /* read next RRA descriptor at s_rrp */ +#define CR_RST 0x0080 /* software reset */ +#define CR_ST 0x0020 /* start timer */ +#define CR_STP 0x0010 /* stop timer */ +#define CR_RXEN 0x0008 /* receiver enable */ +#define CR_RXDIS 0x0004 /* receiver disable */ +#define CR_TXP 0x0002 /* transmit packets */ +#define CR_HTX 0x0001 /* halt transmission */ + +/* + * The data configuration register establishes the SONIC's bus cycle + * operation. This register can only be accessed when the SONIC is in + * reset mode (s_cr.CR_RST is set.) + */ +#define DCR_EXBUS 0x8000 /* extended bus mode (AVF) */ +#define DCR_LBR 0x2000 /* latched bus retry */ +#define DCR_PO1 0x1000 /* programmable output 1 */ +#define DCR_PO0 0x0800 /* programmable output 0 */ +#define DCR_STERM 0x0400 /* synchronous termination */ +#define DCR_USR1 0x0200 /* reflects USR1 input pin */ +#define DCR_USR0 0x0100 /* reflects USR0 input pin */ +#define DCR_WC1 0x0080 /* wait state control 1 */ +#define DCR_WC0 0x0040 /* wait state control 0 */ +#define DCR_DW 0x0020 /* data width select */ +#define DCR_BMS 0x0010 /* DMA block mode select */ +#define DCR_RFT1 0x0008 /* receive FIFO threshold control 1 */ +#define DCR_RFT0 0x0004 /* receive FIFO threshold control 0 */ +#define DCR_TFT1 0x0002 /* transmit FIFO threshold control 1 */ +#define DCR_TFT0 0x0001 /* transmit FIFO threshold control 0 */ + +/* data configuration register aliases */ +#define DCR_SYNC DCR_STERM /* synchronous (memory cycle 2 clocks) */ +#define DCR_ASYNC 0 /* asynchronous (memory cycle 3 clocks) */ + +#define DCR_WAIT0 0 /* 0 wait states added */ +#define DCR_WAIT1 DCR_WC0 /* 1 wait state added */ +#define DCR_WAIT2 DCR_WC1 /* 2 wait states added */ +#define DCR_WAIT3 (DCR_WC1|DCR_WC0) /* 3 wait states added */ + +#define DCR_DW16 0 /* use 16-bit DMA accesses */ +#define DCR_DW32 DCR_DW /* use 32-bit DMA accesses */ + +#define DCR_DMAEF 0 /* DMA until TX/RX FIFO has emptied/filled */ +#define DCR_DMABLOCK DCR_BMS /* DMA until RX/TX threshold crossed */ + +#define DCR_RFT4 0 /* receive threshold 4 bytes */ +#define DCR_RFT8 DCR_RFT0 /* receive threshold 8 bytes */ +#define DCR_RFT16 DCR_RFT1 /* receive threshold 16 bytes */ +#define DCR_RFT24 (DCR_RFT1|DCR_RFT0) /* receive threshold 24 bytes */ + +#define DCR_TFT8 0 /* transmit threshold 8 bytes */ +#define DCR_TFT16 DCR_TFT0 /* transmit threshold 16 bytes */ +#define DCR_TFT24 DCR_TFT1 /* transmit threshold 24 bytes */ +#define DCR_TFT28 (DCR_TFT1|DCR_TFT0) /* transmit threshold 28 bytes */ + +/* + * The receive control register is used to filter incoming packets and + * provides status information on packets received. + * The contents of the register are copied into the RXpkt.status field + * when a packet is received. RCR_MC - RCR_PRX are then reset. + */ +#define RCR_ERR 0x8000 /* accept packets with CRC errors */ +#define RCR_RNT 0x4000 /* accept runt (length < 64) packets */ +#define RCR_BRD 0x2000 /* accept broadcast packets */ +#define RCR_PRO 0x1000 /* accept all physical address packets */ +#define RCR_AMC 0x0800 /* accept all multicast packets */ +#define RCR_LB1 0x0400 /* loopback control 1 */ +#define RCR_LB0 0x0200 /* loopback control 0 */ +#define RCR_MC 0x0100 /* multicast packet received */ +#define RCR_BC 0x0080 /* broadcast packet received */ +#define RCR_LPKT 0x0040 /* last packet in RBA (RBWC < EOBC) */ +#define RCR_CRS 0x0020 /* carrier sense activity */ +#define RCR_COL 0x0010 /* collision activity */ +#define RCR_CRC 0x0008 /* CRC error */ +#define RCR_FAE 0x0004 /* frame alignment error */ +#define RCR_LBK 0x0002 /* loopback packet received */ +#define RCR_PRX 0x0001 /* packet received without errors */ + +/* receiver control register aliases */ +/* the loopback control bits provide the following options */ +#define RCR_LBNONE 0 /* no loopback - normal operation */ +#define RCR_LBMAC RCR_LB0 /* MAC loopback */ +#define RCR_LBENDEC RCR_LB1 /* ENDEC loopback */ +#define RCR_LBTRANS (RCR_LB1|RCR_LB0) /* transceiver loopback */ + +/* + * The transmit control register controls the SONIC's transmit operations. + * TCR_PINT - TCR_EXDIS are loaded from the TXpkt.config field at the + * start of transmission. TCR_EXD-TCR_PTX are cleared at the beginning + * of transmission and updated when the transmission is completed. + */ +#define TCR_PINT 0x8000 /* interrupt when transmission starts */ +#define TCR_POWC 0x4000 /* program out of window collision timer */ +#define TCR_CRCI 0x2000 /* transmit packet without 4 byte FCS */ +#define TCR_EXDIS 0x1000 /* disable excessive deferral timer */ +#define TCR_EXD 0x0400 /* excessive deferrals occurred (>3.2ms) */ +#define TCR_DEF 0x0200 /* deferred transmissions occurred */ +#define TCR_NCRS 0x0100 /* carrier not present during transmission */ +#define TCR_CRSL 0x0080 /* carrier lost during transmission */ +#define TCR_EXC 0x0040 /* excessive collisions (>16) detected */ +#define TCR_OWC 0x0020 /* out of window (bad) collision occurred */ +#define TCR_PMB 0x0008 /* packet monitored bad - the tansmitted + * packet had a bad source address or CRC */ +#define TCR_FU 0x0004 /* FIFO underrun (memory access failed) */ +#define TCR_BCM 0x0002 /* byte count mismatch (TXpkt.pkt_size + * != sum(TXpkt.frag_size) */ +#define TCR_PTX 0x0001 /* packet transmitted without errors */ + +/* transmit control register aliases */ +#define TCR_OWCSFD 0 /* start after start of frame delimiter */ +#define TCR_OWCPRE TCR_POWC /* start after first bit of preamble */ + + +/* + * The interrupt mask register masks the interrupts that + * are generated from the interrupt status register. + * All reserved bits should be written with 0. + */ +#define IMR_BREN 0x4000 /* bus retry occurred enable */ +#define IMR_HBLEN 0x2000 /* heartbeat lost enable */ +#define IMR_LCDEN 0x1000 /* load CAM done interrupt enable */ +#define IMR_PINTEN 0x0800 /* programmable interrupt enable */ +#define IMR_PRXEN 0x0400 /* packet received enable */ +#define IMR_PTXEN 0x0200 /* packet transmitted enable */ +#define IMR_TXEREN 0x0100 /* transmit error enable */ +#define IMR_TCEN 0x0080 /* timer complete enable */ +#define IMR_RDEEN 0x0040 /* receive descriptors exhausted enable */ +#define IMR_RBEEN 0x0020 /* receive buffers exhausted enable */ +#define IMR_RBAEEN 0x0010 /* receive buffer area exceeded enable */ +#define IMR_CRCEN 0x0008 /* CRC tally counter rollover enable */ +#define IMR_FAEEN 0x0004 /* FAE tally counter rollover enable */ +#define IMR_MPEN 0x0002 /* MP tally counter rollover enable */ +#define IMR_RFOEN 0x0001 /* receive FIFO overrun enable */ + + +/* + * The interrupt status register indicates the source of an interrupt when + * the INT pin goes active. The interrupt is acknowledged by writing + * the appropriate bit(s) in this register. + */ +#define ISR_ALL 0xffff /* all interrupts */ +#define ISR_BR 0x4000 /* bus retry occurred */ +#define ISR_HBL 0x2000 /* CD heartbeat lost */ +#define ISR_LCD 0x1000 /* load CAM command has completed */ +#define ISR_PINT 0x0800 /* programmed interrupt from TXpkt.config */ +#define ISR_PKTRX 0x0400 /* packet received */ +#define ISR_TXDN 0x0200 /* no remaining packets to be transmitted */ +#define ISR_TXER 0x0100 /* packet transmission caused error */ +#define ISR_TC 0x0080 /* timer complete */ +#define ISR_RDE 0x0040 /* receive descriptors exhausted */ +#define ISR_RBE 0x0020 /* receive buffers exhausted */ +#define ISR_RBAE 0x0010 /* receive buffer area exceeded */ +#define ISR_CRC 0x0008 /* CRC tally counter rollover */ +#define ISR_FAE 0x0004 /* FAE tally counter rollover */ +#define ISR_MP 0x0002 /* MP tally counter rollover */ +#define ISR_RFO 0x0001 /* receive FIFO overrun */ + +/* + * The second data configuration register allows additional user defined + * pins to be controlled. These bits are only available if s_dcr.DCR_EXBUS + * is set. + */ +#define DCR2_EXPO3 0x8000 /* EXUSR3 output */ +#define DCR2_EXPO2 0x4000 /* EXUSR2 output */ +#define DCR2_EXPO1 0x2000 /* EXUSR1 output */ +#define DCR2_EXPO0 0x1000 /* EXUSR0 output */ +#define DCR2_PHL 0x0010 /* extend HOLD signal by 1/2 clock */ +#define DCR2_LRDY 0x0008 /* set latched ready mode */ +#define DCR2_PCM 0x0004 /* packet compress on match */ +#define DCR2_PCNM 0x0002 /* packet compress on mismatch */ +#define DCR2_RJM 0x0001 /* reject on match */ diff --git a/sys/arch/wgrisc/dev/scsi.h b/sys/arch/wgrisc/dev/scsi.h new file mode 100644 index 00000000000..79f6886db9f --- /dev/null +++ b/sys/arch/wgrisc/dev/scsi.h @@ -0,0 +1,559 @@ +/* $OpenBSD: scsi.h,v 1.1 1997/02/06 16:02:41 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)scsi.h 8.1 (Berkeley) 6/10/93 + * $Id: scsi.h,v 1.1 1997/02/06 16:02:41 pefo Exp $ + * + * scsi.h -- + * + * Common declarations for SCSI command formaters. This file only covers + * definitions pertaining to the SCSI common command set that are + * common to all SCSI device types (ie disk, tapes, WORM, printers, etc). + * Some of the references from the proceedings of the + * 1984 Mini/Micro Northeast conference might help in understanding SCSI. + * + * from: Header: /sprite/src/kernel/dev/RCS/scsi.h, + * v 9.1 90/02/13 23:11:24 jhh Exp SPRITE (Berkeley) + * $Id: scsi.h,v 1.1 1997/02/06 16:02:41 pefo Exp $ + */ + +#ifndef _SCSI_H +#define _SCSI_H + +/* + * "Standard" SCSI Commands. + * SCSI commands are divided into 8 groups as follows: + * Group0 (0x00 - 0x1f). Basic commands. 6 bytes long + * Group1 (0x20 - 0x3f). Extended command. 10 bytes. + * Group2 (0x40 - 0x5f). Reserved. + * Group2 (0x60 - 0x7f). Reserved. + * Group2 (0x80 - 0x9f). Reserved. + * Group2 (0xa0 - 0xbf). Reserved. + * Group6 (0xc0 - 0xdf). Vendor Unique + * Group7 (0xe0 - 0xff). Vendor Unique + */ + +/* + * Scsi Group0 commands all are 6 bytes and have a format according to + * struct ScsiGroup0Cmd. + */ +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REZERO_UNIT 0x01 +#define SCSI_REWIND 0x01 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_FORMAT_UNIT 0x04 +#define SCSI_READ_BLOCK_LIMITS 0x05 +#define SCSI_REASSIGN_BLOCKS 0x07 +#define SCSI_READ 0x08 +#define SCSI_WRITE 0x0a +#define SCSI_SEEK 0x0b +#define SCSI_TRACK_SELECT 0x0b +#define SCSI_READ_REVERSE 0x0f +#define SCSI_WRITE_EOF 0x10 +#define SCSI_SPACE 0x11 +#define SCSI_INQUIRY 0x12 +#define SCSI_VERIFY 0x13 +#define SCSI_READ_BUFFER 0x14 +#define SCSI_MODE_SELECT 0x15 +#define SCSI_RESERVE_UNIT 0x16 +#define SCSI_RELEASE_UNIT 0x17 +#define SCSI_COPY 0x18 +#define SCSI_ERASE_TAPE 0x19 +#define SCSI_MODE_SENSE 0x1a +#define SCSI_START_STOP 0x1b +#define SCSI_LOAD_UNLOAD 0x1b +#define SCSI_RECV_DIAG_RESULTS 0x1c +#define SCSI_SEND_DIAGNOSTIC 0x1d +#define SCSI_PREVENT_ALLOW 0x1e + +/* + * Group1 commands are all 10 bytes and have a format according to + * struct ScsiGroup1Cmd. + */ +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_EXT 0x28 +#define SCSI_WRITE_EXT 0x2a +#define SCSI_SEEK_EXT 0x2b +#define SCSI_WRITE_VERIFY 0x2e +#define SCSI_VERIFY_EXT 0x2f +#define SCSI_SEARCH_HIGH 0x30 +#define SCSI_SEARCH_EQUAL 0x31 +#define SCSI_SEARCH_LOW 0x32 +#define SCSI_SET_LIMITS 0x33 +#define SCSI_COMPARE 0x39 +#define SCSI_COPY_VERIFY 0x3a + +/* + * Control byte flags for Group0 and Group1 commands. + * + * SCSI_CTRL_LINK - This is used to prevent a bus free phase between commands. + * If the command terminates successfully, a SCSI_LINKED_CMD_COMPLETE + * message is returned instead of the normal SCSI_COMMAND_COMPLETE message. * The last command in a chain should not have this bit set + * (and consequently gets a normal SCSI_COMMAND_COMPLETE message). + * SCSI_CTRL_LINK_FLAG - This bit should only set when SCSI_CTRL_LINK is set and + * causes a SCSI_LINKED_FLAGED_CMD_COMPLETE to be returned instead of + * a SCSI_LINKED_CMD_COMPLETE. + */ +#define SCSI_CTRL_LINK 0x01 /* Link commands (no bus free phase) */ +#define SCSI_CTRL_LINK_INTR 0x02 /* Interrupt after linked command */ + +/* + * The standard group0 6-byte SCSI control block. Note that the + * fields between highAddr and blockCount inclusive are command dependent. + * The definitions Addr and BlockCount cover most of the commands we will + * use. + */ +typedef struct ScsiGroup0Cmd { + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ +#if BYTE_ORDER == BIG_ENDIAN + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char highAddr :5; /* High bits of address */ +#else + u_char highAddr :5; /* High bits of address */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ +#endif + u_char midAddr; /* Middle bits of address */ + u_char lowAddr; /* Low bits of address */ + u_char blockCount; /* Blocks to transfer */ + u_char control; /* See flags for common bits */ +} ScsiGroup0Cmd; + +/* + * Format of a SCSI_START_STOP command. This is a group 0 command, but + * the command contents are different. + */ +typedef struct ScsiStartStopCmd { +#if BYTE_ORDER == BIG_ENDIAN + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char pad1 :4; /* Reserved */ + u_char immed :1; /* Immediate status bit */ + u_char pad2; /* Reserved */ + u_char pad3; /* Reserved */ + u_char pad4 :6; /* Reserved */ + u_char loadEject :1; /* Load or eject medium */ + u_char start :1; /* Start or stop medium */ + u_char control; /* See flags for common bits */ +#else + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ + u_char immed :1; /* Immediate status bit */ + u_char pad1 :4; /* Reserved */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char pad2; /* Reserved */ + u_char pad3; /* Reserved */ + u_char start :1; /* Start or stop medium */ + u_char loadEject :1; /* Load or eject medium */ + u_char pad4 :6; /* Reserved */ + u_char control; /* See flags for common bits */ +#endif +} ScsiStartStopCmd; + +/* + * The standard group1 10-byte SCSI control block. Note that the + * fields between highAddr and blockCount inclusive are command dependent. + * The definitions Addr and BlockCount cover most of the commands we will + * use. + */ +typedef struct ScsiGroup1Cmd { + u_char command; /* command code, defined below. The + * upper three bits of this are zero + * to indicate the control block is + * only 6 bytes long */ +#if BYTE_ORDER == BIG_ENDIAN + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ + u_char pad1 :5; /* Reserved */ +#else + u_char pad1 :5; /* Reserved */ + u_char unitNumber :3; /* Logical Unit (LUN) to which to + * pass the command. The device + * has already been selected using + * the "targetID" bit. */ +#endif + u_char highAddr; /* High bits of address */ + u_char midHighAddr; /* Middle high bits of address */ + u_char midLowAddr; /* Middle low bits of address */ + u_char lowAddr; /* Low bits of address */ + u_char pad2; /* Reserved */ + u_char highBlockCount; /* High bits of blocks to transfer */ + u_char lowBlockCount; /* Low bits of blocks to transfer */ + u_char control; /* See flags for common bits */ +} ScsiGroup1Cmd; + +/* + * SCSI status completion information. + * This is returned by the device when a command completes. + */ +#define SCSI_STATUS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */ +#define SCSI_STATUS_CONDMET 0x04 /* Condition Met (ie., search worked) */ +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMED 0x10 /* Intermediate status sent */ +#define SCSI_STATUS_EXT 0x80 /* Extended status valid */ + +/* + * Sense information provided after some errors. This is divided into + * two kinds, classes 0-6, and class 7. This is 30 bytes big to allow + * for the drive specific sense bytes that follow the standard 4 byte header. + * + * For extended sense, this buffer may be cast into another type. Also + * The actual size of the sense data returned is used to detect what + * kind of tape drive is out there. Kludgy, but true. + */ +typedef struct ScsiClass0Sense { +#if BYTE_ORDER == BIG_ENDIAN + u_char valid :1; /* Sense data is valid */ + u_char error :7; /* 3 bits class and 4 bits code */ +#else + u_char error :7; /* 3 bits class and 4 bits code */ + u_char valid :1; /* Sense data is valid */ +#endif + u_char highAddr; /* High byte of block address */ + u_char midAddr; /* Middle byte of block address */ + u_char lowAddr; /* Low byte of block address */ + u_char sense[26]; /* Target specific sense data */ +} ScsiClass0Sense; + +/* + * Definitions for errors in the sense data. The error field is specified + * as a 3 bit class and 4 bit code, but it is easier to treat it as a + * single 7 bit field. + */ +#define SCSI_NO_SENSE_DATA 0x00 +#define SCSI_NOT_READY 0x04 +#define SCSI_NOT_LOADED 0x09 +#define SCSI_INSUF_CAPACITY 0x0a +#define SCSI_HARD_DATA_ERROR 0x11 +#define SCSI_WRITE_PROTECT 0x17 +#define SCSI_CORRECTABLE_ERROR 0x18 +#define SCSI_FILE_MARK 0x1c +#define SCSI_INVALID_COMMAND 0x20 +#define SCSI_UNIT_ATTENTION 0x30 +#define SCSI_END_OF_MEDIA 0x34 + +/* + * The standard "extended" sense data returned by SCSI devices. This + * has an error field of 0x70, for a "class 7" error. + */ +typedef struct ScsiClass7Sense { +#if BYTE_ORDER == BIG_ENDIAN + u_char valid :1; /* Sense data is valid */ + u_char error7 :7; /* == 0x70 */ + u_char pad1; /* Also "segment number" for copy */ + u_char fileMark :1; /* File mark on device */ + u_char endOfMedia :1; /* End of media reached */ + u_char badBlockLen :1; /* Block length mis-match (Exabyte) */ + u_char pad2 :1; + u_char key :4; /* Sense keys defined below */ + u_char info1; /* Information byte 1 */ + u_char info2; /* Information byte 2 */ + u_char info3; /* Information byte 3 */ + u_char info4; /* Information byte 4 */ + u_char length; /* Number of additional info bytes */ +#else + u_char error7 :7; /* == 0x70 */ + u_char valid :1; /* Sense data is valid */ + u_char pad1; /* Also "segment number" for copy */ + u_char key :4; /* Sense keys defined below */ + u_char pad2 :1; + u_char badBlockLen :1; /* Block length mis-match (Exabyte) */ + u_char endOfMedia :1; /* End of media reached */ + u_char fileMark :1; /* File mark on device */ + u_char info1; /* Information byte 1 */ + u_char info2; /* Information byte 2 */ + u_char info3; /* Information byte 3 */ + u_char info4; /* Information byte 4 */ + u_char length; /* Number of additional info bytes */ +#endif +} ScsiClass7Sense; /* 8 Bytes */ + +/* + * Key values for standardized sense class 7. + */ +#define SCSI_CLASS7_NO_SENSE 0 +#define SCSI_CLASS7_RECOVERABLE 1 +#define SCSI_CLASS7_NOT_READY 2 +#define SCSI_CLASS7_MEDIA_ERROR 3 +#define SCSI_CLASS7_HARDWARE_ERROR 4 +#define SCSI_CLASS7_ILLEGAL_REQUEST 5 + +/* + * These seem to have different meanings to different vendors.... + */ +#define SCSI_CLASS7_MEDIA_CHANGE 6 +#define SCSI_CLASS7_UNIT_ATTN 6 + +#define SCSI_CLASS7_WRITE_PROTECT 7 +#define SCSI_CLASS7_BLANK_CHECK 8 +#define SCSI_CLASS7_VENDOR 9 +#define SCSI_CLASS7_POWER_UP_FAILURE 10 +#define SCSI_CLASS7_ABORT 11 +#define SCSI_CLASS7_EQUAL 12 +#define SCSI_CLASS7_OVERFLOW 13 +#define SCSI_CLASS7_RESERVED_14 14 +#define SCSI_CLASS7_RESERVED_15 15 + +/* + * Data return by the SCSI inquiry command. + */ +typedef struct ScsiInquiryData { +#if BYTE_ORDER == BIG_ENDIAN + u_char type; /* Peripheral Device type. See below. */ + u_char rmb:1; /* Removable Medium bit. */ + u_char qualifier:7; /* Device type qualifier. */ + u_char version; /* Version info. */ + u_char reserved:4; /* reserved. */ + u_char format:4; /* Response format. */ + u_char length; /* length of data returned. */ + u_char reserved2[2]; /* Reserved */ + u_char flags; /* SCSI II flags (see below) */ + u_char vendorID[8]; /* Vendor ID (ASCII) */ + u_char productID[16]; /* Product ID (ASCII) */ + u_char revLevel[4]; /* Revision level (ASCII) */ + u_char revData[8]; /* Revision data (ASCII) */ +#else + u_char type; /* Peripheral Device type. See below. */ + u_char qualifier:7; /* Device type qualifier. */ + u_char rmb:1; /* Removable Medium bit. */ + u_char version; /* Version info. */ + u_char format:4; /* Response format. */ + u_char reserved:4; /* reserved. */ + u_char length; /* length of data returned. */ + u_char reserved2[2]; /* Reserved */ + u_char flags; /* SCSI II flags (see below) */ + u_char vendorID[8]; /* Vendor ID (ASCII) */ + u_char productID[16]; /* Product ID (ASCII) */ + u_char revLevel[4]; /* Revision level (ASCII) */ + u_char revData[8]; /* Revision data (ASCII) */ +#endif +} ScsiInquiryData; + +/* + * The SCSI Peripheral type ID codes as return by the SCSI_INQUIRY command. + * + * SCSI_DISK_TYPE - Direct Access Device. + * SCSI_TAPE_TYPE - Sequential Access Device. + * SCSI_PRINTER_TYPE - Printer Device. + * SCSI_HOST_TYPE - Processor Device. + * SCSI_WORM_TYPE - Write-Once Read-Multiple Device. + * SCSI_ROM_TYPE - Read-Only Direct Access Device. + * SCSI_SCANNER_TYPE - Scanner device. + * SCSI_OPTICAL_MEM_TYPE - Optical memory device. + * SCSI_MEDIUM_CHANGER_TYPE - Medium changer device. + * SCSI_COMMUNICATIONS_TYPE - Communications device. + * SCSI_NODEVICE_TYPE - Logical Unit not present or implemented. + * + * Note that codes 0xa-0x7e are reserved and 0x80-0xff are vendor unique. + */ +#define SCSI_DISK_TYPE 0 +#define SCSI_TAPE_TYPE 1 +#define SCSI_PRINTER_TYPE 2 +#define SCSI_HOST_TYPE 3 +#define SCSI_WORM_TYPE 4 +#define SCSI_ROM_TYPE 5 +#define SCSI_SCANNER_TYPE 6 +#define SCSI_OPTICAL_MEM_TYPE 7 +#define SCSI_MEDIUM_CHANGER_TYPE 8 +#define SCSI_COMMUNICATIONS_TYPE 9 +#define SCSI_NODEVICE_TYPE 0x7f + +/* + * The SCSI I & II inquiry flags. + * + * SCSI_REL_ADR - Relative addressing supported. + * SCSI_WIDE_32 - 32 bit wide SCSI bus transfers supported. + * SCSI_WIDE_16 - 16 bit wide SCSI bus transfers supported. + * SCSI_SYNC - Synchronous data transfers supported. + * SCSI_LINKED - Linked commands supported. + * SCSI_CMD_QUEUE - Tagged command queuing supported. + * SCSI_SOFT_RESET - Soft RESET alternative suported. + */ +#define SCSI_REL_ADR 0x80 +#define SCSI_WIDE_32 0x40 +#define SCSI_WIDE_16 0x20 +#define SCSI_SYNC 0x10 +#define SCSI_LINKED 0x08 +#define SCSI_CMD_QUEUE 0x02 +#define SCSI_SOFT_RESET 0x01 + +/* + * Standard header for SCSI_MODE_SENSE and SCSI_MODE_SELECT commands for tapes. + */ +typedef struct ScsiTapeModeSelectHdr { + u_char len; /* length */ + u_char media; /* media type */ +#if BYTE_ORDER == BIG_ENDIAN + u_char writeprot:1; /* Write protected media */ + u_char bufferedMode:3; /* Type of buffer to be done. */ + u_char speed:4; /* Drive speed. */ +#else + u_char speed:4; /* Drive speed. */ + u_char bufferedMode:3; /* Type of buffer to be done. */ + u_char writeprot:1; /* Write protected media */ +#endif + u_char length; /* Block descriptor length. */ + u_char density; /* tape density code */ + u_char blocks_2; /* number of blocks (MSB) */ + u_char blocks_1; /* number of blocks */ + u_char blocks_0; /* number of blocks (LSB) */ + u_char reserved; /* */ + u_char block_size2; /* Tape block size (MSB) */ + u_char block_size1; /* Tape block size */ + u_char block_size0; /* Tape block size (LSB) */ + u_char vendor[6]; /* vendor specific data */ +} ScsiTapeModeSelectHdr; + +/* + * Definitions of SCSI messages. + * + * SCSI_COMMAND_COMPLETE - After a command has completed, successfully + * or not, this is returned to the host from the target. + * + * SCSI_EXTENDED_MSG - Indicates that a multi-byte message is being sent. + * + * The following messages are used with connect/disconnect: + * SCSI_SAVE_DATA_POINTER - Sent from target to host to request saving + * of current DMA address and count. Indicates a pending dis-connect. + * SCSI_RESTORE_POINTER - Sent from the target to the host to request + * restoring pointers saved before a disconnect + * SCSI_DISCONNECT - Sent from the target to the host to disconnect. + * SCSI_ABORT - Sent from the host to the target to abort current request. + * SCSI_MESSAGE_REJECT - Indicates receipt, by either host or target, of + * an unimplemented message. + * SCSI_NO_OP - Sent from host to target if it has no real message to send. + * SCSI_MESSAGE_PARITY_ERROR - Sent from host to target on message parity error + * SCSI_BUS_RESET - Sent from host to target to reset all current I/O + * + * SCSI_IDENTIFY - The low order two bits of this message type indicate + * the Logical Unit of the Target which is requesting a reconnect. + * SCSI_DIS_REC_IDENTIFY - Sent from the host to a target to indicate + * is supports connect/dis-connect + * + */ +#define SCSI_COMMAND_COMPLETE 0x00 +#define SCSI_EXTENDED_MSG 0x01 +#define SCSI_SAVE_DATA_POINTER 0x02 +#define SCSI_RESTORE_POINTERS 0x03 +#define SCSI_DISCONNECT 0x04 +#define SCSI_ABORT 0x06 +#define SCSI_MESSAGE_REJECT 0x07 +#define SCSI_NO_OP 0x08 +#define SCSI_MESSAGE_PARITY_ERROR 0x09 +#define SCSI_LINKED_CMD_COMPLETE 0x0A +#define SCSI_LINKED_FLAGED_CMD_COMPLETE 0x0B +#define SCSI_BUS_RESET 0x0C + +#define SCSI_IDENTIFY 0x80 +#define SCSI_DIS_REC_IDENTIFY 0xc0 + +/* + * Extended message types (2nd byte of SCSI_EXTENDED_MSG). + */ +#define SCSI_MODIFY_DATA_PTR 0x00 +#define SCSI_SYNCHRONOUS_XFER 0x01 +#define SCSI_EXTENDED_IDENTIFY 0x02 /* only in SCSI I */ +#define SCSI_WIDE_XFER 0x03 + +/* + * Driver ioctl's for various scsi operations. + */ +#ifndef _IOCTL_ +#include <sys/ioctl.h> +#endif + +/* + * Control for SCSI "format" mode. + * + * "Format" mode allows a privileged process to issue direct SCSI + * commands to a drive (it is intended primarily to allow on-line + * formatting). SDIOCSFORMAT with a non-zero arg will put the drive + * into format mode; a zero arg will take it out. When in format + * mode, only the process that issued the SDIOCFORMAT can read or + * write the drive. + * + * In format mode, process is expected to + * - do SDIOCSCSICOMMAND to supply cdb for next SCSI op + * - do read or write as appropriate for cdb + * - if i/o error, optionally do SDIOCSENSE to get completion + * status and sense data from last scsi operation. + */ + +struct scsi_fmt_cdb { + int len; /* cdb length (in bytes) */ + u_char cdb[28]; /* cdb to use on next read/write */ +}; + +struct scsi_fmt_sense { + u_int status; /* completion status of last op */ + u_char sense[32]; /* sense data (if any) from last op */ +}; + +#define SDIOCSFORMAT _IOW('S', 0x1, int) +#define SDIOCGFORMAT _IOR('S', 0x2, int) +#define SDIOCSCSICOMMAND _IOW('S', 0x3, struct scsi_fmt_cdb) +#define SDIOCSENSE _IOR('S', 0x4, struct scsi_fmt_sense) + +#ifdef _KERNEL +/* + * Routines. + */ +extern void scsiGroup0Cmd(); +extern void scsiGroup1Cmd(); +#endif /* _KERNEL */ + +#endif /* _SCSI_H */ diff --git a/sys/arch/wgrisc/include/ansi.h b/sys/arch/wgrisc/include/ansi.h new file mode 100644 index 00000000000..cc607a5d559 --- /dev/null +++ b/sys/arch/wgrisc/include/ansi.h @@ -0,0 +1,75 @@ +/* $OpenBSD: ansi.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ +/* $NetBSD: ansi.h,v 1.5 1994/10/26 21:09:33 cgd 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. 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. + * + * @(#)ansi.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _ANSI_H_ +#define _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_ long /* time() */ +#define _BSD_VA_LIST_ char * /* va_list */ + +/* + * 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_RUNE_T_ int /* rune_t */ + +#endif /* _ANSI_H_ */ diff --git a/sys/arch/wgrisc/include/asm.h b/sys/arch/wgrisc/include/asm.h new file mode 100644 index 00000000000..06df98758c2 --- /dev/null +++ b/sys/arch/wgrisc/include/asm.h @@ -0,0 +1,198 @@ +/* $OpenBSD: asm.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifndef _MACHASMDEFS +#define _MACHASMDEFS + +#include <machine/regdef.h> + +#define ABICALLS .abicalls + +#if defined(ABICALLS) && !defined(_KERNEL) + ABICALLS +#endif + +#define RCSID(x) + +#define _C_LABEL(x) x + +/* + * Define how to access unaligned data word + */ +#ifdef MIPSEL +#define LWLO lwl +#define LWHI lwr +#define SWLO swl +#define SWHI swr +#endif +#ifdef MIPSEB +#define LWLO lwr +#define LWHI lwl +#define SWLO swr +#define SWHI swl +#endif + +/* + * Code for setting gp reg if abicalls are used. + */ +#if defined(ABICALLS) && !defined(_KERNEL) +#define ABISETUP \ + .set noreorder; \ + .cpload t9; \ + .set reorder; +#else +#define ABISETUP +#endif + +/* + * Define -pg profile entry code. + */ +#if defined(GPROF) || defined(PROF) +#define MCOUNT \ + .set noreorder; \ + .set noat; \ + move $1,$31; \ + jal _mcount; \ + subu sp,sp,8; \ + .set reorder; \ + .set at; +#else +#define MCOUNT +#endif + +/* + * LEAF(x) + * + * Declare a leaf routine. + */ +#define LEAF(x) \ + .align 3; \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, 0, ra; \ + ABISETUP \ + MCOUNT + +#define ALEAF(x) \ + .globl x; \ +x: + +/* + * NLEAF(x) + * + * Declare a non-profiled leaf routine. + */ +#define NLEAF(x) \ + .align 3; \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, 0, ra; \ + ABISETUP + +/* + * NON_LEAF(x) + * + * Declare a non-leaf routine (a routine that makes other C calls). + */ +#define NON_LEAF(x, fsize, retpc) \ + .align 3; \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, fsize, retpc; \ + ABISETUP \ + MCOUNT + +/* + * NNON_LEAF(x) + * + * Declare a non-profiled non-leaf routine + * (a routine that makes other C calls). + */ +#define NNON_LEAF(x, fsize, retpc) \ + .align 3; \ + .globl x; \ + .ent x, 0; \ +x: ; \ + .frame sp, fsize, retpc \ + ABISETUP + +/* + * END(x) + * + * Mark end of a procedure. + */ +#define END(x) \ + .end x + +#define STAND_FRAME_SIZE 24 +#define STAND_RA_OFFSET 20 + +/* + * Macros to panic and printf from assembly language. + */ +#define PANIC(msg) \ + la a0, 9f; \ + jal panic; \ + MSG(msg) + +#define PRINTF(msg) \ + la a0, 9f; \ + jal printf; \ + MSG(msg) + +#define MSG(msg) \ + .rdata; \ +9: .asciiz msg; \ + .text + +#define ASMSTR(str) \ + .asciiz str; \ + .align 3 + +#endif /* _MACHASMDEFS */ diff --git a/sys/arch/wgrisc/include/autoconf.h b/sys/arch/wgrisc/include/autoconf.h new file mode 100644 index 00000000000..5bd56ec9341 --- /dev/null +++ b/sys/arch/wgrisc/include/autoconf.h @@ -0,0 +1,79 @@ +/* $OpenBSD: autoconf.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* $NetBSD: autoconf.h,v 1.1 1995/02/13 23:07:31 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * 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 the + * rights to redistribute these changes. + */ + +/* + * Machine-dependent structures of autoconfiguration + */ + +#ifndef _ARC_AUTOCONF_H_ +#define _ARC_AUTOCONF_H_ + +struct confargs; + +typedef int (*intr_handler_t) __P((void *)); + +struct abus { + struct device *ab_dv; /* back-pointer to device */ + int ab_type; /* bus type (see below) */ + void (*ab_intr_establish) /* bus's set-handler function */ + __P((struct confargs *, intr_handler_t, void *)); + void (*ab_intr_disestablish) /* bus's unset-handler function */ + __P((struct confargs *)); + caddr_t (*ab_cvtaddr) /* convert slot/offset to address */ + __P((struct confargs *)); + int (*ab_matchname) /* see if name matches driver */ + __P((struct confargs *, char *)); +}; + +#define BUS_MAIN 1 /* mainbus */ +#define BUS_RISC 2 /* RISC Bus */ +#define BUS_ISABR 3 /* ISA Bridge Bus */ + +#define BUS_INTR_ESTABLISH(ca, handler, val) \ + (*(ca)->ca_bus->ab_intr_establish)((ca), (handler), (val)) +#define BUS_INTR_DISESTABLISH(ca) \ + (*(ca)->ca_bus->ab_intr_establish)(ca) +#define BUS_CVTADDR(ca) \ + (*(ca)->ca_bus->ab_cvtaddr)(ca) +#define BUS_MATCHNAME(ca, name) \ + (*(ca)->ca_bus->ab_matchname)((ca), (name)) + +struct confargs { + char *ca_name; /* Device name. */ + int ca_slot; /* Device slot. */ + int ca_offset; /* Offset into slot. */ + struct abus *ca_bus; /* bus device resides on. */ +}; + +void set_clockintr __P((void (*)(struct clockframe *))); +void set_iointr __P((void (*)(void *, int))); +int badaddr __P((void *, u_int64_t)); + +#endif /* _ARC_AUTOCONF_H_ */ diff --git a/sys/arch/wgrisc/include/bus.h b/sys/arch/wgrisc/include/bus.h new file mode 100644 index 00000000000..eb63712fc4f --- /dev/null +++ b/sys/arch/wgrisc/include/bus.h @@ -0,0 +1,155 @@ +/* $OpenBSD: bus.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 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. + * 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 + * for the NetBSD Project. + * 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 _ARC_BUS_H_ +#define _ARC_BUS_H_ + +#ifdef __STDC__ +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#endif + +/* + * Bus access types. + */ +typedef u_int32_t bus_addr_t; +typedef u_int32_t bus_size_t; +typedef u_int32_t bus_space_handle_t; +typedef u_int32_t bus_space_tag_t; + +/* + * Access methods for bus resources + */ +#define bus_space_map(t, addr, size, cacheable, bshp) \ + ((*(bshp) = (t) + (addr)), 0) +#define bus_space_unmap(t, bsh, size) + +#define bus_space_read(n,m) \ +static __inline CAT3(u_int,m,_t) \ +CAT(bus_space_read_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba) \ +{ \ + wbflush(); \ + wbflush(); \ + wbflush(); \ + return *(volatile CAT3(u_int,m,_t) *)(bsh + ba); \ +} + +bus_space_read(1,8) +bus_space_read(2,16) +bus_space_read(4,32) + +#define bus_space_read_8 !!! bus_space_read_8 unimplemented !!! + +#define bus_space_read_multi(n, m) \ +static __inline void \ +CAT(bus_space_read_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, CAT3(u_int,m,_t) *buf, bus_size_t cnt) \ +{ \ + while (cnt--) \ + *buf++ = CAT(bus_space_read_,n)(bst, bsh, ba); \ +} + +bus_space_read_multi(1,8) +bus_space_read_multi(2,16) +bus_space_read_multi(4,32) + +#define bus_space_read_multi_8 !!! bus_space_read_multi_8 not implemented !!! + +#define bus_space_write(n,m) \ +static __inline void \ +CAT(bus_space_write_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, CAT3(u_int,m,_t) x) \ +{ \ + wbflush(); \ + *(volatile CAT3(u_int,m,_t) *)(bsh + ba) = x; \ + wbflush(); \ + wbflush(); \ + wbflush(); \ +} + +bus_space_write(1,8) +bus_space_write(2,16) +bus_space_write(4,32) + +#define bus_space_write_8 !!! bus_space_write_8 unimplemented !!! + +#define bus_space_write_multi(n, m) \ +static __inline void \ +CAT(bus_space_write_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, const CAT3(u_int,m,_t) *buf, bus_size_t cnt) \ +{ \ + while (cnt--) \ + CAT(bus_space_write_,n)(bst, bsh, ba, *buf++); \ +} + +bus_space_write_multi(1,8) +bus_space_write_multi(2,16) +bus_space_write_multi(4,32) + +#define bus_space_write_multi_8 !!! bus_space_write_multi_8 not implemented !!! + +/* These are OpenBSD extensions to the general NetBSD bus interface. */ +#define bus_space_read_raw_multi(n,m,l) \ +static __inline void \ +CAT(bus_space_read_raw_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, u_int8_t *buf, bus_size_t cnt) \ +{ \ + CAT(bus_space_read_multi_,n)(bst, bsh, ba, (CAT3(u_int,m,_t) *)buf, \ + cnt >> l); \ +} + +bus_space_read_raw_multi(2,16,1) +bus_space_read_raw_multi(4,32,2) + +#define bus_space_read_raw_multi_8 \ + !!! bus_space_read_raw_multi_8 not implemented !!! + +#define bus_space_write_raw_multi(n,m,l) \ +static __inline void \ +CAT(bus_space_write_raw_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh,\ + bus_addr_t ba, const u_int8_t *buf, bus_size_t cnt) \ +{ \ + CAT(bus_space_write_multi_,n)(bst, bsh, ba, \ + (const CAT3(u_int,m,_t) *)buf, cnt >> l); \ +} + +bus_space_write_raw_multi(2,16,1) +bus_space_write_raw_multi(4,32,2) + +#define bus_space_write_raw_multi_8 \ + !!! bus_space_write_raw_multi_8 not implemented !!! + +#endif /* _ARC_BUS_H_ */ diff --git a/sys/arch/wgrisc/include/cdefs.h b/sys/arch/wgrisc/include/cdefs.h new file mode 100644 index 00000000000..45491b2df35 --- /dev/null +++ b/sys/arch/wgrisc/include/cdefs.h @@ -0,0 +1,39 @@ +/* $OpenBSD: cdefs.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* $NetBSD: cdefs.h,v 1.3 1995/05/03 06:04:54 mellon Exp $ */ + +/* + * Copyright (c) 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * 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 the + * rights to redistribute these changes. + */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#define _C_LABEL(x) _STRING(x) + +#define __indr_references(sym,msg) /* nothing */ +#define __warn_references(sym,msg) /* nothing */ + +#endif /* !_MACHINE_CDEFS_H_ */ diff --git a/sys/arch/wgrisc/include/cpu.h b/sys/arch/wgrisc/include/cpu.h new file mode 100644 index 00000000000..1ffa44898f9 --- /dev/null +++ b/sys/arch/wgrisc/include/cpu.h @@ -0,0 +1,417 @@ +/* $OpenBSD: cpu.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * 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. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: @(#)cpu.h 8.4 (Berkeley) 1/4/94 + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + +#define KUSEG_ADDR 0x0 +#define CACHED_MEMORY_ADDR 0x80000000 +#define UNCACHED_MEMORY_ADDR 0xa0000000 +#define KSEG2_ADDR 0xc0000000 +#define MAX_MEM_ADDR 0xbe000000 +#define RESERVED_ADDR 0xbfc80000 + +#define CACHED_TO_PHYS(x) ((unsigned)(x) & 0x1fffffff) +#define PHYS_TO_CACHED(x) ((unsigned)(x) | CACHED_MEMORY_ADDR) +#define UNCACHED_TO_PHYS(x) ((unsigned)(x) & 0x1fffffff) +#define PHYS_TO_UNCACHED(x) ((unsigned)(x) | UNCACHED_MEMORY_ADDR) +#define VA_TO_CINDEX(x) ((unsigned)(x) & 0xffffff | CACHED_MEMORY_ADDR) + +#ifdef _KERNEL +/* + * The bits in the cause register. There are actually no diff here + * between the R3K and the R4K except from the width of the EXC field. + * However the bit 6 and bit 7 of the R3K cause register is always '0' + * so we do not make any distinguishing between them. + * + * + * CR_BR_DELAY Exception happened in branch delay slot. + * CR_COP_ERR Coprocessor error. + * CR_IP Interrupt pending bits defined below. + * CR_EXC_CODE The exception type (see exception codes below). + */ +#define CR_BR_DELAY 0x80000000 +#define CR_COP_ERR 0x30000000 +#define CR_EXC_CODE 0x0000007C +#define CR_IP 0x0000FF00 +#define CR_EXC_CODE_SHIFT 2 + +/* + * The bits in the status register. All bits are active when set to 1. + */ +#define SR_COP_USABILITY 0xf0000000 /* R3K - R4K */ +#define SR_COP_0_BIT 0x10000000 /* R3K - R4K */ +#define SR_COP_1_BIT 0x20000000 /* R3K - R4K */ +#define SR_RE 0x02000000 /* R3K - R4K */ +#define SR_BOOT_EXC_VEC 0x00400000 /* R3K - R4K */ +#define SR_TLB_SHUTDOWN 0x00200000 /* R3K - R4K */ +#define SR_INT_MASK 0x0000ff00 /* R3K - R4K */ +#ifndef R4K +#define SR_DIAG_CPE 0x00100000 /* R3K */ +#define SR_CACHE_MISS 0x00080000 /* R3K */ +#define SR_DIAG_PZ 0x00040000 /* R3K */ +#define SR_SWAP_CACHES 0x00020000 /* R3K */ +#define SR_ISOL_CACHES 0x00010000 /* R3K */ +#define SR_KU_OLD 0x00000020 /* R3K */ +#define SR_INT_ENA_OLD 0x00000010 /* R3K */ +#define SR_KU_PREV 0x00000008 /* R3K */ +#define SR_INT_ENA_PREV 0x00000004 /* R3K */ +#define SR_KU_CUR 0x00000002 /* R3K */ +#else +#define SR_RP 0x08000000 /* R4K */ +#define SR_FR_32 0x04000000 /* R4K */ +#define SR_SOFT_RESET 0x00100000 /* R4K */ +#define SR_DIAG_CH 0x00040000 /* R4K */ +#define SR_DIAG_CE 0x00020000 /* R4K */ +#define SR_DIAG_PE 0x00010000 /* R4K */ +#define SR_KX 0x00000080 /* R4K */ +#define SR_SX 0x00000040 /* R4K */ +#define SR_UX 0x00000020 /* R4K */ +#define SR_KSU_MASK 0x00000018 /* R4K */ +#define SR_KSU_USER 0x00000010 /* R4K */ +#define SR_KSU_SUPER 0x00000008 /* R4K */ +#define SR_KSU_KERNEL 0x00000000 /* R4K */ +#define SR_ERL 0x00000004 /* R4K */ +#define SR_EXL 0x00000002 /* R4K */ +#endif +#define SR_INT_ENAB 0x00000001 /* R3K - R4K */ + +/* + * The interrupt masks. These are the same for R3K and R4K. + * If a bit in the mask is 1 then the interrupt is enabled (or pending). + */ +#define INT_MASK 0xff00 /* Provide MAXIMUM enable set */ +#define HARD_INT_MASK (0xfc00 & INT_MASK) +#define INT_MASK_5 0x8000 /* Not used (R4K on chip timer) */ +#define INT_MASK_4 0x4000 +#define INT_MASK_3 0x2000 +#define INT_MASK_2 0x1000 +#define INT_MASK_1 0x0800 +#define INT_MASK_0 0x0400 +#define SOFT_INT_MASK_1 0x0200 +#define SOFT_INT_MASK_0 0x0100 + +/* + * Location of exception vectors. + */ +#define R4K_RESET_EXC_VEC 0xBFC00000 +#define R4K_TLB_MISS_EXC_VEC 0x80000000 +#define R4K_XTLB_MISS_EXC_VEC 0x80000080 +#define R4K_CACHE_ERR_EXC_VEC 0x80000100 +#define R4K_GEN_EXC_VEC 0x80000180 + +#define R3K_RESET_EXC_VEC 0xBFC00000 +#define R3K_TLB_MISS_EXC_VEC 0x80000000 +#define R3K_GEN_EXC_VEC 0x80000080 + +/* + * Coprocessor 0 registers: + */ +#define COP_0_TLB_INDEX $0 +#define COP_0_TLB_RANDOM $1 +#define COP_0_TLB_LO0 $2 +#define COP_0_TLB_LO1 $3 /* R4K only */ +#define COP_0_R3K_CONF $3 /* R3K only */ +#define COP_0_TLB_CONTEXT $4 +#define COP_0_TLB_PG_MASK $5 +#define COP_0_TLB_WIRED $6 +#define COP_0_BAD_VADDR $8 +#define COP_0_TLB_HI $10 +#define COP_0_STATUS_REG $12 +#define COP_0_CAUSE_REG $13 +#define COP_0_EXC_PC $14 +#define COP_0_PRID $15 +#define COP_0_CONFIG $16 +#define COP_0_LLADDR $17 +#define COP_0_WATCH_LO $18 +#define COP_0_WATCH_HI $19 +#define COP_0_TLB_XCONTEXT $20 +#define COP_0_ECC $26 +#define COP_0_CACHE_ERR $27 +#define COP_0_TAG_LO $28 +#define COP_0_TAG_HI $29 +#define COP_0_ERROR_PC $30 + +/* + * Values for the code field in a break instruction. + */ +#define BREAK_INSTR 0x0000000d +#define BREAK_VAL_MASK 0x03ff0000 +#define BREAK_VAL_SHIFT 16 +#define BREAK_KDB_VAL 512 +#define BREAK_SSTEP_VAL 513 +#define BREAK_BRKPT_VAL 514 +#define BREAK_SOVER_VAL 515 +#define BREAK_KDB (BREAK_INSTR | (BREAK_KDB_VAL << BREAK_VAL_SHIFT)) +#define BREAK_SSTEP (BREAK_INSTR | (BREAK_SSTEP_VAL << BREAK_VAL_SHIFT)) +#define BREAK_BRKPT (BREAK_INSTR | (BREAK_BRKPT_VAL << BREAK_VAL_SHIFT)) +#define BREAK_SOVER (BREAK_INSTR | (BREAK_SOVER_VAL << BREAK_VAL_SHIFT)) + +/* + * Mininum and maximum cache sizes. + */ +#define MIN_CACHE_SIZE (4 * 1024) +#define MAX_CACHE_SIZE (256 * 1024) + +/* + * The floating point version and status registers. + */ +#define FPC_ID $0 +#define FPC_CSR $31 + +/* + * The floating point coprocessor status register bits. + */ +#define FPC_ROUNDING_BITS 0x00000003 +#define FPC_ROUND_RN 0x00000000 +#define FPC_ROUND_RZ 0x00000001 +#define FPC_ROUND_RP 0x00000002 +#define FPC_ROUND_RM 0x00000003 +#define FPC_STICKY_BITS 0x0000007c +#define FPC_STICKY_INEXACT 0x00000004 +#define FPC_STICKY_UNDERFLOW 0x00000008 +#define FPC_STICKY_OVERFLOW 0x00000010 +#define FPC_STICKY_DIV0 0x00000020 +#define FPC_STICKY_INVALID 0x00000040 +#define FPC_ENABLE_BITS 0x00000f80 +#define FPC_ENABLE_INEXACT 0x00000080 +#define FPC_ENABLE_UNDERFLOW 0x00000100 +#define FPC_ENABLE_OVERFLOW 0x00000200 +#define FPC_ENABLE_DIV0 0x00000400 +#define FPC_ENABLE_INVALID 0x00000800 +#define FPC_EXCEPTION_BITS 0x0003f000 +#define FPC_EXCEPTION_INEXACT 0x00001000 +#define FPC_EXCEPTION_UNDERFLOW 0x00002000 +#define FPC_EXCEPTION_OVERFLOW 0x00004000 +#define FPC_EXCEPTION_DIV0 0x00008000 +#define FPC_EXCEPTION_INVALID 0x00010000 +#define FPC_EXCEPTION_UNIMPL 0x00020000 +#define FPC_COND_BIT 0x00800000 +#define FPC_FLUSH_BIT 0x01000000 +#define FPC_MBZ_BITS 0xfe7c0000 + +/* + * Constants to determine if have a floating point instruction. + */ +#define OPCODE_SHIFT 26 +#define OPCODE_C1 0x11 + +/* + * The number of TLB entries and the first one that write random hits. + */ +#define R3K_NUM_TLB_ENTRIES 64 +#define R4K_NUM_TLB_ENTRIES 48 /* Pairs, totals 96 */ +#define R3K_NUM_WIRED_ENTRIES 8 +#define R4K_NUM_WIRED_ENTRIES 8 +#define R3K_PID_SHIFT 6 +#define R3K_PID_MASK 0xfc00 +#define R4K_PID_SHIFT 0 +#define R4K_PID_MASK 0x00ff +#define R3K_TLB_INDEX_SHIFT 8 +#define R4K_TLB_INDEX_SHIFT 0 + +/* + * The number of process id entries. + */ +#define R3K_NUM_PIDS 32 +#define R4K_NUM_PIDS 256 + +#endif /* _KERNEL */ + + + +/* + * Exported definitions unique to mips cpu support. + */ + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define COPY_SIGCODE /* copy sigcode above user stack in exec */ + +#define cpu_wait(p) /* nothing */ +#define cpu_set_init_frame(p, fp) /* nothing */ +#define cpu_swapout(p) panic("cpu_swapout: can't get here"); + +#ifndef _LOCORE +/* + * Arguments to hardclock and gatherstats encapsulate the previous + * machine state in an opaque clockframe. + */ +struct clockframe { + int pc; /* program counter at time of interrupt */ + int sr; /* status register at time of interrupt */ + int cr; /* cause register at time of interrupt */ +}; + +#ifndef R4K +#define CLKF_USERMODE(fp) ((fp)->sr & SR_KU_PREV) +#define CLKF_BASEPRI(fp) ((~(fp)->sr & (INT_MASK|SR_INT_ENA_PREV)) == 0) +#else +#define CLKF_USERMODE(fp) ((fp)->sr & SR_KSU_USER) +#define CLKF_BASEPRI(fp) ((~(fp)->sr & (INT_MASK|SR_INT_ENAB)) == 0) +#endif +#define CLKF_PC(fp) ((fp)->pc) +#define CLKF_INTR(fp) (0) + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +#define need_resched() { want_resched = 1; aston(); } + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the PICA, 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; aston(); } + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) aston() + +#define aston() (astpending = 1) + +int astpending; /* need to trap before returning to user mode */ +int want_resched; /* resched() was called */ + +/* + * CPU identification, from PRID register. + */ +union cpuprid { + int cpuprid; + struct { +#if BYTE_ORDER == BIG_ENDIAN + u_int pad1:16; /* reserved */ + u_int cp_imp:8; /* implementation identifier */ + u_int cp_majrev:4; /* major revision identifier */ + u_int cp_minrev:4; /* minor revision identifier */ +#else + u_int cp_minrev:4; /* minor revision identifier */ + u_int cp_majrev:4; /* major revision identifier */ + u_int cp_imp:8; /* implementation identifier */ + u_int pad1:16; /* reserved */ +#endif + } cpu; +}; + +/* + * CTL_MACHDEP definitions. + */ +#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 }, \ +} + +#endif /* !_LOCORE */ + +/* + * MIPS CPU types (cp_imp). + */ +#define MIPS_R2000 0x01 /* MIPS R2000 CPU ISA I */ +#define MIPS_R3000 0x02 /* MIPS R3000 CPU ISA I */ +#define MIPS_R6000 0x03 /* MIPS R6000 CPU ISA II */ +#define MIPS_R4000 0x04 /* MIPS R4000/4400 CPU ISA III */ +#define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivate ISA I */ +#define MIPS_R6000A 0x06 /* MIPS R6000A CPU ISA II */ +#define MIPS_R3IDT 0x07 /* IDT R3000 derivate ISA I */ +#define MIPS_R10000 0x09 /* MIPS R10000/T5 CPU ISA IV */ +#define MIPS_R4200 0x0a /* MIPS R4200 CPU (ICE) ISA III */ +#define MIPS_UNKC1 0x0b /* unnanounced product cpu ISA III */ +#define MIPS_UNKC2 0x0c /* unnanounced product cpu ISA III */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based CPU ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based CPU ISA I */ +#define MIPS_R3NKK 0x23 /* NKK R3000 based CPU ISA I */ + +/* + * MIPS FPU types + */ +#define MIPS_SOFT 0x00 /* Software emulation ISA I */ +#define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ +#define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ +#define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ +#define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ +#define MIPS_R4010 0x05 /* MIPS R4000/R4400 FPC ISA II */ +#define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ +#define MIPS_R10010 0x09 /* MIPS R10000/T5 FPU ISA IV */ +#define MIPS_R4210 0x0a /* MIPS R4200 FPC (ICE) ISA III */ +#define MIPS_UNKF1 0x0b /* unnanounced product cpu ISA III */ +#define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ +#define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ +#define MIPS_R3SONY 0x21 /* Sony R3000 based FPU ISA I */ +#define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ +#define MIPS_R3NKK 0x23 /* NKK R3000 based FPU ISA I */ + +#if defined(_KERNEL) && !defined(_LOCORE) +union cpuprid cpu_id; +union cpuprid fpu_id; +u_int CpuPrimaryDataCacheSize; +u_int CpuPrimaryInstCacheSize; +u_int CpuPrimaryDataCacheLSize; +u_int CpuPrimaryInstCacheLSize; +u_int CpuCacheAliasMask; +u_int CpuTwoWayCache; + +extern struct intr_tab intr_tab[]; +#endif + +/* + * Enable realtime clock (always enabled). + */ +#define enablertclock() + +#endif /* _CPU_H_ */ diff --git a/sys/arch/wgrisc/include/disklabel.h b/sys/arch/wgrisc/include/disklabel.h new file mode 100644 index 00000000000..41df7318418 --- /dev/null +++ b/sys/arch/wgrisc/include/disklabel.h @@ -0,0 +1,88 @@ +/* $OpenBSD: disklabel.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* $NetBSD: disklabel.h,v 1.2 1995/01/18 06:37:55 mellon 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 1 /* sector containing label */ +#define LABELOFFSET 0 /* offset of label in sector */ +#define MAXPARTITIONS 16 /* number of partitions */ +#define PARTITIONSHIFT 4 /* log2 */ +#define PARTITIONMASK 0xf +#define RAW_PART 2 /* raw partition: xx?c */ + +/* DOS partition table -- used when the system is booted from a dos + * partition. This is the case on NT systems. + */ +#define DOSBBSECTOR 0 /* DOS boot block relative sector # */ +#define DOSPARTOFF 446 +#define NDOSPART 4 + +struct dos_partition { + unsigned char dp_flag; /* bootstrap flags */ + unsigned char dp_shd; /* starting head */ + unsigned char dp_ssect; /* starting sector */ + unsigned char dp_scyl; /* starting cylinder */ + unsigned char dp_typ; /* partition type (see below) */ + unsigned char dp_ehd; /* end head */ + unsigned char dp_esect; /* end sector */ + unsigned char dp_ecyl; /* end cylinder */ + unsigned long dp_start; /* absolute starting sector number */ + unsigned long dp_size; /* partition size in sectors */ +} dos_partitions[NDOSPART]; + +/* Known DOS partition types. */ +#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */ +#define DOSPTYP_NETBSD DOSPTYP_386BSD /* NetBSD partition type (XXX) */ +#define DOSPTYP_OPENBSD 0xa6 /* OpenBSD partition type */ +#define DOSPTYP_FAT12 0x1 +#define DOSPTYP_FAT16S 0x4 +#define DOSPTYP_FAT16B 0x6 +#define DOSPTYP_FAT16C 0xe + +#include <sys/dkbad.h> +struct cpu_disklabel { + struct dos_partition dosparts[NDOSPART]; + struct dkbad bad; +}; + +/* Isolate the relevant bits to get sector and cylinder. */ +#define DPSECT(s) ((s) & 0x3f) +#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) + +#ifdef _KERNEL +struct disklabel; +int bounds_check_with_label __P((struct buf *, struct disklabel *, int)); +#endif + +#endif /* _MACHINE_DISKLABEL_H_ */ diff --git a/sys/arch/wgrisc/include/dlfcn.h b/sys/arch/wgrisc/include/dlfcn.h new file mode 100644 index 00000000000..d21e46eb68c --- /dev/null +++ b/sys/arch/wgrisc/include/dlfcn.h @@ -0,0 +1,42 @@ +/* $OpenBSD: dlfcn.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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 _DLFCN_H +#define _DLFCN_H 1 + +/* + * This is a dummy file. Empty until libdl has been done. + */ + +#endif /* _DLFCN_H */ diff --git a/sys/arch/wgrisc/include/ecoff.h b/sys/arch/wgrisc/include/ecoff.h new file mode 100644 index 00000000000..0a7e76b27c2 --- /dev/null +++ b/sys/arch/wgrisc/include/ecoff.h @@ -0,0 +1,94 @@ +/* $OpenBSD: ecoff.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ +/* $NetBSD: ecoff.h,v 1.4 1995/06/16 02:07:33 mellon Exp $ */ + +/* + * Copyright (c) 1994 Adam Glass + * 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 Adam Glass. + * 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 Adam Glass ``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 Adam Glass 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. + */ + +#define ECOFF_LDPGSZ 4096 + +#define ECOFF_PAD + +#define ECOFF_MACHDEP \ + u_long ea_gprmask; \ + u_long ea_cprmask[4]; \ + u_long ea_gp_value + +#define ECOFF_MAGIC_MIPSEL 0x0162 +#define ECOFF_BADMAG(ex) ((ex)->f.f_magic != ECOFF_MAGIC_MIPSEL) + +#define ECOFF_SEGMENT_ALIGNMENT(ep) ((ep)->a.vstamp < 23 ? 8 : 16) + +struct ecoff_symhdr { + int16_t sh_magic; + int16_t sh_vstamp; + int32_t sh_linemax; + int32_t sh_densenummax; + int32_t sh_procmax; + int32_t sh_lsymmax; + int32_t sh_optsymmax; + int32_t sh_auxxymmax; + int32_t sh_lstrmax; + int32_t sh_estrmax; + int32_t sh_fdmax; + int32_t sh_rfdmax; + int32_t sh_esymmax; + long sh_linesize; + long sh_lineoff; + long sh_densenumoff; + long sh_procoff; + long sh_lsymoff; + long sh_optsymoff; + long sh_auxsymoff; + long sh_lstroff; + long sh_estroff; + long sh_fdoff; + long sh_rfdoff; + long sh_esymoff; +}; +/* Some day they will make up their minds.... */ +#define esymMax sh_esymmax +#define cbExtOffset sh_esymoff +#define cbSsExtOffset sh_estroff + +struct ecoff_extsym { + long es_value; + int es_strindex; + unsigned es_type:6; + unsigned es_class:5; + unsigned :1; + unsigned es_symauxindex:20; + unsigned es_jmptbl:1; + unsigned es_cmain:1; + unsigned es_weakext:1; + unsigned :29; + int es_indexfld; +}; + diff --git a/sys/arch/wgrisc/include/elf_abi.h b/sys/arch/wgrisc/include/elf_abi.h new file mode 100644 index 00000000000..be988c70925 --- /dev/null +++ b/sys/arch/wgrisc/include/elf_abi.h @@ -0,0 +1,57 @@ +/* $OpenBSD: elf_abi.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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. + * + */ + +/* From MIPS ABI supplemental */ + +/* Architecture dependent Segment types - p_type */ +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ + +/* Architecture dependent d_tag field for Elf32_Dyn. */ +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime Linker Interface ID */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Cksum of ext. str. and com. sizes */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Segment base address */ +#define DT_MIPS_CONFLICT 0x70000008 /* Adr of .conflict section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of .liblist section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local .GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of .conflict entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of .liblist entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of .dynsym entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in .dynsym */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of debug map pointer */ + diff --git a/sys/arch/wgrisc/include/endian.h b/sys/arch/wgrisc/include/endian.h new file mode 100644 index 00000000000..b08ec1b92eb --- /dev/null +++ b/sys/arch/wgrisc/include/endian.h @@ -0,0 +1,95 @@ +/* $OpenBSD: endian.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: endian.h,v 1.4 1994/10/26 21:09:38 cgd Exp $ */ + +/* + * Copyright (c) 1987, 1991, 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. 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. + * + * @(#)endian.h 8.1 (Berkeley) 6/11/93 + */ + +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +/* + * Define _NOQUAD if the compiler does NOT support 64-bit integers. + */ +/* #define _NOQUAD */ + +/* + * Define the order of 32-bit words in 64-bit words. + */ +#define _QUAD_HIGHWORD 1 +#define _QUAD_LOWWORD 0 + +#ifndef _POSIX_SOURCE +/* + * Definitions for byte order, according to byte significance from low + * address to high. + */ +#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ +#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ + +#define BYTE_ORDER LITTLE_ENDIAN /* ``... Beautiful SPIIIIM!'' */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +unsigned long htonl __P((unsigned long)); +unsigned short htons __P((unsigned short)); +unsigned long ntohl __P((unsigned long)); +unsigned short ntohs __P((unsigned short)); +__END_DECLS + +/* + * Macros for network/external number representation conversion. + */ +#if BYTE_ORDER == BIG_ENDIAN && !defined(lint) +#define ntohl(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define htons(x) (x) + +#define NTOHL(x) (x) +#define NTOHS(x) (x) +#define HTONL(x) (x) +#define HTONS(x) (x) + +#else + +#define NTOHL(x) (x) = ntohl((u_long)x) +#define NTOHS(x) (x) = ntohs((u_short)x) +#define HTONL(x) (x) = htonl((u_long)x) +#define HTONS(x) (x) = htons((u_short)x) +#endif +#endif /* ! _POSIX_SOURCE */ +#endif /* !_ENDIAN_H_ */ diff --git a/sys/arch/wgrisc/include/exec.h b/sys/arch/wgrisc/include/exec.h new file mode 100644 index 00000000000..05ba554d5dc --- /dev/null +++ b/sys/arch/wgrisc/include/exec.h @@ -0,0 +1,62 @@ +/* $OpenBSD: exec.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: exec.h,v 1.5 1994/10/26 21:09:39 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 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. 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. + * + * @(#)exec.h 8.1 (Berkeley) 6/10/93 + */ + +#define __LDPGSZ 4096 + +/* + * Define what exec "formats" we should handle. + */ +#define NATIVE_EXEC_ELF +#define EXEC_SCRIPT + +#define ELF_TARG_CLASS ELFCLASS32 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_MIPS + +/* + * This is what we want nlist(3) to handle. + */ +#define _NLIST_DO_AOUT /* support a.out */ +#define _NLIST_DO_ELF /* support ELF */ +#define _NLIST_DO_ECOFF /* support ECOFF */ + +/* + * This is what we want the kernel to handle. + */ +#define _KERN_DO_ELF + diff --git a/sys/arch/wgrisc/include/float.h b/sys/arch/wgrisc/include/float.h new file mode 100644 index 00000000000..19c9ee76e9b --- /dev/null +++ b/sys/arch/wgrisc/include/float.h @@ -0,0 +1,81 @@ +/* $OpenBSD: float.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: float.h,v 1.7 1995/06/20 20:45:50 jtc Exp $ */ + +/* + * Copyright (c) 1989, 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. 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. + * + * @(#)float.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _MIPS_FLOAT_H_ +#define _MIPS_FLOAT_H_ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +extern int __flt_rounds(); +__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.225073858507201E-308 +#define DBL_MIN_10_EXP -307 +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.797693134862316E+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 /* _MIPS_FLOAT_H_ */ diff --git a/sys/arch/wgrisc/include/ieeefp.h b/sys/arch/wgrisc/include/ieeefp.h new file mode 100644 index 00000000000..6032cbcc0a2 --- /dev/null +++ b/sys/arch/wgrisc/include/ieeefp.h @@ -0,0 +1,25 @@ +/* $OpenBSD: ieeefp.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Written by J.T. Conklin, Apr 11, 1995 + * Public domain. + */ + +#ifndef _MIPS_IEEEFP_H_ +#define _MIPS_IEEEFP_H_ + +typedef int fp_except; +#define FP_X_IMP 0x01 /* imprecise (loss of precision) */ +#define FP_X_UFL 0x02 /* underflow exception */ +#define FP_X_OFL 0x04 /* overflow exception */ +#define FP_X_DZ 0x08 /* divide-by-zero exception */ +#define FP_X_INV 0x10 /* invalid operation exception */ + +typedef enum { + FP_RN=0, /* round to nearest representable number */ + FP_RZ=1, /* round to zero (truncate) */ + FP_RP=2, /* round toward positive infinity */ + FP_RM=3 /* round toward negative infinity */ +} fp_rnd; + +#endif /* _MIPS_IEEEFP_H_ */ diff --git a/sys/arch/wgrisc/include/intr.h b/sys/arch/wgrisc/include/intr.h new file mode 100644 index 00000000000..67e7ad75ff1 --- /dev/null +++ b/sys/arch/wgrisc/include/intr.h @@ -0,0 +1,164 @@ +/* $NetBSD: intr.h,v 1.5 1996/05/13 06:11:28 mycroft Exp $ */ + +/* + * Copyright (c) 1996 Charles M. Hannum. 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 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. + * + * 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 _ARC_INTR_H_ +#define _ARC_INTR_H_ + +/* Interrupt priority `levels'; not mutually exclusive. */ +#define IPL_BIO 0 /* block I/O */ +#define IPL_NET 1 /* network */ +#define IPL_TTY 2 /* terminal */ +#define IPL_CLOCK 3 /* clock */ +#define IPL_IMP 4 /* memory allocation */ +#define IPL_NONE 5 /* nothing */ +#define IPL_HIGH 6 /* everything */ + +/* Interrupt sharing types. */ +#define IST_NONE 0 /* none */ +#define IST_PULSE 1 /* pulsed */ +#define IST_EDGE 2 /* edge-triggered */ +#define IST_LEVEL 3 /* level-triggered */ + +/* Soft interrupt masks. */ +#define SIR_CLOCK 31 +#define SIR_CLOCKMASK ((1 << SIR_CLOCK)) +#define SIR_NET 30 +#define SIR_NETMASK ((1 << SIR_NET) | SIR_CLOCKMASK) +#define SIR_TTY 29 +#define SIR_TTYMASK ((1 << SIR_TTY) | SIR_CLOCKMASK) +#define SIR_ALLMASK (SIR_CLOCKMASK | SIR_NETMASK | SIR_TTYMASK) + +#ifndef _LOCORE + +volatile int cpl, ipending, astpending; +int imask[7]; + +#if 0 +extern void Xspllower __P((void)); + +static __inline int splraise __P((int)); +static __inline int spllower __P((int)); +static __inline void splx __P((int)); +static __inline void softintr __P((int)); + +/* + * Add a mask to cpl, and return the old value of cpl. + */ +static __inline int +splraise(ncpl) + register int ncpl; +{ + register int ocpl = cpl; + + cpl = ocpl | ncpl; + return (ocpl); +} + +/* + * Restore a value to cpl (unmasking interrupts). If any unmasked + * interrupts are pending, call Xspllower() to process them. + */ +static __inline void +splx(ncpl) + register int ncpl; +{ + + cpl = ncpl; + if (ipending & ~ncpl) + Xspllower(); +} + +/* + * Same as splx(), but we return the old value of spl, for the + * benefit of some splsoftclock() callers. + */ +static __inline int +spllower(ncpl) + register int ncpl; +{ + register int ocpl = cpl; + + cpl = ncpl; + if (ipending & ~ncpl) + Xspllower(); + return (ocpl); +} +#endif + +/* + * Hardware interrupt masks + */ +#if 0 +#define splbio() splraise(imask[IPL_BIO]) +#define splnet() splraise(imask[IPL_NET]) +#define spltty() splraise(imask[IPL_TTY]) +#define splclock() splraise(imask[IPL_CLOCK]) +#define splimp() splraise(imask[IPL_IMP]) +#define splstatclock() splclock() + +/* + * Software interrupt masks + * + * NOTE: splsoftclock() is used by hardclock() to lower the priority from + * clock to softclock before it calls softclock(). + */ +#define splsoftclock() spllower(SIR_CLOCKMASK) +#define splsoftnet() splraise(SIR_NETMASK) +#define splsofttty() splraise(SIR_TTYMASK) + +/* + * Miscellaneous + */ +#define splhigh() splraise(-1) +#define spl0() spllower(0) + +#endif +/* + * Software interrupt registration + * + * We hand-code this to ensure that it's atomic. + */ +static __inline void +softintr(mask) + register int mask; +{ + + __asm __volatile("orl %0,_ipending" : : "ir" (mask)); +} + +#define setsoftast() (astpending = 1) +#define setsoftclock() softintr(1 << SIR_CLOCK) +#define setsoftnet() softintr(1 << SIR_NET) +#define setsofttty() softintr(1 << SIR_TTY) + +#endif /* _LOCORE */ + +#endif /* _ARC_INTR_H_ */ diff --git a/sys/arch/wgrisc/include/kbdreg.h b/sys/arch/wgrisc/include/kbdreg.h new file mode 100644 index 00000000000..1cc11515b73 --- /dev/null +++ b/sys/arch/wgrisc/include/kbdreg.h @@ -0,0 +1,82 @@ +/* $OpenBSD: kbdreg.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * 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 Per Fogelstrom. + * 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. + */ +/* + * Keyboard definitions + * + */ + +#define KBSTATP (0x61) /* controller status port (I) */ +#define KBS_DIB 0x01 /* data in buffer */ +#define KBS_IBF 0x02 /* input buffer low */ +#define KBS_WARM 0x04 /* input buffer low */ +#define KBS_OCMD 0x08 /* output buffer has command */ +#define KBS_NOSEC 0x10 /* security lock not engaged */ +#define KBS_TERR 0x20 /* transmission error */ +#define KBS_RERR 0x40 /* receive error */ +#define KBS_PERR 0x80 /* parity error */ + +#define KBCMDP (0x61) /* controller port (O) */ +#define KBDATAP (0x60) /* data port (I) */ +#define KBOUTP (0x60) /* data port (O) */ + +#define K_RDCMDBYTE 0x20 +#define K_LDCMDBYTE 0x60 + +#define KC8_TRANS 0x40 /* convert to old scan codes */ +#define KC8_MDISABLE 0x20 /* disable mouse */ +#define KC8_KDISABLE 0x10 /* disable keyboard */ +#define KC8_IGNSEC 0x08 /* ignore security lock */ +#define KC8_CPU 0x04 /* exit from protected mode reset */ +#define KC8_MENABLE 0x02 /* enable mouse interrupt */ +#define KC8_KENABLE 0x01 /* enable keyboard interrupt */ +#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) + +/* keyboard commands */ +#define KBC_RESET 0xFF /* reset the keyboard */ +#define KBC_RESEND 0xFE /* request the keyboard resend the last byte */ +#define KBC_SETDEFAULT 0xF6 /* resets keyboard to its power-on defaults */ +#define KBC_DISABLE 0xF5 /* as per KBC_SETDEFAULT, but also disable key scanning */ +#define KBC_ENABLE 0xF4 /* enable key scanning */ +#define KBC_TYPEMATIC 0xF3 /* set typematic rate and delay */ +#define KBC_SETTABLE 0xF0 /* set scancode translation table */ +#define KBC_MODEIND 0xED /* set mode indicators (i.e. LEDs) */ +#define KBC_ECHO 0xEE /* request an echo from the keyboard */ + +/* keyboard responses */ +#define KBR_EXTENDED 0xE0 /* extended key sequence */ +#define KBR_RESEND 0xFE /* needs resend of command */ +#define KBR_ACK 0xFA /* received a valid command */ +#define KBR_OVERRUN 0x00 /* flooded */ +#define KBR_FAILURE 0xFD /* diagnosic failure */ +#define KBR_BREAK 0xF0 /* break code prefix - sent on key release */ +#define KBR_RSTDONE 0xAA /* reset complete */ +#define KBR_ECHO 0xEE /* echo response */ diff --git a/sys/arch/wgrisc/include/kcore.h b/sys/arch/wgrisc/include/kcore.h new file mode 100644 index 00000000000..00903c7e50a --- /dev/null +++ b/sys/arch/wgrisc/include/kcore.h @@ -0,0 +1,45 @@ +/* $OpenBSD: kcore.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ +/* $NetBSD: kcore.h,v 1.1 1996/03/10 21:55:18 leo Exp $ */ + +/* + * Copyright (c) 1996 Leo Weppelman. + * 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 Leo Weppelman. + * 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 _MIPS_KCORE_H_ +#define _MIPS_KCORE_H_ + +#define NPHYS_RAM_SEGS 8 + +typedef struct cpu_kcore_hdr { + vm_offset_t kernel_pa; /* Phys. address of kernel VA 0 */ + int mmutype; + phys_ram_seg_t ram_segs[NPHYS_RAM_SEGS]; +} cpu_kcore_hdr_t; + +#endif /* _MIPS_KCORE_H_ */ diff --git a/sys/arch/wgrisc/include/kdbparam.h b/sys/arch/wgrisc/include/kdbparam.h new file mode 100644 index 00000000000..b5e5c27002e --- /dev/null +++ b/sys/arch/wgrisc/include/kdbparam.h @@ -0,0 +1,75 @@ +/* $OpenBSD: kdbparam.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: kdbparam.h,v 1.4 1994/10/26 21:09:42 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)kdbparam.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent definitions for kdb. + */ + +#if BYTE_ORDER == LITTLE_ENDIAN +#define kdbshorten(w) ((w) & 0xFFFF) +#define kdbbyte(w) ((w) & 0xFF) +#define kdbitol(a,b) ((long)(((b) << 16) | ((a) & 0xFFFF))) +#define kdbbtol(a) ((long)(a)) +#endif + +#define LPRMODE "%R" +#define OFFMODE "+%R" + +#define SETBP(ins) BREAK_BRKPT + +/* return the program counter value modified if we are in a delay slot */ +#define kdbgetpc(pcb) (kdbvar[kdbvarchk('t')] < 0 ? \ + (pcb).pcb_regs[34] + 4 : (pcb).pcb_regs[34]) +#define kdbishiddenreg(p) ((p) >= &kdbreglist[33]) +#define kdbisbreak(type) (((type) & CR_EXC_CODE) == 0x24) + +/* check for address wrap around */ +#define kdbaddrwrap(addr,newaddr) (((addr)^(newaddr)) >> 31) + +/* declare machine dependent routines defined in kadb.c */ +void kdbprinttrap __P((unsigned, unsigned)); +void kdbsetsstep __P((void)); +void kdbclrsstep __P((void)); +void kdbreadc __P((char *)); +void kdbwrite __P((char *, int)); +void kdbprintins __P((int, long)); +void kdbstacktrace __P((int)); +char *kdbmalloc __P((int)); diff --git a/sys/arch/wgrisc/include/limits.h b/sys/arch/wgrisc/include/limits.h new file mode 100644 index 00000000000..67584eab9ea --- /dev/null +++ b/sys/arch/wgrisc/include/limits.h @@ -0,0 +1,101 @@ +/* $OpenBSD: limits.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: limits.h,v 1.8 1995/03/28 18:19:16 jtc 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. 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. + * + * @(#)limits.h 8.3 (Berkeley) 1/4/94 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define MB_LEN_MAX 6 /* Allow 31 bit UTF2 */ + +#ifdef _KERNEL +#define CLK_TCK 100 /* ticks per second */ +#endif + +/* + * According to ANSI (section 2.2.4.2), the values below must be usable by + * #if preprocessing directives. Additionally, the expression must have the + * same type as would an expression that is an object of the corresponding + * type converted according to the integral promotions. The subtraction for + * INT_MIN and LONG_MIN is so the value is not unsigned; 2147483648 is an + * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2). + * These numbers work for pcc as well. The UINT_MAX and ULONG_MAX values + * are written as hex so that GCC will be quiet about large integer constants. + */ +#define SCHAR_MAX 127 /* min value for a signed char */ +#define SCHAR_MIN (-128) /* max value for a signed char */ + +#define UCHAR_MAX 255 /* max value for an unsigned char */ +#define CHAR_MAX 127 /* max value for a char */ +#define CHAR_MIN (-128) /* min value for a char */ + +#define USHRT_MAX 65535 /* max value for an unsigned short */ +#define SHRT_MAX 32767 /* max value for a short */ +#define SHRT_MIN (-32768) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 2147483647 /* max value for an int */ +#define INT_MIN (-2147483647-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffff /* max value for an unsigned long */ +#define LONG_MAX 2147483647 /* max value for a long */ +#define LONG_MIN (-2147483647-1) /* min value for a long */ + +#if !defined(_ANSI_SOURCE) +#define SSIZE_MAX INT_MAX /* max value for a ssize_t */ + +#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_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 && !_XOPEN_SOURCE */ +#endif /* !_ANSI_SOURCE */ + +#if (!defined(_ANSI_SOURCE)&&!defined(_POSIX_SOURCE)) || defined(_XOPEN_SOURCE) +#define LONG_BIT 32 +#define WORD_BIT 32 + +#define DBL_DIG 15 +#define DBL_MAX 1.797693134862316E+308 +#define DBL_MIN 2.225073858507201E-308 + +#define FLT_DIG 6 +#define FLT_MAX 3.40282347E+38F +#define FLT_MIN 1.17549435E-38F +#endif diff --git a/sys/arch/wgrisc/include/link.h b/sys/arch/wgrisc/include/link.h new file mode 100644 index 00000000000..411e4e93e56 --- /dev/null +++ b/sys/arch/wgrisc/include/link.h @@ -0,0 +1,68 @@ +/* $OpenBSD: link.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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 _LINK_H +#define _LINK_H 1 + +#include <elf.h> +#include <machine/elf_abi.h> + +/* + * Debug rendezvous struct. Pointer to this is set up in the + * target code pointed by the DT_MIPS_RLD_MAP tag. If it is + * defined. + */ + +struct r_debug { + int r_version; /* Protocol version. */ + struct link_map *r_map; /* Head of list of loaded objects. */ + + /* This is the address of a function internal to the run-time linker, + that will always be called when the linker begins to map in a + library or unmap it, and again when the mapping change is complete. + The debugger can set a breakpoint at this address if it wants to + notice shared object mapping changes. */ + Elf32_Addr r_brk; + enum { + /* This state value describes the mapping change taking place when + the `r_brk' address is called. */ + RT_CONSISTENT, /* Mapping change is complete. */ + RT_ADD, /* Adding a new object. */ + RT_DELETE, /* Removing an object mapping. */ + } r_state; + + Elf32_Addr r_ldbase; /* Base address the linker is loaded at. */ + }; + +#endif /* _LINK_H */ diff --git a/sys/arch/wgrisc/include/memconf.h b/sys/arch/wgrisc/include/memconf.h new file mode 100644 index 00000000000..ea66b629e96 --- /dev/null +++ b/sys/arch/wgrisc/include/memconf.h @@ -0,0 +1,50 @@ +/* $OpenBSD: memconf.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * 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 Per Fogelstrom. + * 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. + */ + +/* + * Memory config list used by pmap_bootstrap. + */ + +#ifndef _MEMCONF_H_ +#define _MEMCONF_H_ + +struct mem_descriptor { + vm_offset_t mem_start; + u_int mem_size; +}; + +#ifdef _KERNEL +#define MAXMEMSEGS 16 +extern struct mem_descriptor mem_layout[]; +#endif + +#endif diff --git a/sys/arch/wgrisc/include/mips_opcode.h b/sys/arch/wgrisc/include/mips_opcode.h new file mode 100644 index 00000000000..b314794d90b --- /dev/null +++ b/sys/arch/wgrisc/include/mips_opcode.h @@ -0,0 +1,260 @@ +/* $OpenBSD: mips_opcode.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)mips_opcode.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Define the instruction formats and opcode values for the + * MIPS instruction set. + */ + +/* + * Define the instruction formats. + */ +typedef union { + unsigned word; + +#if BYTE_ORDER == LITTLE_ENDIAN + struct { + unsigned imm: 16; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } IType; + + struct { + unsigned target: 26; + unsigned op: 6; + } JType; + + struct { + unsigned func: 6; + unsigned shamt: 5; + unsigned rd: 5; + unsigned rt: 5; + unsigned rs: 5; + unsigned op: 6; + } RType; + + struct { + unsigned func: 6; + unsigned fd: 5; + unsigned fs: 5; + unsigned ft: 5; + unsigned fmt: 4; + unsigned : 1; /* always '1' */ + unsigned op: 6; /* always '0x11' */ + } FRType; +#endif +} InstFmt; + +/* + * Values for the 'op' field. + */ +#define OP_SPECIAL 000 +#define OP_BCOND 001 +#define OP_J 002 +#define OP_JAL 003 +#define OP_BEQ 004 +#define OP_BNE 005 +#define OP_BLEZ 006 +#define OP_BGTZ 007 + +#define OP_ADDI 010 +#define OP_ADDIU 011 +#define OP_SLTI 012 +#define OP_SLTIU 013 +#define OP_ANDI 014 +#define OP_ORI 015 +#define OP_XORI 016 +#define OP_LUI 017 + +#define OP_COP0 020 +#define OP_COP1 021 +#define OP_COP2 022 +#define OP_COP3 023 +#define OP_BEQL 024 +#define OP_BNEL 025 +#define OP_BLEZL 026 +#define OP_BGTZL 027 + +#define OP_DADDI 030 +#define OP_DADDIU 031 +#define OP_LDL 032 +#define OP_LDR 033 + +#define OP_LB 040 +#define OP_LH 041 +#define OP_LWL 042 +#define OP_LW 043 +#define OP_LBU 044 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LHU 045 +#define OP_LWR 046 +#define OP_LWU 047 + +#define OP_SB 050 +#define OP_SH 051 +#define OP_SWL 052 +#define OP_SW 053 +#define OP_SDL 054 +#define OP_SDR 055 +#define OP_SWR 056 +#define OP_CACHE 057 + +#define OP_LL 060 +#define OP_LWC1 061 +#define OP_LWC2 062 +#define OP_LWC3 063 +#define OP_LLD 064 +#define OP_LD 067 + +#define OP_SC 070 +#define OP_SWC1 071 +#define OP_SWC2 072 +#define OP_SWC3 073 +#define OP_SCD 074 +#define OP_SD 077 + +/* + * Values for the 'func' field when 'op' == OP_SPECIAL. + */ +#define OP_SLL 000 +#define OP_SRL 002 +#define OP_SRA 003 +#define OP_SLLV 004 +#define OP_SRLV 006 +#define OP_SRAV 007 + +#define OP_JR 010 +#define OP_JALR 011 +#define OP_SYSCALL 014 +#define OP_BREAK 015 +#define OP_SYNC 017 + +#define OP_MFHI 020 +#define OP_MTHI 021 +#define OP_MFLO 022 +#define OP_MTLO 023 +#define OP_DSLLV 024 +#define OP_DSRLV 026 +#define OP_DSRAV 027 + +#define OP_MULT 030 +#define OP_MULTU 031 +#define OP_DIV 032 +#define OP_DIVU 033 +#define OP_DMULT 034 +#define OP_DMULTU 035 +#define OP_DDIV 036 +#define OP_DDIVU 037 + + +#define OP_ADD 040 +#define OP_ADDU 041 +#define OP_SUB 042 +#define OP_SUBU 043 +#define OP_AND 044 +#define OP_OR 045 +#define OP_XOR 046 +#define OP_NOR 047 + +#define OP_SLT 052 +#define OP_SLTU 053 +#define OP_DADD 054 +#define OP_DADDU 055 +#define OP_DSUB 056 +#define OP_DSUBU 057 + +#define OP_TGE 060 +#define OP_TGEU 061 +#define OP_TLT 062 +#define OP_TLTU 063 +#define OP_TEQ 064 +#define OP_TNE 066 + +#define OP_DSLL 070 +#define OP_DSRL 072 +#define OP_DSRA 073 +#define OP_DSLL32 074 +#define OP_DSRL32 076 +#define OP_DSRA32 077 + +/* + * Values for the 'func' field when 'op' == OP_BCOND. + */ +#define OP_BLTZ 000 +#define OP_BGEZ 001 +#define OP_BLTZL 002 +#define OP_BGEZL 003 + +#define OP_TGEI 010 +#define OP_TGEIU 011 +#define OP_TLTI 012 +#define OP_TLTIU 013 +#define OP_TEQI 014 +#define OP_TNEI 016 + +#define OP_BLTZAL 020 +#define OP_BLTZAL 020 +#define OP_BGEZAL 021 +#define OP_BLTZALL 022 +#define OP_BGEZALL 023 + +/* + * Values for the 'rs' field when 'op' == OP_COPz. + */ +#define OP_MF 000 +#define OP_DMF 001 +#define OP_MT 004 +#define OP_DMT 005 +#define OP_BCx 010 +#define OP_BCy 014 +#define OP_CF 002 +#define OP_CT 006 + +/* + * Values for the 'rt' field when 'op' == OP_COPz. + */ +#define COPz_BC_TF_MASK 0x01 +#define COPz_BC_TRUE 0x01 +#define COPz_BC_FALSE 0x00 +#define COPz_BCL_TF_MASK 0x02 +#define COPz_BCL_TRUE 0x02 +#define COPz_BCL_FALSE 0x00 diff --git a/sys/arch/wgrisc/include/param.h b/sys/arch/wgrisc/include/param.h new file mode 100644 index 00000000000..052db4a28eb --- /dev/null +++ b/sys/arch/wgrisc/include/param.h @@ -0,0 +1,165 @@ +/* $OpenBSD: param.h,v 1.1 1997/02/06 16:02:43 pefo 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: machparam.h 1.11 89/08/14 + * from: @(#)param.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent constants for Willowglen Mips RISC machines: + */ +#define MACHINE "wgrisc" +#define MACHINE_ARCH "mips" +#define MID_MACHINE MID_PMAX /* XXX Bogus, but we need it for now... */ + +/* + * Round p (pointer or byte index) up 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. + */ +#define ALIGNBYTES 7 +#define ALIGN(p) (((u_int)(p) + ALIGNBYTES) &~ ALIGNBYTES) + +#define NBPG 4096 /* bytes/page */ +#define PGOFSET (NBPG-1) /* byte offset into page */ +#define PGSHIFT 12 /* LOG2(NBPG) */ +#define NPTEPG (NBPG/4) + +#define NBSEG 0x400000 /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ +#define SEGSHIFT 22 /* LOG2(NBSEG) */ + +#define KERNBASE 0x80000000 /* start of kernel virtual */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define DEV_BSIZE 512 +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define BLKDEV_IOSIZE 2048 +/* XXX Maxphys temporary changed to 32K while SCSI driver is fixed. */ +#define MAXPHYS (32 * 1024) /* max raw I/O transfer size */ + +#define CLSIZE 1 +#define CLSIZELOG2 0 + +/* NOTE: SSIZE, SINCR and UPAGES must be multiples of CLSIZE */ +#define SSIZE 1 /* initial stack size/NBPG */ +#define SINCR 1 /* increment of stack/NBPG */ + +#define UPAGES 2 /* pages of u-area */ +#define UADDR 0xffffc000 /* address of u */ +#define USPACE (UPAGES*NBPG) /* size of u-area in bytes */ +#define UVPN (UADDR>>PGSHIFT)/* virtual page number of u */ +#define KERNELSTACK (UADDR+UPAGES*NBPG) /* top of kernel stack */ + +/* + * Constants related to network buffer management. + * MCLBYTES must be no larger than CLBYTES (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 128 /* size of an mbuf */ +#define MCLBYTES 2048 /* enough for whole Ethernet packet */ +#define MCLSHIFT 10 +#define MCLOFSET (MCLBYTES - 1) +#ifndef NMBCLUSTERS +#ifdef GATEWAY +#define NMBCLUSTERS 2048 /* map size, max cluster allocation */ +#else +#define NMBCLUSTERS 1024 /* map size, max cluster allocation */ +#endif +#endif + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (4096*1024/CLBYTES) +#endif + +/* pages ("clicks") (4096 bytes) 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)) + +/* + * Mach derived conversion macros + */ +#define mips_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1)) +#define mips_trunc_page(x) ((unsigned)(x) & ~(NBPG-1)) +#define mips_btop(x) ((unsigned)(x) >> PGSHIFT) +#define mips_ptob(x) ((unsigned)(x) << PGSHIFT) + +#ifdef _KERNEL +#ifndef _LOCORE +extern int (*Mach_splnet)(), (*Mach_splbio)(), (*Mach_splimp)(), + (*Mach_spltty)(), (*Mach_splclock)(), (*Mach_splstatclock)(); +#define splnet() ((*Mach_splnet)()) +#define splbio() ((*Mach_splbio)()) +#define splimp() ((*Mach_splimp)()) +#define spltty() ((*Mach_spltty)()) +#define splclock() ((*Mach_splclock)()) +#define splstatclock() ((*Mach_splstatclock)()) + +/* + * Delay is based on an assumtion that each time in the loop + * takes 3 clocks. Three is for branch and subtract in the delay slot. + */ +extern int cpuspeed; +#define DELAY(n) { register int N = cpuspeed * (n); while ((N -= 3) > 0); } +#endif + +#else /* !_KERNEL */ +#define DELAY(n) { register int N = (n); while (--N > 0); } +#endif /* !_KERNEL */ diff --git a/sys/arch/wgrisc/include/pcb.h b/sys/arch/wgrisc/include/pcb.h new file mode 100644 index 00000000000..f7f2ce46869 --- /dev/null +++ b/sys/arch/wgrisc/include/pcb.h @@ -0,0 +1,61 @@ +/* $OpenBSD: pcb.h,v 1.1 1997/02/06 16:02:43 pefo 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: pcb.h 1.13 89/04/23 + * from: @(#)pcb.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * ARC process control block + */ +struct pcb +{ + int pcb_regs[71]; /* saved CPU and floating point registers */ + label_t pcb_context; /* kernel context for resume */ + int pcb_onfault; /* for copyin/copyout faults */ + void *pcb_segtab; /* copy of pmap pm_segtab */ +}; + +/* + * The pcb is augmented with machine-dependent additional data for + * core dumps. For the WGRISC, there is nothing to add. + */ +struct md_coredump { + long md_pad[8]; +}; diff --git a/sys/arch/wgrisc/include/pio.h b/sys/arch/wgrisc/include/pio.h new file mode 100644 index 00000000000..a950695eb3e --- /dev/null +++ b/sys/arch/wgrisc/include/pio.h @@ -0,0 +1,46 @@ +/* $OpenBSD: pio.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Copyright (c) 1995 Per Fogelstrom. 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 Per Fogelstrom. + * 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. + */ + +/* + * I/O macros. + */ + +#define outb(a,v) (*(volatile unsigned char*)(a) = (v)) +#define outw(a,v) (*(volatile unsigned short*)(a) = (v)) +#define out16(a,v) outw(a,v) +#define outl(a,v) (*(volatile unsigned int*)(a) = (v)) +#define out32(a,v) outl(a,v) +#define inb(a) (*(volatile unsigned char*)(a)) +#define inw(a) (*(volatile unsigned short*)(a)) +#define in16(a) inw(a) +#define inl(a) (*(volatile unsigned int*)(a)) +#define in32(a) inl(a) + diff --git a/sys/arch/wgrisc/include/pmap.h b/sys/arch/wgrisc/include/pmap.h new file mode 100644 index 00000000000..3044047e584 --- /dev/null +++ b/sys/arch/wgrisc/include/pmap.h @@ -0,0 +1,109 @@ +/* $OpenBSD: pmap.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)pmap.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _PMAP_MACHINE_ +#define _PMAP_MACHINE_ + +/* + * The user address space is 2Gb (0x0 - 0x80000000). + * User programs are laid out in memory as follows: + * address + * USRTEXT 0x00400000 + * USRDATA 0x10000000 + * USRSTACK 0x7FFFFFFF + * + * The user address space is mapped using a two level structure where + * virtual address bits 30..22 are used to index into a segment table which + * points to a page worth of PTEs (4096 page can hold 1024 PTEs). + * Bits 21..12 are then used to index a PTE which describes a page within + * a segment. + * + * The wired entries in the TLB will contain the following: + * 0-1 (UPAGES) for curproc user struct and kernel stack. + * + * Note: The kernel doesn't use the same data structures as user programs. + * All the PTE entries are stored in a single array in Sysmap which is + * dynamically allocated at boot time. + */ + +#define mips_trunc_seg(x) ((vm_offset_t)(x) & ~SEGOFSET) +#define mips_round_seg(x) (((vm_offset_t)(x) + SEGOFSET) & ~SEGOFSET) +#define pmap_segmap(m, v) ((m)->pm_segtab->seg_tab[((v) >> SEGSHIFT)]) + +#define PMAP_SEGTABSIZE 512 + +union pt_entry; + +struct segtab { + union pt_entry *seg_tab[PMAP_SEGTABSIZE]; +}; + +/* + * Machine dependent pmap structure. + */ +typedef struct pmap { + int pm_count; /* pmap reference count */ + simple_lock_data_t pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + int pm_tlbpid; /* address space tag */ + u_int pm_tlbgen; /* TLB PID generation number */ + struct segtab *pm_segtab; /* pointers to pages of PTEs */ +} *pmap_t; + +/* + * Defines for pmap_attributes[phys_mach_page]; + */ +#define PMAP_ATTR_MOD 0x01 /* page has been modified */ +#define PMAP_ATTR_REF 0x02 /* page has been referenced */ + +#ifdef _KERNEL +extern char *pmap_attributes; /* reference and modify bits */ +extern struct pmap 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_kernel() (&kernel_pmap_store) + +#define PMAP_PREFER(pa, va) pmap_prefer((pa), (va)) + +#endif /* _KERNEL */ + +#endif /* _PMAP_MACHINE_ */ diff --git a/sys/arch/wgrisc/include/proc.h b/sys/arch/wgrisc/include/proc.h new file mode 100644 index 00000000000..6b6b1cecd05 --- /dev/null +++ b/sys/arch/wgrisc/include/proc.h @@ -0,0 +1,54 @@ +/* $OpenBSD: proc.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: proc.h,v 1.4 1994/10/26 21:09:52 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)proc.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine-dependent part of the proc structure. + */ +struct mdproc { + int *md_regs; /* registers on current frame */ + int md_flags; /* machine-dependent flags */ + int md_upte[UPAGES]; /* ptes for mapping u page */ + int md_ss_addr; /* single step address for ptrace */ + int md_ss_instr; /* single step instruction for ptrace */ +}; + +/* md_flags */ +#define MDP_FPUSED 0x0001 /* floating point coprocessor used */ diff --git a/sys/arch/wgrisc/include/profile.h b/sys/arch/wgrisc/include/profile.h new file mode 100644 index 00000000000..9d4b5d3efb8 --- /dev/null +++ b/sys/arch/wgrisc/include/profile.h @@ -0,0 +1,81 @@ +/* $OpenBSD: profile.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)profile.h 8.1 (Berkeley) 6/10/93 + */ + +#define _MCOUNT_DECL static void ___mcount + +#define MCOUNT \ + __asm(".globl _mcount;" \ + ".type _mcount,@function;" \ + "_mcount:;" \ + ".set noreorder;" \ + ".set noat;" \ + ".cpload $25;" \ + "sw $4,8($29);" \ + "sw $5,12($29);" \ + "sw $6,16($29);" \ + "sw $7,20($29);" \ + "sw $1,0($29);" \ + "sw $31,4($29);" \ + "move $5,$31;" \ + "jal ___mcount;" \ + "move $4,$1;" \ + "lw $4,8($29);" \ + "lw $5,12($29);" \ + "lw $6,16($29);" \ + "lw $7,20($29);" \ + "lw $31,4($29);" \ + "lw $1,0($29);" \ + "addu $29,$29,8;" \ + "j $31;" \ + "move $31,$1;" \ + ".set reorder;" \ + ".set at"); + +#ifdef _KERNEL +/* + * The following two macros do splhigh and splx respectively. + * They have to be defined this way because these are real + * functions on the MIPS, and we do not want to invoke mcount + * recursively. + */ +#define MCOUNT_ENTER s = _splhigh() + +#define MCOUNT_EXIT _splx(s) +#endif /* _KERNEL */ diff --git a/sys/arch/wgrisc/include/psl.h b/sys/arch/wgrisc/include/psl.h new file mode 100644 index 00000000000..1158aaae34f --- /dev/null +++ b/sys/arch/wgrisc/include/psl.h @@ -0,0 +1,61 @@ +/* $OpenBSD: psl.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)psl.h 8.1 (Berkeley) 6/10/93 + */ + +#include <machine/cpu.h> + +#define PSL_LOWIPL (INT_MASK | SR_INT_ENAB) + +#define R3K_PSL_USERSET ( SR_KU_OLD | SR_INT_ENA_OLD | \ + SR_KU_PREV | SR_INT_ENA_PREV | \ + INT_MASK) + +#define R4K_PSL_USERSET ( SR_KSU_USER | SR_INT_ENAB | \ + SR_EXL | INT_MASK) + +/* + * Macros to decode processor status word. + */ +#define R3K_USERMODE(ps) ((ps) & SR_KU_PREV) +#define R3K_BASEPRI(ps) (((ps) & (INT_MASK | SR_INT_ENA_PREV)) \ + == (INT_MASK | SR_INT_ENA_PREV)) + +#define R4K_USERMODE(ps) (((ps) & SR_KSU_MASK) == SR_KSU_USER) +#define R4K_BASEPRI(ps) (((ps) & (INT_MASK | SR_INT_ENA_PREV)) \ + == (INT_MASK | SR_INT_ENA_PREV)) diff --git a/sys/arch/wgrisc/include/pte.h b/sys/arch/wgrisc/include/pte.h new file mode 100644 index 00000000000..97463fe7ff7 --- /dev/null +++ b/sys/arch/wgrisc/include/pte.h @@ -0,0 +1,176 @@ +/* $OpenBSD: pte.h,v 1.1 1997/02/06 16:02:43 pefo 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: pte.h 1.11 89/09/03 + * from: @(#)pte.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _LOCORE +/* + * R3000 hardware page table entry + * R4000 hardware page table entry + */ +struct pte { +#if BYTE_ORDER == BIG_ENDIAN +#ifdef R4K +unsigned int pg_prot:2, /* SW: access control */ + pg_pfnum:24, /* HW: core page frame number or 0 */ + pg_attr:3, /* HW: cache attribute */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_v:1, /* HW: valid bit */ + pg_g:1; /* HW: ignore pid bit */ +#else +unsigned int pg_pfnum:20, /* HW: core page frame number or 0 */ + pg_n:1, /* HW: non-cacheable bit */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_v:1, /* HW: valid bit */ + pg_g:1, /* HW: ignore pid bit */ + :4, + pg_swapm:1, /* SW: page must be forced to swap */ + pg_fod:1, /* SW: is fill on demand (=0) */ + pg_prot:2; /* SW: access control */ +#endif +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef R4K +unsigned int pg_g:1, /* HW: ignore pid bit */ + pg_v:1, /* HW: valid bit */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_attr:3, /* HW: cache attribute */ + pg_pfnum:24, /* HW: core page frame number or 0 */ + pg_prot:2; /* SW: access control */ +#else +unsigned int pg_prot:2, /* SW: access control */ + pg_fod:1, /* SW: is fill on demand (=0) */ + pg_swapm:1, /* SW: page must be forced to swap */ + :4, + pg_g:1, /* HW: ignore pid bit */ + pg_v:1, /* HW: valid bit */ + pg_m:1, /* HW: modified (dirty) bit */ + pg_n:1, /* HW: non-cacheable bit */ + pg_pfnum:20; /* HW: core page frame number or 0 */ +#endif +#endif +}; + +/* + * Structure defining an tlb entry data set. + */ + +struct tlb { + int tlb_mask; + int tlb_hi; + int tlb_lo0; + int tlb_lo1; +}; + +typedef union pt_entry { + unsigned int pt_entry; /* for copying, etc. */ + struct pte pt_pte; /* for getting to bits by name */ +} pt_entry_t; /* Mach page table entry */ +#endif /* _LOCORE */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) + +#ifdef R4K +#define PG_SVPN 0xfffff000 /* Software page no mask */ +#define PG_HVPN 0xffffe000 /* Hardware page no mask */ +#define PG_ODDPG 0x00001000 /* Odd even pte entry */ +#define PG_ASID 0x000000ff /* Address space ID */ +#define PG_G 0x00000001 /* HW */ +#define PG_V 0x00000002 +#define PG_NV 0x00000000 +#define PG_M 0x00000004 +#define PG_ATTR 0x0000003f +#define PG_UNCACHED 0x00000010 +#define PG_CACHED 0x00000018 +#define PG_CACHEMODE 0x00000038 +#define PG_FRAME 0x3fffffc0 +#define PG_RO 0x40000000 /* SW */ +#define PG_WIRED 0x80000000 /* SW */ +#define PG_SHIFT 6 +#define PG_SIZE_4K 0x00000000 +#define PG_SIZE_16K 0x00006000 +#define PG_SIZE_64K 0x0001e000 +#define PG_SIZE_256K 0x0007e000 +#define PG_SIZE_1M 0x001fe000 +#define PG_SIZE_4M 0x007fe000 +#define PG_SIZE_16M 0x01ffe000 + +#else /* R3K */ +#define PG_PROT 0x00000003 /* Software bits */ +#define PG_RW 0x00000000 /* Read/Write mapped */ +#define PG_RO 0x00000001 /* Read only mapped */ +#define PG_WIRED 0x00000002 /* Page is wired down */ +#define PG_G 0x00000100 /* Global mapped */ +#define PG_V 0x00000200 /* Page is valid */ +#define PG_NV 0x00000000 /* Page is NOT valid */ +#define PG_M 0x00000400 /* Page is dirty */ +#define PG_UNCACHED 0x00000800 /* Non cachable page */ +#define PG_CACHED 0x00000000 /* Non cachable page */ +#define PG_CACHEMODE 0x00000800 +#define PG_FRAME 0xfffff000 +#define PG_SHIFT 0 /* VPN already in place */ +#endif + +#define PG_ROPAGE (PG_V | PG_RO | PG_CACHED) /* Write protected */ +#define PG_RWPAGE (PG_V | PG_M | PG_CACHED) /* Not wr-prot not clean */ +#define PG_CWPAGE (PG_V | PG_CACHED) /* Not wr-prot but clean */ +#define PG_IOPAGE (PG_G | PG_V | PG_M | PG_UNCACHED) + +#define vad_to_pfn(x) (((unsigned)(x) >> PG_SHIFT) & PG_FRAME) +#define vad_to_pfn64(x) (((quad_t)(x) >> PG_SHIFT) & PG_FRAME) +#define pfn_to_vad(x) (((x) & PG_FRAME) << PG_SHIFT) +#define vad_to_vpn(x) ((unsigned)(x) & PG_SVPN) +#define vpn_to_vad(x) ((x) & PG_SVPN) +/* User viritual to pte page entry */ +#define uvtopte(adr) (((adr) >> PGSHIFT) & (NPTEPG -1)) + +#if defined(_KERNEL) && !defined(_LOCORE) +/* + * Kernel virtual address to page table entry and visa versa. + */ +#define kvtopte(va) \ + (Sysmap + (((vm_offset_t)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT)) +#define ptetokv(pte) \ + ((((pt_entry_t *)(pte) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) + +extern pt_entry_t *Sysmap; /* kernel pte table */ +extern u_int Sysmapsize; /* number of pte's in Sysmap */ +#endif diff --git a/sys/arch/wgrisc/include/ptrace.h b/sys/arch/wgrisc/include/ptrace.h new file mode 100644 index 00000000000..cc39ce21efc --- /dev/null +++ b/sys/arch/wgrisc/include/ptrace.h @@ -0,0 +1,45 @@ +/* $OpenBSD: ptrace.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ + +/* + * Copyright (c) 1992, 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. 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: @(#)ptrace.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent trace commands. + * + */ + +#define PT_GETREGS (PT_FIRSTMACH+0) +#define PT_SETREGS (PT_FIRSTMACH+1) +#define PT_STEP (PT_FIRSTMACH+2) diff --git a/sys/arch/wgrisc/include/reg.h b/sys/arch/wgrisc/include/reg.h new file mode 100644 index 00000000000..b76697e21d6 --- /dev/null +++ b/sys/arch/wgrisc/include/reg.h @@ -0,0 +1,62 @@ +/* $OpenBSD: reg.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: reg.h,v 1.6 1995/12/20 02:00:27 jonathan 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: reg.h 1.1 90/07/09 + * @(#)reg.h 8.2 (Berkeley) 1/11/94 + */ + +#ifndef _MACHINE_REG_H_ +#define _MACHINE_REG_H_ +/* + * Location of the users' stored + * registers relative to ZERO. + * Usage is p->p_regs[XX]. + * + * must be visible to assembly code. + */ +#include <machine/regnum.h> + +/* + * Register set accessible via /proc/$pid/reg + */ +struct reg { + int r_regs[71]; /* numbered as above */ +}; +#endif /*_MACHINE_REG_H_*/ diff --git a/sys/arch/wgrisc/include/regdef.h b/sys/arch/wgrisc/include/regdef.h new file mode 100644 index 00000000000..e78cfda0e6b --- /dev/null +++ b/sys/arch/wgrisc/include/regdef.h @@ -0,0 +1,74 @@ +/* $OpenBSD: regdef.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: regdef.h,v 1.4 1994/10/26 21:09:58 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell. This file is derived from the MIPS RISC + * Architecture book by Gerry Kane. + * + * 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. + * + * @(#)regdef.h 8.1 (Berkeley) 6/10/93 + */ + +#define zero $0 /* always zero */ +#define AT $at /* assembler temp */ +#define v0 $2 /* return value */ +#define v1 $3 +#define a0 $4 /* argument registers */ +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 /* temp registers (not saved across subroutine calls) */ +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 /* saved across subroutine calls (callee saved) */ +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 /* two more temp registers */ +#define t9 $25 +#define k0 $26 /* kernel temporary */ +#define k1 $27 +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define s8 $30 /* one more callee saved */ +#define ra $31 /* return address */ diff --git a/sys/arch/wgrisc/include/regnum.h b/sys/arch/wgrisc/include/regnum.h new file mode 100644 index 00000000000..a952baa78e2 --- /dev/null +++ b/sys/arch/wgrisc/include/regnum.h @@ -0,0 +1,136 @@ +/* $OpenBSD: regnum.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ +/* $NetBSD: reg.h,v 1.5 1995/01/18 06:40:12 mellon 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: reg.h 1.1 90/07/09 + * @(#)reg.h 8.2 (Berkeley) 1/11/94 + */ + +/* + * Location of the users' stored + * registers relative to ZERO. + * Usage is p->p_regs[XX]. + */ +#define ZERO 0 +#define AST 1 +#define V0 2 +#define V1 3 +#define A0 4 +#define A1 5 +#define A2 6 +#define A3 7 +#define T0 8 +#define T1 9 +#define T2 10 +#define T3 11 +#define T4 12 +#define T5 13 +#define T6 14 +#define T7 15 +#define S0 16 +#define S1 17 +#define S2 18 +#define S3 19 +#define S4 20 +#define S5 21 +#define S6 22 +#define S7 23 +#define T8 24 +#define T9 25 +#define K0 26 +#define K1 27 +#define GP 28 +#define SP 29 +#define S8 30 +#define RA 31 +#define SR 32 +#define PS SR /* alias for SR */ +#define MULLO 33 +#define MULHI 34 +#define BADVADDR 35 +#define CAUSE 36 +#define PC 37 + +#define FPBASE 38 +#define F0 (FPBASE+0) +#define F1 (FPBASE+1) +#define F2 (FPBASE+2) +#define F3 (FPBASE+3) +#define F4 (FPBASE+4) +#define F5 (FPBASE+5) +#define F6 (FPBASE+6) +#define F7 (FPBASE+7) +#define F8 (FPBASE+8) +#define F9 (FPBASE+9) +#define F10 (FPBASE+10) +#define F11 (FPBASE+11) +#define F12 (FPBASE+12) +#define F13 (FPBASE+13) +#define F14 (FPBASE+14) +#define F15 (FPBASE+15) +#define F16 (FPBASE+16) +#define F17 (FPBASE+17) +#define F18 (FPBASE+18) +#define F19 (FPBASE+19) +#define F20 (FPBASE+20) +#define F21 (FPBASE+21) +#define F22 (FPBASE+22) +#define F23 (FPBASE+23) +#define F24 (FPBASE+24) +#define F25 (FPBASE+25) +#define F26 (FPBASE+26) +#define F27 (FPBASE+27) +#define F28 (FPBASE+28) +#define F29 (FPBASE+29) +#define F30 (FPBASE+30) +#define F31 (FPBASE+31) +#define FSR (FPBASE+32) + +#ifdef IPCREG +#define NIPCREG (FSR + 1) +int ipcreg[NIPCREG] = { + ZERO, AST, V0, V1, A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, T6, T7, + S0, S1, S2, S3, S4, S5, S6, S7, T8, T9, K0, K1, GP, SP, S8, RA, + SR, MULLO, MULHI, BADVADDR, CAUSE, PC, + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, FSR, +}; +#endif diff --git a/sys/arch/wgrisc/include/reloc.h b/sys/arch/wgrisc/include/reloc.h new file mode 100644 index 00000000000..e9652853c1c --- /dev/null +++ b/sys/arch/wgrisc/include/reloc.h @@ -0,0 +1,38 @@ +/* $OpenBSD: reloc.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/*- + * Copyright (c) 1992, 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. 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: @(#)reloc.h 8.1 (Berkeley) 6/10/93 + * from: Header: reloc.h,v 1.6 92/06/20 09:59:37 torek Exp + */ + diff --git a/sys/arch/wgrisc/include/setjmp.h b/sys/arch/wgrisc/include/setjmp.h new file mode 100644 index 00000000000..9e9a2b275f5 --- /dev/null +++ b/sys/arch/wgrisc/include/setjmp.h @@ -0,0 +1,8 @@ +/* $OpenBSD: setjmp.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: setjmp.h,v 1.1 1994/12/20 10:37:05 cgd Exp $ */ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + */ + +#define _JBLEN 83 /* size, in longs, of a jmp_buf */ diff --git a/sys/arch/wgrisc/include/signal.h b/sys/arch/wgrisc/include/signal.h new file mode 100644 index 00000000000..f69bea8f1c7 --- /dev/null +++ b/sys/arch/wgrisc/include/signal.h @@ -0,0 +1,68 @@ +/* $OpenBSD: signal.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: signal.h,v 1.6 1995/01/18 06:42:01 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)signal.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine-dependent signal definitions + */ + +typedef int sig_atomic_t; + +#ifndef _ANSI_SOURCE +/* + * 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. + */ +struct sigcontext { + int sc_onstack; /* sigstack state to restore */ + int sc_mask; /* signal mask to restore */ + int sc_pc; /* pc at time of signal */ + int sc_regs[32]; /* processor regs 0 to 31 */ + int mullo, mulhi; /* mullo and mulhi registers... */ + int sc_fpused; /* fp has been used */ + int sc_fpregs[33]; /* fp regs 0 to 31 and csr */ + int sc_fpc_eir; /* floating point exception instruction reg */ + int xxx[8]; /* XXX reserved */ +}; + +#endif /* !_ANSI_SOURCE */ diff --git a/sys/arch/wgrisc/include/stdarg.h b/sys/arch/wgrisc/include/stdarg.h new file mode 100644 index 00000000000..d7547edec64 --- /dev/null +++ b/sys/arch/wgrisc/include/stdarg.h @@ -0,0 +1,65 @@ +/* $OpenBSD: stdarg.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: stdarg.h,v 1.7 1995/03/28 18:19:28 jtc Exp $ */ + +/*- + * Copyright (c) 1992, 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. 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. + * + * @(#)stdarg.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _MIPS_STDARG_H_ +#define _MIPS_STDARG_H_ + +#include <machine/ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define __va_promote(type) \ + (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int)) + +#define va_start(ap, last) \ + (ap = ((char *)&(last) + __va_promote(last))) + +#ifdef _KERNEL +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type)))[-1] +#else +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type) == sizeof(int) ? sizeof(type) : \ + sizeof(type) > sizeof(int) ? \ + (-(int)(ap) & (sizeof(type) - 1)) + sizeof(type) : \ + (abort(), 0)))[-1] +#endif + +#define va_end(ap) ((void) 0) + +#endif /* !_MIPS_STDARG_H_ */ diff --git a/sys/arch/wgrisc/include/trap.h b/sys/arch/wgrisc/include/trap.h new file mode 100644 index 00000000000..bb9fd65c3fb --- /dev/null +++ b/sys/arch/wgrisc/include/trap.h @@ -0,0 +1,68 @@ +/* $OpenBSD: trap.h,v 1.1 1997/02/06 16:02:43 pefo 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: trap.h 1.1 90/07/09 + * from: @(#)trap.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Trap codes + * also known in trap.c for name strings + */ + +#define T_INT 0 /* Interrupt pending */ +#define T_TLB_MOD 1 /* TLB modified fault */ +#define T_TLB_LD_MISS 2 /* TLB miss on load or ifetch */ +#define T_TLB_ST_MISS 3 /* TLB miss on a store */ +#define T_ADDR_ERR_LD 4 /* Address error on a load or ifetch */ +#define T_ADDR_ERR_ST 5 /* Address error on a store */ +#define T_BUS_ERR_IFETCH 6 /* Bus error on an ifetch */ +#define T_BUS_ERR_LD_ST 7 /* Bus error on a load or store */ +#define T_SYSCALL 8 /* System call */ +#define T_BREAK 9 /* Breakpoint */ +#define T_RES_INST 10 /* Reserved instruction exception */ +#define T_COP_UNUSABLE 11 /* Coprocessor unusable */ +#define T_OVFLOW 12 /* Arithmetic overflow */ +#define T_TRAP 13 /* Trap instruction */ +#define T_VCEI 14 /* Viritual coherency instruction */ +#define T_FPE 15 /* Floating point exception */ +#define T_WATCH 23 /* Watch address reference */ +#define T_VCED 31 /* Viritual coherency data */ + +#define T_USER 0x20 /* user-mode flag or'ed with type */ diff --git a/sys/arch/wgrisc/include/types.h b/sys/arch/wgrisc/include/types.h new file mode 100644 index 00000000000..af2da55a4d1 --- /dev/null +++ b/sys/arch/wgrisc/include/types.h @@ -0,0 +1,82 @@ +/* $OpenBSD: types.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: types.h,v 1.10 1995/07/06 03:39:43 cgd Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)types.h 8.3 (Berkeley) 1/5/94 + */ + +#ifndef _MACHTYPES_H_ +#define _MACHTYPES_H_ + +#include <sys/cdefs.h> + +#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +typedef struct _physadr { + int r[1]; +} *physadr; + +typedef struct label_t { + int val[12]; +} label_t; +#endif + +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_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 short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +/* LONGLONG */ +typedef long long int64_t; +/* LONGLONG */ +typedef unsigned long long u_int64_t; + +typedef int32_t register_t; + +#define __BDEVSW_DUMP_OLD_TYPE +#define __SWAP_BROKEN +#define __FORK_BRAINDAMAGE + +#endif /* _MACHTYPES_H_ */ diff --git a/sys/arch/wgrisc/include/varargs.h b/sys/arch/wgrisc/include/varargs.h new file mode 100644 index 00000000000..8656c4b1607 --- /dev/null +++ b/sys/arch/wgrisc/include/varargs.h @@ -0,0 +1,69 @@ +/* $OpenBSD: varargs.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: varargs.h,v 1.8 1995/03/28 18:19:30 jtc Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * + * @(#)varargs.h 8.2 (Berkeley) 3/22/94 + */ + +#ifndef _MIPS_VARARGS_H_ +#define _MIPS_VARARGS_H_ + +#include <machine/ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define va_dcl int va_alist; ... + +#define va_start(ap) \ + ap = (char *)&va_alist + +#ifdef _KERNEL +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type)))[-1] +#else +#define va_arg(ap, type) \ + ((type *)(ap += sizeof(type) == sizeof(int) ? sizeof(type) : \ + sizeof(type) > sizeof(int) ? \ + (-(int)(ap) & (sizeof(type) - 1)) + sizeof(type) : \ + (abort(), 0)))[-1] +#endif + +#define va_end(ap) ((void) 0) + +#endif /* !_MIPS_VARARGS_H_ */ diff --git a/sys/arch/wgrisc/include/vmparam.h b/sys/arch/wgrisc/include/vmparam.h new file mode 100644 index 00000000000..fc302f59943 --- /dev/null +++ b/sys/arch/wgrisc/include/vmparam.h @@ -0,0 +1,229 @@ +/* $OpenBSD: vmparam.h,v 1.1 1997/02/06 16:02:43 pefo Exp $ */ +/* $NetBSD: vmparam.h,v 1.5 1994/10/26 21:10:10 cgd 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: vmparam.h 1.16 91/01/18 + * @(#)vmparam.h 8.2 (Berkeley) 4/22/94 + */ + +/* + * Machine dependent constants. + */ +/* + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. + */ +#define USRTEXT 0x00400000 +#define USRSTACK 0x80000000 /* Start of user stack */ + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ (24*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ (32*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (32*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ MAXDSIZ /* max stack size */ +#endif + +/* + * Default sizes of swap allocation chunks (see dmap.h). + * The actual values may be changed in vminit() based on MAXDSIZ. + * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024. + * DMMIN should be at least ctod(1) so that vtod() works. + * vminit() insures this. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ + +/* + * Sizes of the system and user portions of the system page table. + */ +/* SYSPTSIZE IS SILLY; (really number of buffers for I/O) */ +#define SYSPTSIZE 1228 +#define USRPTSIZE 1024 + +/* + * PTEs for mapping user space into the kernel for phyio operations. + * 16 pte's are enough to cover 8 disks * MAXBSIZE. + */ +#ifndef USRIOSIZE +#define USRIOSIZE 32 +#endif + +/* + * PTEs for system V style shared memory. + * This is basically slop for kmempt which we actually allocate (malloc) from. + */ +#ifndef SHMMAXPGS +#define SHMMAXPGS 1024 /* 4mb */ +#endif + +/* + * Boundary at which to place first MAPMEM segment if not explicitly + * specified. Should be a power of two. This allows some slop for + * the data segment to grow underneath the first mapped segment. + */ +#define MMSEG 0x200000 + +/* + * The size of the clock loop. + */ +#define LOOPPAGES (maxfree - firstfree) + +/* + * 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 + +/* + * A swapped in process is given a small amount of core without being bothered + * by the page replacement algorithm. Basically this says that if you are + * swapped in you deserve some resources. We protect the last SAFERSS + * pages against paging and will just swap you out rather than paging you. + * Note that each process has at least UPAGES+CLSIZE pages which are not + * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this + * number just means a swapped in process is given around 25k bytes. + * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81), + * so we loan each swapped in process memory worth 100$, or just admit + * that we don't consider it worthwhile and swap it out to disk which costs + * $30/mb or about $0.75. + */ +#define SAFERSS 4 /* nominal ``small'' resident set size + protected against replacement */ + +/* + * DISKRPM is used to estimate the number of paging i/o operations + * which one can expect from a single disk controller. + */ +#define DISKRPM 60 + +/* + * Klustering constants. Klustering is the gathering + * of pages together for pagein/pageout, while clustering + * is the treatment of hardware page size as though it were + * larger than it really is. + * + * KLMAX gives maximum cluster size in CLSIZE page (cluster-page) + * units. Note that ctod(KLMAX*CLSIZE) must be <= DMMIN in dmap.h. + * ctob(KLMAX) should also be less than MAXPHYS (in vm_swp.c) + * unless you like "big push" panics. + */ + +#ifdef notdef /* XXX */ +#define KLMAX (4/CLSIZE) +#define KLSEQL (2/CLSIZE) /* in klust if vadvise(VA_SEQL) */ +#define KLIN (4/CLSIZE) /* default data/stack in klust */ +#define KLTXT (4/CLSIZE) /* default text in klust */ +#define KLOUT (4/CLSIZE) +#else +#define KLMAX (1/CLSIZE) +#define KLSEQL (1/CLSIZE) +#define KLIN (1/CLSIZE) +#define KLTXT (1/CLSIZE) +#define KLOUT (1/CLSIZE) +#endif + +/* + * KLSDIST is the advance or retard of the fifo reclaim for sequential + * processes data space. + */ +#define KLSDIST 3 /* klusters advance/retard for seq. fifo */ + +/* + * Paging thresholds (see vm_sched.c). + * Strategy of 1/19/85: + * lotsfree is 512k bytes, but at most 1/4 of memory + * desfree is 200k bytes, but at most 1/8 of memory + */ +#define LOTSFREE (512 * 1024) +#define LOTSFREEFRACT 4 +#define DESFREE (200 * 1024) +#define DESFREEFRACT 8 + +/* + * There are two clock hands, initially separated by HANDSPREAD bytes + * (but at most all of user memory). The amount of time to reclaim + * a page once the pageout process examines it increases with this + * distance and decreases as the scan rate rises. + */ +#define HANDSPREAD (2 * 1024 * 1024) + +/* + * The number of times per second to recompute the desired paging rate + * and poke the pagedaemon. + */ +#define RATETOSCHEDPAGING 4 + +/* + * Believed threshold (in megabytes) for which interleaved + * swapping area is desirable. + */ +#define LOTSOFMEM 2 + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0x00000000) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0x80000000) +#define VM_MAX_ADDRESS ((vm_offset_t)0x80000000) +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xC0000000) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFFFFC000) + +/* virtual sizes (bytes) for various kernel submaps */ +#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES) +#define VM_KMEM_SIZE (NKMEMCLUSTERS*CLBYTES) +#define VM_PHYS_SIZE (USRIOSIZE*CLBYTES) diff --git a/sys/arch/wgrisc/isa/isa_machdep.h b/sys/arch/wgrisc/isa/isa_machdep.h new file mode 100644 index 00000000000..47d73c6318c --- /dev/null +++ b/sys/arch/wgrisc/isa/isa_machdep.h @@ -0,0 +1,84 @@ +/* $OpenBSD: isa_machdep.h,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * 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 Per Fogelstrom + * 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 _ISA_MACHDEP_H_ +#define _ISA_MACHDEP_H_ + +typedef struct wgrisc_isa_bus *isa_chipset_tag_t; + +/* + * I/O macros to access isa bus ports/memory. + * At the first glance theese macros may seem inefficient. + * However, the cpu executes an instruction every 7.5ns + * so the bus is much slower so it doesn't matter, really. + */ +#define isa_outb(x,y) outb(isa_io_base + (x), y) +#define isa_inb(x) inb(isa_io_base + (x)) + +extern int isa_io_base; /* Base address for ISA I/O space */ +extern int isa_mem_base; /* Base address for ISA MEM space */ + +struct wgrisc_isa_bus { + void *ic_data; + + void (*ic_attach_hook) __P((struct device *, struct device *, + struct isabus_attach_args *)); + void *(*ic_intr_establish) __P((isa_chipset_tag_t, int, int, int, + int (*)(void *), void *, char *)); + void (*ic_intr_disestablish) __P((isa_chipset_tag_t, void *)); +}; + + +/* + * Functions provided to machine-independent ISA code. + */ +#define isa_attach_hook(p, s, a) /* \ + (*(a)->iba_ic->ic_attach_hook)((p), (s), (a)) */ +#define isa_intr_establish(c, i, t, l, f, a, w) \ + (*(c)->ic_intr_establish)((c)->ic_data, (i), (t), (l), (f), (a), (w)) +#define isa_intr_disestablish(c, h) \ + (*(c)->ic_intr_disestablish)((c)->ic_data, (h)) + +/* + * Interrupt control struct used to control the ICU setup. + */ + +struct intrhand { + struct intrhand *ih_next; + int (*ih_fun) __P((void *)); + void *ih_arg; + u_long ih_count; + int ih_level; + int ih_irq; + char *ih_what; +}; + +#endif /* _ISA_MACHDEP_H_ */ diff --git a/sys/arch/wgrisc/isa/isabus.c b/sys/arch/wgrisc/isa/isabus.c new file mode 100644 index 00000000000..2c2c6e4ecde --- /dev/null +++ b/sys/arch/wgrisc/isa/isabus.c @@ -0,0 +1,350 @@ +/* $OpenBSD: isabus.c,v 1.1 1997/02/06 16:02:42 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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/time.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <wgrisc/wgrisc/wgrisctype.h> +#include <wgrisc/riscbus/riscbus.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <wgrisc/isa/isa_machdep.h> + +static int beeping; + +struct isabr_softc { + struct device sc_dv; + struct wgrisc_isa_bus wgrisc_isa_cs; + struct abus sc_bus; +}; + +/* Definition of the driver for autoconfig. */ +int isabrmatch(struct device *, void *, void *); +void isabrattach(struct device *, struct device *, void *); +int isabrprint(void *, const char *); + +struct cfattach isabr_ca = { + sizeof(struct isabr_softc), isabrmatch, isabrattach +}; +struct cfdriver isabr_cd = { + NULL, "isabr", DV_DULL, NULL, 0 +}; + +void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int, + int (*)(void *), void *, char *)); +void isabr_intr_disestablish __P((isa_chipset_tag_t, void*)); +int isabr_iointr __P((unsigned int, struct clockframe *)); + +extern int cputype; + +int +isabrmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* Make sure that we're looking for a ISABR. */ + if (strcmp(ca->ca_name, isabr_cd.cd_name) != 0) + return (0); + + return (1); +} + +void +isabrattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct isabr_softc *sc = (struct isabr_softc *)self; + struct isabus_attach_args iba; + + printf("\n"); + + /* set up interrupt handlers */ + switch(cputype) { + case WGRISC9100: + set_intr(INT_MASK_3 | INT_MASK_5, isabr_iointr, 1); + break; + default: + panic("isabrattach: unkown cputype!"); + } + +/*XXX we may remove the abus part of the softc struct... */ + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_ISABR; + + sc->wgrisc_isa_cs.ic_intr_establish = isabr_intr_establish; + sc->wgrisc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish; + + iba.iba_busname = "isa"; + iba.iba_iot = (bus_space_tag_t)isa_io_base; + iba.iba_memt = (bus_space_tag_t)isa_mem_base; + iba.iba_ic = &sc->wgrisc_isa_cs; + config_found(self, &iba, isabrprint); +} + +int +isabrprint(aux, pnp) + void *aux; + const char *pnp; +{ + struct confargs *ca = aux; + + if (pnp) + printf("%s at %s", ca->ca_name, pnp); + printf(" isa_io_base 0x%lx isa_mem_base 0x%lx", isa_io_base, isa_mem_base); + return (UNCONF); +} + +/* + * Interrupt system driver code + * ============================ + */ + +int intmask; +int intrmask[16], intrlevel[16]; +struct intrhand *intrhand[16]; + +int fakeintr(void *a) {return 0;} + +/* + * Recalculate the interrupt masks from scratch. + * We could code special registry and deregistry versions of this function that + * would be faster, but the code would be nastier, and we don't expect this to + * happen very much anyway. + */ +void +intr_calculatemasks() +{ + int irq, level; + struct intrhand *q; + + /* First, figure out which levels each IRQ uses. */ + for (irq = 0; irq < 16; irq++) { + register int levels = 0; + for (q = intrhand[irq]; q; q = q->ih_next) + levels |= 1 << q->ih_level; + intrlevel[irq] = levels; + } + + /* Then figure out which IRQs use each level. */ + for (level = 0; level < 5; level++) { + register int irqs = 0; + for (irq = 0; irq < 8; irq++) + if (intrlevel[irq] & (1 << level)) + irqs |= 1 << irq; + imask[level] = irqs | SIR_ALLMASK; + } + + /* + * There are tty, network and disk drivers that use free() at interrupt + * time, so imp > (tty | net | bio). + */ + imask[IPL_IMP] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO]; + + /* + * Enforce a hierarchy that gives slow devices a better chance at not + * dropping data. + */ + imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO]; + imask[IPL_NET] |= imask[IPL_BIO]; + + /* + * These are pseudo-levels. + */ + imask[IPL_NONE] = 0x00000000; + imask[IPL_HIGH] = 0xffffffff; + + /* And eventually calculate the complete masks. */ + for (irq = 0; irq < 16; irq++) { + register int irqs = 1 << irq; + for (q = intrhand[irq]; q; q = q->ih_next) + irqs |= imask[q->ih_level]; + intrmask[irq] = irqs | SIR_ALLMASK; + } + + /* Lastly, determine which IRQs are actually in use. */ + { + register int irqs = 0; + for (irq = 0; irq < 16; irq++) + if (intrhand[irq]) + irqs |= 1 << irq; + intmask = ~irqs; + } +} + +/* + * Establish a ISA bus interrupt. + */ +void * +isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what) + isa_chipset_tag_t ic; + int irq; + int type; + int level; + int (*ih_fun) __P((void *)); + void *ih_arg; + char *ih_what; +{ + struct intrhand **p, *q, *ih; + static struct intrhand fakehand = {NULL, fakeintr}; + extern int cold; + + /* no point in sleeping unless someone can free memory. */ + ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) + panic("isa_intr_establish: can't malloc handler info"); + + /* + * Figure out where to put the handler. + * This is O(N^2), but we want to preserve the order, and N is + * generally small. + */ + for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + ; + + /* + * Actually install a fake handler momentarily, since we might be doing + * this with interrupts enabled and don't want the real routine called + * until masking is set up. + */ + fakehand.ih_level = level; + *p = &fakehand; + + switch(irq) { + case 5: + break; + case 6: + intmask |= R3715_ISAIRQ_6; + break; + case 7: + intmask |= R3715_ISAIRQ_7; + break; + case 9: + intmask |= R3715_ISAIRQ_9; + break; + case 10: + intmask |= R3715_ISAIRQ_10; + break; + case 11: + intmask |= R3715_ISAIRQ_11; + break; + default: + printf("non available irq '%d' requested\n",irq); + panic("isa_intr_establish: can't establish"); + } + out32(R3715_INT_MASK, intmask); + + /* + * Poke the real handler in now. + */ + ih->ih_fun = ih_fun; + ih->ih_arg = ih_arg; + ih->ih_count = 0; + ih->ih_next = NULL; + ih->ih_level = level; + ih->ih_irq = irq; + ih->ih_what = ih_what; + *p = ih; + + return (ih); +} + +void +isabr_intr_disestablish(ic, arg) + isa_chipset_tag_t ic; + void *arg; +{ +} + +/* + * Process an interrupt from the ISA bus. + */ +int +isabr_iointr(mask, cf) + unsigned mask; + struct clockframe *cf; +{ + struct intrhand *ih; + int isa_vector; + int cause; + + do { + switch(cputype) { + case WGRISC9100: + cause = in32(R3715_INT_CAUSE) & in32(R3715_INT_MASK); + if(mask & INT_MASK_5) { + isa_vector = 5; + mask = 0; /* Do this only once */ + } + else if(cause & R3715_ISAIRQ_11) + isa_vector = 11; + else if(cause & R3715_ISAIRQ_7) + isa_vector = 7; + else if(cause & R3715_ISAIRQ_6) + isa_vector = 6; + else if(cause & R3715_ISAIRQ_9) + isa_vector = 9; + else if(cause & R3715_ISAIRQ_10) + isa_vector = 10; + else + isa_vector = -1; + break; + } + + ih = intrhand[isa_vector]; + while(ih) { + (*ih->ih_fun)(ih->ih_arg); + ih = ih->ih_next; + } + } while(isa_vector != -1); + + return(~0); /* Dont reenable */ +} + diff --git a/sys/arch/wgrisc/riscbus/riscbus.c b/sys/arch/wgrisc/riscbus/riscbus.c new file mode 100644 index 00000000000..93b54032f7c --- /dev/null +++ b/sys/arch/wgrisc/riscbus/riscbus.c @@ -0,0 +1,318 @@ +/* $OpenBSD: riscbus.c,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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/device.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> + +#include <wgrisc/riscbus/riscbus.h> +#include <wgrisc/wgrisc/wgrisctype.h> + +struct riscbus_softc { + struct device sc_dv; + struct abus sc_bus; + struct riscbus_dev *sc_devs; +}; + +/* Definition of the driver for autoconfig. */ +int riscbusmatch(struct device *, void *, void *); +void riscbusattach(struct device *, struct device *, void *); +int riscbusprint(void *, const char *); + +struct cfattach riscbus_ca = { + sizeof(struct riscbus_softc), riscbusmatch, riscbusattach +}; +struct cfdriver riscbus_cd = { + NULL, "riscbus", DV_DULL, NULL, 0 +}; + +void riscbus_intr_establish __P((struct confargs *, int (*)(void *), void *)); +void riscbus_intr_disestablish __P((struct confargs *)); +caddr_t riscbus_cvtaddr __P((struct confargs *)); +int riscbus_matchname __P((struct confargs *, char *)); +int riscbus_iointr __P((unsigned, struct clockframe *)); +int riscbus_clkintr __P((unsigned, struct clockframe *)); + +extern int cputype; + +/* + * Interrupt dispatch table. + */ +struct riscbus_int_desc int_table[] = { + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 0 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 1 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 2 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 3 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 4 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 5 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 6 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 7 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 8 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 9 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 10 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 11 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 12 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 13 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 14 */ + {0, riscbus_intrnull, (void *)NULL, 0 }, /* 15 */ +}; + +struct riscbus_dev { + struct confargs ps_ca; + u_int ps_mask; + intr_handler_t ps_handler; + void *ps_base; +}; +#ifdef WGRISC9100 +struct riscbus_dev wgrisc9100_cpu[] = { + {{ "dp8571rtc", 0, 0, }, + INT_MASK_2, riscbus_intrnull, (void *)RISC_RTC, }, + {{ "sonic", 1, 0, }, + INT_MASK_4, riscbus_intrnull, (void *)RISC_SONIC, }, + {{ "asc", 2, 0, }, + INT_MASK_1, riscbus_intrnull, (void *)RISC_SCSI, }, + {{ "com", 3, NULL, }, + INT_MASK_5, riscbus_intrnull, (void *)RISC_COM0, }, + {{ "com", 4, 0, }, + INT_MASK_5, riscbus_intrnull, (void *)RISC_COM1, }, + {{ "com", 5, 0, }, + INT_MASK_5, riscbus_intrnull, (void *)RISC_COM2, }, + {{ "com", 6, 0, }, + INT_MASK_5, riscbus_intrnull, (void *)RISC_COM3, }, + {{ NULL, -1, NULL, }, + 0, NULL, (void *)NULL, }, +}; +#define NUM_RISC_DEVS (sizeof(wgrisc9100_cpu) / sizeof(struct riscbus_dev)) +#endif + +struct riscbus_dev *riscbus_cpu_devs[] = { + NULL, /* 0: Unused */ +#ifdef WGRISC9100 + wgrisc9100_cpu, /* 1: WGRISC 9100 R3081 board */ +#else + NULL, +#endif +}; +int nriscbus_cpu_devs = sizeof riscbus_cpu_devs / sizeof riscbus_cpu_devs[0]; + +int local_int_mask = 0; /* Local interrupt enable mask */ + +int +riscbusmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* Make sure that we're looking for a RISC bus. */ + if (strcmp(ca->ca_name, riscbus_cd.cd_name) != 0) + return (0); + + /* Make sure that unit exists. */ + if (cf->cf_unit != 0 || + cputype > nriscbus_cpu_devs || riscbus_cpu_devs[cputype] == NULL) + return (0); + + return (1); +} + +void +riscbusattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct riscbus_softc *sc = (struct riscbus_softc *)self; + struct confargs *nca; + int i; + + printf("\n"); + + /* keep our CPU device description handy */ + sc->sc_devs = riscbus_cpu_devs[cputype]; + + /* set up interrupt handlers */ + set_intr(INT_MASK_1 | INT_MASK_4 | INT_MASK_5, riscbus_iointr, 2); + + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_RISC; + sc->sc_bus.ab_intr_establish = riscbus_intr_establish; + sc->sc_bus.ab_intr_disestablish = riscbus_intr_disestablish; + sc->sc_bus.ab_cvtaddr = riscbus_cvtaddr; + sc->sc_bus.ab_matchname = riscbus_matchname; + + /* Try to configure each attached device */ + for (i = 0; sc->sc_devs[i].ps_ca.ca_slot >= 0; i++) { + + if(sc->sc_devs[i].ps_ca.ca_name == NULL) + continue; /* Empty slot */ + + nca = &sc->sc_devs[i].ps_ca; + nca->ca_bus = &sc->sc_bus; + + /* Tell the autoconfig machinery we've found the hardware. */ + config_found(self, nca, riscbusprint); + } +} + +int +riscbusprint(aux, pnp) + void *aux; + const char *pnp; +{ + struct confargs *ca = aux; + + if (pnp) + printf("%s at %s", ca->ca_name, pnp); + printf(" slot %ld offset 0x%lx", ca->ca_slot, ca->ca_offset); + return (UNCONF); +} + +caddr_t +riscbus_cvtaddr(ca) + struct confargs *ca; +{ + struct riscbus_softc *sc = riscbus_cd.cd_devs[0]; + + return(sc->sc_devs[ca->ca_slot].ps_base + ca->ca_offset); + +} + +void +riscbus_intr_establish(ca, handler, val) + struct confargs *ca; + intr_handler_t handler; + void *val; +{ + struct riscbus_softc *sc = riscbus_cd.cd_devs[0]; + + int slot; + + slot = ca->ca_slot; + + if(int_table[slot].int_mask != 0) { + panic("riscbus intr already set"); + } + else { + int_table[slot].int_mask = sc->sc_devs[slot].ps_mask; + local_int_mask |= int_table[slot].int_mask; + int_table[slot].int_hand = handler; + int_table[slot].param = val; + } + if(slot == 0) { /* Slot 0 is special, clock */ + set_intr(int_table[0].int_mask, riscbus_clkintr, 0); + } +} + +void +riscbus_intr_disestablish(ca) + struct confargs *ca; +{ + struct riscbus_softc *sc = riscbus_cd.cd_devs[0]; + + int slot; + + slot = ca->ca_slot; + if(slot = 0) { /* Slot 0 is special, clock */ + } + else { + local_int_mask &= ~int_table[slot].int_mask; + int_table[slot].int_mask = 0; + int_table[slot].int_hand = riscbus_intrnull; + int_table[slot].param = (void *)NULL; + } +} + +int +riscbus_matchname(ca, name) + struct confargs *ca; + char *name; +{ + + return (strcmp(name, ca->ca_name) == 0); +} + +int +riscbus_intrnull(val) + void *val; +{ + panic("uncaught RISCBUS interrupt for slot %d\n", val); +} + +/* + * Handle riscbus i/o interrupt the generic way. + */ +int +riscbus_iointr(mask, cf) + unsigned mask; + struct clockframe *cf; +{ + int i; + + for(i = 0; i < NUM_RISC_DEVS; i++) { + if(mask & int_table[i].int_mask) + (*int_table[i].int_hand)(int_table[i].param); + } + return(~0); /* Dont reenable */ +} + +/* + * Handle riscbus interval clock interrupt. + */ +int +riscbus_clkintr(mask, cf) + unsigned mask; + struct clockframe *cf; +{ + int temp; + + switch (cputype) { + + case WGRISC9100: + if(dpclock_interrupt()) + hardclock(cf); + break; + } + + /* Re-enable clock interrupts */ + splx(int_table[0].int_mask | SR_INT_ENAB); + + return(~int_table[0].int_mask); /* Keep clock interrupts enabled */ +} + diff --git a/sys/arch/wgrisc/riscbus/riscbus.h b/sys/arch/wgrisc/riscbus/riscbus.h new file mode 100644 index 00000000000..3fb52adc839 --- /dev/null +++ b/sys/arch/wgrisc/riscbus/riscbus.h @@ -0,0 +1,118 @@ +/* $OpenBSD: riscbus.h,v 1.1 1997/02/06 16:02:44 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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 RISCBUS_H +#define RISCBUS_H 1 + +#define RISC_PHYS_MIN 0x00000000 /* 256 Meg */ +#define RISC_PHYS_MAX 0x01ffffff + +/* + * Memory map + */ + +#define RISC_PHYS_MEMORY_START 0x00000000 +#define RISC_PHYS_MEMORY_END 0x01ffffff /* 256 Meg in 8 slots */ + +#define RISC_SRAM_START 0xbfb00000 /* Static ram */ + +/* + * I/O map + */ + +#define RISC_ISA_IO_BASE 0xac000000 /* ISA I/O base adderss */ +#define RISC_ISA_MEM_BASE 0xad000000 /* ISA MEM base adderss */ +#define RISC_LOCAL_IO_BASE 0xae000000 /* I/O Base address */ + +#define RISC_COM0 0xae400000 /* 16550 */ +#define RISC_COM1 0xae410000 /* 16550 */ +#define RISC_COM2 0xae420000 /* 16550 */ +#define RISC_COM3 0xae430000 /* 16550 */ +#define RISC_SCSI 0xae440000 /* AMD53C94 */ +#define RISC_RTC 0xae450000 /* DP8571 */ +#define RISC_SONIC 0xae460000 /* DP83932 */ +#define RISC_SONIC_SRAM 0xae470000 /* 2 * 32KB 70ns sram */ + +#define RISC_CTRL1 0xae800000 /* Watchdog control */ +#define RISC_CTRL2 0xae810000 /* System control */ +#define RISC_STATUS 0xae820000 /* System status */ +#define RISC_FLASH_CTRL 0xae840000 /* Flash */ +#define RISC_FLASH_WRITE 0xae850000 /* Flash */ +#define RISC_FLASH_READ 0xae860000 /* Flash */ +#define RISC_LEDS 0xae870000 /* System LEDS */ + +/* + * I/O map of R3715 chip. + */ +#define R3715_ROM_CONF 0xbd000000 /* Rom config reg */ +#define R3715_PIO_VAL 0xbd000040 /* PIO value reg */ +#define R3715_PIO_CTRL 0xbd000044 /* PIO control reg */ +#define R3715_PIO_READ 0xbd00005c /* PIO read (pin) reg */ +#define R3715_TC_VAL 0xbd000048 /* Timer/Counter value reg */ +#define R3715_TC_CTRL 0xbd00004c /* Timer/Counter control reg */ +#define R3715_INT_CAUSE 0xbd000050 /* R3715 Interrupt cause */ +#define R3715_INT_MASK 0xbd000054 /* R3715 Interrupt mask */ +#define R3715_INT_WRITE 0xbd000060 /* R3715 Interrupt write */ +#define R3715_DRAM_CTRL 0xbd000058 /* R3715 DRAM Control */ +#define R3715_DMA_ADR0 0xbd000080 /* R3715 DMA Address 0 */ +#define R3715_DMA_ADR1 0xbd000084 /* R3715 DMA Address 1 */ +#define R3715_DMA_CNT0 0xbd000090 /* R3715 DMA Size count 0 */ +#define R3715_DMA_CNT1 0xbd000044 /* R3715 DMA Size count 1 */ +#define R3715_IO_TIMING 0xbd0000a0 /* R3715 I/O Timing control */ + +/* + * R3715 Interrupt control register bits. + */ +#define R3715_ISAIRQ_11 0x00100000 +#define R3715_ISAIRQ_7 0x00200000 +#define R3715_ISAIRQ_6 0x00400000 +#define R3715_ISAIRQ_9 0x00800000 +#define R3715_ISAIRQ_10 0x01000000 +#define R3715_DSPINT 0x02000000 +#define R3715_TIMINT 0x00000010 +#define R3715_DMA_INT0 0x00000020 +#define R3715_DMA_INT1 0x00000040 + +/* + * Interrupt vector descriptor for device on risc bus. + */ +struct riscbus_int_desc { + int int_mask; /* Mask to call handler at */ + intr_handler_t int_hand; /* Interrupt handler */ + void *param; /* Parameter to send to handler */ + int spl_mask; /* Spl mask for interrupt */ +}; + +int riscbus_intrnull __P((void *)); +#endif /* RISCBUS_H */ diff --git a/sys/arch/wgrisc/stand/Makefile b/sys/arch/wgrisc/stand/Makefile new file mode 100644 index 00000000000..a7dd6383200 --- /dev/null +++ b/sys/arch/wgrisc/stand/Makefile @@ -0,0 +1,96 @@ +# $NetBSD: Makefile,v 1.5 1995/01/18 06:53:36 mellon Exp $ +# @(#)Makefile 8.3 (Berkeley) 2/16/94 + +DESTDIR= +STAND= ../../stand +#VPATH= ${STAND} + +# RELOC=80200000 allows for boot prog up to 1D0000 (1900544) bytes long +RELOC= 80200000 + +S= ../../.. + +DEFS= -DSTANDALONE -DDEBUG +CFLAGS= -O2 ${INCPATH} ${DEFS} +AFLAGS= -O2 ${INCPATH} ${DEFS} -DLOCORE + +.PATH: ${S}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} +.PATH: ${S}/stand ${S}/lib/libsa + +#INCPATH=-I. -I/sys +INCPATH=-I${.CURDIR} -I${.CURDIR}/../.. -I${S} -I${S}/lib/libsa + +### find out what to use for libkern +.include "$S/lib/libkern/Makefile.inc" +LIBKERN= ${KERNLIB} +#KERNLIB= ${.CURDIR}/../compile/libkern.a + +.include "$S/lib/libsa/Makefile.inc" +LIBSA= ${SA_LIB} + +# not yet: need to write libsa/Makefile.inc first +LIBS= ${.OBJDIR}/libdrive.a ${.CURDIR}/libsa/libsa.a ${KERNLIB} +#LIBS= libdrive.a libsa/libsa.a ../../libkern/obj/libkern.a + +DRIVERS= rz.c +SRCS= ${DRIVERS} +#STUFF= callvec.c devopen.c getenv.c gets.c strcmp.c +STUFF= + +ALL= boot + +.s.o: + ${CPP} -E ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \ + ${AS} -o ${.TARGET} + +all: ${ALL} + +boot: ${LIBS} + +#libsa/libsa.a:: +# cd libsa; make + +${.OBJDIR}/libdrive.a: conf.o ${DRIVERS:.c=.o} + ar crv $@ $? + ranlib $@ + +# depend on DEFS + +#before other deps on bootconf.o +bootconf.o: conf.o + rm -f bootconf.c + ln -s ${.CURDIR}/conf.c bootconf.c + ${CC} -c ${CFLAGS} -DBOOT bootconf.c + rm -f bootconf.c + + +# bootable from real disks + +boot: start.o boot.o bootconf.o filesystem.o ${LIBS} + /usr/gnu/ld -N -Ttext ${RELOC} -e __start start.o boot.o bootconf.o filesystem.o ${LIBS} -o boot.elf + elf2ecoff boot.elf boot + +start.o: ${.CURDIR}/start.S + +# ${CPP} -E ${CFLAGS:M-[ID]*} -DLOCORE ${AINC} ${.IMPSRC} | \ +# ${AS} -o ${.TARGET} + +mkboot: ${.CURDIR}/mkboot.c + ${CC} ${CFLAGS} -o mkboot ${.CURDIR}/mkboot.c + +# utilities + +clean:: + rm -f .depend *.o *.exe *.i errs make.out core* + rm -f a.out ${ALL} + rm -f libdrive.a + cd libsa; make cleandir + +install: + +depend: ${SRCS} + mkdep ${INCPATH} ${DEFS} ${SRCS} + cd libsa; make depend + +.include <bsd.dep.mk> +.include <bsd.obj.mk> diff --git a/sys/arch/wgrisc/stand/boot.c b/sys/arch/wgrisc/stand/boot.c new file mode 100644 index 00000000000..170f6f923de --- /dev/null +++ b/sys/arch/wgrisc/stand/boot.c @@ -0,0 +1,114 @@ +/* $NetBSD: boot.c,v 1.6 1995/06/28 10:22:32 jonathan Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)boot.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/exec.h> +#include <stand.h> + + +char line[1024]; + +/* + * This gets arguments from the PROM, calls other routines to open + * and load the program to boot, and then transfers execution to that + * new program. + * Argv[0] should be something like "rz(0,0,0)vmunix" on a DECstation 3100. + * Argv[0,1] should be something like "boot 5/rz0/vmunix" on a DECstation 5000. + * The argument "-a" means vmunix should do an automatic reboot. + */ +int +main(argc, argv) + int argc; + char **argv; +{ + char *cp; + int ask, entry; + int i; + + ask = 1; + + for(i = 0; i < argc; i++) + printf("Arg %d:%s\n",i,argv[i]); + + do { + printf("Boot: "); + if (ask) { + gets(line); + cp = line; + argv[0] = cp; + argc = 1; + } else + printf("%s\n", cp); + } while(ask && line[0] == '\0'); + + entry = loadfile(cp); + if (entry == -1) { + gets(line); + return 0; + } + + printf("Starting at 0x%x\n\n", entry); + ((void (*)())entry)(argc, argv, 0, 0); +} + +/* + * Open 'filename', read in program and return the entry point or -1 if error. + */ +loadfile(fname) + register char *fname; +{ + struct devices *dp; + int fd, i, n; + struct exec aout; + + if ((fd = open(fname, 0)) < 0) { + printf("open(%s) failed: %d\n", fname, errno); + goto err; + } + + /* read the exec header */ + i = read(fd, (char *)&aout, sizeof(aout)); + +cerr: + (void) close(fd); +err: + printf("Can't boot '%s'\n", fname); + return (-1); +} diff --git a/sys/arch/wgrisc/stand/conf.c b/sys/arch/wgrisc/stand/conf.c new file mode 100644 index 00000000000..cecbc70b64c --- /dev/null +++ b/sys/arch/wgrisc/stand/conf.c @@ -0,0 +1,70 @@ +/* $NetBSD: conf.c,v 1.5 1995/01/18 06:53:39 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)conf.c 8.1 (Berkeley) 6/10/93 + */ + +#include <stand.h> + +int errno; + +extern void nullsys(); +extern int nodev(), noioctl(); + +int rzstrategy(), rzopen(); +#ifdef SMALL +#define rzclose 0 +#else /*!SMALL*/ +int rzclose(); +#endif /*!SMALL*/ + +#define rzioctl noioctl + +#ifndef BOOT +int tzstrategy(), tzopen(), tzclose(); +#endif +#define tzioctl noioctl + + +struct devsw devsw[] = { + { "rz", rzstrategy, rzopen, rzclose, rzioctl }, /*0*/ +#ifndef BOOT + { "tz", tzstrategy, tzopen, tzclose, tzioctl }, /*1*/ +#endif +}; + +int ndevs = (sizeof(devsw)/sizeof(devsw[0])); diff --git a/sys/arch/wgrisc/stand/filesystem.c b/sys/arch/wgrisc/stand/filesystem.c new file mode 100644 index 00000000000..514e6e809bf --- /dev/null +++ b/sys/arch/wgrisc/stand/filesystem.c @@ -0,0 +1,44 @@ +/* $NetBSD: filesystem.c,v 1.2 1995/02/16 02:33:05 cgd Exp $ */ + +/* + * Copyright (c) 1993 Philip A. Nelson. + * 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 Philip A. Nelson. + * 4. The name of Philip A. Nelson may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY PHILIP NELSON ``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 PHILIP NELSON 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. + * + * filesystem.c + */ + +#include <lib/libsa/stand.h> +#include <lib/libsa/ufs.h> + +struct fs_ops file_system[] = { + { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat }, +}; + +int nfsys = sizeof(file_system)/sizeof(struct fs_ops); + diff --git a/sys/arch/wgrisc/stand/libsa/Makefile b/sys/arch/wgrisc/stand/libsa/Makefile new file mode 100644 index 00000000000..d147171311d --- /dev/null +++ b/sys/arch/wgrisc/stand/libsa/Makefile @@ -0,0 +1,14 @@ +# $NetBSD: Makefile,v 1.5 1995/01/18 06:53:51 mellon Exp $ +# @(#)Makefile 8.2 (Berkeley) 2/16/94 + +LIB= sa +SRCS= alloc.c bcopy.c bzero.c close.c dev.c disklabel.c getfile.c \ + getputchar.c ioctl.c lseek.c open.c printf.c read.c ufs.c write.c \ + devopen.c getenv.c gets.c strcat.c strcmp.c strcpy.c strlen.c + +.PATH: ../../../../lib/libsa ../../../../lib/libkern +NOPROFILE=noprofile + +.include <bsd.lib.mk> + +CFLAGS=-O2 -I../../include -I/sys -DSMALL diff --git a/sys/arch/wgrisc/stand/libsa/devopen.c b/sys/arch/wgrisc/stand/libsa/devopen.c new file mode 100644 index 00000000000..79b35f8f595 --- /dev/null +++ b/sys/arch/wgrisc/stand/libsa/devopen.c @@ -0,0 +1,128 @@ +/* $NetBSD: devopen.c,v 1.5 1995/01/18 06:53:54 mellon Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)devopen.c 8.1 (Berkeley) 6/10/93 + */ + +#include <lib/libsa/stand.h> + +/* + * Decode the string 'fname', open the device and return the remaining + * file name if any. + */ +devopen(f, fname, file) + struct open_file *f; + const char *fname; + char **file; /* out */ +{ + register char *cp; + register char *ncp; + register struct devsw *dp; + register int c, i; + int ctlr = 0, unit = 0, part = 0; + char namebuf[20]; + int rc; + + cp = fname; + ncp = namebuf; + + /* expect a string like 'rz(0,0,0)vmunix' */ + while ((c = *cp) != '\0') { + if (c == '(') { + cp++; + break; + } + if (ncp < namebuf + sizeof(namebuf) - 1) + *ncp++ = c; + cp++; + } + + /* get controller number */ + if ((c = *cp) >= '0' && c <= '9') { + ctlr = c - '0'; + c = *++cp; + } + + if (c == ',') { + /* get SCSI device number */ + if ((c = *++cp) >= '0' && c <= '9') { + unit = c - '0'; + c = *++cp; + } + + if (c == ',') { + /* get partition number */ + if ((c = *++cp) >= '0' && c <= '9') { + part = c - '0'; + c = *++cp; + } + } + } + if (c != ')') + return (ENXIO); + cp++; + *ncp = '\0'; + +#ifdef SMALL + if (strcmp (namebuf, "rz")) { + printf ("Unknown device: %s\n", namebuf); + return ENXIO; + } + dp = devsw; + i = 0; +#else + for (dp = devsw, i = 0; i < ndevs; dp++, i++) + if (dp->dv_name && strcmp(namebuf, dp->dv_name) == 0) + goto fnd; + printf("Unknown device '%s'\nKnown devices are:", namebuf); + for (dp = devsw, i = 0; i < ndevs; dp++, i++) + if (dp->dv_name) + printf(" %s", dp->dv_name); + printf("\n"); + return (ENXIO); + +fnd: +#endif + rc = (dp->dv_open)(f, ctlr, unit, part); + if (rc) + return (rc); + + f->f_dev = dp; + if (file && *cp != '\0') + *file = cp; + return (0); +} diff --git a/sys/arch/wgrisc/stand/libsa/getenv.c b/sys/arch/wgrisc/stand/libsa/getenv.c new file mode 100644 index 00000000000..7e063cd4ad5 --- /dev/null +++ b/sys/arch/wgrisc/stand/libsa/getenv.c @@ -0,0 +1,45 @@ +/* $NetBSD: getenv.c,v 1.5 1995/01/18 06:53:55 mellon Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)getenv.c 8.1 (Berkeley) 6/10/93 + */ + +char * +getenv(s) + char *s; +{ +} diff --git a/sys/arch/wgrisc/stand/libsa/getputchar.c b/sys/arch/wgrisc/stand/libsa/getputchar.c new file mode 100644 index 00000000000..dbfae22d4d6 --- /dev/null +++ b/sys/arch/wgrisc/stand/libsa/getputchar.c @@ -0,0 +1,69 @@ +/* $NetBSD: getenv.c,v 1.5 1995/01/18 06:53:55 mellon Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)getenv.c 8.1 (Berkeley) 6/10/93 + */ + +getchar() +{ + char buf[4]; + int cnt; + + if(Bios_Read(0, &buf, 1, &cnt) != 0) + return(-1); + return(buf[0] & 255); +} + +putchar(c) +char c; +{ + char buf[4]; + int cnt; + + if(c == '\n') { + buf[0] = '\r'; + buf[1] = c; + cnt = 2; + } + else { + buf[0] = c; + cnt = 1; + } + if(Bios_Write(1, &buf, cnt, &cnt) != 0) + return(-1); + return(0); +} diff --git a/sys/arch/wgrisc/stand/rz.c b/sys/arch/wgrisc/stand/rz.c new file mode 100644 index 00000000000..1094aef4705 --- /dev/null +++ b/sys/arch/wgrisc/stand/rz.c @@ -0,0 +1,174 @@ +/* $NetBSD: rz.c,v 1.6 1995/06/28 10:22:35 jonathan Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson of Lawrence Berkeley Laboratory 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. + * + * @(#)rz.c 8.1 (Berkeley) 6/10/93 + */ + +#include <stdarg.h> + +#include <stand.h> +#include <sys/param.h> +#include <sys/disklabel.h> + +struct rz_softc { + int sc_fd; /* PROM file id */ + int sc_ctlr; /* controller number */ + int sc_unit; /* disk unit number */ + int sc_part; /* disk partition number */ + struct disklabel sc_label; /* disk label for this disk */ +}; + +int +rzstrategy(devdata, rw, bn, reqcnt, addr, cnt) + void *devdata; + int rw; + daddr_t bn; + u_int reqcnt; + char *addr; + u_int *cnt; /* out: number of bytes transfered */ +{ + register struct rz_softc *sc = (struct rz_softc *)devdata; + register int part = sc->sc_part; + register struct partition *pp = &sc->sc_label.d_partitions[part]; + register int s; + long offset; + + offset = bn * DEV_BSIZE; + +#ifdef DEBUG +/*XXX*/printf("rz:%x %d\n", offset, reqcnt); +#endif + + /* + * Partial-block transfers not handled. + */ + if (reqcnt & (DEV_BSIZE - 1)) { + *cnt = 0; + return (EINVAL); + } + + offset += pp->p_offset * DEV_BSIZE; + + if (Bios_Seek(sc->sc_fd, &offset, 0) != 0) + return (EIO); + s = Bios_Read(sc->sc_fd, addr, reqcnt, &reqcnt); + if (s != 0) + return (EIO); + + *cnt = reqcnt; + return (0); +} + +int +rzopen(struct open_file *f, ...) +{ + int ctlr, unit, part; + + struct rz_softc *sc; + struct disklabel *lp; + int i, fd; + char *msg; + char buf[DEV_BSIZE]; + int cnt; + static char device[] = "scsi()disk(0)rdisk()"; + va_list ap; + + va_start(ap, f); + + ctlr = va_arg(ap, int); + unit = va_arg(ap, int); + part = va_arg(ap, int); + if (unit >= 8 || part >= 8) + return (ENXIO); +#if 0 + device[5] = '0' + unit; +#endif + /* NOTE: only support reads for now */ + + i = Bios_Open(device, 0, &fd); + if (i != 0) { + printf("boot init failed error code %d\n", i); + return (ENXIO); + } + + sc = alloc(sizeof(struct rz_softc)); + bzero(sc, sizeof(struct rz_softc)); + f->f_devdata = (void *)sc; + + sc->sc_fd = fd; + sc->sc_ctlr = ctlr; + sc->sc_unit = unit; + sc->sc_part = part; + + /* try to read disk label and partition table information */ + lp = &sc->sc_label; + lp->d_secsize = DEV_BSIZE; + lp->d_secpercyl = 1; + lp->d_npartitions = MAXPARTITIONS; + lp->d_partitions[part].p_offset = 0; + lp->d_partitions[part].p_size = 0x7fffffff; + i = rzstrategy(sc, F_READ, (daddr_t)LABELSECTOR, DEV_BSIZE, buf, &cnt); + if (i || cnt != DEV_BSIZE) { + printf("rz%d: error reading disk label\n", unit); + goto bad; + } else { + msg = getdisklabel(buf, lp); + if (msg) { + printf("rz%d: %s\n", unit, msg); + goto bad; + } + } + + if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) { + bad: +#ifndef SMALL + free(sc, sizeof(struct rz_softc)); +#endif + return (ENXIO); + } + return (0); +} + +#ifndef SMALL +rzclose(f) + struct open_file *f; +{ + free(f->f_devdata, sizeof(struct rz_softc)); + f->f_devdata = (void *)0; + return (0); +} +#endif diff --git a/sys/arch/wgrisc/stand/start.S b/sys/arch/wgrisc/stand/start.S new file mode 100644 index 00000000000..09114a91b7e --- /dev/null +++ b/sys/arch/wgrisc/stand/start.S @@ -0,0 +1,129 @@ +/* $NetBSD: start.S,v 1.1 1995/01/18 06:19:01 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + */ + +/* + * start.S - + * + * Contains code that is the first executed at boot time. + */ + +#include <machine/regdef.h> +#include <machine/cpu.h> +#include <machine/asm.h> + +/* + * Frame required for the debugger (if we have any) + */ +#define START_FRAME ((4 * 4) + 4 + 4) + + .globl __start +__start: + .set noreorder +#ifdef __GP_SUPPORT__ + la gp, _C_LABEL (_gp) +#endif + la sp, __start - START_FRAME # Stack below program + sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger + sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger + move s0, a0 # save argc + move s1, a1 # save argv + + la a0, _C_LABEL (edata) # clear BSS + la a1, _C_LABEL (end) + jal _C_LABEL(bzero) # bzero(edata, end - edata) + subu a1, a1, a0 + + move a0, s0 # restore argc + jal _C_LABEL(main) # main(argc, argv) + move a1, s1 # restore argv + + j _C_LABEL(Bios_Restart) # restart... + nop + +/* dummy routine for gcc2 */ + .globl _C_LABEL(__main) +_C_LABEL(__main): + j ra + nop + +#define Bios_Call(Name,Offset) \ +LEAF(Name); \ + lw v0,0x80001020; \ + lw v0,Offset(v0); \ + jr v0 ; \ + nop ; \ + END(Name) + +Bios_Call(Bios_Load, 0x00) +Bios_Call(Bios_Invoke, 0x04) +Bios_Call(Bios_Execute, 0x08) +Bios_Call(Bios_Halt, 0x0c) +Bios_Call(Bios_PowerDown, 0x10) +Bios_Call(Bios_Restart, 0x14) +Bios_Call(Bios_Reboot, 0x18) +Bios_Call(Bios_EnterInteractiveMode, 0x1c) +Bios_Call(Bios_Unused1, 0x20) +Bios_Call(Bios_GetPeer, 0x24) +Bios_Call(Bios_GetChild, 0x28) +Bios_Call(Bios_GetParent, 0x2c) +Bios_Call(Bios_GetConfigurationData, 0x30) +Bios_Call(Bios_AddChild, 0x34) +Bios_Call(Bios_DeleteComponent, 0x38) +Bios_Call(Bios_GetComponent, 0x3c) +Bios_Call(Bios_SaveConfiguration, 0x40) +Bios_Call(Bios_GetSystemId, 0x44) +Bios_Call(Bios_GetMemoryDescriptor, 0x48) +Bios_Call(Bios_Unused2, 0x4c) +Bios_Call(Bios_GetTime, 0x50) +Bios_Call(Bios_GetRelativeTime, 0x54) +Bios_Call(Bios_GetDirectoryEntry, 0x58) +Bios_Call(Bios_Open, 0x5c) +Bios_Call(Bios_Close, 0x60) +Bios_Call(Bios_Read, 0x64) +Bios_Call(Bios_GetReadStatus, 0x68) +Bios_Call(Bios_Write, 0x6c) +Bios_Call(Bios_Seek, 0x70) +Bios_Call(Bios_Mount, 0x74) +Bios_Call(Bios_GetEnvironmentVariable, 0x78) +Bios_Call(Bios_SetEnvironmentVariable, 0x7c) +Bios_Call(Bios_GetFileInformation, 0x80) +Bios_Call(Bios_SetFileInformation, 0x84) +Bios_Call(Bios_FlushAllCaches, 0x88) +Bios_Call(Bios_TestUnicodeCharacter, 0x8c) +Bios_Call(Bios_GetDisplayStatus, 0x90) diff --git a/sys/arch/wgrisc/wgrisc/autoconf.c b/sys/arch/wgrisc/wgrisc/autoconf.c new file mode 100644 index 00000000000..6b6102ac7e3 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/autoconf.c @@ -0,0 +1,464 @@ +/* $OpenBSD: autoconf.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ +/* + * Copyright (c) 1996 Per Fogelstrom + * Copyright (c) 1995 Theo de Raadt + * 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: autoconf.c 1.31 91/01/21 + * + * from: @(#)autoconf.c 8.1 (Berkeley) 6/10/93 + * $Id: autoconf.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/disklabel.h> +#include <sys/conf.h> +#include <sys/reboot.h> +#include <sys/device.h> + +#include <machine/autoconf.h> + +struct device *parsedisk __P((char *, int, int, dev_t *)); +void setroot __P((void)); + +/* + * The following several variables are related to + * the configuration process, and are used in initializing + * the machine. + */ +int cold = 1; /* if 1, still working on cold-start */ +int cpuspeed = 25; /* approx # instr per usec. */ +char bootdev[16]; /* to hold boot dev name */ +struct device *bootdv = NULL; + +/* + * Configure all devices found that we know about. + * This is done at boot time. + */ +configure() +{ + (void)splhigh(); /* To be really shure.. */ + if(config_rootfound("mainbus", "mainbus") == 0) + panic("no mainbus found"); + (void)spl0(); + + setroot(); + swapconf(); + cold = 0; +} + +/* + * Configure swap space and related parameters. + */ +swapconf() +{ + register struct swdevt *swp; + register 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 influenced/copied from Theo de Raadt's + * code in the sparc port to nuke the "options GENERIC" stuff. + */ + +static struct nam2blk { + char *name; + int maj; +} nam2blk[] = { + { "sd", 0 }, /* 0 = sd */ + { "fd", 7 }, /* 7 = floppy (ick!)*/ +}; + +static int +findblkmajor(dv) + struct device *dv; +{ + char *name = dv->dv_xname; + register 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); +} + +static struct device * +getdisk(str, len, defpart, devp) + char *str; + int len, defpart; + dev_t *devp; +{ + register 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-h]", 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; +{ + register struct device *dv; + register char *cp, c; + int majdev, mindev, part; + + if (len == 0) + return (NULL); + cp = str + len - 1; + c = *cp; + if (c >= 'a' && c <= 'h') { + 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); + if (majdev < 0) + panic("parsedisk"); + mindev = (dv->dv_unit << PARTITIONSHIFT) + part; + *devp = makedev(majdev, mindev); + 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. + */ +void +setroot() +{ + int majdev, mindev, unit, part, len; + dev_t temp; + struct swdevt *swp; + struct device *dv; + dev_t nrootdev, nswapdev = NODEV; + char buf[128]; + +#if defined(NFSCLIENT) + extern char *nfsbootdevname; +#endif +#if defined(FFS) + extern int ffs_mountroot __P((void)); +#endif + + /* Lookup boot device from boot if not set by configuration */ + if(bootdv == NULL) { + bootdv = parsedisk(bootdev, strlen(bootdev), 0, &temp); + } + if(bootdv == NULL) { + printf("boot device: lookup '%s' failed.\n", bootdev); + boothowto |= RB_ASKNAME; /* Don't Panic :-) */ + } + else { + printf("boot device: %s.\n", bootdv->dv_xname); + } + + 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) { + strcpy(buf, bootdv->dv_xname); + len = strlen(buf); + } + if (len > 0 && buf[len - 1] == '*') { + buf[--len] = '\0'; + dv = getdisk(buf, len, 1, &nrootdev); + if (dv != NULL) { + bootdv = dv; + nswapdev = nrootdev; + goto gotswap; + } + } + dv = getdisk(buf, len, 0, &nrootdev); + if (dv != NULL) { + 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 = makedev(major(nrootdev), + (minor(nrootdev) & ~ PARTITIONMASK) +| 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 disk. + * Boot is always from partition 0. + */ + rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit, 0); + nswapdev = MAKEDISKDEV(majdev, bootdv->dv_unit, 1); + dumpdev = nswapdev; + } + else { + /* + * Root and Swap are on 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 = ffs_mountroot; + majdev = major(rootdev); + mindev = minor(rootdev); + printf("root on %s%c\n", bootdv->dv_xname, + (mindev & PARTITIONMASK) + 'a'); + break; +#endif + default: + printf("can't figure root, hope your kernel is right\n"); + return; + } + + /* + * XXX: What is this doing? + */ + mindev &= ~PARTITIONMASK; + temp = NODEV; + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (majdev == major(swp->sw_dev) && + mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { + 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 */ + sprintf(num, "%d", unit); + lunit = strlen(num); + if (strlen(name) + lunit >= sizeof(fullname) - 1) + panic("config_attach: device name too long"); + + strcpy(fullname, name); + strcat(fullname, num); + + while (strcmp(dev->dv_xname, fullname) != 0) { + if ((dev = dev->dv_list.tqe_next) == NULL) + return NULL; + } + return dev; +} + +/* + * Look at the string 'cp' and decode the boot device. + * Boot names look like: scsi()disk(n)rdisk()partition(1)\bsd + * (beware for empty scsi id's...) + */ +void +makebootdev(cp) + char *cp; +{ + int unit, part, ctrl; + + bootdev[0] = *cp; + ctrl = getpno(&cp); + if(*cp++ == ')') { + bootdev[1] = *cp; + unit = getpno(&cp); + } + sprintf(&bootdev[2], "%d", ctrl*16 + unit); +} +getpno(cp) + char **cp; +{ + int val = 0; + char *cx = *cp; + + while(*cx && *cx != '(') + cx++; + if(*cx == '(') { + cx++; + while(*cx && *cx != ')') { + val = val * 10 + *cx - '0'; + cx++; + } + } + *cp = cx; + return val; +} diff --git a/sys/arch/wgrisc/wgrisc/clock.c b/sys/arch/wgrisc/wgrisc/clock.c new file mode 100644 index 00000000000..2b6156a2638 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/clock.c @@ -0,0 +1,327 @@ +/* $OpenBSD: clock.c,v 1.1 1997/02/06 16:02:45 pefo 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 + * + * from: @(#)clock.c 8.1 (Berkeley) 6/10/93 + * $Id: clock.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <wgrisc/wgrisc/clockvar.h> +#include <wgrisc/wgrisc/wgrisctype.h> + +#include <dev/isa/isavar.h> +#include <wgrisc/isa/isa_machdep.h> + +extern int cputype; /* What kind of cpu we are running on */ + +int clock_started = 0; + +/* Definition of the driver for autoconfig. */ +static int clockmatch __P((struct device *, void *, void *)); +static void clockattach __P((struct device *, struct device *, void *)); + +struct cfdriver clock_cd = { + NULL, "clock", DV_DULL, NULL, 0 +}; + +struct cfattach clock_ca = { + sizeof(struct clock_softc), clockmatch, clockattach +}; + +void dpclock_attach __P((struct device *, struct device *, void *)); + +#define SECMIN ((unsigned)60) /* seconds per minute */ +#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ +#define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */ +#define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */ + +#define LEAPYEAR(year) (((year) % 4) == 0) + +static int +clockmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* See how many clocks this system has */ + switch (cputype) { + + case WGRISC9100: + /* make sure that we're looking for this type of device. */ + if (!BUS_MATCHNAME(ca, "dp8571rtc")) + return (0); + + break; + + default: + panic("unknown CPU"); + } + + if (cf->cf_unit >= 1) + return (0); + + return (1); +} + +int +clockintr(cf) + void *cf; +{ + if(clock_started) + hardclock((struct clockframe *)cf); + return(1); +} + +static void +clockattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct isa_attach_args *ia = aux; + + dpclock_attach(parent, self, aux); + + switch (cputype) { + + case WGRISC9100: + BUS_INTR_ESTABLISH((struct confargs *)aux, + (intr_handler_t)hardclock, self); + break; + + default: + panic("clockattach: it didn't get here. really."); + } + + printf("\n"); +} + +/* + * Wait "n" microseconds. This doesn't belong here. XXX. + */ +void +delay(n) + int n; +{ + DELAY(n); +} + +/* + * 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. + */ + + +/* + * Start the real-time and statistics clocks. Leave stathz 0 since there + * are no other timers available. + */ +void +cpu_initclocks() +{ + extern int tickadj; + struct clock_softc *csc = (struct clock_softc *)clock_cd.cd_devs[0]; + + hz = 100; /* 100 Hz */ + tick = 1000000 / hz; /* number of micro-seconds between interrupts */ + + /* + * Start the clock. + */ + (*csc->sc_init)(csc); + clock_started++; +} + +/* + * 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; +{ +} + +/* + * This code is defunct after 2099. + * Will Unix still be here then?? + */ +static short dayyr[12] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +/* + * 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 tod_time c; + struct clock_softc *csc = (struct clock_softc *)clock_cd.cd_devs[0]; + register int days, yr; + long deltat; + int badbase, s; + + 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; + + /* Read RTC chip registers */ + (*csc->sc_get)(csc, base, &c); + + csc->sc_initted = 1; + + /* simple sanity checks */ + c.year = c.year+80; /* must be multiple of 4 because chip knows leap */ + if (c.year < 70 || c.mon < 1 || c.mon > 12 || c.day < 1 || + c.day > 31 || c.hour > 23 || c.min > 59 || c.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\n"); + resettodr(); + } + goto bad; + } + days = 0; + for (yr = 70; yr < c.year; yr++) + days += LEAPYEAR(yr) ? 366 : 365; + days += dayyr[c.mon - 1] + c.day - 1; + if (LEAPYEAR(yr) && c.mon > 2) + days++; + /* now have days since Jan 1, 1970; the rest is easy... */ + time.tv_sec = days * SECDAY + c.hour * 3600 + c.min * 60 + c.sec; + + 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", 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 tod_time c; + struct clock_softc *csc = (struct clock_softc *)clock_cd.cd_devs[0]; + register int t, t2; + int s; + + if(!csc->sc_initted) + return; + + /* compute the day of week. 1 is Sunday*/ + t2 = time.tv_sec / SECDAY; + c.dow = (t2 + 5) % 7; /* 1/1/1970 was thursday */ + + /* compute the year */ + t2 = time.tv_sec / SECDAY; + c.year = 69; + while (t2 >= 0) { /* whittle off years */ + t = t2; + c.year++; + t2 -= LEAPYEAR(c.year) ? 366 : 365; + } + + /* t = month + day; separate */ + t2 = LEAPYEAR(c.year); + for (c.mon = 1; c.mon < 12; c.mon++) + if (t < dayyr[c.mon] + (t2 && c.mon > 1)) + break; + + c.day = t - dayyr[c.mon - 1] + 1; + if (t2 && c.mon > 2) + c.day--; + + /* the rest is easy */ + t = time.tv_sec % SECDAY; + c.hour = t / 3600; + t %= 3600; + c.min = t / 60; + c.sec = t % 60; + c.year = c.year-80; /* must be multiple of 4 because chip knows leap */ + + (*csc->sc_set)(csc, &c); +} diff --git a/sys/arch/wgrisc/wgrisc/clock_dp.c b/sys/arch/wgrisc/wgrisc/clock_dp.c new file mode 100644 index 00000000000..78cbb096e4a --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/clock_dp.c @@ -0,0 +1,227 @@ +/* $OpenBSD: clock_dp.c,v 1.1 1997/02/06 16:02:47 pefo Exp $ */ +/* $NetBSD: clock_mc.c,v 1.2 1995/06/28 04:30:30 cgd 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 + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/pio.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/ic/dp857xreg.h> + +#include <wgrisc/wgrisc/clockvar.h> +#include <wgrisc/wgrisc/wgrisctype.h> +#include <wgrisc/riscbus/riscbus.h> +#include <wgrisc/isa/isa_machdep.h> + +extern u_int cputype; +extern int cpu_int_mask; + +void dpclock_attach __P((struct device *parent, + struct device *self, void *aux)); +static void dpclock_init_riscbus __P((struct clock_softc *csc)); +static void dpclock_get __P((struct clock_softc *csc, time_t base, + struct tod_time *ct)); +static void dpclock_set __P((struct clock_softc *csc, + struct tod_time *ct)); + +struct dpclockdata { + void (*dp_write) __P((struct clock_softc *csc, u_int reg, + u_int datum)); + u_int (*dp_read) __P((struct clock_softc *csc, u_int reg)); + void *dp_addr; +}; + +#define dp857x_write(sc, reg, datum) \ + (*((struct dpclockdata *)sc->sc_data)->dp_write)(sc, reg, datum) +#define dp857x_read(sc, reg) \ + (*((struct dpclockdata *)sc->sc_data)->dp_read)(sc, reg) + +/* riscbus clock read code */ +static void dp_write_riscbus __P((struct clock_softc *csc, u_int reg, + u_int datum)); +static u_int dp_read_riscbus __P((struct clock_softc *csc, u_int reg)); +static struct dpclockdata dpclockdata_riscbus = { dp_write_riscbus, dp_read_riscbus }; + +void +dpclock_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct clock_softc *csc = (struct clock_softc *)self; + + register volatile struct chiptime *c; + struct confargs *ca = aux; + + printf(": dp857[012] or compatible"); + + csc->sc_get = dpclock_get; + csc->sc_set = dpclock_set; + + switch (cputype) { + + case WGRISC9100: + csc->sc_init = dpclock_init_riscbus; + csc->sc_data = &dpclockdata_riscbus; + dpclockdata_riscbus.dp_addr = BUS_CVTADDR(ca); + break; + + default: + printf("\n"); + panic("don't know how to set up for other system types."); + } + + /* Initialize and turn interrupts off, just in case. */ + + dp857x_write(csc, MAIN_STATUS, 0x40); + dp857x_write(csc, INTERRUPT_CTRL0, 0); + dp857x_write(csc, INTERRUPT_CTRL1, 0); + dp857x_write(csc, OUTPUT_MODE, 0x08); + dp857x_write(csc, REAL_TIME_MODE, + (dp857x_read(csc, REAL_TIME_MODE) & 3) | 0x08); + + dp857x_write(csc, MAIN_STATUS, 0x3c); /* clears pending ints */ + dp857x_write(csc, INTERRUPT_ROUT, 0); + dp857x_write(csc, TIMER0_CTRL, 0); + dp857x_write(csc, TIMER1_CTRL, 0); +} +/* + * TOD clock also used for periodic interrupts. + */ +static struct clock_softc *int_csc; + +static void +dpclock_init_riscbus(csc) + struct clock_softc *csc; +{ + int_csc = csc; + dp857x_write(csc, MAIN_STATUS, 0x40); + dp857x_write(csc, INTERRUPT_CTRL0, 0x10); /* 100 Hz */ + dp857x_write(csc, MAIN_STATUS, 0); +} + +int +dpclock_interrupt() +{ + if(dp857x_read(int_csc, MAIN_STATUS) & 0x04) { /* periodic interrupt */ + dp857x_write(int_csc, MAIN_STATUS, 0x04); + return(1); + } + return(0); +} + +/* + * Get the time of day, based on the clock's value and/or the base value. + */ +static void +dpclock_get(csc, base, ct) + struct clock_softc *csc; + time_t base; + struct tod_time *ct; +{ + dp_todregs regs; + int s; + + s = splclock(); + DP857X_GETTOD(csc, ®s) + splx(s); + + ct->sec = regs[CLK_SECONDS]; + ct->min = regs[CLK_MINUTES]; + ct->hour = regs[CLK_HOURS]; + ct->dow = regs[CLK_WEEKDAY]; + ct->day = regs[CLK_DAY]; + ct->mon = regs[CLK_MONTH]; + ct->year = regs[CLK_YEAR]; +} + +/* + * Reset the TODR based on the time value. + */ +static void +dpclock_set(csc, ct) + struct clock_softc *csc; + struct tod_time *ct; +{ + dp_todregs regs; + int s; + + s = splclock(); + DP857X_GETTOD(csc, ®s) + + regs[CLK_SECONDS] = ct->sec; + regs[CLK_MINUTES] = ct->min; + regs[CLK_HOURS] = ct->hour; + regs[CLK_WEEKDAY] = ct->dow; + regs[CLK_DAY] = ct->day; + regs[CLK_MONTH] = ct->mon; + regs[CLK_YEAR] = ct->year; + + DP857X_PUTTOD(csc, ®s); + splx(s); +} + +static void +dp_write_riscbus(csc, reg, datum) + struct clock_softc *csc; + u_int reg, datum; +{ + outb(((struct dpclockdata *)csc->sc_data)->dp_addr + reg, datum); +} + +static u_int +dp_read_riscbus(csc, reg) + struct clock_softc *csc; + u_int reg; +{ + int i; + i = inb(((struct dpclockdata *)csc->sc_data)->dp_addr + reg); + return(i); +} diff --git a/sys/arch/wgrisc/wgrisc/clockvar.h b/sys/arch/wgrisc/wgrisc/clockvar.h new file mode 100644 index 00000000000..bf174f291e1 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/clockvar.h @@ -0,0 +1,82 @@ +/* $OpenBSD: clockvar.h,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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. + * + */ + +/* + * Definitions for "cpu-independent" clock handling for the mips wgrisc arch. + */ + +/* + * clocktime structure: + * + * structure passed to TOY clocks when setting them. broken out this + * way, so that the time_t -> field conversion can be shared. + */ +struct tod_time { + int year; /* year - 1900 */ + int mon; /* month (1 - 12) */ + int day; /* day (1 - 31) */ + int hour; /* hour (0 - 23) */ + int min; /* minute (0 - 59) */ + int sec; /* second (0 - 59) */ + int dow; /* day of week (0 - 6; 0 = Sunday) */ +}; + +/* + * clockdesc structure: + * + * provides clock-specific functions to do necessary operations. + */ +struct clock_softc { + struct device sc_dev; + + /* + * The functions that all types of clock provide. + */ + void (*sc_attach) __P((struct device *parent, struct device *self, + void *aux)); + void (*sc_init) __P((struct clock_softc *csc)); + void (*sc_get) __P((struct clock_softc *csc, time_t base, + struct tod_time *ct)); + void (*sc_set) __P((struct clock_softc *csc, struct tod_time *ct)); + + /* + * Private storage for particular clock types. + */ + void *sc_data; + + /* + * Has the time been initialized? + */ + int sc_initted; +}; diff --git a/sys/arch/wgrisc/wgrisc/conf.c b/sys/arch/wgrisc/wgrisc/conf.c new file mode 100644 index 00000000000..df8a4e6fc6f --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/conf.c @@ -0,0 +1,365 @@ +/* $OpenBSD: conf.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)conf.c 8.2 (Berkeley) 11/14/93 + * $Id: conf.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/ioctl.h> +#include <sys/proc.h> +#include <sys/vnode.h> +#include <sys/tty.h> +#include <sys/conf.h> + +int ttselect __P((dev_t, int, struct proc *)); + +/* + * Block devices. + */ + +#include "vnd.h" +bdev_decl(vnd); +bdev_decl(sw); +#include "sd.h" +bdev_decl(sd); +#include "cd.h" +bdev_decl(cd); +#if notyet +#include "fdc.h" +bdev_decl(fd); +#endif +#include "wdc.h" +bdev_decl(wd); +#include "acd.h" +bdev_decl(acd); + +struct bdevsw bdevsw[] = +{ + bdev_disk_init(NSD,sd), /* 0: SCSI disk */ + bdev_swap_init(1,sw), /* 1: should be here swap pseudo-dev */ + bdev_disk_init(NVND,vnd), /* 2: vnode disk driver */ + bdev_disk_init(NCD,cd), /* 3: SCSI CD-ROM */ + bdev_disk_init(NWDC,wd), /* 4: ST506/ESDI/IDE disk */ + bdev_disk_init(NACD,cd), /* 5: ATAPI CD-ROM */ + bdev_notdef(), /* 6: */ + bdev_notdef(), /* 7: Floppy disk driver */ + bdev_notdef(), /* 8: */ + bdev_notdef(), /* 9: */ + bdev_notdef(), /* 10: */ + bdev_notdef(), /* 11: */ + bdev_notdef(), /* 12: */ + bdev_notdef(), /* 13: */ + bdev_notdef(), /* 14: */ + bdev_notdef(), /* 15: */ +}; + +int nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]); + +/* + * Character devices. + */ + +/* open, close, read, write, ioctl, tty, mmap */ +#define cdev_pc_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_init(c,n,stop), \ + dev_init(c,n,tty), ttselect, dev_init(c,n,mmap), D_TTY } + +/* open, close, write, ioctl */ +#define cdev_lpt_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, write, ioctl */ +#define cdev_spkr_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 } + +cdev_decl(cn); +cdev_decl(sw); +cdev_decl(ctty); +cdev_decl(random); +#define mmread mmrw +#define mmwrite mmrw +dev_type_read(mmrw); +cdev_decl(mm); +#include "pty.h" +#define ptstty ptytty +#define ptsioctl ptyioctl +cdev_decl(pts); +#define ptctty ptytty +#define ptcioctl ptyioctl +cdev_decl(ptc); +cdev_decl(log); +cdev_decl(fd); +#include "st.h" +cdev_decl(st); +#ifdef notyet +#include "fdc.h" +bdev_decl(fd); +#endif +cdev_decl(vnd); +#include "bpfilter.h" +cdev_decl(bpf); +#include "com.h" +cdev_decl(com); +#include "lpt.h" +cdev_decl(lpt); +cdev_decl(sd); +#ifdef notyet +#include "pc.h" +cdev_decl(pc); +cdev_decl(pms); +#endif +cdev_decl(cd); +#include "uk.h" +cdev_decl(uk); +cdev_decl(wd); +cdev_decl(acd); + +/* open, close, read, ioctl */ +cdev_decl(ipl); +#ifdef IPFILTER +#define NIPF 1 +#else +#define NIPF 0 +#endif + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_swap_init(1,sw), /* 1: /dev/drum (swap pseudo-device) */ + cdev_ctty_init(1,ctty), /* 2: controlling terminal */ + cdev_mm_init(1,mm), /* 3: /dev/{null,mem,kmem,...} */ + 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_fd_init(1,filedesc), /* 7: file descriptor pseudo-dev */ + cdev_disk_init(NCD,cd), /* 8: SCSI CD */ + cdev_disk_init(NSD,sd), /* 9: SCSI disk */ + cdev_tape_init(NST,st), /* 10: SCSI tape */ + cdev_disk_init(NVND,vnd), /* 11: vnode disk */ + cdev_bpftun_init(NBPFILTER,bpf),/* 12: berkeley packet filter */ + cdev_notdef(), /* 13: Floppy disk */ + cdev_notdef(), /* 14: builtin pc style console dev */ + cdev_notdef(), /* 15: builtin PS2 style mouse */ + cdev_lpt_init(NLPT,lpt), /* 16: lpt paralell printer interface */ + cdev_tty_init(NCOM,com), /* 17: com 16C450 serial interface */ + cdev_disk_init(NWDC,wd), /* 18: ST506/ESDI/IDE disk */ + cdev_disk_init(NACD,acd), /* 19: ATAPI CD-ROM */ + cdev_tty_init(NPTY,pts), /* 20: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 21: pseudo-tty master */ + cdev_notdef(), /* 22: */ + cdev_notdef(), /* 23: */ + cdev_notdef(), /* 24: */ + cdev_notdef(), /* 25: */ + cdev_notdef(), /* 26: */ + cdev_notdef(), /* 27: */ + cdev_notdef(), /* 28: */ + cdev_notdef(), /* 29: */ + cdev_notdef(), /* 30: */ + cdev_gen_ipf(NIPF,ipl), /* 31: IP filter log */ + cdev_uk_init(NUK,uk), /* 32: unknown SCSI */ + cdev_random_init(1,random), /* 33: random data source */ +}; + +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(1, 0); + +/* + * Routine that identifies /dev/mem and /dev/kmem. + * + * A minimal stub routine can always return 0. + */ +iskmemdev(dev) + dev_t dev; +{ + +#ifdef COMPAT_BSD44 + if (major(dev) == 2 && (minor(dev) == 0 || minor(dev) == 1)) +#else + if (major(dev) == 3 && (minor(dev) == 0 || minor(dev) == 1)) +#endif + return (1); + return (0); +} + +/* + * Returns true if def is /dev/zero + */ +iszerodev(dev) + dev_t dev; +{ +#ifdef COMPAT_BSD44 + return (major(dev) == 2 && minor(dev) == 12); +#else + return (major(dev) == 3 && minor(dev) == 12); +#endif +} + + +#define MAXDEV 57 +static int chrtoblktbl[MAXDEV] = { + /* VCHR */ /* VBLK */ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ NODEV, + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ NODEV, + /* 9 */ 0, + /* 10 */ NODEV, + /* 11 */ 2, + /* 12 */ NODEV, + /* 13 */ 7, + /* 14 */ NODEV, + /* 15 */ NODEV, + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ 4, + /* 19 */ 5, + /* 20 */ NODEV, + /* 21 */ NODEV, + /* 22 */ NODEV, + /* 23 */ NODEV, + /* 24 */ NODEV, + /* 25 */ NODEV, + /* 26 */ NODEV, + /* 27 */ NODEV, + /* 28 */ NODEV, + /* 29 */ NODEV, + /* 30 */ NODEV, + /* 31 */ NODEV, + /* 32 */ NODEV, + /* 33 */ NODEV, + /* 34 */ NODEV, + /* 35 */ NODEV, + /* 36 */ NODEV, + /* 37 */ NODEV, + /* 38 */ NODEV, + /* 39 */ NODEV, + /* 40 */ NODEV, + /* 41 */ NODEV, + /* 42 */ NODEV, + /* 43 */ NODEV, + /* 44 */ NODEV, + /* 45 */ NODEV, + /* 46 */ NODEV, + /* 47 */ NODEV, + /* 48 */ NODEV, + /* 49 */ NODEV, + /* 50 */ NODEV, + /* 51 */ NODEV, + /* 52 */ NODEV, + /* 53 */ NODEV, + /* 54 */ NODEV, + /* 55 */ NODEV, + /* 56 */ NODEV, +}; +/* + * Routine to convert from character to block device number. + * + * A minimal stub routine can always return NODEV. + */ +chrtoblk(dev) + dev_t dev; +{ + int blkmaj; + + if (major(dev) >= MAXDEV || (blkmaj = chrtoblktbl[major(dev)]) == NODEV) + return (NODEV); + return (makedev(blkmaj, minor(dev))); +} + +/* + * Convert a character device number to a block device number. + */ +dev_t +blktochr(dev) + dev_t dev; +{ + int blkmaj = major(dev); + int i; + + if (blkmaj >= nblkdev) + return (NODEV); + for (i = 0; i < sizeof(chrtoblktbl)/sizeof(chrtoblktbl[0]); i++) + if (blkmaj == chrtoblktbl[i]) + return (makedev(i, minor(dev))); + return (NODEV); +} + +/* + * 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> + +cons_decl(pc); +cons_decl(com); + +struct consdev constab[] = { +#if NPC + NVT > 0 + cons_init(pc), +#endif +#if NCOM > 0 + cons_init(com), +#endif + { 0 }, +}; diff --git a/sys/arch/wgrisc/wgrisc/cpu.c b/sys/arch/wgrisc/wgrisc/cpu.c new file mode 100644 index 00000000000..7f87fd99a0d --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/cpu.c @@ -0,0 +1,192 @@ +/* $OpenBSD: cpu.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Per Fogelstrom + * + * 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 the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/device.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> + + +/* Definition of the driver for autoconfig. */ +static int cpumatch(struct device *, void *, void *); +static void cpuattach(struct device *, struct device *, void *); + +struct cfattach cpu_ca = { + sizeof(struct device), cpumatch, cpuattach +}; +struct cfdriver cpu_cd = { + NULL, "cpu", DV_DULL, NULL, 0 +}; + +static int cpuprint __P((void *, char *pnp)); + +static int +cpumatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* make sure that we're looking for a CPU. */ + if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0) + return (0); + + return (1); +} + +static void +cpuattach(parent, dev, aux) + struct device *parent; + struct device *dev; + void *aux; +{ + struct pcs *p; + int needcomma, needrev, i; + + printf(": "); + + switch(cpu_id.cpu.cp_imp) { + + case MIPS_R2000: + printf("MIPS R2000 CPU"); + break; + case MIPS_R3000: + printf("MIPS R3000 CPU"); + break; + case MIPS_R6000: + printf("MIPS R6000 CPU"); + break; + case MIPS_R4000: + if(CpuPrimaryInstCacheSize == 16384) + printf("MIPS R4400 CPU"); + else + printf("MIPS R4000 CPU"); + break; + case MIPS_R3LSI: + printf("LSI Logic R3000 derivate"); + break; + case MIPS_R6000A: + printf("MIPS R6000A CPU"); + break; + case MIPS_R3IDT: + printf("IDT R3000 derivate"); + break; + case MIPS_R10000: + printf("MIPS R10000 CPU"); + break; + case MIPS_R4200: + printf("MIPS R4200 CPU (ICE)"); + break; + case MIPS_R8000: + printf("MIPS R8000 Blackbird/TFP CPU"); + break; + case MIPS_R4600: + printf("QED R4600 Orion CPU"); + break; + case MIPS_R3SONY: + printf("Sony R3000 based CPU"); + break; + case MIPS_R3TOSH: + printf("Toshiba R3000 based CPU"); + break; + case MIPS_R3NKK: + printf("NKK R3000 based CPU"); + break; + case MIPS_UNKC1: + case MIPS_UNKC2: + default: + printf("Unknown CPU type (0x%x)",cpu_id.cpu.cp_imp); + break; + } + printf(" Rev. %d.%d with ", cpu_id.cpu.cp_majrev, cpu_id.cpu.cp_minrev); + + + switch(fpu_id.cpu.cp_imp) { + + case MIPS_SOFT: + printf("Software emulation float"); + break; + case MIPS_R2360: + printf("MIPS R2360 FPC"); + break; + case MIPS_R2010: + printf("MIPS R2010 FPC"); + break; + case MIPS_R3010: + printf("MIPS R3010 FPC"); + break; + case MIPS_R6010: + printf("MIPS R6010 FPC"); + break; + case MIPS_R4010: + printf("MIPS R4010 FPC"); + break; + case MIPS_R31LSI: + printf("FPC"); + break; + case MIPS_R10010: + printf("MIPS R10000 FPU"); + break; + case MIPS_R4210: + printf("MIPS R4200 FPC (ICE)"); + case MIPS_R8000: + printf("MIPS R8000 Blackbird/TFP"); + break; + case MIPS_R4600: + printf("QED R4600 Orion FPC"); + break; + case MIPS_R3SONY: + printf("Sony R3000 based FPC"); + break; + case MIPS_R3TOSH: + printf("Toshiba R3000 based FPC"); + break; + case MIPS_R3NKK: + printf("NKK R3000 based FPC"); + break; + case MIPS_UNKF1: + default: + printf("Unknown FPU type (0x%x)", fpu_id.cpu.cp_imp); + break; + } + printf(" Rev. %d.%d", fpu_id.cpu.cp_majrev, fpu_id.cpu.cp_minrev); + printf("\n"); + + printf("Primary cache size: %dkb Instruction, %dkb Data.", + CpuPrimaryInstCacheSize / 1024, + CpuPrimaryDataCacheSize / 1024); + if(CpuTwoWayCache) + printf(" Two way set associative.\n"); + else + printf(" Direct mapped.\n"); +} + diff --git a/sys/arch/wgrisc/wgrisc/cpu_exec.c b/sys/arch/wgrisc/wgrisc/cpu_exec.c new file mode 100644 index 00000000000..4e3e657011a --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/cpu_exec.c @@ -0,0 +1,104 @@ +/* $NetBSD: cpu_exec.c,v 1.4 1995/04/25 19:16:46 mellon Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by 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. + * + * @(#)machdep.c 8.3 (Berkeley) 1/12/94 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/exec.h> +#include <sys/resourcevar.h> +#include <vm/vm.h> + +#include <sys/exec_ecoff.h> +#include <machine/reg.h> + +/* + * cpu_exec_aout_makecmds(): + * cpu-dependent a.out format hook for execve(). + * + * Determine of the given exec package refers to something which we + * understand and, if so, set up the vmcmds for it. + * + */ +int +cpu_exec_aout_makecmds(p, epp) + struct proc *p; + struct exec_package *epp; +{ + return ENOEXEC; +} + +#ifdef COMPAT_ULTRIX +extern struct emul emul_ultrix; + +void +cpu_exec_ecoff_setregs(p, pack, stack, retval) + struct proc *p; + struct exec_package *pack; + u_long stack; + register_t *retval; +{ + struct ecoff_aouthdr *eap; + + setregs(p, pack, stack, retval); + eap = (struct ecoff_aouthdr *) + ((caddr_t)pack->ep_hdr + sizeof(struct ecoff_filehdr)); + p->p_md.md_regs[GP] = eap->ea_gp_value; +} + +/* + * cpu_exec_ecoff_hook(): + * cpu-dependent ECOFF format hook for execve(). + * + * Do any machine-dependent diddling of the exec package when doing ECOFF. + * + */ +int +cpu_exec_ecoff_hook(p, epp, eap) + struct proc *p; + struct exec_package *epp; + struct ecoff_aouthdr *eap; +{ + + epp->ep_emul = &emul_ultrix; + return 0; +} +#endif diff --git a/sys/arch/wgrisc/wgrisc/disksubr.c b/sys/arch/wgrisc/wgrisc/disksubr.c new file mode 100644 index 00000000000..64d08bd1275 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/disksubr.c @@ -0,0 +1,355 @@ +/* $OpenBSD: disksubr.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Authors: Keith Bostic, Chris G. Demetriou, Per Fogelstrom (R4000) + * + * 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 the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/ioccom.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/disk.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <machine/cpu.h> +#include <machine/autoconf.h> + +extern struct device *bootdv; + +int fat_types[] = { DOSPTYP_FAT12, DOSPTYP_FAT16S, + DOSPTYP_FAT16B, DOSPTYP_FAT16C, -1 }; + +/* was this the boot device ? */ +void +dk_establish(dk, dev) + struct disk *dk; + struct device *dev; +{ +} + +/* + * Attempt to read a disk label from a device * using the indicated stategy routine. + * The label must be partly set up before this: + * secpercyl and anything required in the strategy routine + * (e.g., sector size) must be filled in before calling us. + * Returns null on success and an error string on failure. + */ +char * +readdisklabel(dev, strat, lp, clp) + dev_t dev; + void (*strat)(); + struct disklabel *lp; + struct cpu_disklabel *clp; +{ + struct buf *bp; + struct disklabel *dlp; + struct dos_partition *dp = clp->dosparts; + char *msg = NULL; + int dospart, dospartoff, i, *ip; + + /* minimal requirements for archtypal disk label */ + if (lp->d_secperunit == 0) + lp->d_secperunit = 0x1fffffff; + lp->d_npartitions = RAW_PART + 1; + for(i = 0; i < RAW_PART; i++) { + lp->d_partitions[i].p_size = 0; + lp->d_partitions[i].p_offset = 0; + } + if (lp->d_partitions[RAW_PART].p_size == 0) + lp->d_partitions[RAW_PART].p_size = 0x1fffffff; + lp->d_partitions[RAW_PART].p_offset = 0; + + /* obtain buffer to probe drive with */ + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + dospartoff = 0; + dospart = -1; + + /* do dos partitions in the process of getting disklabel? */ + if (dp) { + /* read master boot record */ + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_resid = 0; + (*strat)(bp); + + /* if successful, wander through dos partition table */ + if (biowait(bp)) { + msg = "dos partition I/O error"; + goto done; + } + if (*(unsigned int *)(bp->b_data) == 0x8efac033) { + /* XXX how do we check veracity/bounds of this? */ + bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp)); + + for (i = 0, dp = clp->dosparts; i < NDOSPART; i++, dp++) { + if (dp->dp_size && dp->dp_typ == DOSPTYP_OPENBSD + && dospart < 0) + dospart = i; + } + for (i = 0, dp = clp->dosparts; i < NDOSPART; i++, dp++) { + if (dp->dp_size && dp->dp_typ == DOSPTYP_386BSD + && dospart < 0) + dospart = i; + } + if(dospart >= 0) { + /* + * set part a to show OpenBSD part + */ + dp = clp->dosparts+dospart; + dospartoff = dp->dp_start; + + lp->d_partitions[0].p_size = dp->dp_size; + lp->d_partitions[0].p_offset = dp->dp_start; + lp->d_partitions[RAW_PART].p_size = dp->dp_size; + lp->d_partitions[RAW_PART].p_offset = dp->dp_start; + lp->d_ntracks = dp->dp_ehd + 1; + lp->d_nsectors = DPSECT(dp->dp_esect); + lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; + } + /* + * In case the disklabel read below fails, we want to provide + * a fake label in which m/n/o/p are MBR partitions 0/1/2/3 + */ + for (i=0, dp = clp->dosparts; i < NDOSPART; i++, dp++) { + lp->d_partitions[MAXPARTITIONS - NDOSPART + i].p_size = dp->dp_size; + lp->d_partitions[MAXPARTITIONS - NDOSPART + i].p_offset = dp->dp_start; + for (ip = fat_types; *ip != -1; ip++) { + if (dp->dp_typ != *ip) + continue; + lp->d_partitions[MAXPARTITIONS - NDOSPART +i].p_fstype = FS_MSDOS; + } + } + lp->d_bbsize = 8192; + lp->d_sbsize = 64*1024; /* XXX ? */ + lp->d_npartitions = MAXPARTITIONS; + } + + } + /* next, dig out disk label */ + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_resid = 0; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if (biowait(bp)) { + msg = "disk label read error"; + goto done; + } + + dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); + if (dlp->d_magic == DISKMAGIC) { + if (dkcksum(dlp)) { + msg = "OpenBSD disk label corrupted"; + goto done; + } + *lp = *dlp; + goto done; + } + msg = "no disk label"; +done: + bp->b_flags = B_INVAL | B_AGE | B_READ; + brelse(bp); + return (msg); +} + +/* + * Check new disk label for sensibility before setting it. + */ +int +setdisklabel(olp, nlp, openmask, clp) + register struct disklabel *olp, *nlp; + u_long openmask; + struct cpu_disklabel *clp; +{ + register i; + register struct partition *opp, *npp; + + /* sanity clause */ + if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 || + (nlp->d_secsize % DEV_BSIZE) != 0) + return(EINVAL); + + if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || + dkcksum(nlp) != 0) + return (EINVAL); + + while ((i = ffs((long)openmask)) != 0) { + i--; + 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); + /* + * Copy internally-set partition information + * if new label doesn't include it. XXX + */ + if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { + npp->p_fstype = opp->p_fstype; + npp->p_fsize = opp->p_fsize; + npp->p_frag = opp->p_frag; + npp->p_cpg = opp->p_cpg; + } + } + nlp->d_checksum = 0; + nlp->d_checksum = dkcksum(nlp); + *olp = *nlp; + return (0); +} + +/* + * Write disk label back to device after modification. + * this means write out the Rigid disk blocks to represent the + * label. Hope the user was carefull. + */ +int +writedisklabel(dev, strat, lp, clp) + dev_t dev; + void (*strat)(); + register struct disklabel *lp; + struct cpu_disklabel *clp; +{ + struct buf *bp; + struct disklabel *dlp; + struct dos_partition *dp = clp->dosparts; + int error = 0, i; + int dospart, dospartoff; + + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + dospart = -1; + dospartoff = 0; + + /* do dos partitions in the process of getting disklabel? */ + if (dp) { + /* read master boot record */ + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_resid = 0; + (*strat)(bp); + + if (((error = biowait(bp)) == 0) + && *(unsigned int *)(bp->b_data) == 0x8efac033) { + /* XXX how do we check veracity/bounds of this? */ + bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp)); + + for (i = 0, dp = clp->dosparts; i < NDOSPART; i++, dp++) { + if (dp->dp_size && dp->dp_typ == DOSPTYP_OPENBSD + && dospart < 0) { + dospart = i; + dospartoff = dp->dp_start; + } + } + for (i = 0, dp = clp->dosparts; i < NDOSPART; i++, dp++) { + if (dp->dp_size && dp->dp_typ == DOSPTYP_386BSD + && dospart < 0) { + dospart = i; + dospartoff = dp->dp_start; + } + } + } + + } + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_resid = 0; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_READ; /* get current label */ + (*strat)(bp); + if (error = biowait(bp)) + goto done; + + dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); + *dlp = *lp; /* struct assignment */ + + bp->b_flags = B_WRITE; + (*strat)(bp); + error = biowait(bp); + +done: + 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, wlabel) + struct buf *bp; + struct disklabel *lp; + int wlabel; +{ +#define dkpart(dev) (minor(dev) % MAXPARTITIONS ) + + struct partition *p = lp->d_partitions + dkpart(bp->b_dev); + int labelsect = lp->d_partitions[RAW_PART].p_offset; + int maxsz = p->p_size; + int sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; + + /* overwriting disk label ? */ + /* XXX should also protect bootstrap in first 8K */ + if (bp->b_blkno + p->p_offset == LABELSECTOR + labelsect && + (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_resid = (bp->b_blkno + p->p_offset) / lp->d_secpercyl; + return(1); +bad: + bp->b_flags |= B_ERROR; + return(-1); +} diff --git a/sys/arch/wgrisc/wgrisc/fp.S b/sys/arch/wgrisc/wgrisc/fp.S new file mode 100644 index 00000000000..0ba3cfa8d1e --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/fp.S @@ -0,0 +1,3611 @@ +/* $OpenBSD: fp.S,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)fp.s 8.1 (Berkeley) 6/10/93 + * $Id: fp.S,v 1.1 1997/02/06 16:02:45 pefo Exp $ + */ + +/* + * Standard header stuff. + */ + +#include <machine/regdef.h> +#include <machine/asm.h> +#include <machine/cpu.h> + +#include "assym.h" + +#define SEXP_INF 0xff +#define DEXP_INF 0x7ff +#define SEXP_BIAS 127 +#define DEXP_BIAS 1023 +#define SEXP_MIN -126 +#define DEXP_MIN -1022 +#define SEXP_MAX 127 +#define DEXP_MAX 1023 +#define WEXP_MAX 30 /* maximum unbiased exponent for int */ +#define WEXP_MIN -1 /* minimum unbiased exponent for int */ +#define SFRAC_BITS 23 +#define DFRAC_BITS 52 +#define SIMPL_ONE 0x00800000 +#define DIMPL_ONE 0x00100000 +#define SLEAD_ZEROS 31 - 23 +#define DLEAD_ZEROS 31 - 20 +#define STICKYBIT 1 +#define GUARDBIT 0x80000000 +#define SSIGNAL_NAN 0x00400000 +#define DSIGNAL_NAN 0x00080000 +#define SQUIET_NAN 0x003fffff +#define DQUIET_NAN0 0x0007ffff +#define DQUIET_NAN1 0xffffffff +#define INT_MIN 0x80000000 +#define INT_MAX 0x7fffffff + +#define COND_UNORDERED 0x1 +#define COND_EQUAL 0x2 +#define COND_LESS 0x4 +#define COND_SIGNAL 0x8 + +/*---------------------------------------------------------------------------- + * + * CPU_EmulateFP -- + * + * Emulate unimplemented floating point operations. + * This routine should only be called by CPU_FPInterrupt(). + * + * CPU_EmulateFP(instr) + * unsigned instr; + * + * Results: + * None. + * + * Side effects: + * Floating point registers are modified according to instruction. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(CPU_EmulateFP, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) +/* + * Decode the FMT field (bits 24-21) and FUNCTION field (bits 5-0). + */ + srl v0, a0, 21 - 2 # get FMT field + and v0, v0, 0xF << 2 # mask FMT field + and v1, a0, 0x3F # mask FUNC field + sll v1, v1, 5 # align for table lookup + bgt v0, 4 << 2, ill # illegal format + + or v1, v1, v0 + cfc1 a1, FPC_CSR # get exception register + lw a3, func_fmt_tbl(v1) # switch on FUNC & FMT + and a1, a1, ~FPC_EXCEPTION_UNIMPL # clear exception + ctc1 a1, FPC_CSR + j a3 + + .rdata +func_fmt_tbl: + .word add_s # 0 + .word add_d # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word ill # 0 + .word sub_s # 1 + .word sub_d # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word ill # 1 + .word mul_s # 2 + .word mul_d # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word ill # 2 + .word div_s # 3 + .word div_d # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 3 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word ill # 4 + .word abs_s # 5 + .word abs_d # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word ill # 5 + .word mov_s # 6 + .word mov_d # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word ill # 6 + .word neg_s # 7 + .word neg_d # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 7 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 8 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 9 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 10 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 11 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 12 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 13 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 14 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 15 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 16 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 17 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 18 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 19 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 20 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 21 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 22 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 23 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 24 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 25 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 26 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 27 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 28 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 29 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 30 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 31 + .word ill # 32 + .word cvt_s_d # 32 + .word ill # 32 + .word ill # 32 + .word cvt_s_w # 32 + .word ill # 32 + .word ill # 32 + .word ill # 32 + .word cvt_d_s # 33 + .word ill # 33 + .word ill # 33 + .word ill # 33 + .word cvt_d_w # 33 + .word ill # 33 + .word ill # 33 + .word ill # 33 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 34 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word ill # 35 + .word cvt_w_s # 36 + .word cvt_w_d # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 36 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 37 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 38 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 39 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 40 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 41 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 42 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 43 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 44 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 45 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 46 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word ill # 47 + .word cmp_s # 48 + .word cmp_d # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word ill # 48 + .word cmp_s # 49 + .word cmp_d # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word ill # 49 + .word cmp_s # 50 + .word cmp_d # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word ill # 50 + .word cmp_s # 51 + .word cmp_d # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word ill # 51 + .word cmp_s # 52 + .word cmp_d # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word ill # 52 + .word cmp_s # 53 + .word cmp_d # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word ill # 53 + .word cmp_s # 54 + .word cmp_d # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word ill # 54 + .word cmp_s # 55 + .word cmp_d # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word ill # 55 + .word cmp_s # 56 + .word cmp_d # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word ill # 56 + .word cmp_s # 57 + .word cmp_d # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word ill # 57 + .word cmp_s # 58 + .word cmp_d # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word ill # 58 + .word cmp_s # 59 + .word cmp_d # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word ill # 59 + .word cmp_s # 60 + .word cmp_d # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word ill # 60 + .word cmp_s # 61 + .word cmp_d # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word ill # 61 + .word cmp_s # 62 + .word cmp_d # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word ill # 62 + .word cmp_s # 63 + .word cmp_d # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .word ill # 63 + .text + +/* + * Single precision subtract. + */ +sub_s: + jal get_ft_fs_s + xor t4, t4, 1 # negate FT sign bit + b add_sub_s +/* + * Single precision add. + */ +add_s: + jal get_ft_fs_s +add_sub_s: + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t5, SEXP_INF, result_fs_s # if FT is not inf, result=FS + bne t2, zero, result_fs_s # if FS is NAN, result is FS + bne t6, zero, result_ft_s # if FT is NAN, result is FT + bne t0, t4, invalid_s # both infinities same sign? + b result_fs_s # result is in FS +1: + beq t5, SEXP_INF, result_ft_s # if FT is inf, result=FT + bne t1, zero, 4f # is FS a denormalized num? + beq t2, zero, 3f # is FS zero? + bne t5, zero, 2f # is FT a denormalized num? + beq t6, zero, result_fs_s # FT is zero, result=FS + jal renorm_fs_s + jal renorm_ft_s + b 5f +2: + jal renorm_fs_s + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit + b 5f +3: + bne t5, zero, result_ft_s # if FT != 0, result=FT + bne t6, zero, result_ft_s + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_s +1: + and t0, t0, t4 # compute result sign + b result_fs_s +4: + bne t5, zero, 2f # is FT a denormalized num? + beq t6, zero, result_fs_s # FT is zero, result=FS + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit + jal renorm_ft_s + b 5f +2: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +/* + * Perform the addition. + */ +5: + move t8, zero # no shifted bits (sticky reg) + beq t1, t5, 4f # no shift needed + subu v0, t1, t5 # v0 = difference of exponents + move v1, v0 # v1 = abs(difference) + bge v0, zero, 1f + negu v1 +1: + ble v1, SFRAC_BITS+2, 2f # is difference too great? + li t8, STICKYBIT # set the sticky bit + bge v0, zero, 1f # check which exp is larger + move t1, t5 # result exp is FTs + move t2, zero # FSs fraction shifted is zero + b 4f +1: + move t6, zero # FTs fraction shifted is zero + b 4f +2: + li t9, 32 # compute 32 - abs(exp diff) + subu t9, t9, v1 + bgt v0, zero, 3f # if FS > FT, shift FTs frac + move t1, t5 # FT > FS, result exp is FTs + sll t8, t2, t9 # save bits shifted out + srl t2, t2, v1 # shift FSs fraction + b 4f +3: + sll t8, t6, t9 # save bits shifted out + srl t6, t6, v1 # shift FTs fraction +4: + bne t0, t4, 1f # if signs differ, subtract + addu t2, t2, t6 # add fractions + b norm_s +1: + blt t2, t6, 3f # subtract larger from smaller + bne t2, t6, 2f # if same, result=0 + move t1, zero # result=0 + move t2, zero + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_s +1: + and t0, t0, t4 # compute result sign + b result_fs_s +2: + sltu t9, zero, t8 # compute t2:zero - t6:t8 + subu t8, zero, t8 + subu t2, t2, t6 # subtract fractions + subu t2, t2, t9 # subtract barrow + b norm_s +3: + move t0, t4 # sign of result = FTs + sltu t9, zero, t8 # compute t6:zero - t2:t8 + subu t8, zero, t8 + subu t2, t6, t2 # subtract fractions + subu t2, t2, t9 # subtract barrow + b norm_s + +/* + * Double precision subtract. + */ +sub_d: + jal get_ft_fs_d + xor t4, t4, 1 # negate sign bit + b add_sub_d +/* + * Double precision add. + */ +add_d: + jal get_ft_fs_d +add_sub_d: + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t5, DEXP_INF, result_fs_d # if FT is not inf, result=FS + bne t2, zero, result_fs_d # if FS is NAN, result is FS + bne t3, zero, result_fs_d + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + bne t0, t4, invalid_d # both infinities same sign? + b result_fs_d # result is in FS +1: + beq t5, DEXP_INF, result_ft_d # if FT is inf, result=FT + bne t1, zero, 4f # is FS a denormalized num? + bne t2, zero, 1f # is FS zero? + beq t3, zero, 3f +1: + bne t5, zero, 2f # is FT a denormalized num? + bne t6, zero, 1f + beq t7, zero, result_fs_d # FT is zero, result=FS +1: + jal renorm_fs_d + jal renorm_ft_d + b 5f +2: + jal renorm_fs_d + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit + b 5f +3: + bne t5, zero, result_ft_d # if FT != 0, result=FT + bne t6, zero, result_ft_d + bne t7, zero, result_ft_d + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_d +1: + and t0, t0, t4 # compute result sign + b result_fs_d +4: + bne t5, zero, 2f # is FT a denormalized num? + bne t6, zero, 1f + beq t7, zero, result_fs_d # FT is zero, result=FS +1: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit + jal renorm_ft_d + b 5f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +/* + * Perform the addition. + */ +5: + move t8, zero # no shifted bits (sticky reg) + beq t1, t5, 4f # no shift needed + subu v0, t1, t5 # v0 = difference of exponents + move v1, v0 # v1 = abs(difference) + bge v0, zero, 1f + negu v1 +1: + ble v1, DFRAC_BITS+2, 2f # is difference too great? + li t8, STICKYBIT # set the sticky bit + bge v0, zero, 1f # check which exp is larger + move t1, t5 # result exp is FTs + move t2, zero # FSs fraction shifted is zero + move t3, zero + b 4f +1: + move t6, zero # FTs fraction shifted is zero + move t7, zero + b 4f +2: + li t9, 32 + bge v0, zero, 3f # if FS > FT, shift FTs frac + move t1, t5 # FT > FS, result exp is FTs + blt v1, t9, 1f # shift right by < 32? + subu v1, v1, t9 + subu t9, t9, v1 + sll t8, t2, t9 # save bits shifted out + sltu t9, zero, t3 # dont lose any one bits + or t8, t8, t9 # save sticky bit + srl t3, t2, v1 # shift FSs fraction + move t2, zero + b 4f +1: + subu t9, t9, v1 + sll t8, t3, t9 # save bits shifted out + srl t3, t3, v1 # shift FSs fraction + sll t9, t2, t9 # save bits shifted out of t2 + or t3, t3, t9 # and put into t3 + srl t2, t2, v1 + b 4f +3: + blt v1, t9, 1f # shift right by < 32? + subu v1, v1, t9 + subu t9, t9, v1 + sll t8, t6, t9 # save bits shifted out + srl t7, t6, v1 # shift FTs fraction + move t6, zero + b 4f +1: + subu t9, t9, v1 + sll t8, t7, t9 # save bits shifted out + srl t7, t7, v1 # shift FTs fraction + sll t9, t6, t9 # save bits shifted out of t2 + or t7, t7, t9 # and put into t3 + srl t6, t6, v1 +4: + bne t0, t4, 1f # if signs differ, subtract + addu t3, t3, t7 # add fractions + sltu t9, t3, t7 # compute carry + addu t2, t2, t6 # add fractions + addu t2, t2, t9 # add carry + b norm_d +1: + blt t2, t6, 3f # subtract larger from smaller + bne t2, t6, 2f + bltu t3, t7, 3f + bne t3, t7, 2f # if same, result=0 + move t1, zero # result=0 + move t2, zero + move t3, zero + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + bne v0, FPC_ROUND_RM, 1f # round to -infinity? + or t0, t0, t4 # compute result sign + b result_fs_d +1: + and t0, t0, t4 # compute result sign + b result_fs_d +2: + beq t8, zero, 1f # compute t2:t3:zero - t6:t7:t8 + subu t8, zero, t8 + sltu v0, t3, 1 # compute barrow out + subu t3, t3, 1 # subtract barrow + subu t2, t2, v0 +1: + sltu v0, t3, t7 + subu t3, t3, t7 # subtract fractions + subu t2, t2, t6 # subtract fractions + subu t2, t2, v0 # subtract barrow + b norm_d +3: + move t0, t4 # sign of result = FTs + beq t8, zero, 1f # compute t6:t7:zero - t2:t3:t8 + subu t8, zero, t8 + sltu v0, t7, 1 # compute barrow out + subu t7, t7, 1 # subtract barrow + subu t6, t6, v0 +1: + sltu v0, t7, t3 + subu t3, t7, t3 # subtract fractions + subu t2, t6, t2 # subtract fractions + subu t2, t2, v0 # subtract barrow + b norm_d + +/* + * Single precision multiply. + */ +mul_s: + jal get_ft_fs_s + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, SEXP_INF, 2f # is FS an infinity? + bne t2, zero, result_fs_s # if FS is a NAN, result=FS + bne t5, SEXP_INF, 1f # FS is inf, is FT an infinity? + bne t6, zero, result_ft_s # if FT is a NAN, result=FT + b result_fs_s # result is infinity +1: + bne t5, zero, result_fs_s # inf * zero? if no, result=FS + bne t6, zero, result_fs_s + b invalid_s # infinity * zero is invalid +2: + bne t5, SEXP_INF, 1f # FS != inf, is FT an infinity? + bne t1, zero, result_ft_s # zero * inf? if no, result=FT + bne t2, zero, result_ft_s + bne t6, zero, result_ft_s # if FT is a NAN, result=FT + b invalid_s # zero * infinity is invalid +1: + bne t1, zero, 1f # is FS zero? + beq t2, zero, result_fs_s # result is zero + jal renorm_fs_s + b 2f +1: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit +2: + bne t5, zero, 1f # is FT zero? + beq t6, zero, result_ft_s # result is zero + jal renorm_ft_s + b 2f +1: + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +2: + addu t1, t1, t5 # compute result exponent + addu t1, t1, 9 # account for binary point + multu t2, t6 # multiply fractions + mflo t8 + mfhi t2 + b norm_s + +/* + * Double precision multiply. + */ +mul_d: + jal get_ft_fs_d + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, DEXP_INF, 2f # is FS an infinity? + bne t2, zero, result_fs_d # if FS is a NAN, result=FS + bne t3, zero, result_fs_d + bne t5, DEXP_INF, 1f # FS is inf, is FT an infinity? + bne t6, zero, result_ft_d # if FT is a NAN, result=FT + bne t7, zero, result_ft_d + b result_fs_d # result is infinity +1: + bne t5, zero, result_fs_d # inf * zero? if no, result=FS + bne t6, zero, result_fs_d + bne t7, zero, result_fs_d + b invalid_d # infinity * zero is invalid +2: + bne t5, DEXP_INF, 1f # FS != inf, is FT an infinity? + bne t1, zero, result_ft_d # zero * inf? if no, result=FT + bne t2, zero, result_ft_d # if FS is a NAN, result=FS + bne t3, zero, result_ft_d + bne t6, zero, result_ft_d # if FT is a NAN, result=FT + bne t7, zero, result_ft_d + b invalid_d # zero * infinity is invalid +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_d # result is zero +1: + jal renorm_fs_d + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + beq t7, zero, result_ft_d # result is zero +1: + jal renorm_ft_d + b 3f +2: + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +3: + addu t1, t1, t5 # compute result exponent + addu t1, t1, 12 # ??? + multu t3, t7 # multiply fractions (low * low) + move t4, t2 # free up t2,t3 for result + move t5, t3 + mflo a3 # save low order bits + mfhi t8 + not v0, t8 + multu t4, t7 # multiply FS(high) * FT(low) + mflo v1 + mfhi t3 # init low result + sltu v0, v0, v1 # compute carry + addu t8, v1 + multu t5, t6 # multiply FS(low) * FT(high) + addu t3, t3, v0 # add carry + not v0, t8 + mflo v1 + mfhi t2 + sltu v0, v0, v1 + addu t8, v1 + multu t4, t6 # multiply FS(high) * FT(high) + addu t3, v0 + not v1, t3 + sltu v1, v1, t2 + addu t3, t2 + not v0, t3 + mfhi t2 + addu t2, v1 + mflo v1 + sltu v0, v0, v1 + addu t2, v0 + addu t3, v1 + sltu a3, zero, a3 # reduce t8,a3 to just t8 + or t8, a3 + b norm_d + +/* + * Single precision divide. + */ +div_s: + jal get_ft_fs_s + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, result_fs_s # if FS is NAN, result is FS + bne t5, SEXP_INF, result_fs_s # is FT an infinity? + bne t6, zero, result_ft_s # if FT is NAN, result is FT + b invalid_s # infinity/infinity is invalid +1: + bne t5, SEXP_INF, 1f # is FT an infinity? + bne t6, zero, result_ft_s # if FT is NAN, result is FT + move t1, zero # x / infinity is zero + move t2, zero + b result_fs_s +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + bne t5, zero, result_fs_s # FS=zero, is FT zero? + beq t6, zero, invalid_s # 0 / 0 + b result_fs_s # result = zero +1: + jal renorm_fs_s + b 3f +2: + subu t1, t1, SEXP_BIAS # unbias FS exponent + or t2, t2, SIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 + and v0, a1, FPC_ENABLE_DIV0 # trap enabled? + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + li t1, SEXP_INF # result is infinity + move t2, zero + b result_fs_s +1: + jal renorm_ft_s + b 3f +2: + subu t5, t5, SEXP_BIAS # unbias FT exponent + or t6, t6, SIMPL_ONE # set implied one bit +3: + subu t1, t1, t5 # compute exponent + subu t1, t1, 3 # compensate for result position + li v0, SFRAC_BITS+3 # number of bits to divide + move t8, t2 # init dividend + move t2, zero # init result +1: + bltu t8, t6, 3f # is dividend >= divisor? +2: + subu t8, t8, t6 # subtract divisor from dividend + or t2, t2, 1 # remember that we did + bne t8, zero, 3f # if not done, continue + sll t2, t2, v0 # shift result to final position + b norm_s +3: + sll t8, t8, 1 # shift dividend + sll t2, t2, 1 # shift result + subu v0, v0, 1 # are we done? + bne v0, zero, 1b # no, continue + b norm_s + +/* + * Double precision divide. + */ +div_d: + jal get_ft_fs_d + xor t0, t0, t4 # compute sign of result + move t4, t0 + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, result_fs_d # if FS is NAN, result is FS + bne t3, zero, result_fs_d + bne t5, DEXP_INF, result_fs_d # is FT an infinity? + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + b invalid_d # infinity/infinity is invalid +1: + bne t5, DEXP_INF, 1f # is FT an infinity? + bne t6, zero, result_ft_d # if FT is NAN, result is FT + bne t7, zero, result_ft_d + move t1, zero # x / infinity is zero + move t2, zero + move t3, zero + b result_fs_d +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + bne t3, zero, 1f + bne t5, zero, result_fs_d # FS=zero, is FT zero? + bne t6, zero, result_fs_d + beq t7, zero, invalid_d # 0 / 0 + b result_fs_d # result = zero +1: + jal renorm_fs_d + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias FS exponent + or t2, t2, DIMPL_ONE # set implied one bit +3: + bne t5, zero, 2f # is FT zero? + bne t6, zero, 1f + bne t7, zero, 1f + or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 + and v0, a1, FPC_ENABLE_DIV0 # trap enabled? + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # Save exceptions + li t1, DEXP_INF # result is infinity + move t2, zero + move t3, zero + b result_fs_d +1: + jal renorm_ft_d + b 3f +2: + subu t5, t5, DEXP_BIAS # unbias FT exponent + or t6, t6, DIMPL_ONE # set implied one bit +3: + subu t1, t1, t5 # compute exponent + subu t1, t1, 3 # compensate for result position + li v0, DFRAC_BITS+3 # number of bits to divide + move t8, t2 # init dividend + move t9, t3 + move t2, zero # init result + move t3, zero +1: + bltu t8, t6, 3f # is dividend >= divisor? + bne t8, t6, 2f + bltu t9, t7, 3f +2: + sltu v1, t9, t7 # subtract divisor from dividend + subu t9, t9, t7 + subu t8, t8, t6 + subu t8, t8, v1 + or t3, t3, 1 # remember that we did + bne t8, zero, 3f # if not done, continue + bne t9, zero, 3f + li v1, 32 # shift result to final position + blt v0, v1, 2f # shift < 32 bits? + subu v0, v0, v1 # shift by > 32 bits + sll t2, t3, v0 # shift upper part + move t3, zero + b norm_d +2: + subu v1, v1, v0 # shift by < 32 bits + sll t2, t2, v0 # shift upper part + srl t9, t3, v1 # save bits shifted out + or t2, t2, t9 # and put into upper part + sll t3, t3, v0 + b norm_d +3: + sll t8, t8, 1 # shift dividend + srl v1, t9, 31 # save bit shifted out + or t8, t8, v1 # and put into upper part + sll t9, t9, 1 + sll t2, t2, 1 # shift result + srl v1, t3, 31 # save bit shifted out + or t2, t2, v1 # and put into upper part + sll t3, t3, 1 + subu v0, v0, 1 # are we done? + bne v0, zero, 1b # no, continue + sltu v0, zero, t9 # be sure to save any one bits + or t8, t8, v0 # from the lower remainder + b norm_d + +/* + * Single precision absolute value. + */ +abs_s: + jal get_fs_s + move t0, zero # set sign positive + b result_fs_s + +/* + * Double precision absolute value. + */ +abs_d: + jal get_fs_d + move t0, zero # set sign positive + b result_fs_d + +/* + * Single precision move. + */ +mov_s: + jal get_fs_s + b result_fs_s + +/* + * Double precision move. + */ +mov_d: + jal get_fs_d + b result_fs_d + +/* + * Single precision negate. + */ +neg_s: + jal get_fs_s + xor t0, t0, 1 # reverse sign + b result_fs_s + +/* + * Double precision negate. + */ +neg_d: + jal get_fs_d + xor t0, t0, 1 # reverse sign + b result_fs_d + +/* + * Convert double to single. + */ +cvt_s_d: + jal get_fs_d + bne t1, DEXP_INF, 1f # is FS an infinity? + li t1, SEXP_INF # convert to single + sll t2, t2, 3 # convert D fraction to S + srl t8, t3, 32 - 3 + or t2, t2, t8 + b result_fs_s +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_s # result=0 +1: + jal renorm_fs_d + subu t1, t1, 3 # correct exp for shift below + b 3f +2: + subu t1, t1, DEXP_BIAS # unbias exponent + or t2, t2, DIMPL_ONE # add implied one bit +3: + sll t2, t2, 3 # convert D fraction to S + srl t8, t3, 32 - 3 + or t2, t2, t8 + sll t8, t3, 3 + b norm_noshift_s + +/* + * Convert integer to single. + */ +cvt_s_w: + jal get_fs_int + bne t2, zero, 1f # check for zero + move t1, zero + b result_fs_s +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ +1: + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count leading zeros + li t1, 23 # init exponent + subu t1, t1, t9 # compute exponent + beq t9, zero, 1f + li v0, 32 + blt t9, zero, 2f # if shift < 0, shift right + subu v0, v0, t9 + sll t2, t2, t9 # shift left +1: + add t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + b result_fs_s +2: + negu t9 # shift right by t9 + subu v0, v0, t9 + sll t8, t2, v0 # save bits shifted out + srl t2, t2, t9 + b norm_noshift_s + +/* + * Convert single to double. + */ +cvt_d_s: + jal get_fs_s + move t3, zero + bne t1, SEXP_INF, 1f # is FS an infinity? + li t1, DEXP_INF # convert to double + b result_fs_d +1: + bne t1, zero, 2f # is FS denormalized or zero? + beq t2, zero, result_fs_d # is FS zero? + jal renorm_fs_s + move t8, zero + b norm_d +2: + addu t1, t1, DEXP_BIAS - SEXP_BIAS # bias exponent correctly + sll t3, t2, 32 - 3 # convert S fraction to D + srl t2, t2, 3 + b result_fs_d + +/* + * Convert integer to double. + */ +cvt_d_w: + jal get_fs_int + bne t2, zero, 1f # check for zero + move t1, zero # result=0 + move t3, zero + b result_fs_d +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ +1: + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count leading zeros + li t1, DEXP_BIAS + 20 # init exponent + subu t1, t1, t9 # compute exponent + beq t9, zero, 1f + li v0, 32 + blt t9, zero, 2f # if shift < 0, shift right + subu v0, v0, t9 + sll t2, t2, t9 # shift left +1: + and t2, t2, ~DIMPL_ONE # clear implied one bit + move t3, zero + b result_fs_d +2: + negu t9 # shift right by t9 + subu v0, v0, t9 + sll t3, t2, v0 + srl t2, t2, t9 + and t2, t2, ~DIMPL_ONE # clear implied one bit + b result_fs_d + +/* + * Convert single to integer. + */ +cvt_w_s: + jal get_fs_s + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, invalid_w # invalid conversion +1: + bne t1, zero, 1f # is FS zero? + beq t2, zero, result_fs_w # result is zero + move t2, zero # result is an inexact zero + b inexact_w +1: + subu t1, t1, SEXP_BIAS # unbias exponent + or t2, t2, SIMPL_ONE # add implied one bit + sll t3, t2, 32 - 3 # convert S fraction to D + srl t2, t2, 3 + b cvt_w + +/* + * Convert double to integer. + */ +cvt_w_d: + jal get_fs_d + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, invalid_w # invalid conversion + bne t3, zero, invalid_w # invalid conversion +1: + bne t1, zero, 2f # is FS zero? + bne t2, zero, 1f + beq t3, zero, result_fs_w # result is zero +1: + move t2, zero # result is an inexact zero + b inexact_w +2: + subu t1, t1, DEXP_BIAS # unbias exponent + or t2, t2, DIMPL_ONE # add implied one bit +cvt_w: + blt t1, WEXP_MIN, underflow_w # is exponent too small? + li v0, WEXP_MAX+1 + bgt t1, v0, overflow_w # is exponent too large? + bne t1, v0, 1f # special check for INT_MIN + beq t0, zero, overflow_w # if positive, overflow + bne t2, DIMPL_ONE, overflow_w + bne t3, zero, overflow_w + li t2, INT_MIN # result is INT_MIN + b result_fs_w +1: + subu v0, t1, 20 # compute amount to shift + beq v0, zero, 2f # is shift needed? + li v1, 32 + blt v0, zero, 1f # if shift < 0, shift right + subu v1, v1, v0 # shift left + sll t2, t2, v0 + srl t9, t3, v1 # save bits shifted out of t3 + or t2, t2, t9 # and put into t2 + sll t3, t3, v0 # shift FSs fraction + b 2f +1: + negu v0 # shift right by v0 + subu v1, v1, v0 + sll t8, t3, v1 # save bits shifted out + sltu t8, zero, t8 # dont lose any ones + srl t3, t3, v0 # shift FSs fraction + or t3, t3, t8 + sll t9, t2, v1 # save bits shifted out of t2 + or t3, t3, t9 # and put into t3 + srl t2, t2, v0 +/* + * round result (t0 is sign, t2 is integer part, t3 is fractional part). + */ +2: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t3, zero, 5f # if no fraction bits, continue + addu t2, t2, 1 # add rounding bit + blt t2, zero, overflow_w # overflow? + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t3 # add remainder + sltu v1, v0, t3 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result + blt t2, zero, overflow_w # overflow? +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + beq t0, zero, 1f # result positive? + negu t2 # convert to negative integer +1: + beq t3, zero, result_fs_w # is result exact? +/* + * Handle inexact exception. + */ +inexact_w: + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b result_fs_w + +/* + * Conversions to integer which overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an invalid exception. + */ +overflow_w: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + bne v0, zero, fpe_trap + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, inexact_w # inexact traps enabled? + b invalid_w + +/* + * Conversions to integer which underflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an invalid exception. + */ +underflow_w: + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + and v0, a1, FPC_ENABLE_UNDERFLOW + bne v0, zero, fpe_trap + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, inexact_w # inexact traps enabled? + b invalid_w + +/* + * Compare single. + */ +cmp_s: + jal get_cmp_s + bne t1, SEXP_INF, 1f # is FS an infinity? + bne t2, zero, unordered # FS is a NAN +1: + bne t5, SEXP_INF, 2f # is FT an infinity? + bne t6, zero, unordered # FT is a NAN +2: + sll t1, t1, 23 # reassemble exp & frac + or t1, t1, t2 + sll t5, t5, 23 # reassemble exp & frac + or t5, t5, t6 + beq t0, zero, 1f # is FS positive? + negu t1 +1: + beq t4, zero, 1f # is FT positive? + negu t5 +1: + li v0, COND_LESS + blt t1, t5, test_cond # is FS < FT? + li v0, COND_EQUAL + beq t1, t5, test_cond # is FS == FT? + move v0, zero # FS > FT + b test_cond + +/* + * Compare double. + */ +cmp_d: + jal get_cmp_d + bne t1, DEXP_INF, 1f # is FS an infinity? + bne t2, zero, unordered + bne t3, zero, unordered # FS is a NAN +1: + bne t5, DEXP_INF, 2f # is FT an infinity? + bne t6, zero, unordered + bne t7, zero, unordered # FT is a NAN +2: + sll t1, t1, 20 # reassemble exp & frac + or t1, t1, t2 + sll t5, t5, 20 # reassemble exp & frac + or t5, t5, t6 + beq t0, zero, 1f # is FS positive? + not t3 # negate t1,t3 + not t1 + addu t3, t3, 1 + seq v0, t3, zero # compute carry + addu t1, t1, v0 +1: + beq t4, zero, 1f # is FT positive? + not t7 # negate t5,t7 + not t5 + addu t7, t7, 1 + seq v0, t7, zero # compute carry + addu t5, t5, v0 +1: + li v0, COND_LESS + blt t1, t5, test_cond # is FS(MSW) < FT(MSW)? + move v0, zero + bne t1, t5, test_cond # is FS(MSW) > FT(MSW)? + li v0, COND_LESS + bltu t3, t7, test_cond # is FS(LSW) < FT(LSW)? + li v0, COND_EQUAL + beq t3, t7, test_cond # is FS(LSW) == FT(LSW)? + move v0, zero # FS > FT +test_cond: + and v0, v0, a0 # condition match instruction? +set_cond: + bne v0, zero, 1f + and a1, a1, ~FPC_COND_BIT # clear condition bit + b 2f +1: + or a1, a1, FPC_COND_BIT # set condition bit +2: + ctc1 a1, FPC_CSR # save condition bit + b done + +unordered: + and v0, a0, COND_UNORDERED # this cmp match unordered? + bne v0, zero, 1f + and a1, a1, ~FPC_COND_BIT # clear condition bit + b 2f +1: + or a1, a1, FPC_COND_BIT # set condition bit +2: + and v0, a0, COND_SIGNAL + beq v0, zero, 1f # is this a signaling cmp? + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap +1: + ctc1 a1, FPC_CSR # save condition bit + b done + +/* + * Determine the amount to shift the fraction in order to restore the + * normalized position. After that, round and handle exceptions. + */ +norm_s: + move v0, t2 + move t9, zero # t9 = num of leading zeros + bne t2, zero, 1f + move v0, t8 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t8 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count leading zeros + subu t1, t1, t9 # adjust the exponent + beq t9, zero, norm_noshift_s + li v1, 32 + blt t9, zero, 1f # if shift < 0, shift right + subu v1, v1, t9 + sll t2, t2, t9 # shift t2,t8 left + srl v0, t8, v1 # save bits shifted out + or t2, t2, v0 + sll t8, t8, t9 + b norm_noshift_s +1: + negu t9 # shift t2,t8 right by t9 + subu v1, v1, t9 + sll v0, t8, v1 # save bits shifted out + sltu v0, zero, v0 # be sure to save any one bits + srl t8, t8, t9 + or t8, t8, v0 + sll v0, t2, v1 # save bits shifted out + or t8, t8, v0 + srl t2, t2, t9 +norm_noshift_s: + move t5, t1 # save unrounded exponent + move t6, t2 # save unrounded fraction + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t2, t2, 1 # add rounding bit + bne t2, SIMPL_ONE<<1, 5f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result + bne t2, SIMPL_ONE<<1, 4f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + bgt t1, SEXP_MAX, overflow_s # overflow? + blt t1, SEXP_MIN, underflow_s # underflow? + bne t8, zero, inexact_s # is result inexact? + addu t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + b result_fs_s + +/* + * Handle inexact exception. + */ +inexact_s: + addu t1, t1, SEXP_BIAS # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit +inexact_nobias_s: + jal set_fd_s # save result + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an infinity. + */ +overflow_s: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + beq v0, zero, 1f + subu t1, t1, 192 # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + jal set_fd_s # save result + b fpe_trap +1: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 2f # round to +infinity + bne t0, zero, 3f +1: + li t1, SEXP_MAX # result is max finite + li t2, 0x007fffff + b inexact_s +2: + bne t0, zero, 1b +3: + li t1, SEXP_MAX + 1 # result is infinity + move t2, zero + b inexact_s + +/* + * In this implementation, "tininess" is detected "after rounding" and + * "loss of accuracy" is detected as "an inexact result". + */ +underflow_s: + and v0, a1, FPC_ENABLE_UNDERFLOW + beq v0, zero, 1f +/* + * Underflow is enabled so compute the result and trap. + */ + addu t1, t1, 192 # bias exponent + and t2, t2, ~SIMPL_ONE # clear implied one bit + jal set_fd_s # save result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + b fpe_trap +/* + * Underflow is not enabled so compute the result, + * signal inexact result (if it is) and trap (if enabled). + */ +1: + move t1, t5 # get unrounded exponent + move t2, t6 # get unrounded fraction + li t9, SEXP_MIN # compute shift amount + subu t9, t9, t1 # shift t2,t8 right by t9 + blt t9, SFRAC_BITS+2, 3f # shift all the bits out? + move t1, zero # result is inexact zero + move t2, zero + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW +/* + * Now round the zero result. + * Only need to worry about rounding to +- infinity when the sign matches. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, inexact_nobias_s # round to nearest + beq v0, FPC_ROUND_RZ, inexact_nobias_s # round to zero + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, inexact_nobias_s # if sign is positive, truncate + b 2f +1: + bne t0, zero, inexact_nobias_s # if sign is negative, truncate +2: + addu t2, t2, 1 # add rounding bit + b inexact_nobias_s +3: + li v1, 32 + subu v1, v1, t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t2, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t2, t2, t9 +/* + * Now round the denormalized result. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t2, t2, 1 # add rounding bit + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry to result +4: + bne v0, zero, 5f # if rounded remainder is zero + and t2, t2, ~1 # clear LSB (round to nearest) +5: + move t1, zero # denorm or zero exponent + jal set_fd_s # save result + beq t8, zero, done # check for exact result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Determine the amount to shift the fraction in order to restore the + * normalized position. After that, round and handle exceptions. + */ +norm_d: + move v0, t2 + move t9, zero # t9 = num of leading zeros + bne t2, zero, 1f + move v0, t3 + addu t9, 32 + bne t3, zero, 1f + move v0, t8 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t3,t8 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count leading zeros + subu t1, t1, t9 # adjust the exponent + beq t9, zero, norm_noshift_d + li v1, 32 + blt t9, zero, 2f # if shift < 0, shift right + blt t9, v1, 1f # shift by < 32? + subu t9, t9, v1 # shift by >= 32 + subu v1, v1, t9 + sll t2, t3, t9 # shift left by t9 + srl v0, t8, v1 # save bits shifted out + or t2, t2, v0 + sll t3, t8, t9 + move t8, zero + b norm_noshift_d +1: + subu v1, v1, t9 + sll t2, t2, t9 # shift left by t9 + srl v0, t3, v1 # save bits shifted out + or t2, t2, v0 + sll t3, t3, t9 + srl v0, t8, v1 # save bits shifted out + or t3, t3, v0 + sll t8, t8, t9 + b norm_noshift_d +2: + negu t9 # shift right by t9 + subu v1, v1, t9 # (known to be < 32 bits) + sll v0, t8, v1 # save bits shifted out + sltu v0, zero, v0 # be sure to save any one bits + srl t8, t8, t9 + or t8, t8, v0 + sll v0, t3, v1 # save bits shifted out + or t8, t8, v0 + srl t3, t3, t9 + sll v0, t2, v1 # save bits shifted out + or t3, t3, v0 + srl t2, t2, t9 +norm_noshift_d: + move t5, t1 # save unrounded exponent + move t6, t2 # save unrounded fraction (MS) + move t7, t3 # save unrounded fraction (LS) + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 5f # branch if no carry + addu t2, t2, 1 # add carry + bne t2, DIMPL_ONE<<1, 5f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # branch if no carry + addu t3, t3, 1 # add carry + bne t3, zero, 4f # branch if no carry + addu t2, t2, 1 # add carry to result + bne t2, DIMPL_ONE<<1, 4f # need to adjust exponent? + addu t1, t1, 1 # adjust exponent + srl t2, t2, 1 # renormalize fraction +4: + bne v0, zero, 5f # if rounded remainder is zero + and t3, t3, ~1 # clear LSB (round to nearest) +5: + bgt t1, DEXP_MAX, overflow_d # overflow? + blt t1, DEXP_MIN, underflow_d # underflow? + bne t8, zero, inexact_d # is result inexact? + addu t1, t1, DEXP_BIAS # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + b result_fs_d + +/* + * Handle inexact exception. + */ +inexact_d: + addu t1, t1, DEXP_BIAS # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit +inexact_nobias_d: + jal set_fd_d # save result + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Overflow will trap (if enabled), + * or generate an inexact trap (if enabled), + * or generate an infinity. + */ +overflow_d: + or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW + and v0, a1, FPC_ENABLE_OVERFLOW + beq v0, zero, 1f + subu t1, t1, 1536 # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + jal set_fd_d # save result + b fpe_trap +1: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 2f # round to +infinity + bne t0, zero, 3f +1: + li t1, DEXP_MAX # result is max finite + li t2, 0x000fffff + li t3, 0xffffffff + b inexact_d +2: + bne t0, zero, 1b +3: + li t1, DEXP_MAX + 1 # result is infinity + move t2, zero + move t3, zero + b inexact_d + +/* + * In this implementation, "tininess" is detected "after rounding" and + * "loss of accuracy" is detected as "an inexact result". + */ +underflow_d: + and v0, a1, FPC_ENABLE_UNDERFLOW + beq v0, zero, 1f +/* + * Underflow is enabled so compute the result and trap. + */ + addu t1, t1, 1536 # bias exponent + and t2, t2, ~DIMPL_ONE # clear implied one bit + jal set_fd_d # save result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + b fpe_trap +/* + * Underflow is not enabled so compute the result, + * signal inexact result (if it is) and trap (if enabled). + */ +1: + move t1, t5 # get unrounded exponent + move t2, t6 # get unrounded fraction (MS) + move t3, t7 # get unrounded fraction (LS) + li t9, DEXP_MIN # compute shift amount + subu t9, t9, t1 # shift t2,t8 right by t9 + blt t9, DFRAC_BITS+2, 3f # shift all the bits out? + move t1, zero # result is inexact zero + move t2, zero + move t3, zero + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW +/* + * Now round the zero result. + * Only need to worry about rounding to +- infinity when the sign matches. + */ + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, inexact_nobias_d # round to nearest + beq v0, FPC_ROUND_RZ, inexact_nobias_d # round to zero + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, inexact_nobias_d # if sign is positive, truncate + b 2f +1: + bne t0, zero, inexact_nobias_d # if sign is negative, truncate +2: + addu t3, t3, 1 # add rounding bit + b inexact_nobias_d +3: + li v1, 32 + blt t9, v1, 1f # shift by < 32? + subu t9, t9, v1 # shift right by >= 32 + subu v1, v1, t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t2, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t3, t2, t9 + move t2, zero + b 2f +1: + subu v1, v1, t9 # shift right by t9 + sltu v0, zero, t8 # be sure to save any one bits + sll t8, t3, v1 # save bits shifted out + or t8, t8, v0 # include sticky bits + srl t3, t3, t9 + sll v0, t2, v1 # save bits shifted out + or t3, t3, v0 + srl t2, t2, t9 +/* + * Now round the denormalized result. + */ +2: + and v0, a1, FPC_ROUNDING_BITS # get rounding mode + beq v0, FPC_ROUND_RN, 3f # round to nearest + beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) + beq v0, FPC_ROUND_RP, 1f # round to +infinity + beq t0, zero, 5f # if sign is positive, truncate + b 2f +1: + bne t0, zero, 5f # if sign is negative, truncate +2: + beq t8, zero, 5f # if exact, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 5f # if no carry, continue + addu t2, t2, 1 # add carry + b 5f +3: + li v0, GUARDBIT # load guard bit for rounding + addu v0, v0, t8 # add remainder + sltu v1, v0, t8 # compute carry out + beq v1, zero, 4f # if no carry, continue + addu t3, t3, 1 # add rounding bit + bne t3, zero, 4f # if no carry, continue + addu t2, t2, 1 # add carry +4: + bne v0, zero, 5f # if rounded remainder is zero + and t3, t3, ~1 # clear LSB (round to nearest) +5: + move t1, zero # denorm or zero exponent + jal set_fd_d # save result + beq t8, zero, done # check for exact result + or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW + or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT + and v0, a1, FPC_ENABLE_INEXACT + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is a quiet NAN. + */ +invalid_s: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + move t0, zero # result is a quiet NAN + li t1, SEXP_INF + li t2, SQUIET_NAN + jal set_fd_s # save result (in t0,t1,t2) + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is a quiet NAN. + */ +invalid_d: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + move t0, zero # result is a quiet NAN + li t1, DEXP_INF + li t2, DQUIET_NAN0 + li t3, DQUIET_NAN1 + jal set_fd_d # save result (in t0,t1,t2,t3) + b done + +/* + * Signal an invalid operation if the trap is enabled; otherwise, + * the result is INT_MAX or INT_MIN. + */ +invalid_w: # trap invalid operation + or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID + and v0, a1, FPC_ENABLE_INVALID + bne v0, zero, fpe_trap + ctc1 a1, FPC_CSR # save exceptions + bne t0, zero, 1f + li t2, INT_MAX # result is INT_MAX + b result_fs_w +1: + li t2, INT_MIN # result is INT_MIN + b result_fs_w + +/* + * Trap if the hardware should have handled this case. + */ +fpe_trap: + move a2, a1 # code = FP CSR + ctc1 a1, FPC_CSR # save exceptions + break 0 + +/* + * Send an illegal instruction signal to the current process. + */ +ill: + ctc1 a1, FPC_CSR # save exceptions + move a2, a0 # code = FP instruction + break 0 + +result_ft_s: + move t0, t4 # result is FT + move t1, t5 + move t2, t6 +result_fs_s: # result is FS + jal set_fd_s # save result (in t0,t1,t2) + b done + +result_fs_w: + jal set_fd_word # save result (in t2) + b done + +result_ft_d: + move t0, t4 # result is FT + move t1, t5 + move t2, t6 + move t3, t7 +result_fs_d: # result is FS + jal set_fd_d # save result (in t0,t1,t2,t3) + +done: + lw ra, STAND_RA_OFFSET(sp) + addu sp, sp, STAND_FRAME_SIZE + j ra +END(CPU_EmulateFP) + +/*---------------------------------------------------------------------------- + * get_fs_int -- + * + * Read (integer) the FS register (bits 15-11). + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the sign + * t2 contains the fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_fs_int) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_int_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_int_tbl: + .word get_fs_int_f0 + .word get_fs_int_f2 + .word get_fs_int_f4 + .word get_fs_int_f6 + .word get_fs_int_f8 + .word get_fs_int_f10 + .word get_fs_int_f12 + .word get_fs_int_f14 + .word get_fs_int_f16 + .word get_fs_int_f18 + .word get_fs_int_f20 + .word get_fs_int_f22 + .word get_fs_int_f24 + .word get_fs_int_f26 + .word get_fs_int_f28 + .word get_fs_int_f30 + .text + +get_fs_int_f0: + mfc1 t2, $f0 + b get_fs_int_done +get_fs_int_f2: + mfc1 t2, $f2 + b get_fs_int_done +get_fs_int_f4: + mfc1 t2, $f4 + b get_fs_int_done +get_fs_int_f6: + mfc1 t2, $f6 + b get_fs_int_done +get_fs_int_f8: + mfc1 t2, $f8 + b get_fs_int_done +get_fs_int_f10: + mfc1 t2, $f10 + b get_fs_int_done +get_fs_int_f12: + mfc1 t2, $f12 + b get_fs_int_done +get_fs_int_f14: + mfc1 t2, $f14 + b get_fs_int_done +get_fs_int_f16: + mfc1 t2, $f16 + b get_fs_int_done +get_fs_int_f18: + mfc1 t2, $f18 + b get_fs_int_done +get_fs_int_f20: + mfc1 t2, $f20 + b get_fs_int_done +get_fs_int_f22: + mfc1 t2, $f22 + b get_fs_int_done +get_fs_int_f24: + mfc1 t2, $f24 + b get_fs_int_done +get_fs_int_f26: + mfc1 t2, $f26 + b get_fs_int_done +get_fs_int_f28: + mfc1 t2, $f28 + b get_fs_int_done +get_fs_int_f30: + mfc1 t2, $f30 +get_fs_int_done: + srl t0, t2, 31 # init the sign bit + bge t2, zero, 1f + negu t2 +1: + j ra +END(get_fs_int) + +/*---------------------------------------------------------------------------- + * get_ft_fs_s -- + * + * Read (single precision) the FT register (bits 20-16) and + * the FS register (bits 15-11) and break up into fields. + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the FS sign + * t1 contains the FS (biased) exponent + * t2 contains the FS fraction + * t4 contains the FT sign + * t5 contains the FT (biased) exponent + * t6 contains the FT fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_ft_fs_s) + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, get_ft_s_tbl(a3) # switch on register number + j a3 + + .rdata +get_ft_s_tbl: + .word get_ft_s_f0 + .word get_ft_s_f2 + .word get_ft_s_f4 + .word get_ft_s_f6 + .word get_ft_s_f8 + .word get_ft_s_f10 + .word get_ft_s_f12 + .word get_ft_s_f14 + .word get_ft_s_f16 + .word get_ft_s_f18 + .word get_ft_s_f20 + .word get_ft_s_f22 + .word get_ft_s_f24 + .word get_ft_s_f26 + .word get_ft_s_f28 + .word get_ft_s_f30 + .text + +get_ft_s_f0: + mfc1 t4, $f0 + b get_ft_s_done +get_ft_s_f2: + mfc1 t4, $f2 + b get_ft_s_done +get_ft_s_f4: + mfc1 t4, $f4 + b get_ft_s_done +get_ft_s_f6: + mfc1 t4, $f6 + b get_ft_s_done +get_ft_s_f8: + mfc1 t4, $f8 + b get_ft_s_done +get_ft_s_f10: + mfc1 t4, $f10 + b get_ft_s_done +get_ft_s_f12: + mfc1 t4, $f12 + b get_ft_s_done +get_ft_s_f14: + mfc1 t4, $f14 + b get_ft_s_done +get_ft_s_f16: + mfc1 t4, $f16 + b get_ft_s_done +get_ft_s_f18: + mfc1 t4, $f18 + b get_ft_s_done +get_ft_s_f20: + mfc1 t4, $f20 + b get_ft_s_done +get_ft_s_f22: + mfc1 t4, $f22 + b get_ft_s_done +get_ft_s_f24: + mfc1 t4, $f24 + b get_ft_s_done +get_ft_s_f26: + mfc1 t4, $f26 + b get_ft_s_done +get_ft_s_f28: + mfc1 t4, $f28 + b get_ft_s_done +get_ft_s_f30: + mfc1 t4, $f30 +get_ft_s_done: + srl t5, t4, 23 # get exponent + and t5, t5, 0xFF + and t6, t4, 0x7FFFFF # get fraction + srl t4, t4, 31 # get sign + bne t5, SEXP_INF, 1f # is it a signaling NAN? + and v0, t6, SSIGNAL_NAN + bne v0, zero, invalid_s +1: + /* fall through to get FS */ + +/*---------------------------------------------------------------------------- + * get_fs_s -- + * + * Read (single precision) the FS register (bits 15-11) and + * break up into fields. + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * + *---------------------------------------------------------------------------- + */ +ALEAF(get_fs_s) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_s_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_s_tbl: + .word get_fs_s_f0 + .word get_fs_s_f2 + .word get_fs_s_f4 + .word get_fs_s_f6 + .word get_fs_s_f8 + .word get_fs_s_f10 + .word get_fs_s_f12 + .word get_fs_s_f14 + .word get_fs_s_f16 + .word get_fs_s_f18 + .word get_fs_s_f20 + .word get_fs_s_f22 + .word get_fs_s_f24 + .word get_fs_s_f26 + .word get_fs_s_f28 + .word get_fs_s_f30 + .text + +get_fs_s_f0: + mfc1 t0, $f0 + b get_fs_s_done +get_fs_s_f2: + mfc1 t0, $f2 + b get_fs_s_done +get_fs_s_f4: + mfc1 t0, $f4 + b get_fs_s_done +get_fs_s_f6: + mfc1 t0, $f6 + b get_fs_s_done +get_fs_s_f8: + mfc1 t0, $f8 + b get_fs_s_done +get_fs_s_f10: + mfc1 t0, $f10 + b get_fs_s_done +get_fs_s_f12: + mfc1 t0, $f12 + b get_fs_s_done +get_fs_s_f14: + mfc1 t0, $f14 + b get_fs_s_done +get_fs_s_f16: + mfc1 t0, $f16 + b get_fs_s_done +get_fs_s_f18: + mfc1 t0, $f18 + b get_fs_s_done +get_fs_s_f20: + mfc1 t0, $f20 + b get_fs_s_done +get_fs_s_f22: + mfc1 t0, $f22 + b get_fs_s_done +get_fs_s_f24: + mfc1 t0, $f24 + b get_fs_s_done +get_fs_s_f26: + mfc1 t0, $f26 + b get_fs_s_done +get_fs_s_f28: + mfc1 t0, $f28 + b get_fs_s_done +get_fs_s_f30: + mfc1 t0, $f30 +get_fs_s_done: + srl t1, t0, 23 # get exponent + and t1, t1, 0xFF + and t2, t0, 0x7FFFFF # get fraction + srl t0, t0, 31 # get sign + bne t1, SEXP_INF, 1f # is it a signaling NAN? + and v0, t2, SSIGNAL_NAN + bne v0, zero, invalid_s +1: + j ra +END(get_ft_fs_s) + +/*---------------------------------------------------------------------------- + * get_ft_fs_d -- + * + * Read (double precision) the FT register (bits 20-16) and + * the FS register (bits 15-11) and break up into fields. + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the FS sign + * t1 contains the FS (biased) exponent + * t2 contains the FS fraction + * t3 contains the FS remaining fraction + * t4 contains the FT sign + * t5 contains the FT (biased) exponent + * t6 contains the FT fraction + * t7 contains the FT remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_ft_fs_d) + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, get_ft_d_tbl(a3) # switch on register number + j a3 + + .rdata +get_ft_d_tbl: + .word get_ft_d_f0 + .word get_ft_d_f2 + .word get_ft_d_f4 + .word get_ft_d_f6 + .word get_ft_d_f8 + .word get_ft_d_f10 + .word get_ft_d_f12 + .word get_ft_d_f14 + .word get_ft_d_f16 + .word get_ft_d_f18 + .word get_ft_d_f20 + .word get_ft_d_f22 + .word get_ft_d_f24 + .word get_ft_d_f26 + .word get_ft_d_f28 + .word get_ft_d_f30 + .text + +get_ft_d_f0: + mfc1 t7, $f0 + mfc1 t4, $f1 + b get_ft_d_done +get_ft_d_f2: + mfc1 t7, $f2 + mfc1 t4, $f3 + b get_ft_d_done +get_ft_d_f4: + mfc1 t7, $f4 + mfc1 t4, $f5 + b get_ft_d_done +get_ft_d_f6: + mfc1 t7, $f6 + mfc1 t4, $f7 + b get_ft_d_done +get_ft_d_f8: + mfc1 t7, $f8 + mfc1 t4, $f9 + b get_ft_d_done +get_ft_d_f10: + mfc1 t7, $f10 + mfc1 t4, $f11 + b get_ft_d_done +get_ft_d_f12: + mfc1 t7, $f12 + mfc1 t4, $f13 + b get_ft_d_done +get_ft_d_f14: + mfc1 t7, $f14 + mfc1 t4, $f15 + b get_ft_d_done +get_ft_d_f16: + mfc1 t7, $f16 + mfc1 t4, $f17 + b get_ft_d_done +get_ft_d_f18: + mfc1 t7, $f18 + mfc1 t4, $f19 + b get_ft_d_done +get_ft_d_f20: + mfc1 t7, $f20 + mfc1 t4, $f21 + b get_ft_d_done +get_ft_d_f22: + mfc1 t7, $f22 + mfc1 t4, $f23 + b get_ft_d_done +get_ft_d_f24: + mfc1 t7, $f24 + mfc1 t4, $f25 + b get_ft_d_done +get_ft_d_f26: + mfc1 t7, $f26 + mfc1 t4, $f27 + b get_ft_d_done +get_ft_d_f28: + mfc1 t7, $f28 + mfc1 t4, $f29 + b get_ft_d_done +get_ft_d_f30: + mfc1 t7, $f30 + mfc1 t4, $f31 +get_ft_d_done: + srl t5, t4, 20 # get exponent + and t5, t5, 0x7FF + and t6, t4, 0xFFFFF # get fraction + srl t4, t4, 31 # get sign + bne t5, DEXP_INF, 1f # is it a signaling NAN? + and v0, t6, DSIGNAL_NAN + bne v0, zero, invalid_d +1: + /* fall through to get FS */ + +/*---------------------------------------------------------------------------- + * get_fs_d -- + * + * Read (double precision) the FS register (bits 15-11) and + * break up into fields. + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +ALEAF(get_fs_d) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, get_fs_d_tbl(a3) # switch on register number + j a3 + + .rdata +get_fs_d_tbl: + .word get_fs_d_f0 + .word get_fs_d_f2 + .word get_fs_d_f4 + .word get_fs_d_f6 + .word get_fs_d_f8 + .word get_fs_d_f10 + .word get_fs_d_f12 + .word get_fs_d_f14 + .word get_fs_d_f16 + .word get_fs_d_f18 + .word get_fs_d_f20 + .word get_fs_d_f22 + .word get_fs_d_f24 + .word get_fs_d_f26 + .word get_fs_d_f28 + .word get_fs_d_f30 + .text + +get_fs_d_f0: + mfc1 t3, $f0 + mfc1 t0, $f1 + b get_fs_d_done +get_fs_d_f2: + mfc1 t3, $f2 + mfc1 t0, $f3 + b get_fs_d_done +get_fs_d_f4: + mfc1 t3, $f4 + mfc1 t0, $f5 + b get_fs_d_done +get_fs_d_f6: + mfc1 t3, $f6 + mfc1 t0, $f7 + b get_fs_d_done +get_fs_d_f8: + mfc1 t3, $f8 + mfc1 t0, $f9 + b get_fs_d_done +get_fs_d_f10: + mfc1 t3, $f10 + mfc1 t0, $f11 + b get_fs_d_done +get_fs_d_f12: + mfc1 t3, $f12 + mfc1 t0, $f13 + b get_fs_d_done +get_fs_d_f14: + mfc1 t3, $f14 + mfc1 t0, $f15 + b get_fs_d_done +get_fs_d_f16: + mfc1 t3, $f16 + mfc1 t0, $f17 + b get_fs_d_done +get_fs_d_f18: + mfc1 t3, $f18 + mfc1 t0, $f19 + b get_fs_d_done +get_fs_d_f20: + mfc1 t3, $f20 + mfc1 t0, $f21 + b get_fs_d_done +get_fs_d_f22: + mfc1 t3, $f22 + mfc1 t0, $f23 + b get_fs_d_done +get_fs_d_f24: + mfc1 t3, $f24 + mfc1 t0, $f25 + b get_fs_d_done +get_fs_d_f26: + mfc1 t3, $f26 + mfc1 t0, $f27 + b get_fs_d_done +get_fs_d_f28: + mfc1 t3, $f28 + mfc1 t0, $f29 + b get_fs_d_done +get_fs_d_f30: + mfc1 t3, $f30 + mfc1 t0, $f31 +get_fs_d_done: + srl t1, t0, 20 # get exponent + and t1, t1, 0x7FF + and t2, t0, 0xFFFFF # get fraction + srl t0, t0, 31 # get sign + bne t1, DEXP_INF, 1f # is it a signaling NAN? + and v0, t2, DSIGNAL_NAN + bne v0, zero, invalid_d +1: + j ra +END(get_ft_fs_d) + +/*---------------------------------------------------------------------------- + * get_cmp_s -- + * + * Read (single precision) the FS register (bits 15-11) and + * the FT register (bits 20-16) and break up into fields. + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t4 contains the sign + * t5 contains the (biased) exponent + * t6 contains the fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_cmp_s) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, cmp_fs_s_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_fs_s_tbl: + .word cmp_fs_s_f0 + .word cmp_fs_s_f2 + .word cmp_fs_s_f4 + .word cmp_fs_s_f6 + .word cmp_fs_s_f8 + .word cmp_fs_s_f10 + .word cmp_fs_s_f12 + .word cmp_fs_s_f14 + .word cmp_fs_s_f16 + .word cmp_fs_s_f18 + .word cmp_fs_s_f20 + .word cmp_fs_s_f22 + .word cmp_fs_s_f24 + .word cmp_fs_s_f26 + .word cmp_fs_s_f28 + .word cmp_fs_s_f30 + .text + +cmp_fs_s_f0: + mfc1 t0, $f0 + b cmp_fs_s_done +cmp_fs_s_f2: + mfc1 t0, $f2 + b cmp_fs_s_done +cmp_fs_s_f4: + mfc1 t0, $f4 + b cmp_fs_s_done +cmp_fs_s_f6: + mfc1 t0, $f6 + b cmp_fs_s_done +cmp_fs_s_f8: + mfc1 t0, $f8 + b cmp_fs_s_done +cmp_fs_s_f10: + mfc1 t0, $f10 + b cmp_fs_s_done +cmp_fs_s_f12: + mfc1 t0, $f12 + b cmp_fs_s_done +cmp_fs_s_f14: + mfc1 t0, $f14 + b cmp_fs_s_done +cmp_fs_s_f16: + mfc1 t0, $f16 + b cmp_fs_s_done +cmp_fs_s_f18: + mfc1 t0, $f18 + b cmp_fs_s_done +cmp_fs_s_f20: + mfc1 t0, $f20 + b cmp_fs_s_done +cmp_fs_s_f22: + mfc1 t0, $f22 + b cmp_fs_s_done +cmp_fs_s_f24: + mfc1 t0, $f24 + b cmp_fs_s_done +cmp_fs_s_f26: + mfc1 t0, $f26 + b cmp_fs_s_done +cmp_fs_s_f28: + mfc1 t0, $f28 + b cmp_fs_s_done +cmp_fs_s_f30: + mfc1 t0, $f30 +cmp_fs_s_done: + srl t1, t0, 23 # get exponent + and t1, t1, 0xFF + and t2, t0, 0x7FFFFF # get fraction + srl t0, t0, 31 # get sign + + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, cmp_ft_s_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_ft_s_tbl: + .word cmp_ft_s_f0 + .word cmp_ft_s_f2 + .word cmp_ft_s_f4 + .word cmp_ft_s_f6 + .word cmp_ft_s_f8 + .word cmp_ft_s_f10 + .word cmp_ft_s_f12 + .word cmp_ft_s_f14 + .word cmp_ft_s_f16 + .word cmp_ft_s_f18 + .word cmp_ft_s_f20 + .word cmp_ft_s_f22 + .word cmp_ft_s_f24 + .word cmp_ft_s_f26 + .word cmp_ft_s_f28 + .word cmp_ft_s_f30 + .text + +cmp_ft_s_f0: + mfc1 t4, $f0 + b cmp_ft_s_done +cmp_ft_s_f2: + mfc1 t4, $f2 + b cmp_ft_s_done +cmp_ft_s_f4: + mfc1 t4, $f4 + b cmp_ft_s_done +cmp_ft_s_f6: + mfc1 t4, $f6 + b cmp_ft_s_done +cmp_ft_s_f8: + mfc1 t4, $f8 + b cmp_ft_s_done +cmp_ft_s_f10: + mfc1 t4, $f10 + b cmp_ft_s_done +cmp_ft_s_f12: + mfc1 t4, $f12 + b cmp_ft_s_done +cmp_ft_s_f14: + mfc1 t4, $f14 + b cmp_ft_s_done +cmp_ft_s_f16: + mfc1 t4, $f16 + b cmp_ft_s_done +cmp_ft_s_f18: + mfc1 t4, $f18 + b cmp_ft_s_done +cmp_ft_s_f20: + mfc1 t4, $f20 + b cmp_ft_s_done +cmp_ft_s_f22: + mfc1 t4, $f22 + b cmp_ft_s_done +cmp_ft_s_f24: + mfc1 t4, $f24 + b cmp_ft_s_done +cmp_ft_s_f26: + mfc1 t4, $f26 + b cmp_ft_s_done +cmp_ft_s_f28: + mfc1 t4, $f28 + b cmp_ft_s_done +cmp_ft_s_f30: + mfc1 t4, $f30 +cmp_ft_s_done: + srl t5, t4, 23 # get exponent + and t5, t5, 0xFF + and t6, t4, 0x7FFFFF # get fraction + srl t4, t4, 31 # get sign + j ra +END(get_cmp_s) + +/*---------------------------------------------------------------------------- + * get_cmp_d -- + * + * Read (double precision) the FS register (bits 15-11) and + * the FT register (bits 20-16) and break up into fields. + * This is an internal routine used by CPU_EmulateFP only. + * + * Results: + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * t4 contains the sign + * t5 contains the (biased) exponent + * t6 contains the fraction + * t7 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(get_cmp_d) + srl a3, a0, 12 - 2 # get FS field (even regs only) + and a3, a3, 0xF << 2 # mask FS field + lw a3, cmp_fs_d_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_fs_d_tbl: + .word cmp_fs_d_f0 + .word cmp_fs_d_f2 + .word cmp_fs_d_f4 + .word cmp_fs_d_f6 + .word cmp_fs_d_f8 + .word cmp_fs_d_f10 + .word cmp_fs_d_f12 + .word cmp_fs_d_f14 + .word cmp_fs_d_f16 + .word cmp_fs_d_f18 + .word cmp_fs_d_f20 + .word cmp_fs_d_f22 + .word cmp_fs_d_f24 + .word cmp_fs_d_f26 + .word cmp_fs_d_f28 + .word cmp_fs_d_f30 + .text + +cmp_fs_d_f0: + mfc1 t3, $f0 + mfc1 t0, $f1 + b cmp_fs_d_done +cmp_fs_d_f2: + mfc1 t3, $f2 + mfc1 t0, $f3 + b cmp_fs_d_done +cmp_fs_d_f4: + mfc1 t3, $f4 + mfc1 t0, $f5 + b cmp_fs_d_done +cmp_fs_d_f6: + mfc1 t3, $f6 + mfc1 t0, $f7 + b cmp_fs_d_done +cmp_fs_d_f8: + mfc1 t3, $f8 + mfc1 t0, $f9 + b cmp_fs_d_done +cmp_fs_d_f10: + mfc1 t3, $f10 + mfc1 t0, $f11 + b cmp_fs_d_done +cmp_fs_d_f12: + mfc1 t3, $f12 + mfc1 t0, $f13 + b cmp_fs_d_done +cmp_fs_d_f14: + mfc1 t3, $f14 + mfc1 t0, $f15 + b cmp_fs_d_done +cmp_fs_d_f16: + mfc1 t3, $f16 + mfc1 t0, $f17 + b cmp_fs_d_done +cmp_fs_d_f18: + mfc1 t3, $f18 + mfc1 t0, $f19 + b cmp_fs_d_done +cmp_fs_d_f20: + mfc1 t3, $f20 + mfc1 t0, $f21 + b cmp_fs_d_done +cmp_fs_d_f22: + mfc1 t3, $f22 + mfc1 t0, $f23 + b cmp_fs_d_done +cmp_fs_d_f24: + mfc1 t3, $f24 + mfc1 t0, $f25 + b cmp_fs_d_done +cmp_fs_d_f26: + mfc1 t3, $f26 + mfc1 t0, $f27 + b cmp_fs_d_done +cmp_fs_d_f28: + mfc1 t3, $f28 + mfc1 t0, $f29 + b cmp_fs_d_done +cmp_fs_d_f30: + mfc1 t3, $f30 + mfc1 t0, $f31 +cmp_fs_d_done: + srl t1, t0, 20 # get exponent + and t1, t1, 0x7FF + and t2, t0, 0xFFFFF # get fraction + srl t0, t0, 31 # get sign + + srl a3, a0, 17 - 2 # get FT field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, cmp_ft_d_tbl(a3) # switch on register number + j a3 + + .rdata +cmp_ft_d_tbl: + .word cmp_ft_d_f0 + .word cmp_ft_d_f2 + .word cmp_ft_d_f4 + .word cmp_ft_d_f6 + .word cmp_ft_d_f8 + .word cmp_ft_d_f10 + .word cmp_ft_d_f12 + .word cmp_ft_d_f14 + .word cmp_ft_d_f16 + .word cmp_ft_d_f18 + .word cmp_ft_d_f20 + .word cmp_ft_d_f22 + .word cmp_ft_d_f24 + .word cmp_ft_d_f26 + .word cmp_ft_d_f28 + .word cmp_ft_d_f30 + .text + +cmp_ft_d_f0: + mfc1 t7, $f0 + mfc1 t4, $f1 + b cmp_ft_d_done +cmp_ft_d_f2: + mfc1 t7, $f2 + mfc1 t4, $f3 + b cmp_ft_d_done +cmp_ft_d_f4: + mfc1 t7, $f4 + mfc1 t4, $f5 + b cmp_ft_d_done +cmp_ft_d_f6: + mfc1 t7, $f6 + mfc1 t4, $f7 + b cmp_ft_d_done +cmp_ft_d_f8: + mfc1 t7, $f8 + mfc1 t4, $f9 + b cmp_ft_d_done +cmp_ft_d_f10: + mfc1 t7, $f10 + mfc1 t4, $f11 + b cmp_ft_d_done +cmp_ft_d_f12: + mfc1 t7, $f12 + mfc1 t4, $f13 + b cmp_ft_d_done +cmp_ft_d_f14: + mfc1 t7, $f14 + mfc1 t4, $f15 + b cmp_ft_d_done +cmp_ft_d_f16: + mfc1 t7, $f16 + mfc1 t4, $f17 + b cmp_ft_d_done +cmp_ft_d_f18: + mfc1 t7, $f18 + mfc1 t4, $f19 + b cmp_ft_d_done +cmp_ft_d_f20: + mfc1 t7, $f20 + mfc1 t4, $f21 + b cmp_ft_d_done +cmp_ft_d_f22: + mfc1 t7, $f22 + mfc1 t4, $f23 + b cmp_ft_d_done +cmp_ft_d_f24: + mfc1 t7, $f24 + mfc1 t4, $f25 + b cmp_ft_d_done +cmp_ft_d_f26: + mfc1 t7, $f26 + mfc1 t4, $f27 + b cmp_ft_d_done +cmp_ft_d_f28: + mfc1 t7, $f28 + mfc1 t4, $f29 + b cmp_ft_d_done +cmp_ft_d_f30: + mfc1 t7, $f30 + mfc1 t4, $f31 +cmp_ft_d_done: + srl t5, t4, 20 # get exponent + and t5, t5, 0x7FF + and t6, t4, 0xFFFFF # get fraction + srl t4, t4, 31 # get sign + j ra +END(get_cmp_d) + +/*---------------------------------------------------------------------------- + * set_fd_s -- + * + * Write (single precision) the FD register (bits 10-6). + * This is an internal routine used by CPU_EmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * + * set_fd_word -- + * + * Write (integer) the FD register (bits 10-6). + * This is an internal routine used by CPU_EmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t2 contains the integer + * + *---------------------------------------------------------------------------- + */ +LEAF(set_fd_s) + sll t0, t0, 31 # position sign + sll t1, t1, 23 # position exponent + or t2, t2, t0 + or t2, t2, t1 +ALEAF(set_fd_word) + srl a3, a0, 7 - 2 # get FD field (even regs only) + and a3, a3, 0xF << 2 # mask FT field + lw a3, set_fd_s_tbl(a3) # switch on register number + j a3 + + .rdata +set_fd_s_tbl: + .word set_fd_s_f0 + .word set_fd_s_f2 + .word set_fd_s_f4 + .word set_fd_s_f6 + .word set_fd_s_f8 + .word set_fd_s_f10 + .word set_fd_s_f12 + .word set_fd_s_f14 + .word set_fd_s_f16 + .word set_fd_s_f18 + .word set_fd_s_f20 + .word set_fd_s_f22 + .word set_fd_s_f24 + .word set_fd_s_f26 + .word set_fd_s_f28 + .word set_fd_s_f30 + .text + +set_fd_s_f0: + mtc1 t2, $f0 + j ra +set_fd_s_f2: + mtc1 t2, $f2 + j ra +set_fd_s_f4: + mtc1 t2, $f4 + j ra +set_fd_s_f6: + mtc1 t2, $f6 + j ra +set_fd_s_f8: + mtc1 t2, $f8 + j ra +set_fd_s_f10: + mtc1 t2, $f10 + j ra +set_fd_s_f12: + mtc1 t2, $f12 + j ra +set_fd_s_f14: + mtc1 t2, $f14 + j ra +set_fd_s_f16: + mtc1 t2, $f16 + j ra +set_fd_s_f18: + mtc1 t2, $f18 + j ra +set_fd_s_f20: + mtc1 t2, $f20 + j ra +set_fd_s_f22: + mtc1 t2, $f22 + j ra +set_fd_s_f24: + mtc1 t2, $f24 + j ra +set_fd_s_f26: + mtc1 t2, $f26 + j ra +set_fd_s_f28: + mtc1 t2, $f28 + j ra +set_fd_s_f30: + mtc1 t2, $f30 + j ra +END(set_fd_s) + +/*---------------------------------------------------------------------------- + * set_fd_d -- + * + * Write (double precision) the FT register (bits 10-6). + * This is an internal routine used by CPU_EmulateFP only. + * + * Arguments: + * a0 contains the FP instruction + * t0 contains the sign + * t1 contains the (biased) exponent + * t2 contains the fraction + * t3 contains the remaining fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(set_fd_d) + sll t0, t0, 31 # set sign + sll t1, t1, 20 # set exponent + or t0, t0, t1 + or t0, t0, t2 # set fraction + srl a3, a0, 7 - 2 # get FD field (even regs only) + and a3, a3, 0xF << 2 # mask FD field + lw a3, set_fd_d_tbl(a3) # switch on register number + j a3 + + .rdata +set_fd_d_tbl: + .word set_fd_d_f0 + .word set_fd_d_f2 + .word set_fd_d_f4 + .word set_fd_d_f6 + .word set_fd_d_f8 + .word set_fd_d_f10 + .word set_fd_d_f12 + .word set_fd_d_f14 + .word set_fd_d_f16 + .word set_fd_d_f18 + .word set_fd_d_f20 + .word set_fd_d_f22 + .word set_fd_d_f24 + .word set_fd_d_f26 + .word set_fd_d_f28 + .word set_fd_d_f30 + .text + +set_fd_d_f0: + mtc1 t3, $f0 + mtc1 t0, $f1 + j ra +set_fd_d_f2: + mtc1 t3, $f2 + mtc1 t0, $f3 + j ra +set_fd_d_f4: + mtc1 t3, $f4 + mtc1 t0, $f5 + j ra +set_fd_d_f6: + mtc1 t3, $f6 + mtc1 t0, $f7 + j ra +set_fd_d_f8: + mtc1 t3, $f8 + mtc1 t0, $f9 + j ra +set_fd_d_f10: + mtc1 t3, $f10 + mtc1 t0, $f11 + j ra +set_fd_d_f12: + mtc1 t3, $f12 + mtc1 t0, $f13 + j ra +set_fd_d_f14: + mtc1 t3, $f14 + mtc1 t0, $f15 + j ra +set_fd_d_f16: + mtc1 t3, $f16 + mtc1 t0, $f17 + j ra +set_fd_d_f18: + mtc1 t3, $f18 + mtc1 t0, $f19 + j ra +set_fd_d_f20: + mtc1 t3, $f20 + mtc1 t0, $f21 + j ra +set_fd_d_f22: + mtc1 t3, $f22 + mtc1 t0, $f23 + j ra +set_fd_d_f24: + mtc1 t3, $f24 + mtc1 t0, $f25 + j ra +set_fd_d_f26: + mtc1 t3, $f26 + mtc1 t0, $f27 + j ra +set_fd_d_f28: + mtc1 t3, $f28 + mtc1 t0, $f29 + j ra +set_fd_d_f30: + mtc1 t3, $f30 + mtc1 t0, $f31 + j ra +END(set_fd_d) + +/*---------------------------------------------------------------------------- + * renorm_fs_s -- + * + * Results: + * t1 unbiased exponent + * t2 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_fs_s) +/* + * Find out how many leading zero bits are in t2 and put in t9. + */ + move v0, t2 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros + li t1, SEXP_MIN + subu t1, t1, t9 # adjust exponent + sll t2, t2, t9 + j ra +END(renorm_fs_s) + +/*---------------------------------------------------------------------------- + * renorm_fs_d -- + * + * Results: + * t1 unbiased exponent + * t2,t3 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_fs_d) +/* + * Find out how many leading zero bits are in t2,t3 and put in t9. + */ + move v0, t2 + move t9, zero + bne t2, zero, 1f + move v0, t3 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t2,t3 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros + li t1, DEXP_MIN + subu t1, t1, t9 # adjust exponent + li v0, 32 + blt t9, v0, 1f + subu t9, t9, v0 # shift fraction left >= 32 bits + sll t2, t3, t9 + move t3, zero + j ra +1: + subu v0, v0, t9 # shift fraction left < 32 bits + sll t2, t2, t9 + srl v1, t3, v0 + or t2, t2, v1 + sll t3, t3, t9 + j ra +END(renorm_fs_d) + +/*---------------------------------------------------------------------------- + * renorm_ft_s -- + * + * Results: + * t5 unbiased exponent + * t6 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_ft_s) +/* + * Find out how many leading zero bits are in t6 and put in t9. + */ + move v0, t6 + move t9, zero + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t6 the correct number of bits. + */ +1: + subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros + li t5, SEXP_MIN + subu t5, t5, t9 # adjust exponent + sll t6, t6, t9 + j ra +END(renorm_ft_s) + +/*---------------------------------------------------------------------------- + * renorm_ft_d -- + * + * Results: + * t5 unbiased exponent + * t6,t7 normalized fraction + * + *---------------------------------------------------------------------------- + */ +LEAF(renorm_ft_d) +/* + * Find out how many leading zero bits are in t6,t7 and put in t9. + */ + move v0, t6 + move t9, zero + bne t6, zero, 1f + move v0, t7 + addu t9, 32 +1: + srl v1, v0, 16 + bne v1, zero, 1f + addu t9, 16 + sll v0, 16 +1: + srl v1, v0, 24 + bne v1, zero, 1f + addu t9, 8 + sll v0, 8 +1: + srl v1, v0, 28 + bne v1, zero, 1f + addu t9, 4 + sll v0, 4 +1: + srl v1, v0, 30 + bne v1, zero, 1f + addu t9, 2 + sll v0, 2 +1: + srl v1, v0, 31 + bne v1, zero, 1f + addu t9, 1 +/* + * Now shift t6,t7 the correct number of bits. + */ +1: + subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros + li t5, DEXP_MIN + subu t5, t5, t9 # adjust exponent + li v0, 32 + blt t9, v0, 1f + subu t9, t9, v0 # shift fraction left >= 32 bits + sll t6, t7, t9 + move t7, zero + j ra +1: + subu v0, v0, t9 # shift fraction left < 32 bits + sll t6, t6, t9 + srl v1, t7, v0 + or t6, t6, v1 + sll t7, t7, t9 + j ra +END(renorm_ft_d) diff --git a/sys/arch/wgrisc/wgrisc/genassym.c b/sys/arch/wgrisc/wgrisc/genassym.c new file mode 100644 index 00000000000..f8407c88d8b --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/genassym.c @@ -0,0 +1,74 @@ +/* $OpenBSD: genassym.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)genassym.c 8.2 (Berkeley) 9/23/93 + * $Id: genassym.c,v 1.1 1997/02/06 16:02:45 pefo Exp $ + */ + + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/map.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/user.h> + +#include <machine/reg.h> + +main() +{ + register struct proc *p = (struct proc *)0; + register struct user *up = (struct user *)0; + register struct vmmeter *vm = (struct vmmeter *)0; + register int size, s, n; + + printf("#define\tP_FORW %d\n", &p->p_forw); + printf("#define\tP_BACK %d\n", &p->p_back); + printf("#define\tP_PRIORITY %d\n", &p->p_priority); + printf("#define\tP_ADDR %d\n", &p->p_addr); + printf("#define\tP_UPTE %d\n", p->p_md.md_upte); + printf("#define\tU_PCB_REGS %d\n", up->u_pcb.pcb_regs); + printf("#define\tU_PCB_FPREGS %d\n", &up->u_pcb.pcb_regs[F0]); + printf("#define\tU_PCB_CONTEXT %d\n", &up->u_pcb.pcb_context); + printf("#define\tU_PCB_ONFAULT %d\n", &up->u_pcb.pcb_onfault); + printf("#define\tU_PCB_SEGTAB %d\n", &up->u_pcb.pcb_segtab); + printf("#define\tVM_MIN_ADDRESS 0x%x\n", VM_MIN_ADDRESS); + printf("#define\tVM_MIN_KERNEL_ADDRESS 0x%x\n", VM_MIN_KERNEL_ADDRESS); + printf("#define\tV_SWTCH %d\n", &vm->v_swtch); + printf("#define\tSIGILL %d\n", SIGILL); + printf("#define\tSIGFPE %d\n", SIGFPE); + exit(0); +} diff --git a/sys/arch/wgrisc/wgrisc/locore.S b/sys/arch/wgrisc/wgrisc/locore.S new file mode 100644 index 00000000000..c4e33c9ebea --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/locore.S @@ -0,0 +1,4485 @@ + +/* $OpenBSD: locore.S,v 1.1 1997/02/06 16:02:45 pefo Exp $ */ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Digital Equipment Corporation 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. + * + * Copyright (C) 1989 Digital Equipment Corporation. + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies. + * Digital Equipment Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, + * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, + * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) + * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, + * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) + * + * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 + * $Id: locore.S,v 1.1 1997/02/06 16:02:45 pefo Exp $ + */ + +/* + * Contains code that is the first executed at boot time plus + * assembly language support routines. + */ + +#include <sys/errno.h> +#include <sys/syscall.h> + +#include <machine/param.h> +#include <machine/psl.h> +#include <machine/asm.h> +#include <machine/cpu.h> +#include <machine/regnum.h> +#include <machine/pte.h> + +#include "assym.h" + + .set noreorder + +/* + * Amount to take off of the stack for the benefit of the debugger. + */ +#define START_FRAME ((4 * 4) + 4 + 4) + + .globl start +start: + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mtc0 zero, COP_0_CAUSE_REG # Clear soft interrupts + +#ifndef R4K + la v0, 1f # it appears that we have to + or v0, UNCACHED_MEMORY_ADDR # run uncached. + j v0 + nop +1: + mfc0 v0, COP_0_R3K_CONF # reconfigure FP interrupt. + li v1, 0xe3ffffff + and v0, v0, v1 + mtc0 v0, COP_0_R3K_CONF + nop; nop; nop; nop; nop; nop; nop; nop; nop; nop + la v0, 1f + j v0 + nop +1: +#endif + +/* + * Initialize stack and call machine startup. + */ + la sp, start - START_FRAME + la gp, _gp + sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger + jal mips_init # mips_init(argc, argv, envp) + sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger + + li t0, SR_COP_1_BIT # Disable interrupts and + mtc0 t0, COP_0_STATUS_REG # enable the fp coprocessor + li sp, KERNELSTACK - START_FRAME # switch to standard stack + mfc0 t0, COP_0_PRID # read processor ID register + nop + nop # wait for new status to + nop # to be effective + nop + cfc1 t1, FPC_ID # read FPU ID register + sw t0, cpu_id # save PRID register + sw t1, fpu_id # save FPU ID register + jal main # main(regs) + move a0, zero +/* + * proc[1] == /etc/init now running here. + * Restore user registers and return. + */ +#ifdef R4K /* ==================XXXXX============================== */ + .set noat + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtlo t0 + mthi t1 + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + li a0, R4K_PSL_USERSET + mtc0 a0, COP_0_STATUS_REG # switch to user mode (when eret...) + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + eret + .set at +#else + .set noat + li v0, R3K_PSL_USERSET + mtc0 v0, COP_0_STATUS_REG # switch to user mode + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtlo t0 + mthi t1 + lw k0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + j k0 + rfe + .set at +#endif /* ==================XXXXX============================== */ + +/* + * Primitives + */ + +/* + * This table is indexed by u.u_pcb.pcb_onfault in trap(). + * The reason for using this table rather than storing an address in + * u.u_pcb.pcb_onfault is simply to make the code faster. + */ + .globl onfault_table + .data + .align 3 +onfault_table: + .word 0 # invalid index number +#define BADERR 1 + .word baderr +#define COPYERR 2 + .word copyerr +#define FSWBERR 3 + .word fswberr +#define FSWINTRBERR 4 + .word fswintrberr +#ifdef DEBUG +#define MDBERR 5 + .word mdberr +#endif + .text + +/* + * See if access to addr with a len type instruction causes a machine check. + * len is length of access (1=byte, 2=short, 4=long) + * + * badaddr(addr, len) + * char *addr; + * int len; + */ +LEAF(badaddr) + li v0, BADERR + bne a1, 1, 2f + sw v0, UADDR+U_PCB_ONFAULT + b 5f + lbu v0, (a0) +2: + bne a1, 2, 4f + nop + b 5f + lhu v0, (a0) +4: + lw v0, (a0) +5: + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero # made it w/o errors +baderr: + j ra + li v0, 1 # trap sends us here +END(badaddr) + +/* + * This code is copied the user's stack for returning from signal handlers + * (see sendsig() and sigreturn()). We have to compute the address + * of the sigcontext struct for the sigreturn call. + */ + .globl sigcode +sigcode: + addu a0, sp, 16 # address of sigcontext + li v0, SYS_sigreturn # sigreturn(scp) + syscall + break 0 # just in case sigreturn fails + .globl esigcode +esigcode: + +/* + * Copy a null terminated string within the kernel address space. + * Maxlength may be null if count not wanted. + * copystr(fromaddr, toaddr, maxlength, &lencopied) + * caddr_t fromaddr; + * caddr_t toaddr; + * u_int maxlength; + * u_int *lencopied; + */ +LEAF(copystr) + move t2, a2 # Save the number of bytes +1: + lbu t0, 0(a0) + subu a2, a2, 1 + beq t0, zero, 2f + sb t0, 0(a1) + addu a0, a0, 1 + bne a2, zero, 1b + addu a1, a1, 1 +2: + beq a3, zero, 3f + subu a2, t2, a2 # compute length copied + sw a2, 0(a3) +3: + j ra + move v0, zero +END(copystr) + +/* + * fillw(pat, addr, count) + */ +LEAF(fillw) +1: + addiu a2, a2, -1 + sh a0, 0(a1) + bne a2,zero, 1b + addiu a1, a1, 2 + + jr ra + nop +END(fillw) + +/* + * Block I/O routines mainly used by I/O drivers. + * + * Args as: a0 = port + * a1 = memory address + * a2 = count + */ +LEAF(insb) + beq a2, zero, 2f + addu a2, a1 +1: + lbu v0, 0(a0) + addiu a1, 1 + bne a1, a2, 1b + sb v0, -1(a1) +2: + jr ra + nop +END(insb) + +LEAF(insw) + beq a2, zero, 2f + addu a2, a2 + addu a2, a1 +1: + lhu v0, 0(a0) + addiu a1, 2 + bne a1, a2, 1b + sh v0, -2(a1) +2: + jr ra + nop +END(insw) + +LEAF(insl) + beq a2, zero, 2f + sll a2, 2 + addu a2, a1 +1: + lw v0, 0(a0) + addiu a1, 4 + bne a1, a2, 1b + sw v0, -4(a1) +2: + jr ra + nop +END(insl) + +LEAF(outsb) + beq a2, zero, 2f + addu a2, a1 +1: + lbu v0, 0(a1) + addiu a1, 1 + bne a1, a2, 1b + sb v0, 0(a0) +2: + jr ra + nop +END(outsb) + +LEAF(outsw) + beq a2, zero, 2f + addu a2, a2 + li v0, 1 + and v0, a1 + bne v0, zero, 3f # arghh, unaligned. + addu a2, a1 +1: + lhu v0, 0(a1) + addiu a1, 2 + bne a1, a2, 1b + sh v0, 0(a0) +2: + jr ra + nop +3: + LWHI v0, 0(a1) + LWLO v0, 3(a1) + addiu a1, 2 + bne a1, a2, 3b + sh v0, 0(a0) + + jr ra + nop +END(outsw) + +LEAF(outsl) + beq a2, zero, 2f + sll a2, 2 + li v0, 3 + and v0, a1 + bne v0, zero, 3f # arghh, unaligned. + addu a2, a1 +1: + lw v0, 0(a1) + addiu a1, 4 + bne a1, a2, 1b + sw v0, 0(a0) +2: + jr ra + nop +3: + LWHI v0, 0(a1) + LWLO v0, 3(a1) + addiu a1, 4 + bne a1, a2, 3b + sw v0, 0(a0) + + jr ra + nop +END(outsl) + +/* + * Copy a null terminated string from the user address space into + * the kernel address space. + * + * copyinstr(fromaddr, toaddr, maxlength, &lencopied) + * caddr_t fromaddr; + * caddr_t toaddr; + * u_int maxlength; + * u_int *lencopied; + */ +NON_LEAF(copyinstr, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a0, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal copystr + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyinstr) + +/* + * Copy a null terminated string from the kernel address space into + * the user address space. + * + * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) + * caddr_t fromaddr; + * caddr_t toaddr; + * u_int maxlength; + * u_int *lencopied; + */ +NON_LEAF(copyoutstr, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a1, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal copystr + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyoutstr) + +/* + * Copy specified amount of data from user space into the kernel + * copyin(from, to, len) + * caddr_t *from; (user source address) + * caddr_t *to; (kernel destination address) + * unsigned len; + */ +NON_LEAF(copyin, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a0, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal bcopy + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyin) + +/* + * Copy specified amount of data from kernel to the user space + * copyout(from, to, len) + * caddr_t *from; (kernel source address) + * caddr_t *to; (user destination address) + * unsigned len; + */ +NON_LEAF(copyout, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + sw ra, STAND_RA_OFFSET(sp) + blt a1, zero, copyerr # make sure address is in user space + li v0, COPYERR + jal bcopy + sw v0, UADDR+U_PCB_ONFAULT + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + move v0, zero +END(copyout) + +LEAF(copyerr) + lw ra, STAND_RA_OFFSET(sp) + sw zero, UADDR+U_PCB_ONFAULT + addu sp, sp, STAND_FRAME_SIZE + j ra + li v0, EFAULT # return error +END(copyerr) + +/* + * Copy the kernel stack to the new process and save the current context so + * the new process will return nonzero when it is resumed by cpu_switch(). + * + * copykstack(up) + * struct user *up; + */ +LEAF(copykstack) + subu v0, sp, UADDR # compute offset into stack + addu v0, v0, a0 # v0 = new stack address + move v1, sp # v1 = old stack address + li t1, KERNELSTACK +1: + lw t0, 0(v1) # copy stack data + addu v1, v1, 4 + sw t0, 0(v0) + bne v1, t1, 1b + addu v0, v0, 4 + /* FALLTHROUGH */ +/* + * Save registers and state so we can do a longjmp later. + * Note: this only works if p != curproc since + * cpu_switch() will copy over pcb_context. + * + * savectx(up) + * struct user *up; + */ +ALEAF(savectx) + sw s0, U_PCB_CONTEXT+0(a0) + sw s1, U_PCB_CONTEXT+4(a0) + sw s2, U_PCB_CONTEXT+8(a0) + sw s3, U_PCB_CONTEXT+12(a0) + mfc0 v0, COP_0_STATUS_REG + sw s4, U_PCB_CONTEXT+16(a0) + sw s5, U_PCB_CONTEXT+20(a0) + sw s6, U_PCB_CONTEXT+24(a0) + sw s7, U_PCB_CONTEXT+28(a0) + sw sp, U_PCB_CONTEXT+32(a0) + sw s8, U_PCB_CONTEXT+36(a0) + sw ra, U_PCB_CONTEXT+40(a0) + sw v0, U_PCB_CONTEXT+44(a0) + j ra + move v0, zero +END(copykstack) + +/* + * The following primitives manipulate the run queues. _whichqs tells which + * of the 32 queues _qs have processes in them. Setrunqueue puts processes + * into queues, Remrq removes them from queues. The running process is on + * no queue, other processes are on a queue related to p->p_priority, divided + * by 4 actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ +/* + * setrunqueue(p) + * proc *p; + * + * Call should be made at splclock(), and p->p_stat should be SRUN. + */ +NON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + lw t0, P_BACK(a0) ## firewall: p->p_back must be 0 + sw ra, STAND_RA_OFFSET(sp) ## + beq t0, zero, 1f ## + lbu t0, P_PRIORITY(a0) # put on p->p_priority / 4 queue + PANIC("setrunqueue") ## +1: + li t1, 1 # compute corresponding bit + srl t0, t0, 2 # compute index into 'whichqs' + sll t1, t1, t0 + lw t2, whichqs # set corresponding bit + nop + or t2, t2, t1 + sw t2, whichqs + sll t0, t0, 3 # compute index into 'qs' + la t1, qs + addu t0, t0, t1 # t0 = qp = &qs[pri >> 2] + lw t1, P_BACK(t0) # t1 = qp->ph_rlink + sw t0, P_FORW(a0) # p->p_forw = qp + sw t1, P_BACK(a0) # p->p_back = qp->ph_rlink + sw a0, P_FORW(t1) # p->p_back->p_forw = p; + sw a0, P_BACK(t0) # qp->ph_rlink = p + j ra + addu sp, sp, STAND_FRAME_SIZE +END(setrunqueue) + +/* + * Remrq(p) + * + * Call should be made at splclock(). + */ +NON_LEAF(remrunqueue, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + lbu t0, P_PRIORITY(a0) # get from p->p_priority / 4 queue + li t1, 1 # compute corresponding bit + srl t0, t0, 2 # compute index into 'whichqs' + lw t2, whichqs # check corresponding bit + sll t1, t1, t0 + and v0, t2, t1 + sw ra, STAND_RA_OFFSET(sp) ## + bne v0, zero, 1f ## + lw v0, P_BACK(a0) # v0 = p->p_back + PANIC("remrq") ## it wasnt recorded to be on its q +1: + lw v1, P_FORW(a0) # v1 = p->p_forw + nop + sw v1, P_FORW(v0) # p->p_back->p_forw = p->p_forw; + sw v0, P_BACK(v1) # p->p_forw->p_back = p->r_rlink + sll t0, t0, 3 # compute index into 'qs' + la v0, qs + addu t0, t0, v0 # t0 = qp = &qs[pri >> 2] + lw v0, P_FORW(t0) # check if queue empty + nop + bne v0, t0, 2f # No. qp->ph_link != qp + nop + xor t2, t2, t1 # clear corresponding bit in 'whichqs' + sw t2, whichqs +2: + sw zero, P_BACK(a0) ## for firewall checking + j ra + addu sp, sp, STAND_FRAME_SIZE +END(remrunqueue) + +/* + * switch_exit() + * + * 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. + * All interrupts should be blocked at this point. + */ +LEAF(switch_exit) + la v1, nullproc # save state into garbage proc + lw t0, P_UPTE+0(v1) # t0 = first u. pte + lw t1, P_UPTE+4(v1) # t1 = 2nd u. pte + li v0, UADDR # v0 = first HI entry + mtc0 zero, COP_0_TLB_INDEX # set the index register +#ifdef R4K /* ==================XXXXX============================== */ + dmtc0 v0, COP_0_TLB_HI # init high entry + dmtc0 t0, COP_0_TLB_LO0 # init low entry0 + dmtc0 t1, COP_0_TLB_LO1 # init low entry1 + nop + tlbwi # Write the TLB entry. + nop + nop + sw zero, curproc +#else + mtc0 v0, COP_0_TLB_HI # init high entry + mtc0 t0, COP_0_TLB_LO0 # init low entry + li t0, 1 << R3K_TLB_INDEX_SHIFT + tlbwi # Write the TLB entry. + addu v0, v0, NBPG # 2nd HI entry + mtc0 t0, COP_0_TLB_INDEX # set the index register + mtc0 v0, COP_0_TLB_HI # init high entry + mtc0 t1, COP_0_TLB_LO0 # init low entry + sw zero, curproc + tlbwi # Write the TLB entry. +#endif /* ==================XXXXX============================== */ + b cpu_switch + li sp, KERNELSTACK - START_FRAME # switch to standard stack +END(switch_exit) + +/* + * When no processes are on the runq, cpu_switch branches to idle + * to wait for something to come ready. + * Note: this is really a part of cpu_switch() but defined here for kernel + * profiling. + */ +LEAF(idle) + li t0, (INT_MASK | SR_INT_ENAB) # XXX INT_MASK should be a var.. + mtc0 t0, COP_0_STATUS_REG # enable all interrupts + sw zero, curproc # set curproc NULL for stats +1: + lw t0, whichqs # look for non-empty queue + nop + beq t0, zero, 1b + nop + b sw1 + mtc0 zero, COP_0_STATUS_REG # Disable all interrupts +END(idle) + +/* + * cpu_switch() + * Find the highest priority process and resume it. + */ +NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) + sw sp, UADDR+U_PCB_CONTEXT+32 # save old sp + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + lw t2, cnt+V_SWTCH # for statistics + lw t1, whichqs # look for non-empty queue + sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()' + sw s1, UADDR+U_PCB_CONTEXT+4 + sw s2, UADDR+U_PCB_CONTEXT+8 + sw s3, UADDR+U_PCB_CONTEXT+12 + mfc0 t0, COP_0_STATUS_REG # t0 = saved status register + sw s4, UADDR+U_PCB_CONTEXT+16 + sw s5, UADDR+U_PCB_CONTEXT+20 + sw s6, UADDR+U_PCB_CONTEXT+24 + sw s7, UADDR+U_PCB_CONTEXT+28 + sw s8, UADDR+U_PCB_CONTEXT+36 + sw ra, UADDR+U_PCB_CONTEXT+40 # save return address + sw t0, UADDR+U_PCB_CONTEXT+44 # save status register + addu t2, t2, 1 + sw t2, cnt+V_SWTCH + beq t1, zero, idle # if none, idle + mtc0 zero, COP_0_STATUS_REG # Disable all interrupts +sw1: + nop # wait for intrs disabled + nop + nop + nop + lw t0, whichqs # look for non-empty queue + li t2, -1 # t2 = lowest bit set + beq t0, zero, idle # if none, idle + move t3, t0 # t3 = saved whichqs +1: + addu t2, t2, 1 + and t1, t0, 1 # bit set? + beq t1, zero, 1b + srl t0, t0, 1 # try next bit +/* + * Remove process from queue. + */ + sll t0, t2, 3 + la t1, qs + addu t0, t0, t1 # t0 = qp = &qs[highbit] + lw a0, P_FORW(t0) # a0 = p = highest pri process + nop + lw v0, P_FORW(a0) # v0 = p->p_forw + bne t0, a0, 2f # make sure something in queue + sw v0, P_FORW(t0) # qp->ph_link = p->p_forw; + PANIC("cpu_switch") # nothing in queue +2: + sw t0, P_BACK(v0) # p->p_forw->p_back = qp + bne v0, t0, 3f # queue still not empty + sw zero, P_BACK(a0) ## for firewall checking + li v1, 1 # compute bit in 'whichqs' + sll v1, v1, t2 + xor t3, t3, v1 # clear bit in 'whichqs' + sw t3, whichqs +3: +/* + * Switch to new context. + * NOTE: This is hard coded to UPAGES == 2. + * Also, there should be no TLB faults at this point. + */ + sw zero, want_resched + jal pmap_alloc_tlbpid # v0 = TLB PID + move s0, a0 # BDSLOT: save p + sw s0, curproc # set curproc + lw t0, P_UPTE+0(s0) # t0 = first u. pte + lw t1, P_UPTE+4(s0) # t1 = 2nd u. pte +#ifdef R4K /* ==================XXXXX============================== */ + or v0, v0, UADDR # v0 = first HI entry + mtc0 zero, COP_0_TLB_INDEX # set the index register + dmtc0 v0, COP_0_TLB_HI # init high entry + dmtc0 t0, COP_0_TLB_LO0 # init low entry0 + dmtc0 t1, COP_0_TLB_LO1 # init low entry1 + nop + tlbwi # Write the TLB entry. + nop # Delay for effect + nop # Delay for effect + nop + nop +#else + sll v0, v0, R3K_PID_SHIFT + or v0, v0, UADDR + mtc0 zero, COP_0_TLB_INDEX # set the index register + mtc0 v0, COP_0_TLB_HI # init high entry + mtc0 t0, COP_0_TLB_LO0 # init low entry + li t0, 1 << R3K_TLB_INDEX_SHIFT + tlbwi # Write the TLB entry. + addu v0, v0, NBPG # 2nd HI entry + mtc0 t0, COP_0_TLB_INDEX # set the index register + mtc0 v0, COP_0_TLB_HI # init high entry + mtc0 t1, COP_0_TLB_LO0 # init low entry + nop + tlbwi # Write the TLB entry. +#endif /* ==================XXXXX============================== */ + +/* + * Now running on new u struct. + * Restore registers and return. + */ + lw v0, UADDR+U_PCB_CONTEXT+44 # restore kernel context + lw ra, UADDR+U_PCB_CONTEXT+40 + lw s0, UADDR+U_PCB_CONTEXT+0 + lw s1, UADDR+U_PCB_CONTEXT+4 + lw s2, UADDR+U_PCB_CONTEXT+8 + lw s3, UADDR+U_PCB_CONTEXT+12 + lw s4, UADDR+U_PCB_CONTEXT+16 + lw s5, UADDR+U_PCB_CONTEXT+20 + lw s6, UADDR+U_PCB_CONTEXT+24 + lw s7, UADDR+U_PCB_CONTEXT+28 + lw sp, UADDR+U_PCB_CONTEXT+32 + lw s8, UADDR+U_PCB_CONTEXT+36 + mtc0 v0, COP_0_STATUS_REG + j ra + li v0, 1 # possible return to 'savectx()' +END(cpu_switch) + +/* + * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to + * user text space. + * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to + * user data space. + */ +LEAF(fuword) +ALEAF(fuiword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + lw v0, 0(a0) # fetch word + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fuword) + +LEAF(fusword) +ALEAF(fuisword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + lhu v0, 0(a0) # fetch short + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fusword) + +LEAF(fubyte) +ALEAF(fuibyte) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + lbu v0, 0(a0) # fetch byte + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fubyte) + +LEAF(suword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sw a1, 0(a0) # store word + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(suword) + +/* + * Have to flush instruction cache afterwards. + */ +LEAF(suiword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sw a1, 0(a0) # store word + sw zero, UADDR+U_PCB_ONFAULT +#ifdef R4K + b R4K_FlushICache # FlushICache sets v0 = 0. (Ugly) +#else + b R3K_FlushICache # FlushICache sets v0 = 0. (Ugly) +#endif + li a1, 4 # size of word +END(suiword) + +/* + * Will have to flush the instruction cache if byte merging is done in hardware. + */ +LEAF(susword) +ALEAF(suisword) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sh a1, 0(a0) # store short + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(susword) + +LEAF(subyte) +ALEAF(suibyte) + blt a0, zero, fswberr # make sure address is in user space + li v0, FSWBERR + sw v0, UADDR+U_PCB_ONFAULT + sb a1, 0(a0) # store byte + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(subyte) + +LEAF(fswberr) + j ra + li v0, -1 +END(fswberr) + +/* + * fuswintr and suswintr are just like fusword and susword except that if + * the page is not in memory or would cause a trap, then we return an error. + * The important thing is to prevent sleep() and switch(). + */ +LEAF(fuswintr) + blt a0, zero, fswintrberr # make sure address is in user space + li v0, FSWINTRBERR + sw v0, UADDR+U_PCB_ONFAULT + lhu v0, 0(a0) # fetch short + j ra + sw zero, UADDR+U_PCB_ONFAULT +END(fuswintr) + +LEAF(suswintr) + blt a0, zero, fswintrberr # make sure address is in user space + li v0, FSWINTRBERR + sw v0, UADDR+U_PCB_ONFAULT + sh a1, 0(a0) # store short + sw zero, UADDR+U_PCB_ONFAULT + j ra + move v0, zero +END(suswintr) + +LEAF(fswintrberr) + j ra + li v0, -1 +END(fswintrberr) + +/* + * Insert 'p' after 'q'. + * _insque(p, q) + * caddr_t p, q; + */ +LEAF(_insque) + lw v0, 0(a1) # v0 = q->next + sw a1, 4(a0) # p->prev = q + sw v0, 0(a0) # p->next = q->next + sw a0, 4(v0) # q->next->prev = p + j ra + sw a0, 0(a1) # q->next = p +END(_insque) + +/* + * Remove item 'p' from queue. + * _remque(p) + * caddr_t p; + */ +LEAF(_remque) + lw v0, 0(a0) # v0 = p->next + lw v1, 4(a0) # v1 = p->prev + nop + sw v0, 0(v1) # p->prev->next = p->next + j ra + sw v1, 4(v0) # p->next->prev = p->prev +END(_remque) + +/* + * This code is copied to the TLB exception vector address to + * handle TLB translation misses. + * NOTE: This code must be relocatable and max 32 instructions!!! + * Don't check for invalid pte's here. We load them as well and + * let the processor trap to load the correct value after service. + */ +#ifdef R4K /* ==================XXXXX============================== */ + .globl R4K_TLBMiss +R4K_TLBMiss: + .set noat + dmfc0 k0, COP_0_BAD_VADDR # get the virtual address + lw k1, UADDR+U_PCB_SEGTAB # get the current segment table + bltz k0, 1f # kernel address space -> + srl k0, k0, SEGSHIFT - 2 # compute segment table index + andi k0, k0, 0x7fc # PMAP_SEGTABSIZ-1 + addu k1, k1, k0 + dmfc0 k0, COP_0_BAD_VADDR # get the virtual address + lw k1, 0(k1) # get pointer to segment map + srl k0, k0, PGSHIFT - 2 # compute segment map index + andi k0, k0, ((NPTEPG/2) - 1) << 3 + beq k1, zero, 2f # invalid segment map + addu k1, k1, k0 # index into segment map + lw k0, 0(k1) # get page PTE + lw k1, 4(k1) + dsll k0, k0, 34 + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 + dsll k1, k1, 34 + dsrl k1, k1, 34 + dmtc0 k1, COP_0_TLB_LO1 + nop + tlbwr # update TLB + nop + nop + nop + nop + nop + eret +1: + j R4K_TLBMissException + nop +2: + j SlowFault + nop + + .globl R4K_TLBMissEnd +R4K_TLBMissEnd: + .set at + +/* + * This code is copied to the general exception vector address to + * handle all execptions except RESET and TLBMiss. + * NOTE: This code must be relocatable!!! + */ + .globl R4K_Exception +R4K_Exception: +/* + * Find out what mode we came from and jump to the proper handler. + */ + .set noat + mfc0 k0, COP_0_STATUS_REG # Get the status register + mfc0 k1, COP_0_CAUSE_REG # Get the cause register value. + and k0, k0, SR_KSU_USER # test for user mode + # sneaky but the bits are + # with us........ + sll k0, k0, 3 # shift user bit for cause index + and k1, k1, CR_EXC_CODE # Mask out the cause bits. + or k1, k1, k0 # change index to user table +1: + la k0, R4K_ExceptionTable # get base of the jump table + addu k0, k0, k1 # Get the address of the + # function entry. Note that + # the cause is already + # shifted left by 2 bits so + # we dont have to shift. + lw k0, 0(k0) # Get the function address + nop + j k0 # Jump to the function. + nop + .set at + .globl R4K_ExceptionEnd +R4K_ExceptionEnd: + +/* + * We couldn't find a TLB entry. + * Find out what mode we came from and call the appropriate handler. + */ +SlowFault: + .set noat + mfc0 k0, COP_0_STATUS_REG + nop + and k0, k0, SR_KSU_USER + bne k0, zero, R4K_UserGenException + nop + .set at +/* + * Fall though ... + */ + +/*---------------------------------------------------------------------------- + * + * R4K_KernGenException -- + * + * Handle an exception from kernel mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +/* + * The kernel exception stack contains 18 saved general registers, + * the status register and the multiply lo and high registers. + * In addition, we set this up for linkage conventions. + */ +#define KERN_REG_SIZE (18 * 4) +#define KERN_REG_OFFSET (STAND_FRAME_SIZE) +#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) +#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) +#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) +#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) + +NNON_LEAF(R4K_KernGenException, KERN_EXC_FRAME_SIZE, ra) + .set noat +#ifdef DEBUG + la k0, mdbpcb # save registers for mdb + sw s0, (S0 * 4)(k0) + sw s1, (S1 * 4)(k0) + sw s2, (S2 * 4)(k0) + sw s3, (S3 * 4)(k0) + sw s4, (S4 * 4)(k0) + sw s5, (S5 * 4)(k0) + sw s6, (S6 * 4)(k0) + sw s7, (S7 * 4)(k0) + sw s8, (S8 * 4)(k0) + sw gp, (GP * 4)(k0) + sw sp, (SP * 4)(k0) +#endif + subu sp, sp, KERN_EXC_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + * We don't need to save s0 - s8, sp and gp because + * the compiler does it for us. + */ + sw AT, KERN_REG_OFFSET + 0(sp) + sw v0, KERN_REG_OFFSET + 4(sp) + sw v1, KERN_REG_OFFSET + 8(sp) + sw a0, KERN_REG_OFFSET + 12(sp) + mflo v0 + mfhi v1 + sw a1, KERN_REG_OFFSET + 16(sp) + sw a2, KERN_REG_OFFSET + 20(sp) + sw a3, KERN_REG_OFFSET + 24(sp) + sw t0, KERN_REG_OFFSET + 28(sp) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, KERN_REG_OFFSET + 32(sp) + sw t2, KERN_REG_OFFSET + 36(sp) + sw t3, KERN_REG_OFFSET + 40(sp) + sw t4, KERN_REG_OFFSET + 44(sp) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, KERN_REG_OFFSET + 48(sp) + sw t6, KERN_REG_OFFSET + 52(sp) + sw t7, KERN_REG_OFFSET + 56(sp) + sw t8, KERN_REG_OFFSET + 60(sp) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr. + sw t9, KERN_REG_OFFSET + 64(sp) + sw ra, KERN_REG_OFFSET + 68(sp) + sw v0, KERN_MULT_LO_OFFSET(sp) + sw v1, KERN_MULT_HI_OFFSET(sp) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + sw a0, KERN_SR_OFFSET(sp) + + mtc0 zero,COP_0_STATUS_REG # Set kernel no error level +/* + * Call the exception handler. + */ + jal trap + sw a3, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the exception. + * v0 contains the return address. + */ + mtc0 zero,COP_0_STATUS_REG # Make shure int disabled + lw a0, KERN_SR_OFFSET(sp) + lw t0, KERN_MULT_LO_OFFSET(sp) + lw t1, KERN_MULT_HI_OFFSET(sp) + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + mtlo t0 + mthi t1 + dmtc0 v0, COP_0_EXC_PC # set return address + lw AT, KERN_REG_OFFSET + 0(sp) + lw v0, KERN_REG_OFFSET + 4(sp) + lw v1, KERN_REG_OFFSET + 8(sp) + lw a0, KERN_REG_OFFSET + 12(sp) + lw a1, KERN_REG_OFFSET + 16(sp) + lw a2, KERN_REG_OFFSET + 20(sp) + lw a3, KERN_REG_OFFSET + 24(sp) + lw t0, KERN_REG_OFFSET + 28(sp) + lw t1, KERN_REG_OFFSET + 32(sp) + lw t2, KERN_REG_OFFSET + 36(sp) + lw t3, KERN_REG_OFFSET + 40(sp) + lw t4, KERN_REG_OFFSET + 44(sp) + lw t5, KERN_REG_OFFSET + 48(sp) + lw t6, KERN_REG_OFFSET + 52(sp) + lw t7, KERN_REG_OFFSET + 56(sp) + lw t8, KERN_REG_OFFSET + 60(sp) + lw t9, KERN_REG_OFFSET + 64(sp) + lw ra, KERN_REG_OFFSET + 68(sp) + addu sp, sp, KERN_EXC_FRAME_SIZE + eret # exception. + .set at +END(R4K_KernGenException) + +/*---------------------------------------------------------------------------- + * + * R4K_UserGenException -- + * + * Handle an exception from user mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(R4K_UserGenException, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save all of the registers except for the kernel temporaries in u.u_pcb. + */ + sw AT, UADDR+U_PCB_REGS+(AST * 4) + sw v0, UADDR+U_PCB_REGS+(V0 * 4) + sw v1, UADDR+U_PCB_REGS+(V1 * 4) + sw a0, UADDR+U_PCB_REGS+(A0 * 4) + mflo v0 + sw a1, UADDR+U_PCB_REGS+(A1 * 4) + sw a2, UADDR+U_PCB_REGS+(A2 * 4) + sw a3, UADDR+U_PCB_REGS+(A3 * 4) + sw t0, UADDR+U_PCB_REGS+(T0 * 4) + mfhi v1 + sw t1, UADDR+U_PCB_REGS+(T1 * 4) + sw t2, UADDR+U_PCB_REGS+(T2 * 4) + sw t3, UADDR+U_PCB_REGS+(T3 * 4) + sw t4, UADDR+U_PCB_REGS+(T4 * 4) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t5, UADDR+U_PCB_REGS+(T5 * 4) + sw t6, UADDR+U_PCB_REGS+(T6 * 4) + sw t7, UADDR+U_PCB_REGS+(T7 * 4) + sw s0, UADDR+U_PCB_REGS+(S0 * 4) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw s1, UADDR+U_PCB_REGS+(S1 * 4) + sw s2, UADDR+U_PCB_REGS+(S2 * 4) + sw s3, UADDR+U_PCB_REGS+(S3 * 4) + sw s4, UADDR+U_PCB_REGS+(S4 * 4) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr + sw s5, UADDR+U_PCB_REGS+(S5 * 4) + sw s6, UADDR+U_PCB_REGS+(S6 * 4) + sw s7, UADDR+U_PCB_REGS+(S7 * 4) + sw t8, UADDR+U_PCB_REGS+(T8 * 4) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + sw t9, UADDR+U_PCB_REGS+(T9 * 4) + sw gp, UADDR+U_PCB_REGS+(GP * 4) + sw sp, UADDR+U_PCB_REGS+(SP * 4) + sw s8, UADDR+U_PCB_REGS+(S8 * 4) + li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP + sw ra, UADDR+U_PCB_REGS+(RA * 4) + sw v0, UADDR+U_PCB_REGS+(MULLO * 4) + sw v1, UADDR+U_PCB_REGS+(MULHI * 4) + sw a0, UADDR+U_PCB_REGS+(SR * 4) + la gp, _gp # switch to kernel GP + sw a3, UADDR+U_PCB_REGS+(PC * 4) + sw a3, STAND_RA_OFFSET(sp) # for debugging + .set at +# Turn off fpu and enter kernel mode + and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_KSU_MASK | SR_INT_ENAB) + .set noat +/* + * Call the exception handler. + */ + jal trap + mtc0 t0, COP_0_STATUS_REG +/* + * Restore user registers and return. + * First disable interrupts and set exeption level. + */ + mtc0 zero, COP_0_STATUS_REG # disable int + nop + nop + nop + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtc0 a0, COP_0_STATUS_REG # still exeption level + mtlo t0 + mthi t1 + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + eret + .set at +END(R4K_UserGenException) + +/*---------------------------------------------------------------------------- + * + * R4K_KernIntr -- + * + * Handle an interrupt from kernel mode. + * Interrupts use the standard kernel stack. + * switch_exit sets up a kernel stack after exit so interrupts won't fail. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) +#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) +#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) +#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) +#define KINTR_MULT_GP_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) +#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16) + +NNON_LEAF(R4K_KernIntr, KINTR_FRAME_SIZE, ra) + .set noat + subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame + .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + * We don't need to save s0 - s8, sp and gp because + * the compiler does it for us. + */ + sw AT, KINTR_REG_OFFSET + 0(sp) + sw v0, KINTR_REG_OFFSET + 4(sp) + sw v1, KINTR_REG_OFFSET + 8(sp) + sw a0, KINTR_REG_OFFSET + 12(sp) + mflo v0 + mfhi v1 + sw a1, KINTR_REG_OFFSET + 16(sp) + sw a2, KINTR_REG_OFFSET + 20(sp) + sw a3, KINTR_REG_OFFSET + 24(sp) + sw t0, KINTR_REG_OFFSET + 28(sp) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, KINTR_REG_OFFSET + 32(sp) + sw t2, KINTR_REG_OFFSET + 36(sp) + sw t3, KINTR_REG_OFFSET + 40(sp) + sw t4, KINTR_REG_OFFSET + 44(sp) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, KINTR_REG_OFFSET + 48(sp) + sw t6, KINTR_REG_OFFSET + 52(sp) + sw t7, KINTR_REG_OFFSET + 56(sp) + sw t8, KINTR_REG_OFFSET + 60(sp) + mfc0 a2, COP_0_EXC_PC # Third arg is the pc. + sw t9, KINTR_REG_OFFSET + 64(sp) + sw ra, KINTR_REG_OFFSET + 68(sp) + sw v0, KINTR_MULT_LO_OFFSET(sp) + sw v1, KINTR_MULT_HI_OFFSET(sp) + sw a0, KINTR_SR_OFFSET(sp) + + mtc0 zero, COP_0_STATUS_REG # Reset exl, trap possible. +/* + * Call the interrupt handler. + */ + jal interrupt + sw a2, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the interrupt. + */ + mtc0 zero, COP_0_STATUS_REG # Disable interrupt + lw a0, KINTR_SR_OFFSET(sp) + lw t0, KINTR_MULT_LO_OFFSET(sp) + lw t1, KINTR_MULT_HI_OFFSET(sp) + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + mtlo t0 + mthi t1 + lw a0, STAND_RA_OFFSET(sp) + lw AT, KINTR_REG_OFFSET + 0(sp) + lw v0, KINTR_REG_OFFSET + 4(sp) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, KINTR_REG_OFFSET + 8(sp) + lw a0, KINTR_REG_OFFSET + 12(sp) + lw a1, KINTR_REG_OFFSET + 16(sp) + lw a2, KINTR_REG_OFFSET + 20(sp) + lw a3, KINTR_REG_OFFSET + 24(sp) + lw t0, KINTR_REG_OFFSET + 28(sp) + lw t1, KINTR_REG_OFFSET + 32(sp) + lw t2, KINTR_REG_OFFSET + 36(sp) + lw t3, KINTR_REG_OFFSET + 40(sp) + lw t4, KINTR_REG_OFFSET + 44(sp) + lw t5, KINTR_REG_OFFSET + 48(sp) + lw t6, KINTR_REG_OFFSET + 52(sp) + lw t7, KINTR_REG_OFFSET + 56(sp) + lw t8, KINTR_REG_OFFSET + 60(sp) + lw t9, KINTR_REG_OFFSET + 64(sp) + lw ra, KINTR_REG_OFFSET + 68(sp) + addu sp, sp, KINTR_FRAME_SIZE + eret # interrupt. + .set at +END(R4K_KernIntr) + +/*---------------------------------------------------------------------------- + * + * R4K_UserIntr -- + * + * Handle an interrupt from user mode. + * Note: we save minimal state in the u.u_pcb struct and use the standard + * kernel stack since there has to be a u page if we came from user mode. + * If there is a pending software interrupt, then save the remaining state + * and call softintr(). This is all because if we call switch() inside + * interrupt(), not all the user registers have been saved in u.u_pcb. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(R4K_UserIntr, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save the relevant user registers into the u.u_pcb struct. + * We don't need to save s0 - s8 because + * the compiler does it for us. + */ + sw AT, UADDR+U_PCB_REGS+(AST * 4) + sw v0, UADDR+U_PCB_REGS+(V0 * 4) + sw v1, UADDR+U_PCB_REGS+(V1 * 4) + sw a0, UADDR+U_PCB_REGS+(A0 * 4) + mflo v0 + mfhi v1 + sw a1, UADDR+U_PCB_REGS+(A1 * 4) + sw a2, UADDR+U_PCB_REGS+(A2 * 4) + sw a3, UADDR+U_PCB_REGS+(A3 * 4) + sw t0, UADDR+U_PCB_REGS+(T0 * 4) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, UADDR+U_PCB_REGS+(T1 * 4) + sw t2, UADDR+U_PCB_REGS+(T2 * 4) + sw t3, UADDR+U_PCB_REGS+(T3 * 4) + sw t4, UADDR+U_PCB_REGS+(T4 * 4) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, UADDR+U_PCB_REGS+(T5 * 4) + sw t6, UADDR+U_PCB_REGS+(T6 * 4) + sw t7, UADDR+U_PCB_REGS+(T7 * 4) + sw t8, UADDR+U_PCB_REGS+(T8 * 4) + mfc0 a2, COP_0_EXC_PC # Third arg is the pc. + sw t9, UADDR+U_PCB_REGS+(T9 * 4) + sw gp, UADDR+U_PCB_REGS+(GP * 4) + sw sp, UADDR+U_PCB_REGS+(SP * 4) + sw ra, UADDR+U_PCB_REGS+(RA * 4) + li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP + sw v0, UADDR+U_PCB_REGS+(MULLO * 4) + sw v1, UADDR+U_PCB_REGS+(MULHI * 4) + sw a0, UADDR+U_PCB_REGS+(SR * 4) + sw a2, UADDR+U_PCB_REGS+(PC * 4) + la gp, _gp # switch to kernel GP +# Turn off fpu and enter kernel mode + .set at + and t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) + .set noat + mtc0 t0, COP_0_STATUS_REG +/* + * Call the interrupt handler. + */ + jal interrupt + sw a2, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the interrupt. + */ + mtc0 zero, COP_0_STATUS_REG + nop + nop + nop + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw v0, astpending # any pending interrupts? + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + bne v0, zero, 1f # dont restore, call softintr + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + mtlo t0 + mthi t1 + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + eret # interrupt. + +1: +/* + * We have pending software interrupts; save remaining user state in u.u_pcb. + */ + sw s0, UADDR+U_PCB_REGS+(S0 * 4) + sw s1, UADDR+U_PCB_REGS+(S1 * 4) + sw s2, UADDR+U_PCB_REGS+(S2 * 4) + sw s3, UADDR+U_PCB_REGS+(S3 * 4) + sw s4, UADDR+U_PCB_REGS+(S4 * 4) + sw s5, UADDR+U_PCB_REGS+(S5 * 4) + sw s6, UADDR+U_PCB_REGS+(S6 * 4) + sw s7, UADDR+U_PCB_REGS+(S7 * 4) + sw s8, UADDR+U_PCB_REGS+(S8 * 4) + li t0, HARD_INT_MASK | SR_INT_ENAB +/* + * Call the software interrupt handler. + */ + jal softintr + mtc0 t0, COP_0_STATUS_REG # enable interrupts (spl0) +/* + * Restore user registers and return. NOTE: interrupts are enabled. + */ + mtc0 zero, COP_0_STATUS_REG + nop + nop + nop + li v0, SR_EXL + mtc0 v0, COP_0_STATUS_REG # set exeption level bit. + + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtc0 a0, COP_0_STATUS_REG # this should disable interrupts + mtlo t0 + mthi t1 + lw a0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + dmtc0 a0, COP_0_EXC_PC # set return address + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + eret + .set at +END(R4K_UserIntr) + +/*---------------------------------------------------------------------------- + * + * R4K_TLBInvalidException -- + * + * Handle a TLB invalid exception from kernel mode in kernel space. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(R4K_TLBInvalidException) + .set noat + dmfc0 k0, COP_0_BAD_VADDR # get the fault address + li k1, VM_MIN_KERNEL_ADDRESS # compute index + subu k0, k0, k1 + lw k1, Sysmapsize # index within range? + srl k0, k0, PGSHIFT + sltu k1, k0, k1 + beq k1, zero, sys_stk_chk # No. check for valid stack + lw k1, Sysmap + + sll k0, k0, 2 # compute offset from index + tlbp # Probe the invalid entry + addu k1, k1, k0 + and k0, k0, 4 # check even/odd page + bne k0, zero, KernTLBIOdd + nop + + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, sys_stk_chk + sltiu k0, k0, 8 + + bne k0, zero, sys_stk_chk + lw k0, 0(k1) # get PTE entry + + dsll k0, k0, 34 # get rid of "wired" bit + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 # load PTE entry + and k0, k0, PG_V # check for valid entry + beq k0, zero, R4K_KernGenException # PTE invalid + lw k0, 4(k1) # get odd PTE entry + dsll k0, k0, 34 + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO1 # load PTE entry + nop + tlbwi # write TLB + nop + nop + nop + nop + nop + eret + +KernTLBIOdd: + mfc0 k0, COP_0_TLB_INDEX + nop + bltz k0, sys_stk_chk + sltiu k0, k0, 8 + + bne k0, zero, sys_stk_chk + lw k0, 0(k1) # get PTE entry + + dsll k0, k0, 34 # get rid of wired bit + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO1 # save PTE entry + and k0, k0, PG_V # check for valid entry + beq k0, zero, R4K_KernGenException # PTE invalid + lw k0, -4(k1) # get even PTE entry + dsll k0, k0, 34 + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 # save PTE entry + nop + tlbwi # update TLB + nop + nop + nop + nop + nop + eret +END(R4K_TLBInvalidException) + +/*---------------------------------------------------------------------------- + * + * R4K_TLBMissException -- + * + * Handle a TLB miss exception from kernel mode in kernel space. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(R4K_TLBMissException) + .set noat + dmfc0 k0, COP_0_BAD_VADDR # get the fault address + li k1, VM_MIN_KERNEL_ADDRESS # compute index + subu k0, k0, k1 + lw k1, Sysmapsize # index within range? + srl k0, k0, PGSHIFT + sltu k1, k0, k1 + beq k1, zero, sys_stk_chk # No. check for valid stack + lw k1, Sysmap + srl k0, k0, 1 + sll k0, k0, 3 # compute offset from index + addu k1, k1, k0 + lw k0, 0(k1) # get PTE entry + lw k1, 4(k1) # get odd PTE entry + dsll k0, k0, 34 # get rid of "wired" bit + dsrl k0, k0, 34 + dmtc0 k0, COP_0_TLB_LO0 # load PTE entry + dsll k1, k1, 34 + dsrl k1, k1, 34 + dmtc0 k1, COP_0_TLB_LO1 # load PTE entry + nop + tlbwr # write TLB + nop + nop + nop + nop + nop + eret + +sys_stk_chk: + subu k0, sp, UADDR + 0x200 # check to see if we have a + sltiu k0, UPAGES*NBPG - 0x200 # valid kernel stack + bne k0, zero, R4K_KernGenException # Go panic + nop + + la a0, start - START_FRAME - 8 # set sp to a valid place + sw sp, 24(a0) + move sp, a0 + la a0, 1f + mfc0 a2, COP_0_STATUS_REG + mfc0 a3, COP_0_CAUSE_REG + dmfc0 a1, COP_0_EXC_PC + sw a2, 16(sp) + sw a3, 20(sp) + move a2, ra + jal printf + dmfc0 a3, COP_0_BAD_VADDR + .data +1: + .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" + .text + + la sp, start - START_FRAME # set sp to a valid place + PANIC("kernel stack overflow") + .set at +END(R4K_TLBMissException) + +/*---------------------------------------------------------------------------- + * + * wbflush -- + * + * Return when the write buffer is empty. + * + * wbflush() + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(wbflush) + nop + sync + j ra + nop +END(wbflush) + +/*-------------------------------------------------------------------------- + * + * R4K_TLBWriteIndexed -- + * + * Write the given entry into the TLB at the given index. + * + * R4K_TLBWriteIndexed(index, tlb) + * unsigned index; + * tlb *tlb; + * + * Results: + * None. + * + * Side effects: + * TLB entry set. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_TLBWriteIndexed) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + nop + lw a2, 8(a1) + lw a3, 12(a1) + dmfc0 t0, COP_0_TLB_HI # Save the current PID. + + dmtc0 a2, COP_0_TLB_LO0 # Set up entry low0. + dmtc0 a3, COP_0_TLB_LO1 # Set up entry low1. + lw a2, 0(a1) + lw a3, 4(a1) + mtc0 a0, COP_0_TLB_INDEX # Set the index. + dmtc0 a2, COP_0_TLB_PG_MASK # Set up entry mask. + dmtc0 a3, COP_0_TLB_HI # Set up entry high. + nop + tlbwi # Write the TLB + nop + nop + nop # Delay for effect + nop + + dmtc0 t0, COP_0_TLB_HI # Restore the PID. + nop + dmtc0 zero, COP_0_TLB_PG_MASK # Default mask value. + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R4K_TLBWriteIndexed) + +/*-------------------------------------------------------------------------- + * + * R4K_SetPID -- + * + * Write the given pid into the TLB pid reg. + * + * R4K_SetPID(pid) + * int pid; + * + * Results: + * None. + * + * Side effects: + * PID set in the entry hi register. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_SetPID) + dmtc0 a0, COP_0_TLB_HI # Write the hi reg value + j ra + nop +END(R4K_SetPID) + +/*-------------------------------------------------------------------------- + * + * R4K_SetWIRED -- + * + * Write the given value into the TLB wired reg. + * + * R4K_SetPID(wired) + * int wired; + * + * Results: + * None. + * + * Side effects: + * WIRED set in the wired register. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_SetWIRED) + mtc0 a0, COP_0_TLB_WIRED + j ra + nop +END(R4K_SetWIRED) + +/*-------------------------------------------------------------------------- + * + * R4K_GetWIRED -- + * + * Get the value from the TLB wired reg. + * + * R4K_GetWIRED(void) + * + * Results: + * Value of wired reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_GetWIRED) + mfc0 v0, COP_0_TLB_WIRED + j ra + nop +END(R4K_GetWIRED) + +/*-------------------------------------------------------------------------- + * + * R4K_TLBFlush -- + * + * Flush the "random" entries from the TLB. + * Uses "wired" register to determine what register to start with. + * + * R4K_TLBFlush() + * + * Results: + * None. + * + * Side effects: + * The TLB is flushed. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_TLBFlush) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t1, COP_0_TLB_WIRED + li t2, VMNUM_TLB_ENTRIES + li v0, CACHED_MEMORY_ADDR # invalid address + dmfc0 t0, COP_0_TLB_HI # Save the PID + + dmtc0 v0, COP_0_TLB_HI # Mark entry high as invalid + dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry0. + dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry1. + mtc0 zero, COP_0_TLB_PG_MASK # Zero out mask entry. +/* + * Align the starting value (t1) and the upper bound (t2). + */ +1: + mtc0 t1, COP_0_TLB_INDEX # Set the index register. + addu t1, t1, 1 # Increment index. + tlbwi # Write the TLB entry. + nop + nop + bne t1, t2, 1b + nop + + dmtc0 t0, COP_0_TLB_HI # Restore the PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R4K_TLBFlush) + + +/*-------------------------------------------------------------------------- + * + * R4K_TLBFlushAddr -- + * + * Flush any TLB entries for the given address and TLB PID. + * + * R4K_TLBFlushAddr(TLBhi) + * unsigned TLBhi; + * + * Results: + * None. + * + * Side effects: + * The process's page is flushed from the TLB. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_TLBFlushAddr) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + nop + li v0, (PG_HVPN | PG_ASID) + and a0, a0, v0 # Make shure valid hi value. + dmfc0 t0, COP_0_TLB_HI # Get current PID + dmtc0 a0, COP_0_TLB_HI # look for addr & PID + nop + nop + nop + tlbp # Probe for the entry. + nop + nop # Delay for effect + nop + mfc0 v0, COP_0_TLB_INDEX # See what we got + li t1, CACHED_MEMORY_ADDR # Load invalid entry. + bltz v0, 1f # index < 0 => !found + nop + dmtc0 t1, COP_0_TLB_HI # Mark entry high as invalid + + dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry. + dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry. + nop + tlbwi + nop + nop + nop + nop +1: + dmtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R4K_TLBFlushAddr) + +/*-------------------------------------------------------------------------- + * + * R4K_TLBUpdate -- + * + * Update the TLB if highreg is found; otherwise, enter the data. + * + * R4K_TLBUpdate(virpageadr, lowregx) + * unsigned virpageadr, lowregx; + * + * Results: + * < 0 if loaded >= 0 if updated. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_TLBUpdate) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + and t1, a0, 0x1000 # t1 = Even/Odd flag + li v0, (PG_HVPN | PG_ASID) + and a0, a0, v0 + dmfc0 t0, COP_0_TLB_HI # Save current PID + dmtc0 a0, COP_0_TLB_HI # Init high reg + and a2, a1, PG_G # Copy global bit + nop + nop + tlbp # Probe for the entry. + dsll a1, a1, 34 + dsrl a1, a1, 34 + bne t1, zero, 2f # Decide even odd + mfc0 v0, COP_0_TLB_INDEX # See what we got +# EVEN + nop + bltz v0, 1f # index < 0 => !found + nop + + tlbr # update, read entry first + nop + nop + nop + dmtc0 a1, COP_0_TLB_LO0 # init low reg0. + nop + tlbwi # update slot found + b 4f + nop +1: + mtc0 zero, COP_0_TLB_PG_MASK # init mask. + dmtc0 a0, COP_0_TLB_HI # init high reg. + dmtc0 a1, COP_0_TLB_LO0 # init low reg0. + dmtc0 a2, COP_0_TLB_LO1 # init low reg1. + nop + tlbwr # enter into a random slot + b 4f + nop +# ODD +2: + nop + bltz v0, 3f # index < 0 => !found + nop + + tlbr # read the entry first + nop + nop + nop + dmtc0 a1, COP_0_TLB_LO1 # init low reg1. + nop + tlbwi # update slot found + b 4f + nop +3: + mtc0 zero, COP_0_TLB_PG_MASK # init mask. + dmtc0 a0, COP_0_TLB_HI # init high reg. + dmtc0 a2, COP_0_TLB_LO0 # init low reg0. + dmtc0 a1, COP_0_TLB_LO1 # init low reg1. + nop + tlbwr # enter into a random slot + +4: # Make shure pipeline + nop # advances before we + nop # uses the tlb. + nop + nop + dmtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R4K_TLBUpdate) + +/*-------------------------------------------------------------------------- + * + * R4K_TLBRead -- + * + * Read the TLB entry. + * + * R4K_TLBRead(entry, tlb) + * unsigned entry; + * struct tlb *tlb; + * + * Results: + * None. + * + * Side effects: + * tlb will contain the TLB entry found. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_TLBRead) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + nop + nop + nop + dmfc0 t0, COP_0_TLB_HI # Get current PID + + mtc0 a0, COP_0_TLB_INDEX # Set the index register + nop + tlbr # Read from the TLB + nop + nop + nop + mfc0 t2, COP_0_TLB_PG_MASK # fetch the hi entry + dmfc0 t3, COP_0_TLB_HI # fetch the hi entry + dmfc0 t4, COP_0_TLB_LO0 # See what we got + dmfc0 t5, COP_0_TLB_LO1 # See what we got + dmtc0 t0, COP_0_TLB_HI # restore PID + nop + nop + nop # wait for PID active + mtc0 v1, COP_0_STATUS_REG # Restore the status register + sw t2, 0(a1) + sw t3, 4(a1) + sw t4, 8(a1) + j ra + sw t5, 12(a1) +END(R4K_TLBRead) + +/*-------------------------------------------------------------------------- + * + * R4K_TLBGetPID -- + * + * R4K_TLBGetPID() + * + * Results: + * Returns the current TLB pid reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(R4K_TLBGetPID) + dmfc0 v0, COP_0_TLB_HI # get PID + j ra + and v0, v0, VMTLB_PID # mask off PID +END(R4K_TLBGetPID) + +/*---------------------------------------------------------------------------- + * + * R4K_ConfigCache -- + * + * Size the caches. + * NOTE: should only be called from mips_init(). + * + * Results: + * None. + * + * Side effects: + * The size of the data cache is stored into CpuPrimaryDataCacheSize. + * The size of instruction cache is stored into CpuPrimaryInstCacheSize. + * Alignment mask for cache aliasing test is stored in CpuCacheAliasMask. + * + *---------------------------------------------------------------------------- + */ +LEAF(R4K_ConfigCache) + .set noreorder + mfc0 v0, COP_0_CONFIG # Get configuration register + mfc0 v1, COP_0_PRID + srl t1, v0, 9 # Get I cache size. + and t1, 3 + li t2, 4096 + sllv t2, t2, t1 + sw t2, CpuPrimaryDataCacheSize + addiu t2, -1 + and t2, ~(NBPG - 1) + sw t2, CpuCacheAliasMask + + and t2, v0, 0x20 + srl t2, t2, 1 + addu t2, t2, 16 + sw t2, CpuPrimaryDataCacheLSize + + srl t1, v0, 6 # Get I cache size. + and t1, 3 + li t2, 4096 + sllv t2, t2, t1 + sw t2, CpuPrimaryInstCacheSize + + and t2, v0, 0x10 + addu t2, t2, 16 + sw t2, CpuPrimaryInstCacheLSize + and v1, 0xff00 + li t1, (MIPS_R4600 << 8) + li t2, 1 + bnel v1, t1, 1f + li t2, 0 +1: + sw t2, CpuTwoWayCache + j ra + nop +END(R4K_ConfigCache) + +/*---------------------------------------------------------------------------- + * + * R4K_FlushCache -- + * + * Flush the caches. Assumes a line size of 16 bytes for speed. + * + * Results: + * None. + * + * Side effects: + * The contents of the caches is flushed. + * + *---------------------------------------------------------------------------- + */ +LEAF(R4K_FlushCache) + .set noreorder +/*XXX 4600 Bug */ + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts +/*XXX*/ + lw v0, CpuTwoWayCache + lw t1, CpuPrimaryInstCacheSize + lw t2, CpuPrimaryDataCacheSize + # lw t3, CpuPrimaryInstCacheLSize + # lw t4, CpuPrimaryDataCacheLSize +/* + * Flush the instruction cache. + */ + li t0, CACHED_MEMORY_ADDR + addu t1, t0, t1 # End address + subu t1, t1, 128 +1: + bne v0, zero, 2f + cache 0, 0(t0) + + cache 0, 16(t0) + cache 0, 48(t0) + cache 0, 80(t0) + b 3f + cache 0, 112(t0) + +2: + cache 0, 8192+0(t0) + cache 0, 8192+32(t0) + cache 0, 8192+64(t0) + cache 0, 8192+96(t0) + +3: + cache 0, 32(t0) + cache 0, 64(t0) + cache 0, 96(t0) + bne t0, t1, 1b + addu t0, t0, 128 + +/* + * Flush the data cache. + */ + li t0, CACHED_MEMORY_ADDR + addu t1, t0, t2 # End address + subu t1, t1, 128 +1: + bne v0, zero, 2f + cache 1, 0(t0) + + cache 1, 16(t0) + cache 1, 48(t0) + cache 1, 80(t0) + b 3f + cache 1, 112(t0) + +2: + cache 1, 8192+0(t0) + cache 1, 8192+32(t0) + cache 1, 8192+64(t0) + cache 1, 8192+96(t0) + +3: + cache 1, 32(t0) + cache 1, 64(t0) + cache 1, 96(t0) + bne t0, t1, 1b + addu t0, t0, 128 + +/*XXX 4600 Bug */ + mtc0 v1, COP_0_STATUS_REG # Restore the status register. +/*XXX*/ + j ra + nop +END(R4K_FlushCache) + +/*---------------------------------------------------------------------------- + * + * R4K_FlushICache -- + * + * void R4K_FlushICache(addr, len) + * vm_offset_t addr, len; + * + * Flush instruction cache for range of addr to addr + len - 1. + * The address can be any valid address so long as no TLB misses occur. + * Assumes a cache line size of 16 bytes for speed. + * + * Results: + * None. + * + * Side effects: + * The contents of the cache is flushed. + * Must not touch v0. + * + *---------------------------------------------------------------------------- + */ +LEAF(R4K_FlushICache) +/*XXX 4600 Bug */ + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts +/*XXX*/ + lw v0, CpuTwoWayCache + addu a1, 127 # Align + srl a1, a1, 7 # Number of unrolled loops +1: + bne v0, zero, 2f + addu a1, -1 + + cache 0, 16(a0) + cache 0, 48(a0) + cache 0, 80(a0) + b 3f + cache 0, 112(a0) + +2: + cache 0, 8192+0(a0) + cache 0, 8192+32(a0) + cache 0, 8192+64(a0) + cache 0, 8192+96(a0) + +3: + cache 0, 0(a0) + cache 0, 32(a0) + cache 0, 64(a0) + cache 0, 96(a0) + bne a1, zero, 1b + addu a0, 128 + +/*XXX 4600 Bug */ + mtc0 v1, COP_0_STATUS_REG # Restore the status register. +/*XXX*/ + j ra + move v0, zero # suiword depends on this!! +END(R4K_FlushICache) + +/*---------------------------------------------------------------------------- + * + * R4K_FlushDCache -- + * + * void R4K_FlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for index range of addr to addr + len - 1. + * The address is reduced to a kseg0 index. + * + * Results: + * None. + * + * Side effects: + * The contents of the cache is written back to primary memory. + * The cache line is invalidated. + * + *---------------------------------------------------------------------------- + */ +LEAF(R4K_FlushDCache) +/*XXX 4600 Bug */ + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts +/*XXX*/ + lw v0, CpuTwoWayCache + lw a2, CpuPrimaryDataCacheSize + addiu a2, -1 + and a0, a0, a2 + addu a1, 127 # Align + li a2, 0x80000000 + addu a0, a0, a2 + addu a1, a1, a0 + and a0, a0, -128 + subu a1, a1, a0 + srl a1, a1, 7 # Compute number of cache lines +1: + bne v0, zero, 2f + addu a1, -1 + + cache 1, 16(a0) + cache 1, 48(a0) + cache 1, 80(a0) + b 3f + cache 1, 112(a0) + +2: + cache 1, 8192+0(a0) + cache 1, 8192+32(a0) + cache 1, 8192+64(a0) + cache 1, 8192+96(a0) + +3: + cache 1, 0(a0) + cache 1, 32(a0) + cache 1, 64(a0) + cache 1, 96(a0) + bne a1, zero, 1b + addu a0, 128 + +/*XXX 4600 Bug */ + mtc0 v1, COP_0_STATUS_REG # Restore the status register. +/*XXX*/ + j ra + nop +END(R4K_FlushDCache) + +/*---------------------------------------------------------------------------- + * + * R4K_HitFlushDCache -- + * + * void R4K_HitFlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for range of addr to addr + len - 1. + * The address can be any valid viritual address as long + * as no TLB invalid traps occur. Only lines with matching + * addr is flushed. + * + * Results: + * None. + * + * Side effects: + * The contents of the cache is written back to primary memory. + * The cache line is invalidated. + * + *---------------------------------------------------------------------------- + */ +LEAF(R4K_HitFlushDCache) + lw v0, CpuTwoWayCache + beq a1, zero, 3f + addu a1, 127 # Align + addu a1, a1, a0 + and a0, a0, -128 + subu a1, a1, a0 + srl a1, a1, 7 # Compute number of cache lines +1: + bne v0, zero, 2f + addu a1, -1 + + cache 0x15, 16(a0) + cache 0x15, 48(a0) + cache 0x15, 80(a0) + cache 0x15, 112(a0) + +2: + cache 0x15, 0(a0) + cache 0x15, 32(a0) + cache 0x15, 64(a0) + cache 0x15, 96(a0) + bne a1, zero, 1b + addu a0, 128 + +3: + j ra + nop +END(R4K_HitFlushDCache) +/*---------------------------------------------------------------------------- + * + * R4K_InvalidateDCache -- + * + * void R4K_FlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for range of addr to addr + len - 1. + * The address can be any valid address as long as no TLB misses occur. + * (Be sure to use cached K0SEG kernel addresses or mapped addresses) + * Results: + * None. + * + * Side effects: + * The cache line is invalidated. + * + *---------------------------------------------------------------------------- + */ +LEAF(R4K_InvalidateDCache) + addu a1, a1, a0 # compute ending address +1: + cache 0x11,8194(a0) + addu a0, a0, 4 + bne a0, a1, 1b + cache 0x11,-4(a0) + + j ra + nop +END(R4K_InvalidateDCache) + +#else /* ==================XXXXX============================== */ + +/* + *---------------------------------------------------------------------------- + * + * R3K_UTLBmiss -- + * + * Vector code for a MIPS-I user-space TLB miss from user-space. + * + * + * This code is copied to the UTLB exception vector address to + * handle user level TLB translation misses. + * NOTE: This code must be relocatable!!! + */ + .globl R3K_UTLBMiss +R3K_UTLBMiss: + .set noat + mfc0 k0, COP_0_BAD_VADDR # get the virtual address + lw k1, UADDR+U_PCB_SEGTAB # get the current segment table + bltz k0, 1f # R3000 chip bug + srl k0, k0, SEGSHIFT # compute segment table index + sll k0, k0, 2 + addu k1, k1, k0 + mfc0 k0, COP_0_BAD_VADDR # get the virtual address + lw k1, 0(k1) # get pointer to segment map + srl k0, k0, PGSHIFT - 2 # compute segment map index + andi k0, k0, (NPTEPG - 1) << 2 + beq k1, zero, 2f # invalid segment map + addu k1, k1, k0 # index into segment map + lw k0, 0(k1) # get page PTE + nop + beq k0, zero, 2f # dont load invalid entries + mtc0 k0, COP_0_TLB_LO0 + mfc0 k1, COP_0_EXC_PC # get return address + tlbwr # update TLB + j k1 + rfe +1: + mfc0 k1, COP_0_EXC_PC # get return address + nop + j k1 + rfe +2: + j R3K_SlowFault # handle the rest + nop + .set at + .globl R3K_UTLBMissEnd +R3K_UTLBMissEnd: + + +/* + *---------------------------------------------------------------------------- + * + * R3K_execption -- + * + * Vector code for the general exception vector 0x80000080 + * on an r2000 or r3000. + * + * This code is copied to the general exception vector address to + * handle all execptions except RESET and UTLBMiss. + * NOTE: This code must be relocatable!!! + * + *---------------------------------------------------------------------------- + */ + .globl R3K_Exception +R3K_Exception: + .set noat + mfc0 k0, COP_0_STATUS_REG # Get the status register + mfc0 k1, COP_0_CAUSE_REG # Get the cause register value. + and k0, k0, SR_KU_PREV # test for user mode + sll k0, k0, 4 # shift user bit for cause index + and k1, k1, CR_EXC_CODE # Mask out the cause bits. + or k1, k1, k0 # change index to user table +1: + la k0, R3K_ExceptionTable # get base of the jump table + addu k0, k0, k1 # Get the address of the + # function entry. Note that + # the cause is already + # shifted left by 2 bits so + # we dont have to shift. + lw k0, 0(k0) # Get the function address + nop + j k0 # Jump to the function. + nop + .set at + .globl R3K_ExceptionEnd +R3K_ExceptionEnd: + +/*---------------------------------------------------------------------------- + * + * R3K_SlowFault -- + * + * Alternate entry point into the R3K_UserGenExceptionor or + * or R3K_user_Kern_exception, when the ULTB miss handler couldn't + * find a TLB entry. + * + * Find out what mode we came from and call the appropriate handler. + */ +R3K_SlowFault: + .set noat + mfc0 k0, COP_0_STATUS_REG + nop + and k0, k0, SR_KU_PREV + bne k0, zero, R3K_UserGenException + nop + .set at +/* + * Fall though ... + */ + +/*---------------------------------------------------------------------------- + * + * R3K_KernGenException -- + * + * Handle an exception from kernel mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +/* + * The kernel exception stack contains 18 saved general registers, + * the status register and the multiply lo and high registers. + * In addition, we set this up for linkage conventions. + */ +#define KERN_REG_SIZE (18 * 4) +#define KERN_REG_OFFSET (STAND_FRAME_SIZE) +#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) +#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) +#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) +#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) + +NNON_LEAF(R3K_KernGenException, KERN_EXC_FRAME_SIZE, ra) + .set noat +#ifdef DEBUG + la k0, mdbpcb # save registers for kadb + sw s0, (S0 * 4)(k0) + sw s1, (S1 * 4)(k0) + sw s2, (S2 * 4)(k0) + sw s3, (S3 * 4)(k0) + sw s4, (S4 * 4)(k0) + sw s5, (S5 * 4)(k0) + sw s6, (S6 * 4)(k0) + sw s7, (S7 * 4)(k0) + sw s8, (S8 * 4)(k0) + sw gp, (GP * 4)(k0) + sw sp, (SP * 4)(k0) +#endif + subu sp, sp, KERN_EXC_FRAME_SIZE + .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + * We don't need to save s0 - s8, sp and gp because + * the compiler does it for us. + */ + sw AT, KERN_REG_OFFSET + 0(sp) + sw v0, KERN_REG_OFFSET + 4(sp) + sw v1, KERN_REG_OFFSET + 8(sp) + sw a0, KERN_REG_OFFSET + 12(sp) + mflo v0 + mfhi v1 + sw a1, KERN_REG_OFFSET + 16(sp) + sw a2, KERN_REG_OFFSET + 20(sp) + sw a3, KERN_REG_OFFSET + 24(sp) + sw t0, KERN_REG_OFFSET + 28(sp) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, KERN_REG_OFFSET + 32(sp) + sw t2, KERN_REG_OFFSET + 36(sp) + sw t3, KERN_REG_OFFSET + 40(sp) + sw t4, KERN_REG_OFFSET + 44(sp) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, KERN_REG_OFFSET + 48(sp) + sw t6, KERN_REG_OFFSET + 52(sp) + sw t7, KERN_REG_OFFSET + 56(sp) + sw t8, KERN_REG_OFFSET + 60(sp) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr. + sw t9, KERN_REG_OFFSET + 64(sp) + sw ra, KERN_REG_OFFSET + 68(sp) + sw v0, KERN_MULT_LO_OFFSET(sp) + sw v1, KERN_MULT_HI_OFFSET(sp) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + sw a0, KERN_SR_OFFSET(sp) +/* + * Call the exception handler. + */ + jal trap + sw a3, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the exception. + * v0 contains the return address. + */ + lw a0, KERN_SR_OFFSET(sp) + lw t0, KERN_MULT_LO_OFFSET(sp) + lw t1, KERN_MULT_HI_OFFSET(sp) + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + mtlo t0 + mthi t1 + move k0, v0 + + lw AT, KERN_REG_OFFSET + 0(sp) + lw v0, KERN_REG_OFFSET + 4(sp) + lw v1, KERN_REG_OFFSET + 8(sp) + lw a0, KERN_REG_OFFSET + 12(sp) + lw a1, KERN_REG_OFFSET + 16(sp) + lw a2, KERN_REG_OFFSET + 20(sp) + lw a3, KERN_REG_OFFSET + 24(sp) + lw t0, KERN_REG_OFFSET + 28(sp) + lw t1, KERN_REG_OFFSET + 32(sp) + lw t2, KERN_REG_OFFSET + 36(sp) + lw t3, KERN_REG_OFFSET + 40(sp) + lw t4, KERN_REG_OFFSET + 44(sp) + lw t5, KERN_REG_OFFSET + 48(sp) + lw t6, KERN_REG_OFFSET + 52(sp) + lw t7, KERN_REG_OFFSET + 56(sp) + lw t8, KERN_REG_OFFSET + 60(sp) + lw t9, KERN_REG_OFFSET + 64(sp) + lw ra, KERN_REG_OFFSET + 68(sp) + + addu sp, sp, KERN_EXC_FRAME_SIZE + j k0 # Now return from the + rfe # exception. + .set at +END(R3K_KernGenException) + +/*---------------------------------------------------------------------------- + * + * R3K_UserGenException -- + * + * Handle an exception from user mode. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(R3K_UserGenException, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save all of the registers except for the kernel temporaries in u.u_pcb. + */ + sw AT, UADDR+U_PCB_REGS+(AST * 4) + sw v0, UADDR+U_PCB_REGS+(V0 * 4) + sw v1, UADDR+U_PCB_REGS+(V1 * 4) + sw a0, UADDR+U_PCB_REGS+(A0 * 4) + mflo v0 + sw a1, UADDR+U_PCB_REGS+(A1 * 4) + sw a2, UADDR+U_PCB_REGS+(A2 * 4) + sw a3, UADDR+U_PCB_REGS+(A3 * 4) + sw t0, UADDR+U_PCB_REGS+(T0 * 4) + mfhi v1 + sw t1, UADDR+U_PCB_REGS+(T1 * 4) + sw t2, UADDR+U_PCB_REGS+(T2 * 4) + sw t3, UADDR+U_PCB_REGS+(T3 * 4) + sw t4, UADDR+U_PCB_REGS+(T4 * 4) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t5, UADDR+U_PCB_REGS+(T5 * 4) + sw t6, UADDR+U_PCB_REGS+(T6 * 4) + sw t7, UADDR+U_PCB_REGS+(T7 * 4) + sw s0, UADDR+U_PCB_REGS+(S0 * 4) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw s1, UADDR+U_PCB_REGS+(S1 * 4) + sw s2, UADDR+U_PCB_REGS+(S2 * 4) + sw s3, UADDR+U_PCB_REGS+(S3 * 4) + sw s4, UADDR+U_PCB_REGS+(S4 * 4) + mfc0 a2, COP_0_BAD_VADDR # Third arg is the fault addr + sw s5, UADDR+U_PCB_REGS+(S5 * 4) + sw s6, UADDR+U_PCB_REGS+(S6 * 4) + sw s7, UADDR+U_PCB_REGS+(S7 * 4) + sw t8, UADDR+U_PCB_REGS+(T8 * 4) + mfc0 a3, COP_0_EXC_PC # Fourth arg is the pc. + sw t9, UADDR+U_PCB_REGS+(T9 * 4) + sw gp, UADDR+U_PCB_REGS+(GP * 4) + sw sp, UADDR+U_PCB_REGS+(SP * 4) + sw s8, UADDR+U_PCB_REGS+(S8 * 4) + li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP + sw ra, UADDR+U_PCB_REGS+(RA * 4) + sw v0, UADDR+U_PCB_REGS+(MULLO * 4) + sw v1, UADDR+U_PCB_REGS+(MULHI * 4) + sw a0, UADDR+U_PCB_REGS+(SR * 4) + la gp, _gp # switch to kernel GP + sw a3, UADDR+U_PCB_REGS+(PC * 4) + sw a3, STAND_RA_OFFSET(sp) # for debugging + .set at + and t0, a0, ~SR_COP_1_BIT # Turn off the FPU. + .set noat +/* + * Call the exception handler. + */ + jal trap + mtc0 t0, COP_0_STATUS_REG +/* + * Restore user registers and return. NOTE: interrupts are enabled. + */ + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtc0 a0, COP_0_STATUS_REG # this should disable interrupts + mtlo t0 + mthi t1 + lw k0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + + j k0 + rfe + .set at +END(R3K_UserGenException) + +/*---------------------------------------------------------------------------- + * + * R3K_KernIntr -- + * + * Handle an interrupt from kernel mode. + * Interrupts use the standard kernel stack. + * switch_exit sets up a kernel stack after exit so interrupts won't fail. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) +#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) +#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) +#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) +#define KINTR_GP_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) +#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16) + +NNON_LEAF(R3K_KernIntr, KINTR_FRAME_SIZE, ra) + .set noat + subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame + .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) +/* + * Save the relevant kernel registers onto the stack. + * We don't need to save s0 - s8 and sp because + * the compiler does it for us. + */ + sw AT, KINTR_REG_OFFSET + 0(sp) + sw v0, KINTR_REG_OFFSET + 4(sp) + sw v1, KINTR_REG_OFFSET + 8(sp) + sw a0, KINTR_REG_OFFSET + 12(sp) + mflo v0 + mfhi v1 + sw a1, KINTR_REG_OFFSET + 16(sp) + sw a2, KINTR_REG_OFFSET + 20(sp) + sw a3, KINTR_REG_OFFSET + 24(sp) + sw t0, KINTR_REG_OFFSET + 28(sp) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, KINTR_REG_OFFSET + 32(sp) + sw t2, KINTR_REG_OFFSET + 36(sp) + sw t3, KINTR_REG_OFFSET + 40(sp) + sw t4, KINTR_REG_OFFSET + 44(sp) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, KINTR_REG_OFFSET + 48(sp) + sw t6, KINTR_REG_OFFSET + 52(sp) + sw t7, KINTR_REG_OFFSET + 56(sp) + sw t8, KINTR_REG_OFFSET + 60(sp) + mfc0 a2, COP_0_EXC_PC # Third arg is the pc. + sw t9, KINTR_REG_OFFSET + 64(sp) + sw ra, KINTR_REG_OFFSET + 68(sp) + sw v0, KINTR_MULT_LO_OFFSET(sp) + sw v1, KINTR_MULT_HI_OFFSET(sp) + sw a0, KINTR_SR_OFFSET(sp) + sw gp, KINTR_GP_OFFSET(sp) + la gp, _gp # switch to kernel GP +/* + * Call the interrupt handler. + */ + jal interrupt + sw a2, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the interrupt. + */ + lw a0, KINTR_SR_OFFSET(sp) + lw t0, KINTR_MULT_LO_OFFSET(sp) + lw t1, KINTR_MULT_HI_OFFSET(sp) + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + mtlo t0 + mthi t1 + lw k0, STAND_RA_OFFSET(sp) + lw AT, KINTR_REG_OFFSET + 0(sp) + lw v0, KINTR_REG_OFFSET + 4(sp) + lw v1, KINTR_REG_OFFSET + 8(sp) + lw a0, KINTR_REG_OFFSET + 12(sp) + lw a1, KINTR_REG_OFFSET + 16(sp) + lw a2, KINTR_REG_OFFSET + 20(sp) + lw a3, KINTR_REG_OFFSET + 24(sp) + lw t0, KINTR_REG_OFFSET + 28(sp) + lw t1, KINTR_REG_OFFSET + 32(sp) + lw t2, KINTR_REG_OFFSET + 36(sp) + lw t3, KINTR_REG_OFFSET + 40(sp) + lw t4, KINTR_REG_OFFSET + 44(sp) + lw t5, KINTR_REG_OFFSET + 48(sp) + lw t6, KINTR_REG_OFFSET + 52(sp) + lw t7, KINTR_REG_OFFSET + 56(sp) + lw t8, KINTR_REG_OFFSET + 60(sp) + lw t9, KINTR_REG_OFFSET + 64(sp) + lw ra, KINTR_REG_OFFSET + 68(sp) + + addu sp, sp, KINTR_FRAME_SIZE + j k0 # Now return from the + rfe # interrupt. + .set at +END(R3K_KernIntr) + +/*---------------------------------------------------------------------------- + * + * R3K_UserIntr -- + * + * Handle an interrupt from user mode. + * Note: we save minimal state in the u.u_pcb struct and use the standard + * kernel stack since there has to be a u page if we came from user mode. + * If there is a pending software interrupt, then save the remaining state + * and call softintr(). This is all because if we call switch() inside + * interrupt(), not all the user registers have been saved in u.u_pcb. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NNON_LEAF(R3K_UserIntr, STAND_FRAME_SIZE, ra) + .set noat + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) +/* + * Save the relevant user registers into the u.u_pcb struct. + * We don't need to save s0 - s8 because + * the compiler does it for us. + */ + sw AT, UADDR+U_PCB_REGS+(AST * 4) + sw v0, UADDR+U_PCB_REGS+(V0 * 4) + sw v1, UADDR+U_PCB_REGS+(V1 * 4) + sw a0, UADDR+U_PCB_REGS+(A0 * 4) + mflo v0 + mfhi v1 + sw a1, UADDR+U_PCB_REGS+(A1 * 4) + sw a2, UADDR+U_PCB_REGS+(A2 * 4) + sw a3, UADDR+U_PCB_REGS+(A3 * 4) + sw t0, UADDR+U_PCB_REGS+(T0 * 4) + mfc0 a0, COP_0_STATUS_REG # First arg is the status reg. + sw t1, UADDR+U_PCB_REGS+(T1 * 4) + sw t2, UADDR+U_PCB_REGS+(T2 * 4) + sw t3, UADDR+U_PCB_REGS+(T3 * 4) + sw t4, UADDR+U_PCB_REGS+(T4 * 4) + mfc0 a1, COP_0_CAUSE_REG # Second arg is the cause reg. + sw t5, UADDR+U_PCB_REGS+(T5 * 4) + sw t6, UADDR+U_PCB_REGS+(T6 * 4) + sw t7, UADDR+U_PCB_REGS+(T7 * 4) + sw t8, UADDR+U_PCB_REGS+(T8 * 4) + mfc0 a2, COP_0_EXC_PC # Third arg is the pc. + sw t9, UADDR+U_PCB_REGS+(T9 * 4) + sw gp, UADDR+U_PCB_REGS+(GP * 4) + sw sp, UADDR+U_PCB_REGS+(SP * 4) + sw ra, UADDR+U_PCB_REGS+(RA * 4) + li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP + sw v0, UADDR+U_PCB_REGS+(MULLO * 4) + sw v1, UADDR+U_PCB_REGS+(MULHI * 4) + sw a0, UADDR+U_PCB_REGS+(SR * 4) + sw a2, UADDR+U_PCB_REGS+(PC * 4) + la gp, _gp # switch to kernel GP + .set at + and t0, a0, ~SR_COP_1_BIT # Turn off the FPU. + .set noat + mtc0 t0, COP_0_STATUS_REG +/* + * Call the interrupt handler. + */ + jal interrupt + sw a2, STAND_RA_OFFSET(sp) # for debugging +/* + * Restore registers and return from the interrupt. + */ + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw v0, astpending # any pending interrupts? + mtc0 a0, COP_0_STATUS_REG # Restore the SR, disable intrs + bne v0, zero, 1f # dont restore, call softintr + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + lw k0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + mtlo t0 + mthi t1 + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + j k0 # Now return from the + rfe # interrupt. + +1: +/* + * We have pending software interrupts; save remaining user state in u.u_pcb. + */ + sw s0, UADDR+U_PCB_REGS+(S0 * 4) + sw s1, UADDR+U_PCB_REGS+(S1 * 4) + sw s2, UADDR+U_PCB_REGS+(S2 * 4) + sw s3, UADDR+U_PCB_REGS+(S3 * 4) + sw s4, UADDR+U_PCB_REGS+(S4 * 4) + sw s5, UADDR+U_PCB_REGS+(S5 * 4) + sw s6, UADDR+U_PCB_REGS+(S6 * 4) + sw s7, UADDR+U_PCB_REGS+(S7 * 4) + sw s8, UADDR+U_PCB_REGS+(S8 * 4) + li t0, HARD_INT_MASK | SR_INT_ENAB +/* + * Call the software interrupt handler. + */ + jal softintr + mtc0 t0, COP_0_STATUS_REG # enable interrupts (spl0) +/* + * Restore user registers and return. NOTE: interrupts are enabled. + */ + lw a0, UADDR+U_PCB_REGS+(SR * 4) + lw t0, UADDR+U_PCB_REGS+(MULLO * 4) + lw t1, UADDR+U_PCB_REGS+(MULHI * 4) + mtc0 a0, COP_0_STATUS_REG # this should disable interrupts + mtlo t0 + mthi t1 + lw k0, UADDR+U_PCB_REGS+(PC * 4) + lw AT, UADDR+U_PCB_REGS+(AST * 4) + lw v0, UADDR+U_PCB_REGS+(V0 * 4) + lw v1, UADDR+U_PCB_REGS+(V1 * 4) + lw a0, UADDR+U_PCB_REGS+(A0 * 4) + lw a1, UADDR+U_PCB_REGS+(A1 * 4) + lw a2, UADDR+U_PCB_REGS+(A2 * 4) + lw a3, UADDR+U_PCB_REGS+(A3 * 4) + lw t0, UADDR+U_PCB_REGS+(T0 * 4) + lw t1, UADDR+U_PCB_REGS+(T1 * 4) + lw t2, UADDR+U_PCB_REGS+(T2 * 4) + lw t3, UADDR+U_PCB_REGS+(T3 * 4) + lw t4, UADDR+U_PCB_REGS+(T4 * 4) + lw t5, UADDR+U_PCB_REGS+(T5 * 4) + lw t6, UADDR+U_PCB_REGS+(T6 * 4) + lw t7, UADDR+U_PCB_REGS+(T7 * 4) + lw s0, UADDR+U_PCB_REGS+(S0 * 4) + lw s1, UADDR+U_PCB_REGS+(S1 * 4) + lw s2, UADDR+U_PCB_REGS+(S2 * 4) + lw s3, UADDR+U_PCB_REGS+(S3 * 4) + lw s4, UADDR+U_PCB_REGS+(S4 * 4) + lw s5, UADDR+U_PCB_REGS+(S5 * 4) + lw s6, UADDR+U_PCB_REGS+(S6 * 4) + lw s7, UADDR+U_PCB_REGS+(S7 * 4) + lw t8, UADDR+U_PCB_REGS+(T8 * 4) + lw t9, UADDR+U_PCB_REGS+(T9 * 4) + lw gp, UADDR+U_PCB_REGS+(GP * 4) + lw sp, UADDR+U_PCB_REGS+(SP * 4) + lw s8, UADDR+U_PCB_REGS+(S8 * 4) + lw ra, UADDR+U_PCB_REGS+(RA * 4) + + j k0 + rfe + .set at +END(R3K_UserIntr) + + + +#if 0 +/*---------------------------------------------------------------------------- + * + * R3K_TLBModException -- + * + * Handle a TLB modified exception. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(R3K_TLBModException) + .set noat + tlbp # find the TLB entry + mfc0 k0, COP_0_TLB_LO0 # get the physical address + mfc0 k1, COP_0_TLB_INDEX # check to be sure its valid + or k0, k0, VM_TLB_MOD_BIT # update TLB + blt k1, zero, 4f # not found!!! + mtc0 k0, COP_0_TLB_LO0 + li k1, CACHED_MEMORY_ADDR + subu k0, k0, k1 + srl k0, k0, VM_TLB_PHYS_PAGE_SHIFT + la k1, pmap_attributes + addu k0, k0, k1 + lbu k1, 0(k0) # fetch old value + nop + or k1, k1, 1 # set modified bit + sb k1, 0(k0) # save new value + mfc0 k0, COP_0_EXC_PC # get return address + nop + j k0 + rfe +4: + break 0 # panic + .set at +END(R3K_TLBModException) +#endif + +/*---------------------------------------------------------------------------- + * + * R3K_TLBMissException -- + * + * Handle a TLB miss exception from kernel mode. + * The BaddVAddr, Context, and EntryHi registers contain the failed + * virtual address. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NLEAF(R3K_TLBMissException) + .set noat + mfc0 k0, COP_0_BAD_VADDR # get the fault address + li k1, VM_MIN_KERNEL_ADDRESS # compute index + subu k0, k0, k1 + lw k1, Sysmapsize # index within range? + srl k0, k0, PGSHIFT + sltu k1, k0, k1 + beq k1, zero, 1f # No. check for valid stack + nop + lw k1, Sysmap + sll k0, k0, 2 # compute offset from index + addu k1, k1, k0 + lw k0, 0(k1) # get PTE entry + mfc0 k1, COP_0_EXC_PC # get return address + mtc0 k0, COP_0_TLB_LO0 # save PTE entry + and k0, k0, PG_V # check for valid entry + beq k0, zero, R3K_KernGenException # PTE invalid + nop + tlbwr # update TLB + j k1 + rfe + +1: + subu k0, sp, UADDR + 0x200 # check to see if we have a + sltiu k0, UPAGES*NBPG - 0x200 # valid kernel stack + bne k0, zero, R3K_KernGenException # Go panic + nop + + la a0, start - START_FRAME - 8 # set sp to a valid place + sw sp, 24(a0) + move sp, a0 + la a0, 1f + mfc0 a2, COP_0_STATUS_REG + mfc0 a3, COP_0_CAUSE_REG + mfc0 a1, COP_0_EXC_PC + sw a2, 16(sp) + sw a3, 20(sp) + move a2, ra + jal printf + mfc0 a3, COP_0_BAD_VADDR + .data +1: + .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" + .text + + la sp, start - START_FRAME # set sp to a valid place + PANIC("kernel stack overflow") + .set at +END(R3K_TLBMissException) + +/*---------------------------------------------------------------------------- + * + * wbflush -- + * + * Return when the write buffer is empty. + * + * wbflush() + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(wbflush) + lbu v0,0xa0000000 + nop + j ra + nop +END(wbflush) + + +/*-------------------------------------------------------------------------- + * + * R3K_TLBWriteIndexed -- + * + * Write the given entry into the TLB at the given index. + * + * R3K_TLBWriteIndexed(index, highEntry, lowEntry) + * int index; + * int highEntry; + * int lowEntry; + * + * Results: + * None. + * + * Side effects: + * TLB entry set. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_TLBWriteIndexed) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t0, COP_0_TLB_HI # Save the current PID. + + sll a0, a0, R3K_TLB_INDEX_SHIFT + mtc0 a0, COP_0_TLB_INDEX # Set the index. + mtc0 a1, COP_0_TLB_HI # Set up entry high. + mtc0 a2, COP_0_TLB_LO0 # Set up entry low. + nop + tlbwi # Write the TLB + + mtc0 t0, COP_0_TLB_HI # Restore the PID. + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R3K_TLBWriteIndexed) + +/*-------------------------------------------------------------------------- + * + * R3K_SetPID -- + * + * Write the given pid into the TLB pid reg. + * + * R3K_SetPID(pid) + * int pid; + * + * Results: + * None. + * + * Side effects: + * PID set in the entry hi register. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_SetPID) + sll a0, a0, R3K_PID_SHIFT # put PID in right spot + mtc0 a0, COP_0_TLB_HI # Write the hi reg value + j ra + nop +END(R3K_SetPID) + +/*-------------------------------------------------------------------------- + * + * R3K_TLBFlush -- + * + * Flush the "random" entries from the TLB. + * + * R3K_TLBFlush() + * + * Results: + * None. + * + * Side effects: + * The TLB is flushed. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_TLBFlush) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t0, COP_0_TLB_HI # Save the PID + li t1, CACHED_MEMORY_ADDR # invalid address + mtc0 t1, COP_0_TLB_HI # Mark entry high as invalid + mtc0 zero, COP_0_TLB_LO0 # Zero out low entry. +/* + * Align the starting value (t1) and the upper bound (t2). + */ + li t1, R3K_NUM_WIRED_ENTRIES << R3K_TLB_INDEX_SHIFT + li t2, R3K_NUM_TLB_ENTRIES << R3K_TLB_INDEX_SHIFT +1: + mtc0 t1, COP_0_TLB_INDEX # Set the index register. + addu t1, t1, 1 << R3K_TLB_INDEX_SHIFT # Increment index. + bne t1, t2, 1b + tlbwi # Write the TLB entry. + + mtc0 t0, COP_0_TLB_HI # Restore the PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R3K_TLBFlush) + +/*-------------------------------------------------------------------------- + * + * R3K_TLBFlushAddr -- + * + * Flush any TLB entries for the given address and TLB PID. + * + * R3K_TLBFlushAddr(highreg) + * unsigned highreg; + * + * Results: + * None. + * + * Side effects: + * The process's page is flushed from the TLB. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_TLBFlushAddr) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t0, COP_0_TLB_HI # Get current PID + nop + + mtc0 a0, COP_0_TLB_HI # look for addr & PID + nop + tlbp # Probe for the entry. + mfc0 v0, COP_0_TLB_INDEX # See what we got + li t1, CACHED_MEMORY_ADDR # Load invalid entry. + bltz v0, 1f # index < 0 => !found + mtc0 t1, COP_0_TLB_HI # Mark entry high as invalid + mtc0 zero, COP_0_TLB_LO0 # Zero out low entry. + nop + tlbwi +1: + mtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R3K_TLBFlushAddr) + +/*-------------------------------------------------------------------------- + * + * R3K_TLBUpdate -- + * + * Update the TLB if highreg is found; otherwise, enter the data. + * + * R3K_TLBUpdate(highreg, lowreg) + * unsigned highreg, lowreg; + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_TLBUpdate) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t0, COP_0_TLB_HI # Save current PID + nop # 2 cycles before intr disabled + mtc0 a0, COP_0_TLB_HI # init high reg. + nop + tlbp # Probe for the entry. + mfc0 v0, COP_0_TLB_INDEX # See what we got + mtc0 a1, COP_0_TLB_LO0 # init low reg. + bltz v0, 1f # index < 0 => !found + sra v0, v0, R3K_TLB_INDEX_SHIFT # convert index to regular num + b 2f + tlbwi # update slot found +1: + mtc0 a0, COP_0_TLB_HI # init high reg. + nop + tlbwr # enter into a random slot +2: + mtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R3K_TLBUpdate) + +/*-------------------------------------------------------------------------- + * + * R3K_TLBFind -- + * + * Search the TLB for the given entry. + * + * R3K_TLBFind(hi) + * unsigned hi; + * + * Results: + * Returns a value >= 0 if the entry was found (the index). + * Returns a value < 0 if the entry was not found. + * + * Side effects: + * tlbhi and tlblo will contain the TLB entry found. + * + *-------------------------------------------------------------------------- + */ + .comm tlbhi, 4 + .comm tlblo, 4 +LEAF(R3K_TLBFind) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t0, COP_0_TLB_HI # Get current PID + nop + mtc0 a0, COP_0_TLB_HI # Set up entry high. + nop + tlbp # Probe for the entry. + mfc0 v0, COP_0_TLB_INDEX # See what we got + nop + bltz v0, 1f # not found + nop + tlbr # read TLB + mfc0 t1, COP_0_TLB_HI # See what we got + mfc0 t2, COP_0_TLB_LO0 # See what we got + sw t1, tlbhi + sw t2, tlblo + srl v0, v0, R3K_TLB_INDEX_SHIFT # convert index to regular num +1: + mtc0 t0, COP_0_TLB_HI # Restore current PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R3K_TLBFind) + +/*-------------------------------------------------------------------------- + * + * R3K_TLBRead -- + * + * Read the TLB entry. + * + * R3K_TLBRead(entry) + * unsigned entry; + * + * Results: + * None. + * + * Side effects: + * tlbhi and tlblo will contain the TLB entry found. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_TLBRead) + mfc0 v1, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts + mfc0 t0, COP_0_TLB_HI # Get current PID + + sll a0, a0, R3K_TLB_INDEX_SHIFT + mtc0 a0, COP_0_TLB_INDEX # Set the index register + nop + tlbr # Read from the TLB + mfc0 t3, COP_0_TLB_HI # fetch the hi entry + mfc0 t4, COP_0_TLB_LO0 # fetch the low entry + sw t3, tlbhi + sw t4, tlblo + + mtc0 t0, COP_0_TLB_HI # restore PID + j ra + mtc0 v1, COP_0_STATUS_REG # Restore the status register +END(R3K_TLBRead) + +/*-------------------------------------------------------------------------- + * + * R3K_TLBGetPID -- + * + * R3K_TLBGetPID() + * + * Results: + * Returns the current TLB pid reg. + * + * Side effects: + * None. + * + *-------------------------------------------------------------------------- + */ +LEAF(R3K_TLBGetPID) + mfc0 v0, COP_0_TLB_HI # get PID + nop + and v0, v0, R3K_PID_MASK # mask off PID + j ra + srl v0, v0, R3K_PID_SHIFT # put PID in right spot +END(R3K_TLBGetPID) + +/*---------------------------------------------------------------------------- + * + * R3K_ConfigCache -- + * + * Size the caches. + * NOTE: should only be called from mips_init(). + * + * Results: + * None. + * + * Side effects: + * The size of the data cache is stored into CpuPrimaryDataCacheSize and + * the size of instruction cache is stored into CpuPrimaryInstCacheSize. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(R3K_ConfigCache, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + sw ra, STAND_RA_OFFSET(sp) # Save return address. + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + mtc0 zero, COP_0_STATUS_REG # Disable interrupts. + la v0, 1f + or v0, UNCACHED_MEMORY_ADDR # Run uncached. + j v0 + nop +1: +/* + * This works because jal doesn't change pc[31..28] and the + * linker still thinks SizeCache is in the cached region so it computes + * the correct address without complaining. + */ + jal R3K_SizeCache # Get the size of the d-cache. + nop + sw v0, CpuPrimaryDataCacheSize + nop # Make sure sw out of pipe + nop + nop + nop + li v0, SR_SWAP_CACHES # Swap caches + mtc0 v0, COP_0_STATUS_REG + nop # Insure caches stable + nop + nop + nop + jal R3K_SizeCache # Get the size of the i-cache. + nop + mtc0 zero, COP_0_STATUS_REG # Swap back caches and enable. + nop + nop + nop + nop + sw v0, CpuPrimaryInstCacheSize + la t0, 1f + j t0 # Back to cached mode + nop +1: + lw ra, STAND_RA_OFFSET(sp) # Restore return addr + addu sp, sp, STAND_FRAME_SIZE # Restore sp. + j ra + nop +END(R3K_ConfigCache) + +/*---------------------------------------------------------------------------- + * + * R3K_SizeCache -- + * + * Get the size of the cache. + * + * Results: + * The size of the cache. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(R3K_SizeCache) + mfc0 t0, COP_0_STATUS_REG # Save the current status reg. + nop + or v0, t0, SR_ISOL_CACHES # Isolate the caches. + nop # Make sure no stores in pipe + mtc0 v0, COP_0_STATUS_REG + nop # Make sure isolated + nop + nop +/* + * Clear cache size boundaries. + */ + li v0, MIN_CACHE_SIZE + li v1, CACHED_MEMORY_ADDR + li t2, MAX_CACHE_SIZE +1: + addu t1, v0, v1 # Compute address to clear + sw zero, 0(t1) # Clear cache memory + bne v0, t2, 1b + sll v0, v0, 1 + + li v0, -1 + sw v0, 0(v1) # Store marker in cache + li v0, MIN_CACHE_SIZE +2: + addu t1, v0, v1 # Compute address + lw t3, 0(t1) # Look for marker + nop + bne t3, zero, 3f # Found marker. + nop + bne v0, t2, 2b # keep looking + sll v0, v0, 1 # cache size * 2 + + move v0, zero # must be no cache +3: + mtc0 t0, COP_0_STATUS_REG + nop # Make sure unisolated + nop + nop + nop + j ra + nop +END(R3K_SizeCache) + +/*---------------------------------------------------------------------------- + * + * R3K_FlushCache -- + * + * Flush the caches. + * + * Results: + * None. + * + * Side effects: + * The contents of the caches is flushed. + * + *---------------------------------------------------------------------------- + */ +LEAF(R3K_FlushCache) + lw t1, CpuPrimaryInstCacheSize # Must load before isolating + lw t2, CpuPrimaryDataCacheSize # Must load before isolating + mfc0 t3, COP_0_STATUS_REG # Save the status register. + mtc0 zero, COP_0_STATUS_REG # Disable interrupts. + la v0, 1f + or v0, UNCACHED_MEMORY_ADDR # Run uncached. + j v0 + nop +/* + * Flush the instruction cache. + */ +1: + li v0, SR_ISOL_CACHES | SR_SWAP_CACHES + mtc0 v0, COP_0_STATUS_REG # Isolate and swap caches. + li t0, UNCACHED_MEMORY_ADDR + subu t0, t0, t1 + li t1, UNCACHED_MEMORY_ADDR + la v0, 1f # Run cached + j v0 + nop +1: + addu t0, t0, 4 + bne t0, t1, 1b + sb zero, -4(t0) + + la v0, 1f + or v0, UNCACHED_MEMORY_ADDR + j v0 # Run uncached + nop +/* + * Flush the data cache. + */ +1: + li v0, SR_ISOL_CACHES + mtc0 v0, COP_0_STATUS_REG # Isolate and swap back caches + li t0, UNCACHED_MEMORY_ADDR + subu t0, t0, t2 + la v0, 1f + j v0 # Back to cached mode + nop +1: + addu t0, t0, 4 + bne t0, t1, 1b + sb zero, -4(t0) + + nop # Insure isolated stores + nop # out of pipe. + nop + nop + mtc0 t3, COP_0_STATUS_REG # Restore status reg. + nop # Insure cache unisolated. + nop + nop + nop + j ra + nop +END(R3K_FlushCache) + +/*---------------------------------------------------------------------------- + * + * R3K_FlushICache -- + * + * void R3K_FlushICache(addr, len) + * vm_offset_t addr, len; + * + * Flush instruction cache for range of addr to addr + len - 1. + * The address can be any valid address so long as no TLB misses occur. + * + * Results: + * Returns zero. + * + * Side effects: + * The contents of the cache is flushed. + * + *---------------------------------------------------------------------------- + */ +LEAF(R3K_FlushICache) + mfc0 t0, COP_0_STATUS_REG # Save SR + mtc0 zero, COP_0_STATUS_REG # Disable interrupts. + + la v1, 1f + or v1, UNCACHED_MEMORY_ADDR # Run uncached. + j v1 + nop + +1: + lbu v1, 0xa0000000 # make sure stores are complete +# XXX is executing from uncached sufficient so the above can be skipped? + li v1, SR_ISOL_CACHES | SR_SWAP_CACHES + mtc0 v1, COP_0_STATUS_REG + nop + addu a1, a1, a0 # compute ending address +2: + addu a0, a0, 4 + bne a0, a1, 2b + sb zero, -4(a0) + + mtc0 t0, COP_0_STATUS_REG # enable interrupts + j ra # return and run cached + li v0, 0 +END(R3K_FlushICache) + +/*---------------------------------------------------------------------------- + * + * R3K_FlushDCache -- + * + * void R3K_FlushDCache(addr, len) + * vm_offset_t addr, len; + * + * Flush data cache for range of addr to addr + len - 1. + * The address can be any valid address so long as no TLB misses occur. + * (Be sure to use cached K0SEG kernel addresses) + * Results: + * None. + * + * Side effects: + * The contents of the cache is flushed. + * + *---------------------------------------------------------------------------- + */ +LEAF(R3K_FlushDCache) +ALEAF(R3K_HitFlushDCache) + mfc0 t0, COP_0_STATUS_REG # Save SR + mtc0 zero, COP_0_STATUS_REG # Disable interrupts. + nop + + lbu v1, 0xa0000000 # make sure stores are complete + + li v1, SR_ISOL_CACHES + mtc0 v1, COP_0_STATUS_REG + nop + addu t1, a1, a0 # compute ending address +1: + sb zero, 0(a0) + sb zero, 4(a0) + sb zero, 8(a0) + sb zero, 12(a0) + sb zero, 16(a0) + sb zero, 20(a0) + sb zero, 24(a0) + addu a0, 32 + bltu a0, t1, 1b + sb zero, -4(a0) + + nop # drain pipeline + nop + mtc0 t0, COP_0_STATUS_REG # enable interrupts + nop + j ra # return and run cached + nop +END(R3K_FlushDCache) + +#endif /* ==================XXXXX============================== */ + +/* + * Set/clear software interrupt routines. + */ + +LEAF(setsoftclock) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + or v0, v0, SOFT_INT_MASK_0 # set soft clock interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(setsoftclock) + +LEAF(clearsoftclock) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + and v0, v0, ~SOFT_INT_MASK_0 # clear soft clock interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(clearsoftclock) + +LEAF(setsoftnet) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + or v0, v0, SOFT_INT_MASK_1 # set soft net interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(setsoftnet) + +LEAF(clearsoftnet) + mfc0 v0, COP_0_CAUSE_REG # read cause register + nop + and v0, v0, ~SOFT_INT_MASK_1 # clear soft net interrupt + mtc0 v0, COP_0_CAUSE_REG # save it + j ra + nop +END(clearsoftnet) + +/* + * Set/change interrupt priority routines. + */ + +LEAF(CPU_EnableIntr) + mfc0 v0, COP_0_STATUS_REG # read status register + nop + or v0, v0, SR_INT_ENAB + mtc0 v0, COP_0_STATUS_REG # enable all interrupts + j ra + nop +END(CPU_EnableIntr) + +LEAF(spl0) + mfc0 v0, COP_0_STATUS_REG # read status register + nop + or t0, v0, (INT_MASK | SR_INT_ENAB) + mtc0 t0, COP_0_STATUS_REG # enable all interrupts + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(spl0) + +LEAF(splsoftclock) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~SOFT_INT_MASK_0 # disable soft clock + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(splsoftclock) + +LEAF(splsoftnet) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(splsoftnet) + +LEAF(CPU__spl0) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_0|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(CPU__spl0) + +LEAF(CPU__spl1) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_1|SOFT_INT_MASK_0|SOFT_INT_MASK_1) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(CPU__spl1) + +LEAF(CPU__spl2) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_2|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(CPU__spl2) + +LEAF(CPU__spl3) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_3|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(CPU__spl3) + +LEAF(CPU__spl4) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_4|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(CPU__spl4) + +LEAF(CPU__spl5) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~(INT_MASK_5|SOFT_INT_MASK_1|SOFT_INT_MASK_0) + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(CPU__spl5) + +/* + * We define an alternate entry point after mcount is called so it + * can be used in mcount without causeing a recursive loop. + */ +LEAF(splhigh) +ALEAF(_splhigh) + mfc0 v0, COP_0_STATUS_REG # read status register + li t0, ~SR_INT_ENAB # disable all interrupts + and t0, t0, v0 + mtc0 t0, COP_0_STATUS_REG # save it + nop # 3 ins to disable + j ra + and v0, v0, (INT_MASK | SR_INT_ENAB) +END(splhigh) + +/* + * Restore saved interrupt mask. + */ +LEAF(splx) +ALEAF(_splx) + mfc0 v0, COP_0_STATUS_REG + li t0, ~(INT_MASK | SR_INT_ENAB) + and t0, t0, v0 + or t0, t0, a0 + mtc0 t0, COP_0_STATUS_REG + nop # 3 ins to disable + j ra + nop +END(splx) + +/*---------------------------------------------------------------------------- + * + * CPU_SwitchFPState -- + * + * Save the current state into 'from' and restore it from 'to'. + * + * CPU_SwitchFPState(from, to) + * struct proc *from; + * struct user *to; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +LEAF(CPU_SwitchFPState) + mfc0 t1, COP_0_STATUS_REG # Save old SR + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + + beq a0, zero, 1f # skip save if NULL pointer + nop +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + lw a0, P_ADDR(a0) # get pointer to pcb for proc + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + li t3, ~SR_COP_1_BIT + lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register + sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status + and t2, t2, t3 # clear COP_1 enable bit + sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register +/* + * Save the floating point registers. + */ + swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) + swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) + swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) + swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) + swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) + swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) + swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) + swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) + swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) + swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) + swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) + swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) + swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) + swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) + swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) + swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) + swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) + swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) + swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) + swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) + swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) + swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) + swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) + swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) + swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) + swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) + swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) + swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) + swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) + swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) + swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) + swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) + +1: +/* + * Restore the floating point registers. + */ + lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register + lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) + lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) + lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) + lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) + lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) + lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) + lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) + lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) + lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) + lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) + lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) + lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) + lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) + lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) + lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) + lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) + lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) + lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) + lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) + lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) + lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) + lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) + lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) + lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) + lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) + lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) + lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) + lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) + lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) + lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) + lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) + lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) + + and t0, t0, ~FPC_EXCEPTION_BITS + ctc1 t0, FPC_CSR + nop + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + j ra + nop +END(CPU_SwitchFPState) + +/*---------------------------------------------------------------------------- + * + * CPU_SaveCurFPState -- + * + * Save the current floating point coprocessor state. + * + * CPU_SaveCurFPState(p) + * struct proc *p; + * + * Results: + * None. + * + * Side effects: + * cpuFPCurProcPtr is cleared. + * + *---------------------------------------------------------------------------- + */ +LEAF(CPU_SaveCurFPState) + lw a0, P_ADDR(a0) # get pointer to pcb for proc + mfc0 t1, COP_0_STATUS_REG # Disable interrupts and + li t0, SR_COP_1_BIT # enable the coprocessor + mtc0 t0, COP_0_STATUS_REG + sw zero, cpuFPCurProcPtr # indicate state has been saved +/* + * First read out the status register to make sure that all FP operations + * have completed. + */ + lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register + li t3, ~SR_COP_1_BIT + and t2, t2, t3 # clear COP_1 enable bit + cfc1 t0, FPC_CSR # stall til FP done + cfc1 t0, FPC_CSR # now get status + sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register + sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status +/* + * Save the floating point registers. + */ + swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) + swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) + swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) + swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) + swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) + swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) + swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) + swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) + swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) + swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) + swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) + swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) + swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) + swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) + swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) + swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) + swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) + swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) + swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) + swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) + swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) + swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) + swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) + swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) + swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) + swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) + swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) + swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) + swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) + swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) + swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) + swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) + + mtc0 t1, COP_0_STATUS_REG # Restore the status register. + j ra + nop +END(CPU_SaveCurFPState) + +/*---------------------------------------------------------------------------- + * + * CPU_FPTrap -- + * + * Handle a floating point Trap. + * + * CPU_FPTrap(statusReg, causeReg, pc) + * unsigned statusReg; + * unsigned causeReg; + * unsigned pc; + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ +NON_LEAF(CPU_FPTrap, STAND_FRAME_SIZE, ra) + subu sp, sp, STAND_FRAME_SIZE + mfc0 t0, COP_0_STATUS_REG + sw ra, STAND_RA_OFFSET(sp) + .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) + + or t1, t0, SR_COP_1_BIT + mtc0 t1, COP_0_STATUS_REG + nop + nop + nop + nop + cfc1 t1, FPC_CSR # stall til FP done + cfc1 t1, FPC_CSR # now get status + nop + sll t2, t1, (31 - 17) # unimplemented operation? + bgez t2, 3f # no, normal trap + nop +/* + * We got an unimplemented operation trap so + * fetch the instruction, compute the next PC and emulate the instruction. + */ + bgez a1, 1f # Check the branch delay bit. + nop +/* + * The instruction is in the branch delay slot so the branch will have to + * be emulated to get the resulting PC. + */ + sw a2, STAND_FRAME_SIZE + 8(sp) + li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers + move a1, a2 # second arg is instruction PC + move a2, t1 # third arg is floating point CSR + jal CPU_EmulateBranch # compute PC after branch + move a3, zero # fourth arg is FALSE +/* + * Now load the floating-point instruction in the branch delay slot + * to be emulated. + */ + lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc + b 2f + lw a0, 4(a2) # a0 = coproc instruction +/* + * This is not in the branch delay slot so calculate the resulting + * PC (epc + 4) into v0 and continue to CPU_EmulateFP(). + */ +1: + lw a0, 0(a2) # a0 = coproc instruction + addu v0, a2, 4 # v0 = next pc +2: + sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc +/* + * Check to see if the instruction to be emulated is a floating-point + * instruction. + */ + srl a3, a0, OPCODE_SHIFT + beq a3, OPCODE_C1, 4f # this should never fail + nop +/* + * Send a floating point exception signal to the current process. + */ +3: + lw a0, curproc # get current process + cfc1 a2, FPC_CSR # code = FP execptions + ctc1 zero, FPC_CSR # Clear exceptions + jal trapsignal + li a1, SIGFPE + b FPReturn + nop + +/* + * Finally, we can call CPU_EmulateFP() where a0 is the instruction to emulate. + */ +4: + jal CPU_EmulateFP + nop + +/* + * Turn off the floating point coprocessor and return. + */ +FPReturn: + mfc0 t0, COP_0_STATUS_REG + lw ra, STAND_RA_OFFSET(sp) + and t0, t0, ~SR_COP_1_BIT + mtc0 t0, COP_0_STATUS_REG + j ra + addu sp, sp, STAND_FRAME_SIZE +END(CPU_FPTrap) + +#ifdef DEBUG +/* + * Read a long and return it. + * Note: addresses can be unaligned! + * + * long +L* mdbpeek(addr) +L* caddt_t addr; +L* { +L* return (*(long *)addr); +L* } + */ +LEAF(mdbpeek) + li v0, MDBERR + sw v0, UADDR+U_PCB_ONFAULT + and v0, a0, 3 # unaligned address? + bne v0, zero, 1f + nop + b 2f + lw v0, (a0) # aligned access +1: + LWHI v0, 0(a0) # get next 4 bytes (unaligned) + LWLO v0, 3(a0) +2: + j ra # made it w/o errors + sw zero, UADDR+U_PCB_ONFAULT +mdberr: + li v0, 1 # trap sends us here + sw v0, mdbmkfault + j ra + nop +END(mdbpeek) + +/* + * Write a long to 'addr'. + * Note: addresses can be unaligned! + * +L* void +L* mdbpoke(addr, value) +L* caddt_t addr; +L* long value; +L* { +L* *(long *)addr = value; +L* } + */ +LEAF(mdbpoke) + li v0, MDBERR + sw v0, UADDR+U_PCB_ONFAULT + and v0, a0, 3 # unaligned address? + bne v0, zero, 1f + nop + b 2f + sw a1, (a0) # aligned access +1: + SWHI a1, 0(a0) # store next 4 bytes (unaligned) + SWLO a1, 3(a0) + and a0, a0, ~3 # align address for cache flush +2: + sw zero, UADDR+U_PCB_ONFAULT +#ifdef R4K + b R4K_FlushICache # flush instruction cache +#else + b R3K_FlushICache # flush instruction cache +#endif + li a1, 8 +END(mdbpoke) + +/* + * Save registers and state so we can do a 'mdbreset' (like longjmp) later. + * Always returns zero. + * +L* int mdb_savearea[11]; +L* +L* int +L* mdbsetexit() +L* { +L* mdb_savearea[0] = 0; +L* return (0); +L* } + */ + .comm mdb_savearea, (11 * 4) + +LEAF(mdbsetexit) + la a0, mdb_savearea + sw s0, 0(a0) + sw s1, 4(a0) + sw s2, 8(a0) + sw s3, 12(a0) + sw s4, 16(a0) + sw s5, 20(a0) + sw s6, 24(a0) + sw s7, 28(a0) + sw sp, 32(a0) + sw s8, 36(a0) + sw ra, 40(a0) + j ra + move v0, zero +END(mdbsetexit) + +/* + * Restore registers and state (like longjmp) and return x. + * +L* int +L* mdbreset(x) +L* { +L* return (x); +L* } + */ +LEAF(mdbreset) + la v0, mdb_savearea + lw ra, 40(v0) + lw s0, 0(v0) + lw s1, 4(v0) + lw s2, 8(v0) + lw s3, 12(v0) + lw s4, 16(v0) + lw s5, 20(v0) + lw s6, 24(v0) + lw s7, 28(v0) + lw sp, 32(v0) + lw s8, 36(v0) + j ra + move v0, a0 +END(mdbreset) + +/* + * Trap into the debugger. + */ +LEAF(mdbpanic) + break BREAK_SOVER_VAL + j ra + nop +END(mdbpanic) +#endif /* DEBUG */ + +#ifdef DEBUG +LEAF(cpu_getregs) + sw sp, 0(a0) + sw ra, 4(a0) + j ra + sw s8, 8(a0) +END(cpu_getregs) +#endif /* DEBUG */ + +/* + * Interrupt counters for vmstat. + */ + .data + .globl intrcnt + .globl eintrcnt + .globl intrnames + .globl eintrnames +intrnames: + .asciiz "softclock" + .asciiz "softnet" + .asciiz "local_dma" + .asciiz "local_dev" + .asciiz "isa_dev" + .asciiz "isa_nmi" + .asciiz "clock" + .asciiz "statclock" +eintrnames: + .align 3 +intrcnt: + .word 0,0,0,0,0,0,0,0 +eintrcnt: diff --git a/sys/arch/wgrisc/wgrisc/machdep.c b/sys/arch/wgrisc/wgrisc/machdep.c new file mode 100644 index 00000000000..427b4d950a4 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/machdep.c @@ -0,0 +1,1060 @@ +/* $OpenBSD: machdep.c,v 1.1 1997/02/06 16:02:46 pefo 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, The Mach Operating System project at + * Carnegie-Mellon University 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: @(#)machdep.c 8.3 (Berkeley) 1/12/94 + * $Id: machdep.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + +/* from: Utah Hdr: machdep.c 1.63 91/04/24 */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/signalvar.h> +#include <sys/kernel.h> +#include <sys/map.h> +#include <sys/proc.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/clist.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/msgbuf.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/user.h> +#include <sys/exec.h> +#include <sys/sysctl.h> +#include <sys/mount.h> +#include <sys/syscallargs.h> +#ifdef SYSVSHM +#include <sys/shm.h> +#endif +#ifdef SYSVSEM +#include <sys/sem.h> +#endif +#ifdef SYSVMSG +#include <sys/msg.h> +#endif + +#include <vm/vm_kern.h> + +#include <machine/cpu.h> +#include <machine/reg.h> +#include <machine/pio.h> +#include <machine/psl.h> +#include <machine/pte.h> +#include <machine/autoconf.h> +#include <machine/memconf.h> + +#include <sys/exec_ecoff.h> + +#include <dev/cons.h> + +#include <wgrisc/wgrisc/wgrisctype.h> +#include <wgrisc/riscbus/riscbus.h> + +extern struct consdev *cn_tab; + +/* the following is used externally (sysctl_hw) */ +char machine[] = "wgrisc"; /* cpu "architecture" */ +char cpu_model[30]; + +vm_map_t buffer_map; + +/* + * Declare these as initialized data so we can patch them. + */ +int nswbuf = 0; +#ifdef NBUF +int nbuf = NBUF; +#else +int nbuf = 0; +#endif +#ifdef BUFPAGES +int bufpages = BUFPAGES; +#else +int bufpages = 0; +#endif +int msgbufmapped = 0; /* set when safe to use msgbuf */ +int physmem; /* max supported memory, changes to actual */ +int cpucfg; /* Value of processor config register */ +int cputype; /* Mother board type */ +int ncpu = 1; /* At least one cpu in the system */ +int isa_io_base; /* Base address of ISA io port space */ +int isa_mem_base; /* Base address of ISA memory space */ + +struct mem_descriptor mem_layout[MAXMEMSEGS]; + +extern int Mach_spl0(), Mach_spl1(), Mach_spl2(), Mach_spl3(); +extern int Mach_spl4(), Mach_spl5(), splhigh(); +int (*Mach_splnet)() = splhigh; +int (*Mach_splbio)() = splhigh; +int (*Mach_splimp)() = splhigh; +int (*Mach_spltty)() = splhigh; +int (*Mach_splclock)() = splhigh; +int (*Mach_splstatclock)() = splhigh; + +static void tlb_init_pica(); +static void tlb_init_tyne(); + + +/* + * safepri is a safe priority for sleep to set for a spin-wait + * during autoconfiguration or after a panic. + */ +int safepri = PSL_LOWIPL; + +struct user *proc0paddr; +struct proc nullproc; /* for use by swtch_exit() */ + +/* + * Do all the stuff that locore normally does before calling main(). + * Process arguments passed to us by the BOOT. + * Reset mapping and set up mapping to hardware and init "wired" reg. + * Return the first page address following the system. + */ +mips_init(argc, argv, code) + int argc; + char *argv[]; + u_int code; +{ + register char *cp; + register int i; + register unsigned firstaddr; + register caddr_t sysend; + caddr_t start; + struct tlb tlb; + extern char _ftext[], edata[], end[]; + + /* clear the BSS segment in OpenBSD code */ + sysend = (caddr_t)mips_round_page(end); + bzero(edata, sysend - edata); + + /* Initialize the CPU type */ + cputype = WGRISC9100; + mem_layout[0].mem_start = 0; + mem_layout[0].mem_size = mips_trunc_page(CACHED_TO_PHYS(_ftext)); + mem_layout[1].mem_start = CACHED_TO_PHYS((int)sysend); + mem_layout[1].mem_size = 0x400000 - (int)(CACHED_TO_PHYS(sysend)); + physmem = 4096 * 1024; + + + switch (cputype) { + case WGRISC9100: + strcpy(cpu_model, "Willowglen RISC PC 9100"); + isa_io_base = RISC_ISA_IO_BASE; + isa_mem_base = RISC_ISA_MEM_BASE; + + /* + * Set up interrupt handling and I/O addresses. + */ +#if 0 /* XXX FIXME */ + Mach_splnet = Mach_spl1; + Mach_splbio = Mach_spl0; + Mach_splimp = Mach_spl1; + Mach_spltty = Mach_spl2; + Mach_splstatclock = Mach_spl3; +#endif + break; + + default: + boot(RB_HALT | RB_NOSYNC); + } + physmem = btoc(physmem); + + /* look at argv[0] and compute bootdev for autoconfig setup */ + makebootdev(argv[0]); + + /* + * Look at arguments passed to us and compute boothowto. + * Default to SINGLE and ASKNAME if no args. + */ + boothowto = RB_SINGLE | RB_ASKNAME; +#ifdef KADB + boothowto |= RB_KDB; +#endif + if (argc > 1) { + for (i = 1; i < argc; i++) { + if(strncasecmp("osloadoptions=",argv[i],14) == 0) { + for (cp = argv[i]+14; *cp; cp++) { + switch (*cp) { + case 'a': /* autoboot */ + boothowto &= ~RB_SINGLE; + break; + + case 'd': /* use compiled in default root */ + boothowto |= RB_DFLTROOT; + break; + + case 'm': /* mini root present in memory */ + boothowto |= RB_MINIROOT; + break; + + case 'n': /* ask for names */ + boothowto |= RB_ASKNAME; + break; + + case 'N': /* don't ask for names */ + boothowto &= ~RB_ASKNAME; + break; + } + + } + } + } + } + +#ifdef MFS + /* + * Check to see if a mini-root was loaded into memory. It resides + * at the start of the next page just after the end of BSS. + */ + if (boothowto & RB_MINIROOT) { + boothowto |= RB_DFLTROOT; + sysend += mfs_initminiroot(sysend); + } +#endif + +#ifdef R4K + R4K_SetWIRED(0); + R4K_TLBFlush(); + R4K_SetWIRED(R4K_NUM_WIRED_ENTRIES); + + switch (cputype) { + case ACER_PICA_61: + tlb_init_pica(); + break; + } + +#else + R3K_TLBFlush(); +#endif + + /* + * Init mapping for u page(s) for proc[0], pm_tlbpid 1. + */ + sysend = (caddr_t)((int)sysend + 3 & -4); + start = sysend; + curproc->p_addr = proc0paddr = (struct user *)sysend; + curproc->p_md.md_regs = proc0paddr->u_pcb.pcb_regs; + firstaddr = CACHED_TO_PHYS(sysend); + for (i = 0; i < UPAGES;) { +#ifdef R4K + tlb.tlb_mask = PG_SIZE_4K; + tlb.tlb_hi = vad_to_vpn((UADDR + (i << PGSHIFT))) | 1; + tlb.tlb_lo0 = vad_to_pfn(firstaddr) | PG_V | PG_M | PG_CACHED; + tlb.tlb_lo1 = vad_to_pfn(firstaddr + NBPG) | PG_V | PG_M | PG_CACHED; + curproc->p_md.md_upte[i] = tlb.tlb_lo0; + curproc->p_md.md_upte[i+1] = tlb.tlb_lo1; + R4K_TLBWriteIndexed(i,&tlb); + firstaddr += NBPG * 2; + i += 2; + R4K_SetPID(1); +#else + R3K_TLBWriteIndexed(i, + (UADDR + (i << PGSHIFT)) | (1 << R3K_PID_SHIFT), + (curproc->p_md.md_upte[i] = firstaddr | PG_V | PG_M)); + firstaddr += NBPG; + i += 1; + R3K_SetPID(1); +#endif + } + sysend += UPAGES * NBPG; + sysend = (caddr_t)((int)sysend+3 & -4); + + /* + * init nullproc for swtch_exit(). + * init mapping for u page(s), pm_tlbpid 0 + * This could be used for an idle process. + */ + nullproc.p_addr = (struct user *)sysend; + nullproc.p_md.md_regs = nullproc.p_addr->u_pcb.pcb_regs; + bcopy("nullproc", nullproc.p_comm, sizeof("nullproc")); + firstaddr = CACHED_TO_PHYS(sysend); + for (i = 0; i < UPAGES; i+=2) { + nullproc.p_md.md_upte[i] = vad_to_pfn(firstaddr) | PG_V | PG_M | PG_CACHED; + nullproc.p_md.md_upte[i+1] = vad_to_pfn(firstaddr + NBPG) | PG_V | PG_M | PG_CACHED; + firstaddr += NBPG * 2; + } + sysend += UPAGES * NBPG; + + /* clear pages for u areas */ + bzero(start, sysend - start); + + /* + * Copy down exception vector code. + */ + { +#ifdef R4K + extern char R4K_TLBMiss[], R4K_TLBMissEnd[]; + extern char R4K_Exception[], R4K_ExceptionEnd[]; + + if (R4K_TLBMissEnd - R4K_TLBMiss > 0x80) + panic("startup: TLB code too large"); + bcopy(R4K_TLBMiss, (char *)R4K_TLB_MISS_EXC_VEC, + R4K_TLBMissEnd - R4K_TLBMiss); + bcopy(R4K_Exception, (char *)R4K_GEN_EXC_VEC, + R4K_ExceptionEnd - R4K_Exception); + + cpucfg = R4K_ConfigCache(); + R4K_FlushCache(); +#else + extern char R3K_UTLBMiss[], R3K_UTLBMissEnd[]; + extern char R3K_Exception[], R3K_ExceptionEnd[]; + if (R3K_UTLBMissEnd - R3K_UTLBMiss > 0x80) + panic("startup: TLB code too large"); + bcopy(R3K_UTLBMiss, (char *)R3K_TLB_MISS_EXC_VEC, + R3K_UTLBMissEnd - R3K_UTLBMiss); + bcopy(R3K_Exception, (char *)R3K_GEN_EXC_VEC, + R3K_ExceptionEnd - R3K_Exception); + + cpucfg = R3K_ConfigCache(); + R3K_FlushCache(); +#endif + } + + /* + * Initialize error message buffer. + */ + msgbufp = (struct msgbuf *)(sysend); + sysend = (caddr_t)(sysend + (sizeof(struct msgbuf))); + msgbufmapped = 1; + + /* + * Allocate space for system data structures. + * The first available kernel virtual address is in "sysend". + * As pages of kernel virtual memory are allocated, "sysend" + * is incremented. + * + * These data structures are allocated here instead of cpu_startup() + * because physical memory is directly addressable. We don't have + * to map these into virtual address space. + */ + start = sysend; + +#define valloc(name, type, num) \ + (name) = (type *)sysend; sysend = (caddr_t)((name)+(num)) +#define valloclim(name, type, num, lim) \ + (name) = (type *)sysend; sysend = (caddr_t)((lim) = ((name)+(num))) +#ifdef REAL_CLISTS + valloc(cfree, struct cblock, nclist); +#endif + valloc(callout, struct callout, ncallout); + valloc(swapmap, struct map, nswapmap = maxproc * 2); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif +#ifdef SYSVSEM + valloc(sema, struct semid_ds, seminfo.semmni); + valloc(sem, struct sem, seminfo.semmns); + /* This is pretty disgusting! */ + valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); +#endif +#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 allocate more buffer space than the BSD standard of + * using 10% of memory for the first 2 Meg, 5% of remaining. + * We just allocate a flat 10%. Ensure a minimum of 16 buffers. + * We allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + bufpages = physmem / 10 / CLSIZE; + if (nbuf == 0) { + nbuf = bufpages; + if (nbuf < 16) + nbuf = 16; + } + if (nswbuf == 0) { + nswbuf = (nbuf / 2) &~ 1; /* force even */ + if (nswbuf > 256) + nswbuf = 256; /* sanity */ + } + valloc(swbuf, struct buf, nswbuf); + valloc(buf, struct buf, nbuf); + + /* + * Clear allocated memory. + */ + bzero(start, sysend - start); + + /* + * Initialize the virtual memory system. + */ + pmap_bootstrap((vm_offset_t)sysend); +} + +#if keep_for_future_r4k_machines +void +tlb_init_pica() +{ + struct tlb tlb; + + tlb.tlb_mask = PG_SIZE_256K; + tlb.tlb_hi = vad_to_vpn(R4030_V_LOCAL_IO_BASE); + tlb.tlb_lo0 = vad_to_pfn(R4030_P_LOCAL_IO_BASE) | PG_IOPAGE; + tlb.tlb_lo1 = vad_to_pfn(PICA_P_INT_SOURCE) | PG_IOPAGE; + R4K_TLBWriteIndexed(1, &tlb); +} +#endif + +/* + * Console initialization: called early on from main, + * before vm init or startup. Do enough configuration + * to choose and initialize a console. + */ +void +consinit() +{ + static int initted; + + if (initted) + return; + initted = 1; + cninit(); +mdbpanic(); +} + +/* + * cpu_startup: allocate memory for variable-sized tables, + * initialize cpu, and do autoconfiguration. + */ +void +cpu_startup() +{ + register unsigned i; + register caddr_t v; + int base, residual; + vm_offset_t minaddr, maxaddr; + vm_size_t size; +#ifdef DEBUG + extern int pmapdebug; + int opmapdebug = pmapdebug; + + pmapdebug = 0; /* Shut up pmap debug during bootstrap */ +#endif + + /* + * Good {morning,afternoon,evening,night}. + */ + printf(version); + printf("real mem = %d\n", ctob(physmem)); + + /* + * Allocate virtual address space for file I/O buffers. + * Note they are different than the array of headers, 'buf', + * and usually occupy more virtual memory than physical. + */ + size = MAXBSIZE * nbuf; + buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers, + &maxaddr, size, TRUE); + minaddr = (vm_offset_t)buffers; + if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0, + &minaddr, size, FALSE) != KERN_SUCCESS) + panic("startup: cannot allocate buffers"); + base = bufpages / nbuf; + residual = bufpages % nbuf; + for (i = 0; i < nbuf; i++) { + vm_size_t curbufsize; + vm_offset_t curbuf; + + /* + * First <residual> buffers get (base+1) physical pages + * allocated for them. The rest get (base) physical pages. + * + * The rest of each buffer occupies virtual space, + * but has no physical memory allocated for it. + */ + curbuf = (vm_offset_t)buffers + i * MAXBSIZE; + curbufsize = CLBYTES * (i < residual ? base+1 : base); + vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); + vm_map_simplify(buffer_map, curbuf); + } + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + 16 * NCARGS, TRUE); + /* + * Allocate a submap for physio + */ + phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + VM_PHYS_SIZE, TRUE); + + /* + * Finally, allocate mbuf pool. Since mclrefcnt is an off-size + * we use the more space efficient malloc in place of kmem_alloc. + */ + mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, + M_MBUF, M_NOWAIT); + bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); + mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr, + VM_MBUF_SIZE, FALSE); + /* + * Initialize callouts + */ + callfree = callout; + for (i = 1; i < ncallout; i++) + callout[i-1].c_next = &callout[i]; + callout[i-1].c_next = NULL; + +#ifdef DEBUG + pmapdebug = opmapdebug; +#endif + printf("avail mem = %d\n", ptoa(cnt.v_free_count)); + printf("using %d buffers containing %d bytes of memory\n", + nbuf, bufpages * CLBYTES); + /* + * Set up CPU-specific registers, cache, etc. + */ + initcpu(); + + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + /* + * Configure the system. + */ + if (boothowto & RB_CONFIG) { +#ifdef BOOT_CONFIG + user_config(); +#else + printf("kernel does not support -c; continuing..\n"); +#endif + } + configure(); + + spl0(); /* safe to turn interrupts on now */ +} + +/* + * machine dependent system variables. + */ +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 at 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 */ +} + +/* + * Set registers on exec. + * Clear all registers except sp, pc. + */ +void +setregs(p, pack, stack, retval) + register struct proc *p; + struct exec_package *pack; + u_long stack; + register_t *retval; +{ + extern struct proc *cpuFPCurProcPtr; + + bzero((caddr_t)p->p_md.md_regs, (FSR + 1) * sizeof(int)); + p->p_md.md_regs[SP] = stack; + p->p_md.md_regs[PC] = pack->ep_entry & ~3; + p->p_md.md_regs[T9] = pack->ep_entry & ~3; /* abicall req */ +#ifdef R4K + p->p_md.md_regs[PS] = R4K_PSL_USERSET; +#else + p->p_md.md_regs[PS] = R3K_PSL_USERSET; +#endif + p->p_md.md_flags & ~MDP_FPUSED; + if (cpuFPCurProcPtr == p) + cpuFPCurProcPtr = (struct proc *)0; + p->p_md.md_ss_addr = 0; +} + +/* + * WARNING: code in locore.s assumes the layout shown for sf_signum + * thru sf_handler so... don't screw with them! + */ +struct sigframe { + int sf_signum; /* signo for handler */ + siginfo_t *sf_sip; /* pointer to siginfo_t */ + 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; + u_long code; + int type; + union sigval val; +{ + register struct proc *p = curproc; + register struct sigframe *fp; + register int *regs; + register struct sigacts *psp = p->p_sigacts; + int oonstack, fsize; + struct sigcontext ksc; + extern char sigcode[], esigcode[]; + + regs = p->p_md.md_regs; + oonstack = psp->ps_sigstk.ss_flags & SA_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_siginfo & sigmask(sig))) + fsize -= sizeof(siginfo_t); + if ((psp->ps_flags & SAS_ALTSTACK) && + (psp->ps_sigstk.ss_flags & SA_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 |= SA_ONSTACK; + } else + fp = (struct sigframe *)(regs[SP] - fsize); + if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) + (void)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. + */ + ksc.sc_onstack = oonstack; + ksc.sc_mask = mask; + ksc.sc_pc = regs[PC]; + ksc.mullo = regs[MULLO]; + ksc.mulhi = regs[MULHI]; + ksc.sc_regs[ZERO] = 0xACEDBADE; /* magic number */ + bcopy((caddr_t)®s[1], (caddr_t)&ksc.sc_regs[1], + sizeof(ksc.sc_regs) - sizeof(int)); + ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED; + if (ksc.sc_fpused) { + extern struct proc *cpuFPCurProcPtr; + + /* if FPU has current state, save it first */ + if (p == cpuFPCurProcPtr) + CPU_SaveCurFPState(p); + bcopy((caddr_t)&p->p_md.md_regs[F0], (caddr_t)ksc.sc_fpregs, + sizeof(ksc.sc_fpregs)); + } + + if (psp->ps_siginfo & sigmask(sig)) { + siginfo_t si; + + initsiginfo(&si, sig, code, type, val); + if (copyout((caddr_t)&si, (caddr_t)&fp->sf_si, sizeof si)) + goto bail; + } + + if (copyout((caddr_t)&ksc, (caddr_t)&fp->sf_sc, sizeof(ksc))) { +bail: + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ + SIGACTION(p, SIGILL) = SIG_DFL; + sig = sigmask(SIGILL); + p->p_sigignore &= ~sig; + p->p_sigcatch &= ~sig; + p->p_sigmask &= ~sig; + psignal(p, SIGILL); + return; + } + /* + * Build the argument list for the signal handler. + */ + regs[A0] = sig; + regs[A1] = (psp->ps_siginfo & sigmask(sig)) ? (int)&fp->sf_si : NULL; + regs[A2] = (int)&fp->sf_sc; + regs[A3] = (int)catcher; + + regs[PC] = (int)catcher; + regs[T9] = (int)catcher; + regs[SP] = (int)fp; + /* + * Signal trampoline code is at base of user stack. + */ + regs[RA] = (int)PS_STRINGS - (esigcode - sigcode); +#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 priviledges or to cause + * a machine fault. + */ +/* ARGSUSED */ +sys_sigreturn(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sys_sigreturn_args /* { + syscallarg(struct sigcontext *) sigcntxp; + } */ *uap = v; + register struct sigcontext *scp; + register int *regs; + struct sigcontext ksc; + int error; + + scp = SCARG(uap, sigcntxp); +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); +#endif + regs = p->p_md.md_regs; + /* + * Test and fetch the context structure. + * We grab it all at once for speed. + */ + error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(ksc)); + if (error || ksc.sc_regs[ZERO] != 0xACEDBADE) { +#ifdef DEBUG + if (!(sigdebug & SDB_FOLLOW)) + printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); + printf(" old sp %x ra %x pc %x\n", + regs[SP], regs[RA], regs[PC]); + printf(" new sp %x ra %x pc %x err %d z %x\n", + ksc.sc_regs[SP], ksc.sc_regs[RA], ksc.sc_regs[PC], + error, ksc.sc_regs[ZERO]); +#endif + return (EINVAL); + } + scp = &ksc; + /* + * Restore the user supplied information + */ + if (scp->sc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + p->p_sigmask = scp->sc_mask &~ sigcantmask; + regs[PC] = scp->sc_pc; + regs[MULLO] = scp->mullo; + regs[MULHI] = scp->mulhi; + bcopy((caddr_t)&scp->sc_regs[1], (caddr_t)®s[1], + sizeof(scp->sc_regs) - sizeof(int)); + if (scp->sc_fpused) + bcopy((caddr_t)scp->sc_fpregs, (caddr_t)&p->p_md.md_regs[F0], + sizeof(scp->sc_fpregs)); + return (EJUSTRETURN); +} + +int waittime = -1; + +void +boot(howto) + register int howto; +{ + + /* take a snap shot before clobbering any registers */ + if (curproc) + savectx(curproc->p_addr, 0); + +#ifdef DEBUG + if (panicstr) + stacktrace(); +#endif + + boothowto = howto; + if ((howto & RB_NOSYNC) == 0 && waittime < 0) { + extern struct proc proc0; + /* fill curproc with live object */ + if (curproc == NULL) + curproc = &proc0; + /* + * Synchronize the disks.... + */ + waittime = 0; + vfs_shutdown(); + + /* + * If we've been adjusting the clock, the todr + * will be out of synch; adjust it now. + */ + resettodr(); + } + (void) splhigh(); /* extreme priority */ + if (howto & RB_HALT) { + printf("System halted.\n"); + while(1); /* Forever */ + } + else { + if (howto & RB_DUMP) + dumpsys(); + printf("System restart.\n"); + delay(2000000); + __asm__(" li $2, 0xbfc00000; jr $2; nop\n"); + while(1); /* Forever */ + } + /*NOTREACHED*/ +} + +int dumpmag = (int)0x8fca0101; /* magic number for savecore */ +int dumpsize = 0; /* also for savecore */ +long dumplo = 0; + +dumpconf() +{ + int nblks; + + dumpsize = physmem; + if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) { + nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); + if (dumpsize > btoc(dbtob(nblks - dumplo))) + dumpsize = btoc(dbtob(nblks - dumplo)); + else if (dumplo == 0) + dumplo = nblks - btodb(ctob(physmem)); + } + /* + * Don't dump on the first CLBYTES (why CLBYTES?) + * in case the dump device includes a disk label. + */ + if (dumplo < btodb(CLBYTES)) + dumplo = btodb(CLBYTES); +} + +/* + * Doadump comes here after turning off memory management and + * getting on the dump stack, either when called above, or by + * the auto-restart code. + */ +dumpsys() +{ + int error; + + msgbufmapped = 0; + if (dumpdev == NODEV) + return; + /* + * For dumps during autoconfiguration, + * if dump device has already configured... + */ + if (dumpsize == 0) + dumpconf(); + if (dumplo < 0) + return; + printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); + printf("dump "); + switch (error = (*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { + + 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; + + default: + printf("error %d\n", error); + break; + + case 0: + printf("succeeded\n"); + } +} + +/* + * Return the best possible estimate of the time in the timeval + * to which tvp points. Unfortunately, we can't read the hardware registers. + * We guarantee that the time will be greater than the value obtained by a + * previous call. + */ +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); +} + +initcpu() +{ + +} + +/* + * Convert an ASCII string into an integer. + */ +int +atoi(s) + char *s; +{ + int c; + unsigned base = 10, d; + int neg = 0, val = 0; + + if (s == 0 || (c = *s++) == 0) + goto out; + + /* skip spaces if any */ + while (c == ' ' || c == '\t') + c = *s++; + + /* parse sign, allow more than one (compat) */ + while (c == '-') { + neg = !neg; + c = *s++; + } + + /* parse base specification, if any */ + if (c == '0') { + c = *s++; + switch (c) { + case 'X': + case 'x': + base = 16; + c = *s++; + break; + case 'B': + case 'b': + base = 2; + c = *s++; + break; + default: + base = 8; + } + } + + /* parse number proper */ + for (;;) { + if (c >= '0' && c <= '9') + d = c - '0'; + else if (c >= 'a' && c <= 'z') + d = c - 'a' + 10; + else if (c >= 'A' && c <= 'Z') + d = c - 'A' + 10; + else + break; + val *= base; + val += d; + c = *s++; + } + if (neg) + val = -val; +out: + return val; +} diff --git a/sys/arch/wgrisc/wgrisc/mainbus.c b/sys/arch/wgrisc/wgrisc/mainbus.c new file mode 100644 index 00000000000..12c7545a2cf --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/mainbus.c @@ -0,0 +1,160 @@ +/* $OpenBSD: mainbus.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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/device.h> +#include <sys/reboot.h> + +#include <wgrisc/wgrisc/wgrisctype.h> +#include <machine/autoconf.h> + +struct mainbus_softc { + struct device sc_dv; + struct abus sc_bus; +}; + +/* Definition of the mainbus driver. */ +static int mbmatch __P((struct device *, void *, void *)); +static void mbattach __P((struct device *, struct device *, void *)); +static int mbprint __P((void *, const char *)); + +struct cfattach mainbus_ca = { + sizeof(struct device), mbmatch, mbattach +}; +struct cfdriver mainbus_cd = { + NULL, "mainbus", DV_DULL, NULL, 0 +}; + +void mb_intr_establish __P((struct confargs *, int (*)(void *), void *)); +void mb_intr_disestablish __P((struct confargs *)); +caddr_t mb_cvtaddr __P((struct confargs *)); +int mb_matchname __P((struct confargs *, char *)); + +static int +mbmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + + if (cf->cf_unit > 0) + return(0); + return(1); +} + +static void +mbattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct mainbus_softc *sc = (struct mainbus_softc *)self; + struct confargs nca; + extern int cputype, ncpus; + + printf("\n"); + + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_MAIN; + sc->sc_bus.ab_intr_establish = mb_intr_establish; + sc->sc_bus.ab_intr_disestablish = mb_intr_disestablish; + sc->sc_bus.ab_cvtaddr = mb_cvtaddr; + sc->sc_bus.ab_matchname = mb_matchname; + + nca.ca_name = "cpu"; + nca.ca_slot = 0; + nca.ca_offset = 0; + nca.ca_bus = &sc->sc_bus; + config_found(self, &nca, mbprint); + + nca.ca_name = "riscbus"; + nca.ca_slot = 0; + nca.ca_offset = 0; + nca.ca_bus = &sc->sc_bus; + config_found(self, &nca, mbprint); + + nca.ca_name = "isabr"; + nca.ca_slot = 0; + nca.ca_offset = 0; + nca.ca_bus = &sc->sc_bus; + config_found(self, &nca, mbprint); +} + +static int +mbprint(aux, pnp) + void *aux; + const char *pnp; +{ + + if (pnp) + return (QUIET); + return (UNCONF); +} + +void +mb_intr_establish(ca, handler, val) + struct confargs *ca; + int (*handler) __P((void *)); + void *val; +{ + + panic("can never mb_intr_establish"); +} + +void +mb_intr_disestablish(ca) + struct confargs *ca; +{ + + panic("can never mb_intr_disestablish"); +} + +caddr_t +mb_cvtaddr(ca) + struct confargs *ca; +{ + + return (NULL); +} + +int +mb_matchname(ca, name) + struct confargs *ca; + char *name; +{ + + return (strcmp(name, ca->ca_name) == 0); +} diff --git a/sys/arch/wgrisc/wgrisc/mem.c b/sys/arch/wgrisc/wgrisc/mem.c new file mode 100644 index 00000000000..b898f9546ac --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/mem.c @@ -0,0 +1,173 @@ +/* $OpenBSD: mem.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ +/* $NetBSD: mem.c,v 1.6 1995/04/10 11:55:03 mycroft 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 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. + * + * @(#)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/msgbuf.h> +#include <sys/systm.h> +#include <sys/uio.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> + +#include <vm/vm.h> + +extern vm_offset_t avail_end; +caddr_t zeropage; + +/*ARGSUSED*/ +int +mmopen(dev, flag, mode) + dev_t dev; + int flag, mode; +{ + + return (0); +} + +/*ARGSUSED*/ +int +mmclose(dev, flag, mode) + dev_t dev; + int flag, mode; +{ + + return (0); +} + +/*ARGSUSED*/ +int +mmrw(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + register vm_offset_t o, v; + register int c; + register struct iovec *iov; + int error = 0; + + 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: + v = uio->uio_offset; + c = iov->iov_len; + if (v + c > ctob(physmem)) + return (EFAULT); + v += CACHED_MEMORY_ADDR; + error = uiomove((caddr_t)v, c, uio); + continue; + +/* minor device 1 is kernel memory */ + case 1: + v = uio->uio_offset; + c = min(iov->iov_len, MAXPHYS); + if (v < CACHED_MEMORY_ADDR) + return (EFAULT); + if (v + c > PHYS_TO_CACHED(avail_end + + sizeof (struct msgbuf)) && + (v < KSEG2_ADDR || + !kernacc((caddr_t)v, c, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE))) + 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); + +/* 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(CLBYTES, M_TEMP, M_WAITOK); + bzero(zeropage, CLBYTES); + } + c = min(iov->iov_len, CLBYTES); + 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; + } + return (error); +} + +int +mmmmap(dev, off, prot) + dev_t dev; + int off, prot; +{ + + return (EOPNOTSUPP); +} diff --git a/sys/arch/wgrisc/wgrisc/minidebug.c b/sys/arch/wgrisc/wgrisc/minidebug.c new file mode 100644 index 00000000000..3b13aa67782 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/minidebug.c @@ -0,0 +1,975 @@ +/* $OpenBSD: minidebug.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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: @(#)kadb.c 8.1 (Berkeley) 6/10/93 + * $Id: minidebug.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + +/* + * Define machine dependent primitives for mdb. + */ + +#include <sys/types.h> +#include <machine/pte.h> +#include <vm/vm_prot.h> +#undef SP +#include <machine/cpu.h> +#include <machine/reg.h> +#include <machine/pcb.h> +#include <machine/trap.h> +#include <machine/mips_opcode.h> + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifdef R4K +#define FlushDCache(a,s) R4K_FlushDCache(a,s) +#define FlushICache(a,s) R4K_FlushICache(a,s) +#define FlushCache() R4K_FlushCache() +#define TLBFlush() R4K_TLBFlush() +#else +#define FlushDCache(a,s) R3K_FlushDCache(a,s) +#define FlushICache(a,s) R3K_FlushICache(a,s) +#define FlushCache() R3K_FlushCache() +#define TLBFlush() R3K_TLBFlush() +#endif + +void mips_dump_tlb(int, int); + +static char *op_name[64] = { +/* 0 */ "spec", "bcond","j", "jal", "beq", "bne", "blez", "bgtz", +/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui", +/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl", +/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37", +/*32 */ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", +/*40 */ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", +/*48 */ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", +/*56 */ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" +}; + +static char *spec_name[64] = { +/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav", +/* 8 */ "jr", "jalr", "spec12","spec13","syscall","break","spec16","sync", +/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav", +/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu", +/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", +/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu", +/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67", +/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32" +}; + +static char *bcond_name[32] = { +/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?", +/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?", +/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?", +/*24 */ "?", "?", "?", "?", "?", "?", "?", "?", +}; + +static char *cop1_name[64] = { +/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg", +/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f", +/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17", +/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f", +/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27", +/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f", +/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult", + "fcmp.ole","fcmp.ule", +/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge", + "fcmp.le","fcmp.ngt" +}; + +static char *fmt_name[16] = { + "s", "d", "e", "fmt3", + "w", "fmt5", "fmt6", "fmt7", + "fmt8", "fmt9", "fmta", "fmtb", + "fmtc", "fmtd", "fmte", "fmtf" +}; + +static char *reg_name[32] = { + "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" +}; + +static char *c0_opname[64] = { + "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07", + "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17", + "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27", + "eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37", + "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47", + "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57", + "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67", + "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77", +}; + +static char *c0_reg[32] = { + "index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7", + "badvaddr","count","tlbhi","c0r11","sr","cause","epc", "prid", + "config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23", + "c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31" +}; + +extern char *trap_type[]; + +struct pcb mdbpcb; +int mdbmkfault; + +#define MAXBRK 10 +struct brk { + int inst; + int addr; +} brk_tab[MAXBRK]; + +/* + * Mini debugger for kernel. + */ +int gethex(u_int *val, u_int dotval) +{ + u_int c; + + *val = 0; + while((c = cngetc()) != '\e' && c != '\n' && c != '\r') { + if(c >= '0' && c <= '9') { + *val = (*val << 4) + c - '0'; + cnputc(c); + } + else if(c >= 'a' && c <= 'f') { + *val = (*val << 4) + c - 'a' + 10; + cnputc(c); + } + else if(c == '\b') { + *val = *val >> 4; + printf("\b \b"); + } + else if(c == ',') { + cnputc(c); + return(c); + } + else if(c == '.') { + *val = dotval;; + cnputc(c); + } + } + if(c == '\r') + c = '\n'; + return(c); +} + +void dump(u_int *addr, u_int size) +{ + int cnt; + + cnt = 0; + + size = (size + 3) / 4; + while(size--) { + if((cnt++ & 3) == 0) + printf("\n%08x: ",(int)addr); + printf("%08x ",*addr++); + } +} + +void print_regs() +{ + printf("\n"); + printf("T0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", + mdbpcb.pcb_regs[T0],mdbpcb.pcb_regs[T1], + mdbpcb.pcb_regs[T2],mdbpcb.pcb_regs[T3], + mdbpcb.pcb_regs[T4],mdbpcb.pcb_regs[T5], + mdbpcb.pcb_regs[T6],mdbpcb.pcb_regs[T7]); + printf("T8-9 %08x %08x A0-4 %08x %08x %08x %08x\n", + mdbpcb.pcb_regs[T8],mdbpcb.pcb_regs[T9], + mdbpcb.pcb_regs[A0],mdbpcb.pcb_regs[A1], + mdbpcb.pcb_regs[A2],mdbpcb.pcb_regs[A3]); + printf("S0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", + mdbpcb.pcb_regs[S0],mdbpcb.pcb_regs[S1], + mdbpcb.pcb_regs[S2],mdbpcb.pcb_regs[S3], + mdbpcb.pcb_regs[S4],mdbpcb.pcb_regs[S5], + mdbpcb.pcb_regs[S6],mdbpcb.pcb_regs[S7]); + printf(" S8 %08x V0-1 %08x %08x GP %08x SP %08x\n", + mdbpcb.pcb_regs[S8],mdbpcb.pcb_regs[V0], + mdbpcb.pcb_regs[V1],mdbpcb.pcb_regs[GP], + mdbpcb.pcb_regs[SP]); + printf(" AT %08x PC %08x RA %08x SR %08x", + mdbpcb.pcb_regs[AST],mdbpcb.pcb_regs[PC], + mdbpcb.pcb_regs[RA],mdbpcb.pcb_regs[SR]); +} + +set_break(va) +{ + int i; + + va = va & ~3; + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr == 0) { + brk_tab[i].addr = va; + brk_tab[i].inst = *(u_int *)va; + return; + } + } + printf(" Break table full!!"); +} + +del_break(va) +{ + int i; + + va = va & ~3; + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr == va) { + brk_tab[i].addr = 0; + return; + } + } + printf(" Break to remove not found!!"); +} + +break_insert() +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr != 0) { + brk_tab[i].inst = *(u_int *)brk_tab[i].addr; + *(u_int *)brk_tab[i].addr = BREAK_BRKPT; + FlushDCache(brk_tab[i].addr,4); + FlushICache(brk_tab[i].addr,4); + } + } +} + +break_restore() +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr != 0) { + *(u_int *)brk_tab[i].addr = brk_tab[i].inst; + FlushDCache(brk_tab[i].addr,4); + FlushICache(brk_tab[i].addr,4); + } + } +} + +break_find(va) +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr == va) { + return(i); + } + } + return(-1); +} + +prt_break() +{ + int i; + + for(i = 0; i < MAXBRK; i++) { + if(brk_tab[i].addr != 0) { + printf("\n %08x\t", brk_tab[i].addr); + mdbprintins(brk_tab[i].inst, brk_tab[i].addr); + } + } +} +mdb(causeReg, vadr, p, kernelmode) +{ + int c; + int newaddr; + int size; + int cause; +static int ssandrun; /* Single step and run flag (when cont at brk) */ + + splhigh(); + cause = (causeReg & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; + newaddr = (int)(mdbpcb.pcb_regs[PC]); + switch(cause) { + case T_BREAK: + if(*(int *)newaddr == BREAK_SOVER) { + break_restore(); + mdbpcb.pcb_regs[PC] += 4; + printf("\nStop break (panic)\n# "); + printf(" %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + printf("\n# "); + break; + } + if(*(int *)newaddr == BREAK_BRKPT) { + break_restore(); + printf("\rBRK %08x\t",newaddr); + if(mdbprintins(*(int *)newaddr, newaddr)) { + newaddr += 4; + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + } + printf("\n# "); + break; + } + if(mdbclrsstep(causeReg)) { + if(ssandrun) { /* Step over bp before free run */ + ssandrun = 0; + break_insert(); + return(TRUE); + } + printf("\r %08x\t",newaddr); + if(mdbprintins(*(int *)newaddr, newaddr)) { + newaddr += 4; + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + } + printf("\n# "); + } + break; + + default: + printf("\n-- %s --\n# ",trap_type[cause]); + } + ssandrun = 0; + break_restore(); + + while(c = cngetc()) { + switch(c) { + case 'T': + trapDump("Debugger"); + break; + case 'b': + printf("break-"); + c = cngetc(); + switch(c) { + case 's': + printf("set at "); + c = gethex(&newaddr, newaddr); + if(c != '\e') { + set_break(newaddr); + } + break; + + case 'd': + printf("delete at "); + c = gethex(&newaddr, newaddr); + if(c != '\e') { + del_break(newaddr); + } + break; + + case 'p': + printf("print"); + prt_break(); + break; + } + break; + + case 'r': + print_regs(); + break; + + case 'I': + printf("Instruction at "); + c = gethex(&newaddr, newaddr); + while(c != '\e') { + printf("\n %08x\t",newaddr); + mdbprintins(*(int *)newaddr, newaddr); + newaddr += 4; + c = cngetc(); + } + break; + + case 'c': + printf("continue"); + if(break_find((int)(mdbpcb.pcb_regs[PC])) >= 0) { + ssandrun = 1; + mdbsetsstep(); + } + else { + break_insert(); + } + return(TRUE); + case 'S': + printf("Stack traceback:\n"); + stacktrace(); + return(TRUE); + case 's': + set_break(mdbpcb.pcb_regs[PC] + 8); + return(TRUE); + case ' ': + mdbsetsstep(); + return(TRUE); + + case 'd': + printf("dump "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size,256); + } + else { + size = 16; + } + if(c == '\n' && newaddr != 0) { + dump((u_int *)newaddr, size); + newaddr += size; + } + break; + + case 'm': + printf("mod "); + c = gethex(&newaddr, newaddr); + while(c == ',') { + c = gethex(&size, 0); + if(c != '\e') + *((u_int *)newaddr)++ = size; + } + break; + + case 'i': + printf("in-"); + c = cngetc(); + switch(c) { + case 'b': + printf("byte "); + c = gethex(&newaddr, newaddr); + if(c == '\n') { + printf("= %02x", + *(u_char *)newaddr); + } + break; + case 'h': + printf("halfword "); + c = gethex(&newaddr, newaddr); + if(c == '\n') { + printf("= %04x", + *(u_short *)newaddr); + } + break; + case 'w': + printf("word "); + c = gethex(&newaddr, newaddr); + if(c == '\n') { + printf("= %08x", + *(u_int *)newaddr); + } + break; + } + break; + + case 'o': + printf("out-"); + c = cngetc(); + switch(c) { + case 'b': + printf("byte "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size, 0); + if(c == '\n') { + *(u_char *)newaddr = size; + } + } + break; + case 'h': + printf("halfword "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size, 0); + if(c == '\n') { + *(u_short *)newaddr = size; + } + } + break; + case 'w': + printf("word "); + c = gethex(&newaddr, newaddr); + if(c == ',') { + c = gethex(&size, 0); + if(c == '\n') { + *(u_int *)newaddr = size; + } + } + break; + } + break; + + case 't': + printf("tlb-dump\n"); + mips_dump_tlb(0,23); + (void)cngetc(); + mips_dump_tlb(24,47); + break; + + case 'f': + printf("flush-"); + c = cngetc(); + switch(c) { + case 't': + printf("tlb"); + TLBFlush(); + break; + + case 'c': + printf("cache"); + FlushCache(); + break; + } + break; + + default: + cnputc('\a'); + break; + } + printf("\n# "); + } +} + +u_int mdb_ss_addr; +u_int mdb_ss_instr; + +mdbsetsstep() +{ + register u_int va; + register int *locr0 = mdbpcb.pcb_regs; + int i; + + /* compute next address after current location */ + if(mdbpeek(locr0[PC]) != 0) { + va = CPU_EmulateBranch(locr0, locr0[PC], 0, mdbpeek(locr0[PC])); + } + else { + va = locr0[PC] + 4; + } + if (mdb_ss_addr) { + printf("mdbsetsstep: breakpoint already set at %x (va %x)\n", + mdb_ss_addr, va); + return; + } + mdb_ss_addr = va; + + if ((int)va < 0) { + /* kernel address */ + mdb_ss_instr = mdbpeek(va); + mdbpoke((caddr_t)va, BREAK_SSTEP); + FlushDCache(va,4); + FlushICache(va,4); + return; + } +} + +mdbclrsstep(cr) + int cr; +{ + register u_int pc, va; + u_int instr; + + /* fix pc if break instruction is in the delay slot */ + pc = mdbpcb.pcb_regs[PC]; + if (cr < 0) + pc += 4; + + /* check to be sure its the one we are expecting */ + va = mdb_ss_addr; + if (!va || va != pc) + return(FALSE); + + /* read break instruction */ + instr = mdbpeek(va); + if (instr != BREAK_SSTEP) + return(FALSE); + + if ((int)va < 0) { + /* kernel address */ + mdbpoke((caddr_t)va, mdb_ss_instr); + FlushDCache(va,4); + FlushICache(va,4); + mdb_ss_addr = 0; + return(TRUE); + } + + printf("can't clear break at %x\n", va); + mdb_ss_addr = 0; + return(FALSE); +} + +void +mdbreadc(lp) + char *lp; +{ + int c; + + c = cngetc(); + if (c == '\r') + c = '\n'; + *lp = c; +} + +void +mdbwrite(lp, len) + char *lp; + int len; +{ + while (len-- > 0) + cnputc(*lp++); +} + +/* ARGSUSED */ +mdbprintins(ins, mdbdot) +{ + InstFmt i; + int delay = 0; + + i.word = ins; + + switch (i.JType.op) { + case OP_SPECIAL: + if (i.word == 0) { + printf("nop"); + break; + } + if (i.RType.func == OP_ADDU && i.RType.rt == 0) { + printf("move\t%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs]); + break; + } + printf("%s", spec_name[i.RType.func]); + switch (i.RType.func) { + case OP_SLL: + case OP_SRL: + case OP_SRA: + case OP_DSLL: + case OP_DSRL: + case OP_DSRA: + case OP_DSLL32: + case OP_DSRL32: + case OP_DSRA32: + printf("\t%s,%s,%d", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + i.RType.shamt); + break; + + case OP_SLLV: + case OP_SRLV: + case OP_SRAV: + case OP_DSLLV: + case OP_DSRLV: + case OP_DSRAV: + printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rt], + reg_name[i.RType.rs]); + break; + + case OP_MFHI: + case OP_MFLO: + printf("\t%s", reg_name[i.RType.rd]); + break; + + case OP_JR: + case OP_JALR: + delay = 1; + /* FALLTHROUGH */ + case OP_MTLO: + case OP_MTHI: + printf("\t%s", reg_name[i.RType.rs]); + break; + + case OP_MULT: + case OP_MULTU: + case OP_DMULT: + case OP_DMULTU: + case OP_DIV: + case OP_DIVU: + case OP_DDIV: + case OP_DDIVU: + printf("\t%s,%s", + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + break; + + case OP_SYSCALL: + case OP_SYNC: + break; + + case OP_BREAK: + printf("\t%d", (i.RType.rs << 5) | i.RType.rt); + break; + + default: + printf("\t%s,%s,%s", + reg_name[i.RType.rd], + reg_name[i.RType.rs], + reg_name[i.RType.rt]); + }; + break; + + case OP_BCOND: + printf("%s\t%s,", bcond_name[i.IType.rt], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BLEZ: + case OP_BLEZL: + case OP_BGTZ: + case OP_BGTZL: + printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rs]); + goto pr_displ; + + case OP_BEQ: + case OP_BEQL: + if (i.IType.rs == 0 && i.IType.rt == 0) { + printf("b\t"); + goto pr_displ; + } + /* FALLTHROUGH */ + case OP_BNE: + case OP_BNEL: + printf("%s\t%s,%s,", op_name[i.IType.op], + reg_name[i.IType.rs], + reg_name[i.IType.rt]); + pr_displ: + delay = 1; + printf("0x%08x", mdbdot + 4 + ((short)i.IType.imm << 2)); + break; + + case OP_COP0: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + printf("bc0%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + printf("mtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMT: + printf("dmtc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_MF: + printf("mfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + case OP_DMF: + printf("dmfc0\t%s,%s", + reg_name[i.RType.rt], + c0_reg[i.RType.rd]); + break; + + default: + printf("%s", c0_opname[i.FRType.func]); + }; + break; + + case OP_COP1: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + printf("bc1%c\t", + "ft"[i.RType.rt & COPz_BC_TF_MASK]); + goto pr_displ; + + case OP_MT: + printf("mtc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_MF: + printf("mfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CT: + printf("ctc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + case OP_CF: + printf("cfc1\t%s,f%d", + reg_name[i.RType.rt], + i.RType.rd); + break; + + default: + printf("%s.%s\tf%d,f%d,f%d", + cop1_name[i.FRType.func], + fmt_name[i.FRType.fmt], + i.FRType.fd, i.FRType.fs, i.FRType.ft); + }; + break; + + case OP_J: + case OP_JAL: + printf("%s\t", op_name[i.JType.op]); + printf("0x%8x",(mdbdot & 0xF0000000) | (i.JType.target << 2)); + delay = 1; + break; + + case OP_LWC1: + case OP_SWC1: + printf("%s\tf%d,", op_name[i.IType.op], + i.IType.rt); + goto loadstore; + + case OP_LB: + case OP_LH: + case OP_LW: + case OP_LD: + case OP_LBU: + case OP_LHU: + case OP_LWU: + case OP_SB: + case OP_SH: + case OP_SW: + case OP_SD: + printf("%s\t%s,", op_name[i.IType.op], + reg_name[i.IType.rt]); + loadstore: + printf("%d(%s)", (short)i.IType.imm, + reg_name[i.IType.rs]); + break; + + case OP_ORI: + case OP_XORI: + if (i.IType.rs == 0) { + printf("li\t%s,0x%x", + reg_name[i.IType.rt], + i.IType.imm); + break; + } + /* FALLTHROUGH */ + case OP_ANDI: + printf("%s\t%s,%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + i.IType.imm); + break; + + case OP_LUI: + printf("%s\t%s,0x%x", op_name[i.IType.op], + reg_name[i.IType.rt], + i.IType.imm); + break; + + case OP_ADDI: + case OP_DADDI: + case OP_ADDIU: + case OP_DADDIU: + if (i.IType.rs == 0) { + printf("li\t%s,%d", + reg_name[i.IType.rt], + (short)i.IType.imm); + break; + } + /* FALLTHROUGH */ + default: + printf("%s\t%s,%s,%d", op_name[i.IType.op], + reg_name[i.IType.rt], + reg_name[i.IType.rs], + (short)i.IType.imm); + } + return(delay); +} + +#define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ + +/* + * Very simple memory allocator for mdb. + */ +char * +mdbmalloc(size) + int size; +{ + static char buffer[4096]; + static char *bufp = buffer; + char *p; + + /* round size up to sizeof(int) */ + size = (size + sizeof(int) - 1) & ~(sizeof(int) - 1); + p = bufp; + bufp = p + size; + return (p); +} + +/* + * Dump TLB contents. + */ +void mips_dump_tlb(int first,int last) +{ + int tlbno; + struct tlb tlb; + + tlbno = first; + +#ifdef R4K + while(tlbno <= last) { + R4K_TLBRead(tlbno, &tlb); + if(tlb.tlb_lo0 & PG_V || tlb.tlb_lo1 & PG_V) { + printf("TLB %2d vad 0x%08x ", tlbno, tlb.tlb_hi); + } + else { + printf("TLB*%2d vad 0x%08x ", tlbno, tlb.tlb_hi); + } + printf("0=0x%08x ", pfn_to_vad(tlb.tlb_lo0)); + printf("%c", tlb.tlb_lo0 & PG_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo0 & PG_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo0 >> 3) & 7); + printf("1=0x%08x ", pfn_to_vad(tlb.tlb_lo1)); + printf("%c", tlb.tlb_lo1 & PG_M ? 'M' : ' '); + printf("%c", tlb.tlb_lo1 & PG_G ? 'G' : ' '); + printf(" atr %x ", (tlb.tlb_lo1 >> 3) & 7); + printf(" sz=%x\n", tlb.tlb_mask); + + tlbno++; + } +#else + printf("dumptlb not implemented for r3k yet, sorry.\n"); +#endif +} diff --git a/sys/arch/wgrisc/wgrisc/pmap.c b/sys/arch/wgrisc/wgrisc/pmap.c new file mode 100644 index 00000000000..0abc9c6bdaf --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/pmap.c @@ -0,0 +1,1823 @@ +/* $OpenBSD: pmap.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ +/* + * 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: @(#)pmap.c 8.4 (Berkeley) 1/26/94 + * $Id: pmap.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + +/* + * Manages physical address maps. + * + * In addition to hardware address maps, this + * module is called upon to provide software-use-only + * maps which may or may not be stored in the same + * form as hardware maps. These pseudo-maps are + * used to store intermediate results from copy + * operations to and from address spaces. + * + * Since the information managed by this module is + * also stored by the logical address mapping module, + * this module may throw away valid virtual-to-physical + * mappings at almost any time. However, invalidations + * of virtual-to-physical mappings must be done as + * requested. + * + * In order to cope with hardware architectures which + * make virtual-to-physical map invalidates expensive, + * this module may delay invalidate or reduced protection + * operations until such time as they are actually + * necessary. This module is given full information as + * to which processors are currently using which maps, + * and to when physical maps must be made correct. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/user.h> +#include <sys/buf.h> +#ifdef SYSVSHM +#include <sys/shm.h> +#endif + +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_pageout.h> + +#include <machine/cpu.h> +#include <machine/pte.h> +#include <machine/memconf.h> + +extern vm_page_t vm_page_alloc1 __P((void)); +extern void vm_page_free1 __P((vm_page_t)); + +/* + * For each vm_page_t, there is a list of all currently valid virtual + * mappings of that page. An entry is a pv_entry_t, the list is pv_table. + * XXX really should do this as a part of the higher level code. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + int pv_flags; /* Some flags for the mapping */ +} *pv_entry_t; +#define PV_UNCACHED 0x0001 /* Page is mapped unchached */ + +pv_entry_t pv_table; /* array of entries, one per page */ +int pmap_remove_pv(); + +#ifdef MACHINE_NONCONTIG +static vm_offset_t avail_next; +static vm_offset_t avail_remaining; + +struct physseg { + vm_offset_t start; + vm_offset_t end; + int first_page; +} physsegs[MAXMEMSEGS+1]; + +#define pa_index(pa) pmap_page_index(pa) + +#else +#define pa_index(pa) atop((pa) - first_phys_addr) +#endif /* MACHINE_NONCONTIG */ + +#define pa_to_pvh(pa) (&pv_table[pa_index(pa)]) + +#ifdef DEBUG +struct { + int kernel; /* entering kernel mapping */ + int user; /* entering user mapping */ + int ptpneeded; /* needed to allocate a PT page */ + int pwchange; /* no mapping change, just wiring or protection */ + int wchange; /* no mapping change, just wiring */ + int mchange; /* was mapped but mapping to different page */ + int managed; /* a managed page */ + int firstpv; /* first mapping for this PA */ + int secondpv; /* second mapping for this PA */ + int ci; /* cache inhibited */ + int unmanaged; /* not a managed page */ + int flushes; /* cache flushes */ + int cachehit; /* new entry forced valid entry out */ +} enter_stats; +struct { + int calls; + int removes; + int flushes; + int pidflushes; /* HW pid stolen */ + int pvfirst; + int pvsearch; +} remove_stats; + +#define PDB_FOLLOW 0x0001 +#define PDB_INIT 0x0002 +#define PDB_ENTER 0x0004 +#define PDB_REMOVE 0x0008 +#define PDB_CREATE 0x0010 +#define PDB_PTPAGE 0x0020 +#define PDB_PVENTRY 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_TLBPID 0x0400 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +extern int _ftext[]; +extern int _end[]; +int pmapdebug = 0x0; + +#endif /* DEBUG */ + +struct pmap kernel_pmap_store; + +vm_offset_t avail_start; /* PA of first available physical page */ +vm_offset_t avail_end; /* PA of last available physical page */ +vm_size_t mem_size; /* memory size in bytes */ +vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/ +vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ +#ifdef ATTR +char *pmap_attributes; /* reference and modify bits */ +#endif +struct segtab *free_segtab; /* free list kept locally */ +u_int tlbpid_gen = 1; /* TLB PID generation count */ +int tlbpid_cnt = 2; /* next available TLB PID */ +pt_entry_t *Sysmap; /* kernel pte table */ +u_int Sysmapsize; /* number of pte's in Sysmap */ + +/* + * Bootstrap the system enough to run with virtual memory. + * firstaddr is the first unused kseg0 address (not page aligned). + */ +void +pmap_bootstrap(firstaddr) + vm_offset_t firstaddr; +{ + register int i, n, nextpage; + register pt_entry_t *spte; + struct physseg *pseg; + vm_offset_t start = firstaddr; + extern int physmem; + +#define valloc(name, type, num) \ + (name) = (type *)firstaddr; firstaddr = (vm_offset_t)((name)+(num)) + /* + * Allocate a PTE table for the kernel. + * The '1024' comes from PAGER_MAP_SIZE in vm_pager_init(). + * This should be kept in sync. + * We also reserve space for kmem_alloc_pageable() for vm_fork(). + */ + Sysmapsize = (VM_KMEM_SIZE + VM_MBUF_SIZE + VM_PHYS_SIZE + + nbuf * MAXBSIZE + 16 * NCARGS) / NBPG + 1024 + 256; + Sysmapsize += maxproc * UPAGES * 2; +#ifdef SYSVSHM + Sysmapsize += shminfo.shmall; +#endif + valloc(Sysmap, pt_entry_t, Sysmapsize); +#ifdef ATTR + valloc(pmap_attributes, char, physmem); +#endif + /* + * Allocate memory for pv_table. + * This will allocate more entries than we really need. + * We could do this in pmap_init when we know the actual + * phys_start and phys_end but its better to use kseg0 addresses + * rather than kernel virtual addresses mapped through the TLB. + */ +#ifdef MACHINE_NONCONTIG + i = 0; + for( n = 0; n < MAXMEMSEGS; n++) { + i += mips_btop(mem_layout[n].mem_size); + } +#else + i = physmem - mips_btop(CACHED_TO_PHYS(firstaddr)); +#endif /*MACHINE_NONCONTIG*/ + valloc(pv_table, struct pv_entry, i); + + /* + * Clear allocated memory. + */ + firstaddr = mips_round_page(firstaddr); + bzero((caddr_t)start, firstaddr - start); + + avail_start = CACHED_TO_PHYS(firstaddr); + avail_end = mips_ptob(physmem); + +#ifdef MACHINE_NONCONTIG + avail_remaining = 0; + nextpage = 0; + + /* + * Now set up memory areas. Be careful to remove areas used + * for the OS and for exception vector stuff. + */ + pseg = &physsegs[0]; + + for( i = 0; i < MAXMEMSEGS; i++) { + /* Adjust for the kernel exeption vectors and sys data area */ + if(mem_layout[i].mem_start < 0x20000) { + if((mem_layout[i].mem_start + mem_layout[i].mem_size) < 0x8000) + continue; /* To small skip it */ + mem_layout[i].mem_size -= 0x20000 - mem_layout[i].mem_start; + mem_layout[i].mem_start = 0x20000; /* Adjust to be above vec's */ + } + /* Adjust for the kernel expansion area (bufs etc) */ + if((mem_layout[i].mem_start + mem_layout[i].mem_size > CACHED_TO_PHYS(_ftext)) && + (mem_layout[i].mem_start < CACHED_TO_PHYS(avail_start))) { + mem_layout[i].mem_size -= CACHED_TO_PHYS(avail_start) - mem_layout[i].mem_start; + mem_layout[i].mem_start = CACHED_TO_PHYS(avail_start); + } + + if(mem_layout[i].mem_size == 0) + continue; + + pseg->start = mem_layout[i].mem_start; + pseg->end = pseg->start + mem_layout[i].mem_size; + pseg->first_page = nextpage; + nextpage += (pseg->end - pseg->start) / NBPG; + avail_remaining += (pseg->end - pseg->start) / NBPG; + pseg++; + } + + avail_next = physsegs[0].start; + +#endif /* MACHINE_NONCONTIG */ + + virtual_avail = VM_MIN_KERNEL_ADDRESS; + virtual_end = VM_MIN_KERNEL_ADDRESS + Sysmapsize * NBPG; + /* XXX need to decide how to set cnt.v_page_size */ + + simple_lock_init(&pmap_kernel()->pm_lock); + pmap_kernel()->pm_count = 1; + + /* + * The R4?00 stores only one copy of the Global bit in the + * translation lookaside buffer for each 2 page entry. + * Thus invalid entrys must have the Global bit set so + * when Entry LO and Entry HI G bits are anded together + * they will produce a global bit to store in the tlb. + */ + for(i = 0, spte = Sysmap; i < Sysmapsize; i++, spte++) + spte->pt_entry = PG_G; +} + +/* + * Bootstrap memory allocator. This function allows for early dynamic + * memory allocation until the virtual memory system has been bootstrapped. + * After that point, either kmem_alloc or malloc should be used. This + * function works by stealing pages from the (to be) managed page pool, + * stealing virtual address space, then mapping the pages and zeroing them. + * + * It should be used from pmap_bootstrap till vm_page_startup, afterwards + * it cannot be used, and will generate a panic if tried. Note that this + * memory will never be freed, and in essence it is wired down. + */ +void * +pmap_bootstrap_alloc(size) + int size; +{ + vm_offset_t val; + extern boolean_t vm_page_startup_initialized; + + if (vm_page_startup_initialized) + panic("pmap_bootstrap_alloc: called after startup initialized"); + + val = PHYS_TO_CACHED(avail_start); + size = round_page(size); + avail_start += size; + + blkclr((caddr_t)val, size); + return ((void *)val); +} + +/* + * Initialize the pmap module. + * Called by vm_init, to initialize any structures that the pmap + * system needs to map virtual memory. + */ +void +#ifdef MACHINE_NONCONTIG +pmap_init() +#else +pmap_init(phys_start, phys_end) + vm_offset_t phys_start, phys_end; +#endif +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_INIT)) +#ifdef MACHINE_NONCONTIG + printf("pmap_init(%lx, %lx)\n", avail_start, avail_end); +#else + printf("pmap_init(%lx, %lx)\n", phys_start, phys_end); +#endif +#endif /*DEBUG*/ +} + +#ifdef MACHINE_NONCONTIG +inline int +pmap_page_index(pa) + vm_offset_t pa; +{ + struct physseg *ps = &physsegs[0]; + while (ps->start) { + if(pa >= ps->start && pa < ps->end) { + return(atop(pa - ps->start) + ps->first_page); + } + ps++; + } + return -1; +} + +unsigned int +pmap_free_pages() +{ + return avail_remaining; +} + +void +pmap_virtual_space(startp, endp) + vm_offset_t *startp; + vm_offset_t *endp; +{ + *startp = virtual_avail; + *endp = virtual_end; +} + +int +pmap_next_page(p_addr) + vm_offset_t *p_addr; +{ + static int cur_seg = 0; + + if (physsegs[cur_seg].start == 0) + return FALSE; + if (avail_next == physsegs[cur_seg].end) { + avail_next = physsegs[++cur_seg].start; + } + + if (avail_next == 0) + return FALSE; + *p_addr = avail_next; + avail_next += NBPG; + avail_remaining--; + return TRUE; +} +#endif /*MACHINE_NONCONTIG*/ + +/* + * 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. + */ +pmap_t +pmap_create(size) + vm_size_t size; +{ + register pmap_t pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_create(%x)\n", size); +#endif + /* + * Software use map does not need a pmap + */ + if (size) + return (NULL); + + /* XXX: is it ok to wait here? */ + pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); +#ifdef notifwewait + if (pmap == NULL) + panic("pmap_create: cannot allocate a pmap"); +#endif + bzero(pmap, sizeof(*pmap)); + pmap_pinit(pmap); + return (pmap); +} + +/* + * Initialize a preallocated and zeroed pmap structure, + * such as one in a vmspace structure. + */ +void +pmap_pinit(pmap) + register struct pmap *pmap; +{ + register int i; + int s; + extern struct vmspace vmspace0; + extern struct user *proc0paddr; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_pinit(%x)\n", pmap); +#endif + simple_lock_init(&pmap->pm_lock); + pmap->pm_count = 1; + if (free_segtab) { + s = splimp(); + pmap->pm_segtab = free_segtab; + free_segtab = *(struct segtab **)free_segtab; + pmap->pm_segtab->seg_tab[0] = NULL; + splx(s); + } else { + register struct segtab *stp; + vm_page_t mem; + void pmap_zero_page(); + + do { + mem = vm_page_alloc1(); + if (mem == NULL) { + VM_WAIT; /* XXX What else can we do */ + } /* XXX Deadlock situations? */ + } while (mem == NULL); + + pmap_zero_page(VM_PAGE_TO_PHYS(mem)); + pmap->pm_segtab = stp = (struct segtab *) + PHYS_TO_CACHED(VM_PAGE_TO_PHYS(mem)); + i = NBPG / sizeof(struct segtab); + s = splimp(); + while (--i != 0) { + stp++; + *(struct segtab **)stp = free_segtab; + free_segtab = stp; + } + splx(s); + } +#ifdef DIAGNOSTIC + for (i = 0; i < PMAP_SEGTABSIZE; i++) + if (pmap->pm_segtab->seg_tab[i] != 0) + panic("pmap_pinit: pm_segtab != 0"); +#endif + if (pmap == &vmspace0.vm_pmap) { + /* + * The initial process has already been allocated a TLBPID + * in mach_init(). + */ + pmap->pm_tlbpid = 1; + pmap->pm_tlbgen = tlbpid_gen; + proc0paddr->u_pcb.pcb_segtab = (void *)pmap->pm_segtab; + } else { + pmap->pm_tlbpid = 0; + pmap->pm_tlbgen = 0; + } +} + +/* + * Retire the given physical map from service. + * Should only be called if the map contains + * no valid mappings. + */ +void +pmap_destroy(pmap) + register pmap_t pmap; +{ + int count; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_destroy(%x)\n", pmap); +#endif + if (pmap == NULL) + return; + + simple_lock(&pmap->pm_lock); + count = --pmap->pm_count; + simple_unlock(&pmap->pm_lock); + if (count == 0) { + pmap_release(pmap); + free((caddr_t)pmap, M_VMPMAP); + } +} + +/* + * Release any resources held by the given physical map. + * Called when a pmap initialized by pmap_pinit is being released. + * Should only be called if the map contains no valid mappings. + */ +void +pmap_release(pmap) + register pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_release(%x)\n", pmap); +#endif + + if (pmap->pm_segtab) { + register pt_entry_t *pte; + register int i; + int s; +#ifdef DIAGNOSTIC + register int j; +#endif + + for (i = 0; i < PMAP_SEGTABSIZE; i++) { + /* get pointer to segment map */ + pte = pmap->pm_segtab->seg_tab[i]; + if (!pte) + continue; +#ifdef DIAGNOSTIC + for (j = 0; j < NPTEPG; j++) { + if ((pte+j)->pt_entry) + panic("pmap_release: segmap not empty"); + } +#endif +#ifdef R4K + R4K_HitFlushDCache(pte, PAGE_SIZE); +#endif + vm_page_free1( + PHYS_TO_VM_PAGE(CACHED_TO_PHYS(pte))); + pmap->pm_segtab->seg_tab[i] = NULL; + } + s = splimp(); + *(struct segtab **)pmap->pm_segtab = free_segtab; + free_segtab = pmap->pm_segtab; + splx(s); + pmap->pm_segtab = NULL; + } +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%x)\n", pmap); +#endif + if (pmap != NULL) { + simple_lock(&pmap->pm_lock); + pmap->pm_count++; + simple_unlock(&pmap->pm_lock); + } +} + +/* + * Remove the given range of addresses from the specified map. + * + * It is assumed that the start and end are properly + * rounded to the page size. + */ +void +pmap_remove(pmap, sva, eva) + register pmap_t pmap; + vm_offset_t sva, eva; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + unsigned entry; + int flush; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); + remove_stats.calls++; +#endif + if (pmap == NULL) + return; + + if (!pmap->pm_segtab) { + register pt_entry_t *pte; + + /* remove entries from kernel pmap */ +#ifdef DIAGNOSTIC + if (sva < VM_MIN_KERNEL_ADDRESS || eva > virtual_end) + panic("pmap_remove: kva not in range"); +#endif + pte = kvtopte(sva); + for (; sva < eva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + if (entry & PG_WIRED) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + if(pmap_remove_pv(pmap, sva, pfn_to_vad(entry))) { +#ifdef R4K + R4K_FlushDCache(sva, PAGE_SIZE); +#endif + } +#ifdef ATTR + pmap_attributes[atop(pfn_to_vad(entry))] = 0; +#endif + /* + * Flush the TLB for the given address. + */ + pte->pt_entry = PG_NV | PG_G; /* See above about G bit */ +#ifdef R4K + R4K_TLBFlushAddr(sva); +#else + R3K_TLBFlushAddr(sva); +#endif +#ifdef DEBUG + remove_stats.flushes++; + +#endif + } + return; + } + +#ifdef DIAGNOSTIC + if (eva > VM_MAXUSER_ADDRESS) + panic("pmap_remove: uva not in range"); +#endif + while (sva < eva) { + nssva = mips_trunc_seg(sva) + NBSEG; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!(pte = pmap_segmap(pmap, sva))) { + sva = nssva; + continue; + } + /* + * Invalidate every valid mapping within this segment. + */ + pte += uvtopte(sva); + for (; sva < nssva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + if (entry & PG_WIRED) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + if(pmap_remove_pv(pmap, sva, pfn_to_vad(entry))) { +#ifdef R4K + R4K_FlushDCache(sva, PAGE_SIZE); +#endif + } +#ifdef ATTR + pmap_attributes[atop(pfn_to_vad(entry))] = 0; +#endif + pte->pt_entry = PG_NV; + /* + * Flush the TLB for the given address. + */ + if (pmap->pm_tlbgen == tlbpid_gen) { +#ifdef R4K + R4K_TLBFlushAddr(sva | (pmap->pm_tlbpid << + R4K_PID_SHIFT)); +#else + R3K_TLBFlushAddr(sva | (pmap->pm_tlbpid << + R3K_PID_SHIFT)); +#endif +#ifdef DEBUG + remove_stats.flushes++; +#endif + } + } + } +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(pa, prot) + vm_offset_t pa; + vm_prot_t prot; +{ + register pv_entry_t pv; + register vm_offset_t va; + int s; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || + prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE)) + printf("pmap_page_protect(%x, %x)\n", pa, prot); +#endif + if (!IS_VM_PHYSADDR(pa)) + return; + + switch (prot) { + case VM_PROT_READ|VM_PROT_WRITE: + case VM_PROT_ALL: + break; + + /* copy_on_write */ + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Loop over all current mappings setting/clearing as appropos. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + extern vm_offset_t pager_sva, pager_eva; + + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (va >= pager_sva && va < pager_eva) + continue; + pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE, + prot); + } + } + splx(s); + break; + + /* remove_all */ + default: + pv = pa_to_pvh(pa); + s = splimp(); + while (pv->pv_pmap != NULL) { + pmap_remove(pv->pv_pmap, pv->pv_va, + pv->pv_va + PAGE_SIZE); + } + splx(s); + } +} + +/* + * Set the physical protection on the + * specified range of this map as requested. + */ +void +pmap_protect(pmap, sva, eva, prot) + register pmap_t pmap; + vm_offset_t sva, eva; + vm_prot_t prot; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + register unsigned entry; + u_int p; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot); +#endif + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + + p = (prot & VM_PROT_WRITE) ? PG_M : PG_RO; + + if (!pmap->pm_segtab) { + /* + * Change entries in kernel pmap. + * This will trap if the page is writeable (in order to set + * the dirty bit) even if the dirty bit is already set. The + * optimization isn't worth the effort since this code isn't + * executed much. The common case is to make a user page + * read-only. + */ +#ifdef DIAGNOSTIC + if (sva < VM_MIN_KERNEL_ADDRESS || eva > virtual_end) + panic("pmap_protect: kva not in range"); +#endif + pte = kvtopte(sva); + for (; sva < eva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + entry = (entry & ~(PG_M | PG_RO)) | p; + pte->pt_entry = entry; + /* + * Update the TLB if the given address is in the cache. + */ +#ifdef R4K + R4K_TLBUpdate(sva, entry); +#else + R3K_TLBUpdate(sva, entry); +#endif + } + return; + } + +#ifdef DIAGNOSTIC + if (eva > VM_MAXUSER_ADDRESS) + panic("pmap_protect: uva not in range"); +#endif + while (sva < eva) { + nssva = mips_trunc_seg(sva) + NBSEG; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!(pte = pmap_segmap(pmap, sva))) { + sva = nssva; + continue; + } + /* + * Change protection on every valid mapping within this segment. + */ + pte += (sva >> PGSHIFT) & (NPTEPG - 1); + for (; sva < nssva; sva += NBPG, pte++) { + entry = pte->pt_entry; + if (!(entry & PG_V)) + continue; + entry = (entry & ~(PG_M | PG_RO)) | p; + pte->pt_entry = entry; + /* + * Update the TLB if the given address is in the cache. + */ + if (pmap->pm_tlbgen == tlbpid_gen) +#ifdef R4K + R4K_TLBUpdate(sva | (pmap->pm_tlbpid << + R4K_PID_SHIFT), entry); +#else + R3K_TLBUpdate(sva | (pmap->pm_tlbpid << + R3K_PID_SHIFT), entry); +#endif + } + } +} + +/* + * Return RO protection of page. + */ +int +pmap_is_page_ro(pmap, va, entry) + pmap_t pmap; + vm_offset_t va; + int entry; +{ + return(entry & PG_RO); +} + +/* + * pmap_page_cache: + * + * Change all mappings of a page to cached/uncached. + */ +void +pmap_page_cache(pa,mode) + vm_offset_t pa; +{ + register pv_entry_t pv; + register pt_entry_t *pte; + register vm_offset_t va; + register unsigned entry; + register unsigned newmode; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_page_uncache(%x)\n", pa); +#endif + if (!IS_VM_PHYSADDR(pa)) + return; + + newmode = mode & PV_UNCACHED ? PG_UNCACHED : PG_CACHED; + pv = pa_to_pvh(pa); + s = splimp(); + while (pv) { + pv->pv_flags = (pv->pv_flags & ~PV_UNCACHED) | mode; + if (!pv->pv_pmap->pm_segtab) { + /* + * Change entries in kernel pmap. + */ + pte = kvtopte(pv->pv_va); + entry = pte->pt_entry; + if (entry & PG_V) { + entry = (entry & ~PG_CACHEMODE) | newmode; + pte->pt_entry = entry; +#ifdef R4K + R4K_TLBUpdate(pv->pv_va, entry); +#else + R3K_TLBUpdate(pv->pv_va, entry); +#endif + } + } + else { + if (pte = pmap_segmap(pv->pv_pmap, pv->pv_va)) { + pte += (pv->pv_va >> PGSHIFT) & (NPTEPG - 1); + entry = pte->pt_entry; + if (entry & PG_V) { + entry = (entry & ~PG_CACHEMODE) | newmode; + pte->pt_entry = entry; + if (pv->pv_pmap->pm_tlbgen == tlbpid_gen) +#ifdef R4K + R4K_TLBUpdate(pv->pv_va | (pv->pv_pmap->pm_tlbpid << + R4K_PID_SHIFT), entry); +#else + R3K_TLBUpdate(pv->pv_va | (pv->pv_pmap->pm_tlbpid << + R3K_PID_SHIFT), entry); +#endif + } + } + } + pv = pv->pv_next; + } + + splx(s); +} + +/* + * Insert the given physical page (p) at + * the specified virtual address (v) in the + * target physical map with the protection requested. + * + * If specified, the page will be wired down, meaning + * that the related pte can not be reclaimed. + * + * NB: This is the only routine which MAY NOT lazy-evaluate + * or lose information. That is, this routine must actually + * insert this page into the given map NOW. + */ +void +pmap_enter(pmap, va, pa, prot, wired) + register pmap_t pmap; + vm_offset_t va; + register vm_offset_t pa; + vm_prot_t prot; + boolean_t wired; +{ + register pt_entry_t *pte; + register u_int npte; + register int i, j; + vm_page_t mem; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%x, %x, %x, %x, %x)\n", + pmap, va, pa, prot, wired); +#endif +#ifdef DIAGNOSTIC + if (!pmap) + panic("pmap_enter: pmap"); + if (!pmap->pm_segtab) { + enter_stats.kernel++; + if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) + panic("pmap_enter: kva"); + } else { + enter_stats.user++; + if (va >= VM_MAXUSER_ADDRESS) + panic("pmap_enter: uva"); + } + if (pa & 0x80000000) + panic("pmap_enter: pa"); + if (!(prot & VM_PROT_READ)) + panic("pmap_enter: prot"); +#endif + + if (IS_VM_PHYSADDR(pa)) { + register pv_entry_t pv, npv; + int s; + + if (!(prot & VM_PROT_WRITE)) + npte = PG_ROPAGE; + else { + register vm_page_t mem; + + mem = PHYS_TO_VM_PAGE(pa); + if ((int)va < 0) { + /* + * Don't bother to trap on kernel writes, + * just record page as dirty. + */ + npte = PG_RWPAGE; +#if 0 /*XXX*/ + mem->flags &= ~PG_CLEAN; +#endif + } else +#ifdef ATTR + if ((pmap_attributes[atop(pa)] & + PMAP_ATTR_MOD) || !(mem->flags & PG_CLEAN)) +#else + if (!(mem->flags & PG_CLEAN)) +#endif + npte = PG_RWPAGE; + else + npte = PG_CWPAGE; + } + +#ifdef DEBUG + enter_stats.managed++; +#endif + /* + * Enter the pmap and virtual address into the + * physical to virtual map table. + */ + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("pmap_enter: pv %x: was %x/%x/%x\n", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next); +#endif + if (pv->pv_pmap == NULL) { + /* + * No entries yet, use header as the first entry + */ +#ifdef DEBUG + if (pmapdebug & PDB_PVENTRY) + printf("pmap_enter: first pv: pmap %x va %x\n", + pmap, va); + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_flags = 0; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + } else { +#ifdef R4K + if (!(pv->pv_flags & PV_UNCACHED)) { + /* + * There is at least one other VA mapping this page. + * Check if they are cache index compatible. If not + * remove all mappings, flush the cache and set page + * to be mapped uncached. Caching will be restored + * when pages are mapped compatible again. NOT! + */ + for (npv = pv; npv; npv = npv->pv_next) { + /* + * Check cache aliasing incompatibility + */ + if((npv->pv_va & CpuCacheAliasMask) != (va & CpuCacheAliasMask)) { + printf("pmap_enter: creating uncached mapping 0x%x, 0x%x.\n",npv->pv_va, va); + pmap_page_cache(pa,PV_UNCACHED); + R4K_FlushDCache(pv->pv_va, PAGE_SIZE); + npte = (npte & ~PG_CACHEMODE) | PG_UNCACHED; + break; + } + } + } + else { + npte = (npte & ~PG_CACHEMODE) | PG_UNCACHED; + } +#endif + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + * + * Note: the entry may already be in the table if + * we are only changing the protection bits. + */ + for (npv = pv; npv; npv = npv->pv_next) { + if (pmap == npv->pv_pmap && va == npv->pv_va) { +#ifdef DIAGNOSTIC + unsigned entry; + + if (!pmap->pm_segtab) + entry = kvtopte(va)->pt_entry; + else { + pte = pmap_segmap(pmap, va); + if (pte) { + pte += (va >> PGSHIFT) & + (NPTEPG - 1); + entry = pte->pt_entry; + } else + entry = 0; + } + if (!(entry & PG_V) || + pfn_to_vad(entry) != pa) + printf( + "pmap_enter: found va %x pa %x in pv_table but != %x\n", + va, pa, entry); +#endif + goto fnd; + } + } +#ifdef DEBUG + if (pmapdebug & PDB_PVENTRY) + printf("pmap_enter: new pv: pmap %x va %x\n", + pmap, va); +#endif + /* can this cause us to recurse forever? */ + npv = (pv_entry_t) + malloc(sizeof *npv, M_VMPVENT, M_NOWAIT); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + npv->pv_flags = pv->pv_flags; + pv->pv_next = npv; +#ifdef DEBUG + if (!npv->pv_next) + enter_stats.secondpv++; +#endif + fnd: + ; + } + splx(s); + } else { + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ +#ifdef DEBUG + enter_stats.unmanaged++; +#endif + npte = (prot & VM_PROT_WRITE) ? (PG_IOPAGE & ~PG_G) : (PG_IOPAGE& ~(PG_G | PG_M)); + } + + /* + * The only time we need to flush the cache is if we + * execute from a physical address and then change the data. + * This is the best place to do this. + * pmap_protect() and pmap_remove() are mostly used to switch + * between R/W and R/O pages. + * NOTE: we only support cache flush for read only text. + */ + if (prot == (VM_PROT_READ | VM_PROT_EXECUTE)) +#ifdef R4K + R4K_FlushICache(PHYS_TO_CACHED(pa), PAGE_SIZE); +#else + R3K_FlushICache(PHYS_TO_CACHED(pa), PAGE_SIZE); +#endif + + if (!pmap->pm_segtab) { + /* enter entries into kernel pmap */ + pte = kvtopte(va); + npte |= vad_to_pfn(pa) | PG_ROPAGE | PG_G; + if (wired) { + pmap->pm_stats.wired_count++; + npte |= PG_WIRED; + } + if (!(pte->pt_entry & PG_V)) { + pmap->pm_stats.resident_count++; + } else { +#ifdef DIAGNOSTIC + if (pte->pt_entry & PG_WIRED) + panic("pmap_enter: kernel wired"); +#endif + } + /* + * Update the same virtual address entry. + */ +#ifdef R4K + j = R4K_TLBUpdate(va, npte); +#else + j = R3K_TLBUpdate(va, npte); +#endif + pte->pt_entry = npte; + return; + } + + if (!(pte = pmap_segmap(pmap, va))) { + do { + mem = vm_page_alloc1(); + if (mem == NULL) { + VM_WAIT; /* XXX What else can we do */ + } /* XXX Deadlock situations? */ + } while (mem == NULL); + + pmap_zero_page(VM_PAGE_TO_PHYS(mem)); + pmap_segmap(pmap, va) = pte = (pt_entry_t *) + PHYS_TO_CACHED(VM_PAGE_TO_PHYS(mem)); +#ifdef DIAGNOSTIC + for (i = 0; i < NPTEPG; i++) { + if ((pte+i)->pt_entry) + panic("pmap_enter: new segmap not empty"); + } +#endif + } + pte += (va >> PGSHIFT) & (NPTEPG - 1); + + /* + * Now validate mapping with desired protection/wiring. + */ + npte |= vad_to_pfn(pa); + if (wired) { + pmap->pm_stats.wired_count++; + npte |= PG_WIRED; + } +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) { + printf("pmap_enter: new pte %x", npte); + if (pmap->pm_tlbgen == tlbpid_gen) + printf(" tlbpid %d", pmap->pm_tlbpid); + printf("\n"); + } +#endif + if (!(pte->pt_entry & PG_V)) { + pmap->pm_stats.resident_count++; + } + pte->pt_entry = npte; + if (pmap->pm_tlbgen == tlbpid_gen) +#ifdef R4K + j = R4K_TLBUpdate(va | (pmap->pm_tlbpid << R4K_PID_SHIFT), npte); +#else + j = R3K_TLBUpdate(va | (pmap->pm_tlbpid << R3K_PID_SHIFT), npte); +#endif +} + +/* + * Routine: pmap_change_wiring + * Function: Change the wiring attribute for a map/virtual-address + * pair. + * In/out conditions: + * The mapping must already exist in the pmap. + */ +void +pmap_change_wiring(pmap, va, wired) + register pmap_t pmap; + vm_offset_t va; + boolean_t wired; +{ + register pt_entry_t *pte; + u_int p; + register int i; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_WIRING)) + printf("pmap_change_wiring(%x, %x, %x)\n", pmap, va, wired); +#endif + if (pmap == NULL) + return; + + p = wired ? PG_WIRED : 0; + + /* + * Don't need to flush the TLB since PG_WIRED is only in software. + */ + if (!pmap->pm_segtab) { + /* change entries in kernel pmap */ +#ifdef DIAGNOSTIC + if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) + panic("pmap_change_wiring"); +#endif + pte = kvtopte(va); + } else { + if (!(pte = pmap_segmap(pmap, va))) + return; + pte += (va >> PGSHIFT) & (NPTEPG - 1); + } + + if (!(pte->pt_entry & PG_WIRED) && p) + pmap->pm_stats.wired_count++; + else if ((pte->pt_entry & PG_WIRED) && !p) + pmap->pm_stats.wired_count--; + + if (pte->pt_entry & PG_V) + pte->pt_entry = (pte->pt_entry & ~PG_WIRED) | p; +} + +/* + * Routine: pmap_extract + * Function: + * Extract the physical page address associated + * with the given map/virtual_address pair. + */ +vm_offset_t +pmap_extract(pmap, va) + register pmap_t pmap; + vm_offset_t va; +{ + register vm_offset_t pa; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract(%x, %x) -> ", pmap, va); +#endif + + if (!pmap->pm_segtab) { +#ifdef DIAGNOSTIC + if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) + panic("pmap_extract"); +#endif + pa = pfn_to_vad(kvtopte(va)->pt_entry); + } else { + register pt_entry_t *pte; + + if (!(pte = pmap_segmap(pmap, va))) + pa = 0; + else { + pte += (va >> PGSHIFT) & (NPTEPG - 1); + pa = pfn_to_vad(pte->pt_entry); + } + } + if (pa) + pa |= va & PGOFSET; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract: pa %x\n", pa); +#endif + return (pa); +} + +/* + * Copy the range specified by src_addr/len + * from the source map to the range dst_addr/len + * in the destination map. + * + * This routine is only advisory and need not do anything. + */ +void +pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) + pmap_t dst_pmap; + pmap_t src_pmap; + vm_offset_t dst_addr; + vm_size_t len; + vm_offset_t src_addr; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy(%x, %x, %x, %x, %x)\n", + dst_pmap, src_pmap, dst_addr, len, src_addr); +#endif +} + +/* + * Require that all active physical maps contain no + * incorrect entries NOW. [This update includes + * forcing updates of any address map caching.] + * + * Generally used to insure that a thread about + * to run will see a semantically correct world. + */ +void +pmap_update() +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_update()\n"); +#endif +} + +/* + * Routine: pmap_collect + * Function: + * Garbage collects the physical map system for + * pages which are no longer used. + * Success need not be guaranteed -- that is, there + * may well be pages which are not referenced, but + * others may be collected. + * Usage: + * Called by the pageout daemon when pages are scarce. + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_collect(%x)\n", pmap); +#endif +} + +/* + * pmap_zero_page zeros the specified (machine independent) page. + */ +void +pmap_zero_page(phys) + vm_offset_t phys; +{ + register int *p, *end; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)\n", phys); +#endif +/*XXX FIXME Not very sophisticated */ +#ifdef R4K + R4K_FlushCache(); +#endif + p = (int *)PHYS_TO_CACHED(phys); + end = p + PAGE_SIZE / sizeof(int); + do { + p[0] = 0; + p[1] = 0; + p[2] = 0; + p[3] = 0; + p += 4; + } while (p != end); +/*XXX FIXME Not very sophisticated */ +#ifdef R4K + R4K_FlushCache(); +#endif +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page. + */ +void +pmap_copy_page(src, dst) + vm_offset_t src, dst; +{ + register int *s, *d, *end; + register int tmp0, tmp1, tmp2, tmp3; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)\n", src, dst); +#endif +/*XXX FIXME Not very sophisticated */ +#ifdef R4K + R4K_FlushCache(); +#endif + s = (int *)PHYS_TO_CACHED(src); + d = (int *)PHYS_TO_CACHED(dst); + end = s + PAGE_SIZE / sizeof(int); + do { + tmp0 = s[0]; + tmp1 = s[1]; + tmp2 = s[2]; + tmp3 = s[3]; + d[0] = tmp0; + d[1] = tmp1; + d[2] = tmp2; + d[3] = tmp3; + s += 4; + d += 4; + } while (s != end); +/*XXX FIXME Not very sophisticated */ +#ifdef R4K + R4K_FlushCache(); +#endif +} + +/* + * Routine: pmap_pageable + * Function: + * Make the specified pages (by pmap, offset) + * pageable (or not) as requested. + * + * A page which is not pageable may not take + * a fault; therefore, its page table entry + * must remain valid for the duration. + * + * This routine is merely advisory; pmap_enter + * will specify that these pages are to be wired + * down (or not) as appropriate. + */ +void +pmap_pageable(pmap, sva, eva, pageable) + pmap_t pmap; + vm_offset_t sva, eva; + boolean_t pageable; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_pageable(%x, %x, %x, %x)\n", + pmap, sva, eva, pageable); +#endif +} + +/* + * Clear the modify bits on the specified physical page. + */ +void +pmap_clear_modify(pa) + vm_offset_t pa; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_modify(%x)\n", pa); +#endif +#ifdef ATTR + pmap_attributes[atop(pa)] &= ~PMAP_ATTR_MOD; +#endif +} + +/* + * pmap_clear_reference: + * + * Clear the reference bit on the specified physical page. + */ +void +pmap_clear_reference(pa) + vm_offset_t pa; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_clear_reference(%x)\n", pa); +#endif +#ifdef ATTR + pmap_attributes[atop(pa)] &= ~PMAP_ATTR_REF; +#endif +} + +/* + * pmap_is_referenced: + * + * Return whether or not the specified physical page is referenced + * by any physical maps. + */ +boolean_t +pmap_is_referenced(pa) + vm_offset_t pa; +{ +#ifdef ATTR + return (pmap_attributes[atop(pa)] & PMAP_ATTR_REF); +#else + return (FALSE); +#endif +} + +/* + * pmap_is_modified: + * + * Return whether or not the specified physical page is modified + * by any physical maps. + */ +boolean_t +pmap_is_modified(pa) + vm_offset_t pa; +{ +#ifdef ATTR + return (pmap_attributes[atop(pa)] & PMAP_ATTR_MOD); +#else + return (FALSE); +#endif +} + +vm_offset_t +pmap_phys_address(ppn) + int ppn; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_phys_address(%x)\n", ppn); +#endif + return (mips_ptob(ppn)); +} + +/* + * Miscellaneous support routines + */ + +/* + * Allocate a hardware PID and return it. + * It takes almost as much or more time to search the TLB for a + * specific PID and flush those entries as it does to flush the entire TLB. + * Therefore, when we allocate a new PID, we just take the next number. When + * we run out of numbers, we flush the TLB, increment the generation count + * and start over. PID zero is reserved for kernel use. + * This is called only by switch(). + */ +int +pmap_alloc_tlbpid(p) + register struct proc *p; +{ + register pmap_t pmap; + register int id; + + pmap = &p->p_vmspace->vm_pmap; + if (pmap->pm_tlbgen != tlbpid_gen) { + id = tlbpid_cnt; +#ifdef R4K + if (id == R4K_NUM_PIDS) { + R4K_TLBFlush(); +#else + if (id == R3K_NUM_PIDS) { + R3K_TLBFlush(); +#endif + /* reserve tlbpid_gen == 0 to alway mean invalid */ + if (++tlbpid_gen == 0) + tlbpid_gen = 1; + id = 1; + } + tlbpid_cnt = id + 1; + pmap->pm_tlbpid = id; + pmap->pm_tlbgen = tlbpid_gen; + } else + id = pmap->pm_tlbpid; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_TLBPID)) { + if (curproc) + printf("pmap_alloc_tlbpid: curproc %d '%s' ", + curproc->p_pid, curproc->p_comm); + else + printf("pmap_alloc_tlbpid: curproc <none> "); + printf("segtab %x tlbpid %d pid %d '%s'\n", + pmap->pm_segtab, id, p->p_pid, p->p_comm); + } +#endif + return (id); +} + +/* + * Remove a physical to virtual address translation. + * Returns TRUE if it was the last mapping and cached, else FALSE. + */ +int +pmap_remove_pv(pmap, va, pa) + pmap_t pmap; + vm_offset_t va, pa; +{ + register pv_entry_t pv, npv; + int s, last; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PVENTRY)) + printf("pmap_remove_pv(%x, %x, %x)\n", pmap, va, pa); +#endif + /* + * Remove page from the PV table (raise IPL since we + * may be called at interrupt time). + */ + if (!IS_VM_PHYSADDR(pa)) + return(TRUE); + pv = pa_to_pvh(pa); + s = splimp(); + /* + * If it is the first entry on the list, it is actually + * in the header and we must copy the following entry up + * to the header. Otherwise we must search the list for + * the entry. In either case we free the now unused entry. + */ + if (pmap == pv->pv_pmap && va == pv->pv_va) { + last = (pv->pv_flags & PV_UNCACHED) ? FALSE : TRUE; + npv = pv->pv_next; + if (npv) { + *pv = *npv; + free((caddr_t)npv, M_VMPVENT); + } else + pv->pv_pmap = NULL; +#ifdef DEBUG + remove_stats.pvfirst++; +#endif + } else { + last = FALSE; + for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) { +#ifdef DEBUG + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + goto fnd; + } +#ifdef DIAGNOSTIC + printf("pmap_remove_pv(%x, %x, %x) not found\n", pmap, va, pa); + panic("pmap_remove_pv"); +#endif + fnd: + pv->pv_next = npv->pv_next; + free((caddr_t)npv, M_VMPVENT); + } + splx(s); + return(last); +} + +/* + * vm_page_alloc1: + * + * Allocate and return a memory cell with no associated object. + */ +vm_page_t +vm_page_alloc1() +{ + register vm_page_t mem; + int spl; + + spl = splimp(); /* XXX */ + simple_lock(&vm_page_queue_free_lock); + if (vm_page_queue_free.tqh_first == NULL) { + simple_unlock(&vm_page_queue_free_lock); + splx(spl); + return (NULL); + } + + mem = vm_page_queue_free.tqh_first; + TAILQ_REMOVE(&vm_page_queue_free, mem, pageq); + + cnt.v_free_count--; + simple_unlock(&vm_page_queue_free_lock); + splx(spl); + + mem->flags = PG_BUSY | PG_CLEAN | PG_FAKE; + mem->wire_count = 0; + + /* + * Decide if we should poke the pageout daemon. + * We do this if the free count is less than the low + * water mark, or if the free count is less than the high + * water mark (but above the low water mark) and the inactive + * count is less than its target. + * + * We don't have the counts locked ... if they change a little, + * it doesn't really matter. + */ + + if (cnt.v_free_count < cnt.v_free_min || + (cnt.v_free_count < cnt.v_free_target && + cnt.v_inactive_count < cnt.v_inactive_target)) + thread_wakeup((void *)&vm_pages_needed); + return (mem); +} + +/* + * vm_page_free1: + * + * Returns the given page to the free list, + * disassociating it with any VM object. + * + * Object and page must be locked prior to entry. + */ +void +vm_page_free1(mem) + register vm_page_t mem; +{ + + if (mem->flags & PG_ACTIVE) { + TAILQ_REMOVE(&vm_page_queue_active, mem, pageq); + mem->flags &= ~PG_ACTIVE; + cnt.v_active_count--; + } + + if (mem->flags & PG_INACTIVE) { + TAILQ_REMOVE(&vm_page_queue_inactive, mem, pageq); + mem->flags &= ~PG_INACTIVE; + cnt.v_inactive_count--; + } + + if (!(mem->flags & PG_FICTITIOUS)) { + int spl; + + spl = splimp(); + simple_lock(&vm_page_queue_free_lock); + TAILQ_INSERT_TAIL(&vm_page_queue_free, mem, pageq); + + cnt.v_free_count++; + simple_unlock(&vm_page_queue_free_lock); + splx(spl); + } +} + +/* + * Find first virtual address >= *vap that doesn't cause + * a cache alias conflict. + */ +void +pmap_prefer(foff, vap) + register vm_offset_t foff; + register vm_offset_t *vap; +{ + register vm_offset_t va = *vap; + register long m, d; + + m = 0x10000; /* Max aliased cache size */ + + d = foff - va; + d &= (m-1); + *vap = va + d; +} + diff --git a/sys/arch/wgrisc/wgrisc/process_machdep.c b/sys/arch/wgrisc/wgrisc/process_machdep.c new file mode 100644 index 00000000000..116348abefe --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/process_machdep.c @@ -0,0 +1,114 @@ +/* $OpenBSD: process_machdep.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ +/* + * Copyright (c) 1994 Adam Glass + * 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. 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: + * Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel + * + * $Id: process_machdep.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + +/* + * 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 <sys/ptrace.h> +#include <machine/psl.h> +#include <machine/reg.h> + +int +process_read_regs(p, regs) + struct proc *p; + struct reg *regs; +{ + bcopy((caddr_t)p->p_md.md_regs, (caddr_t)regs, sizeof(struct reg)); + return (0); +} + +int +process_write_regs(p, regs) + struct proc *p; + struct reg *regs; +{ + bcopy((caddr_t)regs, (caddr_t)p->p_md.md_regs, sizeof(struct reg)); +/*XXX Clear to user set bits!! */ + return (0); +} + +int +process_sstep(p, sstep) + struct proc *p; +{ + if(sstep) + cpu_singlestep(p); + return (0); +} + +int +process_set_pc(p, addr) + struct proc *p; + caddr_t addr; +{ + p->p_md.md_regs[PC] = (int)addr; + return (0); +} + diff --git a/sys/arch/wgrisc/wgrisc/swapgeneric.c b/sys/arch/wgrisc/wgrisc/swapgeneric.c new file mode 100644 index 00000000000..00391d6c7d2 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/swapgeneric.c @@ -0,0 +1,61 @@ +/* $OpenBSD: swapgeneric.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ + +/*- + * Copyright (c) 1994 + * 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. 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. + * + * @(#)swapgeneric.c 8.2 (Berkeley) 3/21/94 + */ + +/* + * fake swapgeneric.c -- should do this differently. + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <machine/disklabel.h> + +int (*mountroot)() = NULL; /* tells autoconf.c that we are "generic" */ + +dev_t rootdev = NODEV; +dev_t dumpdev = NODEV; + +struct swdevt swdevt[] = { + { makedev(3, 0*MAXPARTITIONS+1), 0, 0 }, /* sd0b */ + { makedev(3, 1*MAXPARTITIONS+1), 0, 0 }, /* sd1b */ + { makedev(3, 2*MAXPARTITIONS+1), 0, 0 }, /* sd2b */ + { makedev(3, 3*MAXPARTITIONS+1), 0, 0 }, /* sd3b */ + { makedev(3, 4*MAXPARTITIONS+1), 0, 0 }, /* sd4b */ + { makedev(3, 5*MAXPARTITIONS+1), 0, 0 }, /* sd5b */ + { makedev(3, 6*MAXPARTITIONS+1), 0, 0 }, /* sd6b */ + { makedev(3, 7*MAXPARTITIONS+1), 0, 0 }, /* sd7b */ + { NODEV, 0, 0 } +}; diff --git a/sys/arch/wgrisc/wgrisc/sys_machdep.c b/sys/arch/wgrisc/wgrisc/sys_machdep.c new file mode 100644 index 00000000000..9e52c5c6cd5 --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/sys_machdep.c @@ -0,0 +1,130 @@ +/* $OpenBSD: sys_machdep.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ */ +/* $NetBSD: sys_machdep.c,v 1.6 1994/10/26 21:10:42 cgd Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)sys_machdep.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/file.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/mtio.h> +#include <sys/buf.h> +#include <sys/trace.h> + +#include <sys/mount.h> +#include <sys/syscallargs.h> + +#ifdef TRACE +int nvualarm; + +vtrace(p, uap, retval) + struct proc *p; + register struct vtrace_args /* { + syscallarg(int) request; + syscallarg(int) value; + } */ *uap; + register_t *retval; +{ + int vdoualarm(); + + switch (SCARG(uap, request)) { + + case VTR_DISABLE: /* disable a trace point */ + case VTR_ENABLE: /* enable a trace point */ + if (SCARG(uap, value) < 0 || SCARG(uap, value) >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[SCARG(uap, value)]; + traceflags[SCARG(uap, value)] = SCARG(uap, request); + break; + + case VTR_VALUE: /* return a trace point setting */ + if (SCARG(uap, value) < 0 || SCARG(uap, value) >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[SCARG(uap, value)]; + break; + + case VTR_UALARM: /* set a real-time ualarm, less than 1 min */ + if (SCARG(uap, value) <= 0 || SCARG(uap, value) > 60 * hz || + nvualarm > 5) + return (EINVAL); + nvualarm++; + timeout(vdoualarm, (caddr_t)p->p_pid, SCARG(uap, value)); + break; + + case VTR_STAMP: + trace(TR_STAMP, SCARG(uap, value), p->p_pid); + break; + } + return (0); +} + +vdoualarm(arg) + int arg; +{ + register struct proc *p; + + p = pfind(arg); + if (p) + psignal(p, 16); + nvualarm--; +} +#endif + +sys_sysarch(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sys_sysarch_args /* { + syscallarg(int) op; + syscallarg(char *) parms; + } */ *uap = v; + int error = 0; + + switch(SCARG(uap, op)) { + default: + error = EINVAL; + break; + } + return(error); +} diff --git a/sys/arch/wgrisc/wgrisc/trap.c b/sys/arch/wgrisc/wgrisc/trap.c new file mode 100644 index 00000000000..ce22ad2e05b --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/trap.c @@ -0,0 +1,1653 @@ +/* $OpenBSD: trap.c,v 1.1 1997/02/06 16:02:46 pefo 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: trap.c 1.32 91/04/06 + * + * from: @(#)trap.c 8.5 (Berkeley) 1/11/94 + * $Id: trap.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/signalvar.h> +#include <sys/syscall.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/device.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif +#include <net/netisr.h> + +#include <machine/trap.h> +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> +#include <machine/pte.h> +#include <machine/pmap.h> +#include <machine/mips_opcode.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> + +#include <wgrisc/wgrisc/wgrisctype.h> + +#include <sys/cdefs.h> +#include <sys/syslog.h> + +struct proc *cpuFPCurProcPtr; /* pointer to last proc to use FP */ + +unsigned CPU_EmulateBranch(); + +#ifdef R4K +extern void R4K_KernGenException(); +extern void R4K_UserGenException(); +extern void R4K_KernIntr(); +extern void R4K_UserIntr(); +extern void R4K_TLBModException(); +extern void R4K_TLBInvalidException(); + +void (*R4K_ExceptionTable[])() = { +/* + * The kernel exception handlers. + */ + R4K_KernIntr, /* external interrupt */ + R4K_KernGenException, /* TLB modification */ + R4K_TLBInvalidException, /* TLB miss (load or instr. fetch) */ + R4K_TLBInvalidException, /* TLB miss (store) */ + R4K_KernGenException, /* address error (load or I-fetch) */ + R4K_KernGenException, /* address error (store) */ + R4K_KernGenException, /* bus error (I-fetch) */ + R4K_KernGenException, /* bus error (load or store) */ + R4K_KernGenException, /* system call */ + R4K_KernGenException, /* breakpoint */ + R4K_KernGenException, /* reserved instruction */ + R4K_KernGenException, /* coprocessor unusable */ + R4K_KernGenException, /* arithmetic overflow */ + R4K_KernGenException, /* trap exception */ + R4K_KernGenException, /* viritual coherence exception inst */ + R4K_KernGenException, /* floating point exception */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* watch exception */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* reserved */ + R4K_KernGenException, /* viritual coherence exception data */ +/* + * The user exception handlers. + */ + R4K_UserIntr, /* 0 */ + R4K_UserGenException, /* 1 */ + R4K_UserGenException, /* 2 */ + R4K_UserGenException, /* 3 */ + R4K_UserGenException, /* 4 */ + R4K_UserGenException, /* 5 */ + R4K_UserGenException, /* 6 */ + R4K_UserGenException, /* 7 */ + R4K_UserGenException, /* 8 */ + R4K_UserGenException, /* 9 */ + R4K_UserGenException, /* 10 */ + R4K_UserGenException, /* 11 */ + R4K_UserGenException, /* 12 */ + R4K_UserGenException, /* 13 */ + R4K_UserGenException, /* 14 */ + R4K_UserGenException, /* 15 */ + R4K_UserGenException, /* 16 */ + R4K_UserGenException, /* 17 */ + R4K_UserGenException, /* 18 */ + R4K_UserGenException, /* 19 */ + R4K_UserGenException, /* 20 */ + R4K_UserGenException, /* 21 */ + R4K_UserGenException, /* 22 */ + R4K_UserGenException, /* 23 */ + R4K_UserGenException, /* 24 */ + R4K_UserGenException, /* 25 */ + R4K_UserGenException, /* 26 */ + R4K_UserGenException, /* 27 */ + R4K_UserGenException, /* 28 */ + R4K_UserGenException, /* 29 */ + R4K_UserGenException, /* 20 */ + R4K_UserGenException, /* 31 */ +}; +#else +extern void R3K_KernGenException(); +extern void R3K_UserGenException(); +extern void R3K_KernIntr(); +extern void R3K_UserIntr(); +extern void R3K_TLBModException(); +extern void R3K_TLBMissException(); + +void (*R3K_ExceptionTable[])() = { +/* + * The kernel exception handlers. + */ + R3K_KernIntr, /* external interrupt */ + R3K_KernGenException, /* TLB modification */ + R3K_TLBMissException, /* TLB miss (load or instr. fetch) */ + R3K_TLBMissException, /* TLB miss (store) */ + R3K_KernGenException, /* address error (load or I-fetch) */ + R3K_KernGenException, /* address error (store) */ + R3K_KernGenException, /* bus error (I-fetch) */ + R3K_KernGenException, /* bus error (load or store) */ + R3K_KernGenException, /* system call */ + R3K_KernGenException, /* breakpoint */ + R3K_KernGenException, /* reserved instruction */ + R3K_KernGenException, /* coprocessor unusable */ + R3K_KernGenException, /* arithmetic overflow */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ + R3K_KernGenException, /* Reserved */ +/* + * The user exception handlers. + */ + R3K_UserIntr, /* 0 */ + R3K_UserGenException, /* 1 */ + R3K_UserGenException, /* 2 */ + R3K_UserGenException, /* 3 */ + R3K_UserGenException, /* 4 */ + R3K_UserGenException, /* 5 */ + R3K_UserGenException, /* 6 */ + R3K_UserGenException, /* 7 */ + R3K_UserGenException, /* 8 */ + R3K_UserGenException, /* 9 */ + R3K_UserGenException, /* 10 */ + R3K_UserGenException, /* 11 */ + R3K_UserGenException, /* 12 */ + R3K_UserGenException, /* 13 */ + R3K_UserGenException, /* 14 */ + R3K_UserGenException, /* 15 */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ + R3K_UserGenException, /* Reserved */ +}; +#endif + +char *trap_type[] = { + "external interrupt", + "TLB modification", + "TLB miss (load or instr. fetch)", + "TLB miss (store)", + "address error (load or I-fetch)", + "address error (store)", + "bus error (I-fetch)", + "bus error (load or store)", + "system call", + "breakpoint", + "reserved instruction", + "coprocessor unusable", + "arithmetic overflow", + "trap", + "viritual coherency instruction", + "floating point", + "reserved 16", + "reserved 17", + "reserved 18", + "reserved 19", + "reserved 20", + "reserved 21", + "reserved 22", + "watch", + "reserved 24", + "reserved 25", + "reserved 26", + "reserved 27", + "reserved 28", + "reserved 29", + "reserved 30", + "viritual coherency data", +}; + +#define NHWI 8 +struct { + int int_mask; + int (*int_hand)(); +} cpu_int_tab[NHWI]; + +#ifdef DEBUG +#define TRAPSIZE 10 +struct trapdebug { /* trap history buffer for debugging */ + u_int status; + u_int cause; + u_int vadr; + u_int pc; + u_int ra; + u_int sp; + u_int code; +} trapdebug[TRAPSIZE], *trp = trapdebug; +#endif /* DEBUG */ + +#ifdef DEBUG /* stack trace code, also useful for DDB one day */ +extern void stacktrace(); +extern void logstacktrace(); + +/* extern functions printed by name in stack backtraces */ +extern void idle(), cpu_switch(), splx(), wbflush(); +extern void R4K_TLBMiss(); +extern void R3K_TLBMiss(); +#endif /* DEBUG */ + +static void mips_errintr(); +extern const struct callback *callv; +extern volatile struct chiptime *Mach_clock_addr; +extern u_long intrcnt[]; +extern u_int cputype; + +/* + * Handle an exception. + * Called from RxK_KernGenException() or RxK_UserGenException() + * when a processor trap occurs. + * In the case of a kernel trap, we return the pc where to resume if + * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc. + */ +unsigned +trap(statusReg, causeReg, vadr, pc, args) + unsigned statusReg; /* status register at time of the exception */ + unsigned causeReg; /* cause register at time of exception */ + unsigned vadr; /* address (if any) the fault occured on */ + unsigned pc; /* program counter where to continue */ +{ + register int type, i, usermode; + unsigned ucode = 0; + register struct proc *p = curproc; + u_quad_t sticks; + vm_prot_t ftype; + extern unsigned onfault_table[]; + int typ = 0; + +#ifdef R4K + usermode = R4K_USERMODE(statusReg); +#else + usermode = R3K_USERMODE(statusReg); +#endif +#ifdef DEBUG + trp->status = statusReg; + trp->cause = causeReg; + trp->vadr = vadr; + trp->pc = pc; + trp->ra = !usermode ? ((int *)&args)[19] : + p->p_md.md_regs[RA]; + trp->sp = (int)&args; + trp->code = 0; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; +#endif + + cnt.v_trap++; + type = (causeReg & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; + if (usermode) { + type |= T_USER; + sticks = p->p_sticks; + } + + /* + * Enable hardware interrupts if they were on before. + * We only respond to software interrupts when returning to user mode. + */ + if (statusReg & SR_INT_ENAB) + splx((statusReg & HARD_INT_MASK) | SR_INT_ENAB); + + switch (type) { + case T_TLB_MOD: + /* check for kernel address */ + if ((int)vadr < 0) { + register pt_entry_t *pte; + register unsigned entry; + register vm_offset_t pa; + + pte = kvtopte(vadr); + entry = pte->pt_entry; +#ifdef DIAGNOSTIC + if (!(entry & PG_V) || (entry & PG_M)) + panic("trap: ktlbmod: invalid pte"); +#endif + if (pmap_is_page_ro(pmap_kernel(), mips_trunc_page(vadr), entry)) { + /* write to read only page in the kernel */ + ftype = VM_PROT_WRITE; + goto kernel_fault; + } + entry |= PG_M; + pte->pt_entry = entry; + vadr &= ~PGOFSET; +#ifdef R4K + R4K_TLBUpdate(vadr, entry); +#else + R3K_TLBUpdate(vadr, entry); +#endif + pa = pfn_to_vad(entry); +#ifdef ATTR + pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD; +#else + if (!IS_VM_PHYSADDR(pa)) + panic("trap: ktlbmod: unmanaged page"); + PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; +#endif + return (pc); + } + /* FALLTHROUGH */ + + case T_TLB_MOD+T_USER: + { + register pt_entry_t *pte; + register unsigned entry; + register vm_offset_t pa; + pmap_t pmap = &p->p_vmspace->vm_pmap; + + if (!(pte = pmap_segmap(pmap, vadr))) + panic("trap: utlbmod: invalid segmap"); + pte += (vadr >> PGSHIFT) & (NPTEPG - 1); + entry = pte->pt_entry; +#ifdef DIAGNOSTIC + if (!(entry & PG_V) || (entry & PG_M)) { + panic("trap: utlbmod: invalid pte"); + } +#endif + if (pmap_is_page_ro(pmap, mips_trunc_page(vadr), entry)) { + /* write to read only page */ + ftype = VM_PROT_WRITE; + goto dofault; + } + entry |= PG_M; + pte->pt_entry = entry; +#ifdef R4K + vadr = (vadr & ~PGOFSET) | (pmap->pm_tlbpid << R4K_PID_SHIFT); + R4K_TLBUpdate(vadr, entry); +#else + vadr = (vadr & ~PGOFSET) | (pmap->pm_tlbpid << R3K_PID_SHIFT); + R3K_TLBUpdate(vadr, entry); +#endif + pa = pfn_to_vad(entry); +#ifdef ATTR + pmap_attributes[atop(pa)] |= PMAP_ATTR_MOD; +#else + if (!IS_VM_PHYSADDR(pa)) { + panic("trap: utlbmod: unmanaged page"); + } + PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN; +#endif + if (!usermode) + return (pc); + goto out; + } + + case T_TLB_LD_MISS: + case T_TLB_ST_MISS: + ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; + /* check for kernel address */ + if ((int)vadr < 0) { + register vm_offset_t va; + int rv; + + kernel_fault: + va = trunc_page((vm_offset_t)vadr); + rv = vm_fault(kernel_map, va, ftype, FALSE); + if (rv == KERN_SUCCESS) + return (pc); + if (i = ((struct pcb *)UADDR)->pcb_onfault) { + ((struct pcb *)UADDR)->pcb_onfault = 0; + return (onfault_table[i]); + } + goto err; + } + /* + * It is an error for the kernel to access user space except + * through the copyin/copyout routines. + */ + if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 0) + goto err; + /* check for fuswintr() or suswintr() getting a page fault */ + if (i == 4) + return (onfault_table[i]); + goto dofault; + + case T_TLB_LD_MISS+T_USER: + ftype = VM_PROT_READ; + goto dofault; + + case T_TLB_ST_MISS+T_USER: + ftype = VM_PROT_WRITE; + dofault: + { + register vm_offset_t va; + register struct vmspace *vm; + register vm_map_t map; + int rv; + + vm = p->p_vmspace; + map = &vm->vm_map; + va = trunc_page((vm_offset_t)vadr); + rv = vm_fault(map, va, ftype, FALSE); +#ifdef VMFAULT_TRACE + printf("vm_fault(%x (pmap %x), %x (%x), %x, %d) -> %x at pc %x\n", + map, &vm->vm_pmap, va, vadr, ftype, FALSE, rv, pc); +#endif + /* + * If this was a stack access we keep track of the maximum + * accessed stack size. Also, if vm_fault gets a protection + * failure it is due to accessing the stack region outside + * the current limit and we need to reflect that as an access + * error. + */ + if ((caddr_t)va >= vm->vm_maxsaddr) { + if (rv == KERN_SUCCESS) { + unsigned nss; + + nss = clrnd(btoc(USRSTACK-(unsigned)va)); + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + } else if (rv == KERN_PROTECTION_FAILURE) + rv = KERN_INVALID_ADDRESS; + } + if (rv == KERN_SUCCESS) { + if (!usermode) + return (pc); + goto out; + } + if (!usermode) { + if (i = ((struct pcb *)UADDR)->pcb_onfault) { + ((struct pcb *)UADDR)->pcb_onfault = 0; + return (onfault_table[i]); + } + goto err; + } + ucode = ftype; + i = SIGSEGV; + typ = SEGV_MAPERR; + break; + } + + case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ + case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ + ucode = 0; /* XXX should be VM_PROT_something */ + i = SIGBUS; + typ = BUS_ADRALN; + break; + case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ + case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ + ucode = 0; /* XXX should be VM_PROT_something */ + i = SIGBUS; + typ = BUS_OBJERR; + break; + + case T_SYSCALL+T_USER: + { + register int *locr0 = p->p_md.md_regs; + register struct sysent *callp; + unsigned int code; + int numsys; + struct args { + int i[8]; + } args; + int rval[2]; + + cnt.v_syscall++; + /* compute next PC after syscall instruction */ + if ((int)causeReg < 0) + locr0[PC] = CPU_EmulateBranch(locr0, pc, 0, 0); + else + locr0[PC] += 4; + callp = p->p_emul->e_sysent; + numsys = p->p_emul->e_nsysent; + code = locr0[V0]; + switch (code) { + case SYS_syscall: + /* + * Code is first argument, followed by actual args. + */ + code = locr0[A0]; + if (code >= numsys) + callp += p->p_emul->e_nosys; /* (illegal) */ + else + callp += code; + i = callp->sy_argsize / sizeof(int); + args.i[0] = locr0[A1]; + args.i[1] = locr0[A2]; + args.i[2] = locr0[A3]; + if (i > 3) { + i = copyin((caddr_t)(locr0[SP] + + 4 * sizeof(int)), + (caddr_t)&args.i[3], + (u_int)(i - 3) * sizeof(int)); + if (i) { + locr0[V0] = i; + locr0[A3] = 1; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, + callp->sy_argsize, + args.i); +#endif + goto done; + } + } + break; + + case SYS___syscall: + /* + * Like syscall, but code is a quad, so as to maintain + * quad alignment for the rest of the arguments. + */ + code = locr0[A0 + _QUAD_LOWWORD]; + if (code >= numsys) + callp += p->p_emul->e_nosys; /* (illegal) */ + else + callp += code; + i = callp->sy_argsize / sizeof(int); + args.i[0] = locr0[A2]; + args.i[1] = locr0[A3]; + if (i > 2) { + i = copyin((caddr_t)(locr0[SP] + + 4 * sizeof(int)), + (caddr_t)&args.i[2], + (u_int)(i - 2) * sizeof(int)); + if (i) { + locr0[V0] = i; + locr0[A3] = 1; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, + callp->sy_argsize, + args.i); +#endif + goto done; + } + } + break; + + default: + if (code >= numsys) + callp += p->p_emul->e_nosys; /* (illegal) */ + else + callp += code; + i = callp->sy_narg; + args.i[0] = locr0[A0]; + args.i[1] = locr0[A1]; + args.i[2] = locr0[A2]; + args.i[3] = locr0[A3]; + if (i > 4) { + i = copyin((caddr_t)(locr0[SP] + + 4 * sizeof(int)), + (caddr_t)&args.i[4], + (u_int)(i - 4) * sizeof(int)); + if (i) { + locr0[V0] = i; + locr0[A3] = 1; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, + callp->sy_argsize, + args.i); +#endif + goto done; + } + } + } +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args.i); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, callp->sy_argsize, args.i); +#endif + rval[0] = 0; + rval[1] = locr0[V1]; +#ifdef DEBUG + if (trp == trapdebug) + trapdebug[TRAPSIZE - 1].code = code; + else + trp[-1].code = code; +#endif + i = (*callp->sy_call)(p, &args, rval); + /* + * Reinitialize proc pointer `p' as it may be different + * if this is a child returning from fork syscall. + */ + p = curproc; + locr0 = p->p_md.md_regs; +#ifdef DEBUG + { int s; + s = splhigh(); + trp->status = statusReg; + trp->cause = causeReg; + trp->vadr = locr0[SP]; + trp->pc = locr0[PC]; + trp->ra = locr0[RA]; + trp->code = -code; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; + splx(s); + } +#endif + switch (i) { + case 0: + locr0[V0] = rval[0]; + locr0[V1] = rval[1]; + locr0[A3] = 0; + break; + + case ERESTART: + locr0[PC] = pc; + break; + + case EJUSTRETURN: + break; /* nothing to do */ + + default: + locr0[V0] = i; + locr0[A3] = 1; + } + if(code == SYS_ptrace) +#ifdef R4K + R4K_FlushCache(); +#else + R3K_FlushCache(); +#endif + done: +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, i, rval); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, i, rval[0]); +#endif + goto out; + } + + case T_BREAK+T_USER: + { + register unsigned va, instr; + struct uio uio; + struct iovec iov; + + /* compute address of break instruction */ + va = pc; + if ((int)causeReg < 0) + va += 4; + + /* read break instruction */ + instr = fuiword((caddr_t)va); +#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 + if (p->p_md.md_ss_addr != va || instr != BREAK_SSTEP) { + i = SIGTRAP; + typ = TRAP_TRACE; + break; + } + + /* + * Restore original instruction and clear BP + */ + iov.iov_base = (caddr_t)&p->p_md.md_ss_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; + i = procfs_domem(p, p, NULL, &uio); +#ifdef R4K + R4K_FlushCache(); +#else + R3K_FlushCache(); +#endif + + if (i < 0) + printf("Warning: can't restore instruction at %x: %x\n", + p->p_md.md_ss_addr, p->p_md.md_ss_instr); + + p->p_md.md_ss_addr = 0; + i = SIGTRAP; + typ = TRAP_TRACE; + break; + } + + case T_RES_INST+T_USER: + i = SIGILL; + typ = ILL_ILLOPC; + break; + + case T_COP_UNUSABLE+T_USER: + if ((causeReg & CR_COP_ERR) != 0x10000000) { + i = SIGILL; /* only FPU instructions allowed */ + typ = ILL_ILLOPC; + break; + } + CPU_SwitchFPState(cpuFPCurProcPtr, p->p_md.md_regs); + cpuFPCurProcPtr = p; + p->p_md.md_regs[PS] |= SR_COP_1_BIT; + p->p_md.md_flags |= MDP_FPUSED; + goto out; + + case T_FPE: +#ifdef DEBUG + trapDump("fpintr"); +#else + printf("FPU Trap: PC %x CR %x SR %x\n", + pc, causeReg, statusReg); + goto err; +#endif + + case T_FPE+T_USER: + CPU_FPTrap(statusReg, causeReg, pc); + goto out; + + case T_OVFLOW+T_USER: + i = SIGFPE; + typ = FPE_FLTOVF; + break; + + case T_ADDR_ERR_LD: /* misaligned access */ + case T_ADDR_ERR_ST: /* misaligned access */ + case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ + if (i = ((struct pcb *)UADDR)->pcb_onfault) { + ((struct pcb *)UADDR)->pcb_onfault = 0; + return (onfault_table[i]); + } + /* FALLTHROUGH */ + + default: + err: +#ifdef DEBUG + { + extern struct pcb mdbpcb; + + if (usermode) + mdbpcb = p->p_addr->u_pcb; + else { + mdbpcb.pcb_regs[ZERO] = 0; + mdbpcb.pcb_regs[AST] = ((int *)&args)[2]; + mdbpcb.pcb_regs[V0] = ((int *)&args)[3]; + mdbpcb.pcb_regs[V1] = ((int *)&args)[4]; + mdbpcb.pcb_regs[A0] = ((int *)&args)[5]; + mdbpcb.pcb_regs[A1] = ((int *)&args)[6]; + mdbpcb.pcb_regs[A2] = ((int *)&args)[7]; + mdbpcb.pcb_regs[A3] = ((int *)&args)[8]; + mdbpcb.pcb_regs[T0] = ((int *)&args)[9]; + mdbpcb.pcb_regs[T1] = ((int *)&args)[10]; + mdbpcb.pcb_regs[T2] = ((int *)&args)[11]; + mdbpcb.pcb_regs[T3] = ((int *)&args)[12]; + mdbpcb.pcb_regs[T4] = ((int *)&args)[13]; + mdbpcb.pcb_regs[T5] = ((int *)&args)[14]; + mdbpcb.pcb_regs[T6] = ((int *)&args)[15]; + mdbpcb.pcb_regs[T7] = ((int *)&args)[16]; + mdbpcb.pcb_regs[T8] = ((int *)&args)[17]; + mdbpcb.pcb_regs[T9] = ((int *)&args)[18]; + mdbpcb.pcb_regs[RA] = ((int *)&args)[19]; + mdbpcb.pcb_regs[MULLO] = ((int *)&args)[21]; + mdbpcb.pcb_regs[MULHI] = ((int *)&args)[22]; + mdbpcb.pcb_regs[PC] = pc; + mdbpcb.pcb_regs[SR] = statusReg; + bzero((caddr_t)&mdbpcb.pcb_regs[F0], 33 * sizeof(int)); + } + if (mdb(causeReg, vadr, p, !usermode)) + return (mdbpcb.pcb_regs[PC]); + } +#else +#ifdef DEBUG + stacktrace(); + trapDump("trap"); +#endif +#endif + panic("trap"); + } + p->p_md.md_regs[PC] = pc; + p->p_md.md_regs[CAUSE] = causeReg; + p->p_md.md_regs[BADVADDR] = vadr; + trapsignal(p, i, ucode, typ, (caddr_t)vadr); +out: + /* + * Note: we should only get here if returning to user mode. + */ + /* take pending signals */ + while ((i = CURSIG(p)) != 0) + postsig(i); + p->p_priority = p->p_usrpri; + astpending = 0; + if (want_resched) { + int s; + + /* + * Since we are curproc, clock will normally just change + * our priority without moving us from one queue to another + * (since the running process is not on a queue.) + * If that happened after we put ourselves on the run queue + * but before we switched, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + splx(s); + while ((i = CURSIG(p)) != 0) + postsig(i); + } + + /* + * If profiling, charge system time to the trapped pc. + */ + if (p->p_flag & P_PROFIL) { + extern int psratio; + + addupc_task(p, pc, (int)(p->p_sticks - sticks) * psratio); + } + + curpriority = p->p_priority; + return (pc); +} + +/* + * Handle an interrupt. + * Called from RxK_KernIntr() or RxK_UserIntr() + * Note: curproc might be NULL. + */ +interrupt(statusReg, causeReg, pc, what, args) + unsigned statusReg; /* status register at time of the exception */ + unsigned causeReg; /* cause register at time of exception */ + unsigned pc; /* program counter where to continue */ +{ + register unsigned mask, causemask; + register int i; + struct clockframe cf; + +#ifdef DEBUG + trp->status = statusReg; + trp->cause = causeReg; + trp->vadr = 0; + trp->pc = pc; + trp->ra = 0; + trp->sp = (int)&args; + trp->code = 0; + if (++trp == &trapdebug[TRAPSIZE]) + trp = trapdebug; +#endif + + cnt.v_intr++; + mask = causeReg & statusReg; /* pending interrupts & enable mask */ + cf.pc = pc; + cf.sr = statusReg; + cf.cr = causeReg; + +#ifndef R4K + if(mask & INT_MASK_0) { + if(R3K_USERMODE(statusReg)) + CPU_FPTrap(statusReg, causeReg, pc); + else + printf("FPU Int @ 0x%x\n", pc); + } +#endif + + /* + * Check off all enabled interrupts. Called interrupt routine + * returns mask of interrupts to reenable. + */ + causemask = 0; + for(i = 0; i < NHWI; i++) { + if(cpu_int_tab[i].int_mask & mask) { + causemask |= cpu_int_tab[i].int_mask; + causeReg &= (*cpu_int_tab[i].int_hand)(mask, &cf); + } + } + causeReg |= causemask; + /* + * Reenable all non served hardware levels. + */ + splx((statusReg & ~causeReg & HARD_INT_MASK) | SR_INT_ENAB); + + + if (mask & SOFT_INT_MASK_0) { + clearsoftclock(); + cnt.v_soft++; + softclock(); + } + /* + * Process network interrupt if we trapped or will very soon + */ + if ((mask & SOFT_INT_MASK_1) || + netisr && (statusReg & SOFT_INT_MASK_1)) { + clearsoftnet(); + cnt.v_soft++; + intrcnt[1]++; +#ifdef INET + if (netisr & (1 << NETISR_ARP)) { + netisr &= ~(1 << NETISR_ARP); + arpintr(); + } + if (netisr & (1 << NETISR_IP)) { + netisr &= ~(1 << NETISR_IP); + ipintr(); + } +#endif +#ifdef NS + if (netisr & (1 << NETISR_NS)) { + netisr &= ~(1 << NETISR_NS); + nsintr(); + } +#endif +#ifdef ISO + if (netisr & (1 << NETISR_ISO)) { + netisr &= ~(1 << NETISR_ISO); + clnlintr(); + } +#endif +#include "ppp.h" +#if NPPP > 0 + if(netisr & (1 << NETISR_PPP)) { + netisr &= ~(1 << NETISR_PPP); + pppintr(); + } +#endif + } + if (mask & SOFT_INT_MASK_0) { + clearsoftclock(); + intrcnt[0]++; + cnt.v_soft++; + softclock(); + } +} + +/* + * Set up handler for external interrupt events. + * Events are checked in priority order. + */ +void +set_intr(mask, int_hand, prio) + int mask; + int (*int_hand)(); + int prio; +{ + if(prio > NHWI) + panic("set_intr: to high priority"); + + if(cpu_int_tab[prio].int_mask != 0) + panic("set_intr: int already set"); + + cpu_int_tab[prio].int_hand = int_hand; + cpu_int_tab[prio].int_mask = mask; +} + +/* + * This is called from RxK_UserIntr() if astpending is set. + * This is very similar to the tail of trap(). + */ +softintr(statusReg, pc) + unsigned statusReg; /* status register at time of the exception */ + unsigned pc; /* program counter where to continue */ +{ + register struct proc *p = curproc; + int sig; + + cnt.v_soft++; + /* take pending signals */ + while ((sig = CURSIG(p)) != 0) + postsig(sig); + p->p_priority = p->p_usrpri; + astpending = 0; + if (p->p_flag & P_OWEUPC) { + p->p_flag &= ~P_OWEUPC; + ADDUPROF(p); + } + if (want_resched) { + int s; + + /* + * Since we are curproc, clock will normally just change + * our priority without moving us from one queue to another + * (since the running process is not on a queue.) + * If that happened after we put ourselves on the run queue + * but before we switched, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + splx(s); + while ((sig = CURSIG(p)) != 0) + postsig(sig); + } + curpriority = p->p_priority; +} + +#ifdef DEBUG +trapDump(msg) + char *msg; +{ + register int i; + int s; + + s = splhigh(); + printf("trapDump(%s)\n", msg); + for (i = 0; i < TRAPSIZE; i++) { + if (trp == trapdebug) + trp = &trapdebug[TRAPSIZE - 1]; + else + trp--; + if (trp->cause == 0) + break; + printf("%s: ADR %x PC %x CR %x SR %x\n", + trap_type[(trp->cause & CR_EXC_CODE) >> + CR_EXC_CODE_SHIFT], + trp->vadr, trp->pc, trp->cause, trp->status); + printf(" RA %x SP %x code %d\n", trp->ra, trp->sp, trp->code); + } + splx(s); +} +#endif + +/* + *---------------------------------------------------------------------- + * + * MemErrorInterrupts -- + * + * Handler an interrupt for the control register. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static void +mips_errintr() +{ +#if 0 + volatile u_short *sysCSRPtr = + (u_short *)PHYS_TO_UNCACHED(KN01_SYS_CSR); + u_short csr; + + csr = *sysCSRPtr; + + if (csr & KN01_CSR_MERR) { + printf("Memory error at 0x%x\n", + *(unsigned *)PHYS_TO_UNCACHED(KN01_SYS_ERRADR)); + panic("Mem error interrupt"); + } + *sysCSRPtr = (csr & ~KN01_CSR_MBZ) | 0xff; +#endif +} + + +/* + * Return the resulting PC as if the branch was executed. + */ +unsigned +CPU_EmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch) + unsigned *regsPtr; + unsigned instPC; + unsigned fpcCSR; + int allowNonBranch; +{ + InstFmt inst; + unsigned retAddr; + int condition; + +#define GetBranchDest(InstPtr, inst) \ + ((unsigned)InstPtr + 4 + ((short)inst.IType.imm << 2)) + + + if(allowNonBranch == 0) { + inst = *(InstFmt *)instPC; + } + else { + inst = *(InstFmt *)&allowNonBranch; + } +#if 0 + printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC, + inst.word, fpcCSR); /* XXX */ +#endif + switch ((int)inst.JType.op) { + case OP_SPECIAL: + switch ((int)inst.RType.func) { + case OP_JR: + case OP_JALR: + retAddr = regsPtr[inst.RType.rs]; + break; + + default: + if (!allowNonBranch) + panic("CPU_EmulateBranch: Non-branch"); + retAddr = instPC + 4; + break; + } + break; + + case OP_BCOND: + switch ((int)inst.IType.rt) { + case OP_BLTZ: + case OP_BLTZL: + case OP_BLTZAL: + case OP_BLTZALL: + if ((int)(regsPtr[inst.RType.rs]) < 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BGEZ: + case OP_BGEZL: + case OP_BGEZAL: + case OP_BGEZALL: + if ((int)(regsPtr[inst.RType.rs]) >= 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + default: + panic("CPU_EmulateBranch: Bad branch cond"); + } + break; + + case OP_J: + case OP_JAL: + retAddr = (inst.JType.target << 2) | + ((unsigned)instPC & 0xF0000000); + break; + + case OP_BEQ: + case OP_BEQL: + if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt]) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BNE: + case OP_BNEL: + if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt]) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BLEZ: + case OP_BLEZL: + if ((int)(regsPtr[inst.RType.rs]) <= 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_BGTZ: + case OP_BGTZL: + if ((int)(regsPtr[inst.RType.rs]) > 0) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + case OP_COP1: + switch (inst.RType.rs) { + case OP_BCx: + case OP_BCy: + if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) + condition = fpcCSR & FPC_COND_BIT; + else + condition = !(fpcCSR & FPC_COND_BIT); + if (condition) + retAddr = GetBranchDest(instPC, inst); + else + retAddr = instPC + 8; + break; + + default: + if (!allowNonBranch) + panic("CPU_EmulateBranch: Bad coproc branch instruction"); + retAddr = instPC + 4; + } + break; + + default: + if (!allowNonBranch) + panic("CPU_EmulateBranch: Non-branch instruction"); + retAddr = instPC + 4; + } +#if 0 + printf("Target addr=%x\n", retAddr); /* XXX */ +#endif + return (retAddr); +} + +/* + * This routine is called by procxmt() to single step one instruction. + * We do this by storing a break instruction after the current instruction, + * resuming execution, and then restoring the old instruction. + */ +cpu_singlestep(p) + register struct proc *p; +{ + register unsigned va; + register int *locr0 = p->p_md.md_regs; + int i; + int bpinstr = BREAK_SSTEP; + int curinstr; + struct uio uio; + struct iovec iov; + + /* + * Fetch what's at the current location. + */ + iov.iov_base = (caddr_t)&curinstr; + iov.iov_len = sizeof(int); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = (off_t)locr0[PC]; + uio.uio_resid = sizeof(int); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_procp = curproc; + procfs_domem(curproc, p, NULL, &uio); + + /* compute next address after current location */ + if(curinstr != 0) { + va = CPU_EmulateBranch(locr0, locr0[PC], locr0[FSR], curinstr); + } + else { + va = locr0[PC] + 4; + } + if (p->p_md.md_ss_addr) { + printf("SS %s (%d): breakpoint already set at %x (va %x)\n", + p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */ + return (EFAULT); + } + p->p_md.md_ss_addr = va; + /* + * Fetch what's at the current location. + */ + iov.iov_base = (caddr_t)&p->p_md.md_ss_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_READ; + uio.uio_procp = curproc; + procfs_domem(curproc, p, NULL, &uio); + + /* + * Store breakpoint instruction at the "next" location now. + */ + iov.iov_base = (caddr_t)&bpinstr; + 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; + i = procfs_domem(curproc, p, NULL, &uio); +#ifdef R4K + R4K_FlushCache(); +#else + R3K_FlushCache(); +#endif + + if (i < 0) + return (EFAULT); +#if 0 + printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", + p->p_comm, p->p_pid, p->p_md.md_ss_addr, + p->p_md.md_ss_instr, locr0[PC], curinstr); /* XXX */ +#endif + return (0); +} + +#ifdef DEBUG +kdbpeek(addr) +{ + if (addr & 3) { + printf("kdbpeek: unaligned address %x\n", addr); + return (-1); + } + return (*(int *)addr); +} +#endif + +#ifdef DEBUG +#define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ + +/* forward */ +char *fn_name(unsigned addr); +void stacktrace_subr __P((int, int, int, int, int (*)(const char*, ...))); + +/* + * Print a stack backtrace. + */ +void +stacktrace(a0, a1, a2, a3) + int a0, a1, a2, a3; +{ + stacktrace_subr(a0, a1, a2, a3, printf); +} + +void +logstacktrace(a0, a1, a2, a3) + int a0, a1, a2, a3; +{ + stacktrace_subr(a0, a1, a2, a3, addlog); +} + +void +stacktrace_subr(a0, a1, a2, a3, printfn) + int a0, a1, a2, a3; + int (*printfn) __P((const char*, ...)); +{ + unsigned pc, sp, fp, ra, va, subr; + unsigned instr, mask; + InstFmt i; + int more, stksize; + int regs[3]; + extern setsoftclock(); + extern char start[], edata[]; + unsigned int frames = 0; + + cpu_getregs(regs); + + /* get initial values from the exception frame */ + sp = regs[0]; + pc = regs[1]; + ra = 0; + fp = regs[2]; + +/* Jump here when done with a frame, to start a new one */ +loop: + ra = 0; + +/* Jump here after a nonstandard (interrupt handler) frame */ +specialframe: + stksize = 0; + subr = 0; + if (frames++ > 100) { + (*printfn)("\nstackframe count exceeded\n"); + /* return breaks stackframe-size heuristics with gcc -O2 */ + goto finish; /*XXX*/ + } + + /* check for bad SP: could foul up next frame */ + if (sp & 3 || sp < 0x80000000) { + (*printfn)("SP 0x%x: not in kernel\n", sp); + ra = 0; + subr = 0; + goto done; + } + + /* check for bad PC */ + if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) { + (*printfn)("PC 0x%x: not in kernel\n", pc); + ra = 0; + goto done; + } + + /* + * Find the beginning of the current subroutine by scanning backwards + * from the current PC for the end of the previous subroutine. + */ + if (!subr) { + va = pc - sizeof(int); + while ((instr = kdbpeek(va)) != MIPS_JR_RA) + va -= sizeof(int); + va += 2 * sizeof(int); /* skip back over branch & delay slot */ + /* skip over nulls which might separate .o files */ + while ((instr = kdbpeek(va)) == 0) + va += sizeof(int); + subr = va; + } + + /* + * Jump here for locore entry pointsn for which the preceding + * function doesn't end in "j ra" + */ +stackscan: + /* scan forwards to find stack size and any saved registers */ + stksize = 0; + more = 3; + mask = 0; + for (va = subr; more; va += sizeof(int), + more = (more == 3) ? 3 : more - 1) { + /* stop if hit our current position */ + if (va >= pc) + break; + instr = kdbpeek(va); + i.word = instr; + switch (i.JType.op) { + case OP_SPECIAL: + switch (i.RType.func) { + case OP_JR: + case OP_JALR: + more = 2; /* stop after next instruction */ + break; + + case OP_SYSCALL: + case OP_BREAK: + more = 1; /* stop now */ + }; + break; + + case OP_BCOND: + case OP_J: + case OP_JAL: + case OP_BEQ: + case OP_BNE: + case OP_BLEZ: + case OP_BGTZ: + more = 2; /* stop after next instruction */ + break; + + case OP_COP0: + case OP_COP1: + case OP_COP2: + case OP_COP3: + switch (i.RType.rs) { + case OP_BCx: + case OP_BCy: + more = 2; /* stop after next instruction */ + }; + break; + + case OP_SW: + /* look for saved registers on the stack */ + if (i.IType.rs != 29) + break; + /* only restore the first one */ + if (mask & (1 << i.IType.rt)) + break; + mask |= (1 << i.IType.rt); + switch (i.IType.rt) { + case 4: /* a0 */ + a0 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 5: /* a1 */ + a1 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 6: /* a2 */ + a2 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 7: /* a3 */ + a3 = kdbpeek(sp + (short)i.IType.imm); + break; + + case 30: /* fp */ + fp = kdbpeek(sp + (short)i.IType.imm); + break; + + case 31: /* ra */ + ra = kdbpeek(sp + (short)i.IType.imm); + } + break; + + case OP_ADDI: + case OP_ADDIU: + /* look for stack pointer adjustment */ + if (i.IType.rs != 29 || i.IType.rt != 29) + break; + stksize = - ((short)i.IType.imm); + } + } + +done: + (*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", + fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); + + if (ra) { + if (pc == ra && stksize == 0) + (*printfn)("stacktrace: loop!\n"); + else { + pc = ra; + sp += stksize; + ra = 0; + goto loop; + } + } else { +finish: + if (curproc) + (*printfn)("User-level: pid %d\n", curproc->p_pid); + else + (*printfn)("User-level: curproc NULL\n"); + } +} + +/* + * Functions ``special'' enough to print by name + */ +#ifdef __STDC__ +#define Name(_fn) { (void*)_fn, # _fn } +#else +#define Name(_fn) { _fn, "_fn"} +#endif +static struct { void *addr; char *name;} names[] = { + Name(interrupt), + Name(trap), +#ifdef R4K + Name(R4K_KernGenException), + Name(R4K_UserGenException), + Name(R4K_KernIntr), + Name(R4K_UserIntr), +#else + Name(R3K_KernGenException), + Name(R3K_UserGenException), + Name(R3K_KernIntr), + Name(R3K_UserIntr), +#endif + Name(splx), + Name(idle), + Name(cpu_switch), + {0, 0} +}; + +/* + * Map a function address to a string name, if known; or a hex string. + */ +char * +fn_name(unsigned addr) +{ + static char buf[17]; + int i = 0; + + for (i = 0; names[i].name; i++) + if (names[i].addr == (void*)addr) + return (names[i].name); + sprintf(buf, "%x", addr); + return (buf); +} + +#endif /* DEBUG */ diff --git a/sys/arch/wgrisc/wgrisc/vm_machdep.c b/sys/arch/wgrisc/wgrisc/vm_machdep.c new file mode 100644 index 00000000000..f27b9b49c3a --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/vm_machdep.c @@ -0,0 +1,494 @@ +/* $OpenBSD: vm_machdep.c,v 1.1 1997/02/06 16:02:46 pefo 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: vm_machdep.c 1.21 91/04/06 + * + * from: @(#)vm_machdep.c 8.3 (Berkeley) 1/4/94 + * $Id: vm_machdep.c,v 1.1 1997/02/06 16:02:46 pefo Exp $ + */ + + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/vnode.h> +#include <sys/user.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#if 0 +#include <vm/vm_object.h> +#endif + +#include <machine/pte.h> +#include <machine/cpu.h> + +vm_offset_t kmem_alloc_wait_align(); + +/* + * 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. + */ +cpu_fork(p1, p2) + register struct proc *p1, *p2; +{ + register struct user *up = p2->p_addr; + register pt_entry_t *pte; + register int i; + extern struct proc *cpuFPCurProcPtr; + + p2->p_md.md_regs = up->u_pcb.pcb_regs; + p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; + + /* + * Cache the PTEs for the user area in the machine dependent + * part of the proc struct so cpu_switch() can quickly map in + * the user struct and kernel stack. Note: if the virtual address + * translation changes (e.g. swapout) we have to update this. + */ + pte = kvtopte(up); + for (i = 0; i < UPAGES; i++) { + p2->p_md.md_upte[i] = pte->pt_entry & ~(PG_G | PG_RO | PG_WIRED); + pte++; + } + + /* + * Copy floating point state from the FP chip if this process + * has state stored there. + */ + if (p1 == cpuFPCurProcPtr) + CPU_SaveCurFPState(p1); + + /* + * Copy pcb and stack from proc p1 to p2. + * We do this as cheaply as possible, copying only the active + * part of the stack. The stack and pcb need to agree; + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + /* cache segtab for ULTBMiss() */ + p2->p_addr->u_pcb.pcb_segtab = (void *)p2->p_vmspace->vm_pmap.pm_segtab; + + /* + * Arrange for a non-local goto when the new process + * is started, to resume here, returning nonzero from setjmp. + */ +#ifdef DIAGNOSTIC + if (p1 != curproc) + panic("cpu_fork: curproc"); +#endif + if (copykstack(up)) { + /* + * Return 1 in child. + */ + return (1); + } + 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(p) + register struct proc *p; +{ + register struct user *up = p->p_addr; + register pt_entry_t *pte; + register int i; + + /* + * Cache the PTEs for the user area in the machine dependent + * part of the proc struct so cpu_switch() can quickly map in + * the user struct and kernel stack. + */ + pte = kvtopte(up); + for (i = 0; i < UPAGES; i++) { + p->p_md.md_upte[i] = pte->pt_entry & ~(PG_G | PG_RO | PG_WIRED); + pte++; + } +} + +/* + * 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(p) + struct proc *p; +{ + extern struct proc *cpuFPCurProcPtr; + + if (cpuFPCurProcPtr == p) + cpuFPCurProcPtr = (struct proc *)0; + + vmspace_free(p->p_vmspace); + + (void) splhigh(); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); + switch_exit(); + /* NOTREACHED */ +} + +/* + * Dump the machine specific header information at the start of a core dump. + */ +cpu_coredump(p, vp, cred, core) + struct proc *p; + struct vnode *vp; + struct ucred *cred; + struct core *core; +{ + extern struct proc *cpuFPCurProcPtr; + + /* + * Copy floating point state from the FP chip if this process + * has state stored there. + */ + if (p == cpuFPCurProcPtr) + CPU_SaveCurFPState(p); + + return (vn_rdwr(UIO_WRITE, vp, (caddr_t)p->p_addr, ctob(UPAGES), + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, + p)); +} + +/* + * Move pages from one kernel virtual address to another. + * Both addresses are assumed to reside in the Sysmap, + * and size must be a multiple of CLSIZE. + */ +void +pagemove(from, to, size) + register caddr_t from, to; + size_t size; +{ + register pt_entry_t *fpte, *tpte; + + if (size % CLBYTES) + panic("pagemove"); + fpte = kvtopte(from); + tpte = kvtopte(to); +#ifdef R4K + if(((int)from & CpuCacheAliasMask) != ((int)to & CpuCacheAliasMask)) { + R4K_HitFlushDCache(from, size); + } +#endif + while (size > 0) { +#ifdef R4K + R4K_TLBFlushAddr(from); + R4K_TLBUpdate(to, *fpte); +#else + R3K_TLBFlushAddr(from); + R3K_TLBUpdate(to, *fpte); +#endif + *tpte++ = *fpte; + fpte->pt_entry = PG_NV | PG_G; + fpte++; + size -= NBPG; + from += NBPG; + to += NBPG; + } +} + +extern vm_map_t phys_map; + +/* + * 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 the phys_map + */ +void +vmapbuf(bp, len) + struct buf *bp; + vm_size_t len; +{ + register caddr_t addr; + register vm_size_t sz; + struct proc *p; + int off; + vm_offset_t kva; + register vm_offset_t pa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + addr = bp->b_saveaddr = bp->b_un.b_addr; + off = (int)addr & PGOFSET; + p = bp->b_proc; + sz = round_page(off + len); + kva = kmem_alloc_wait_align(phys_map, sz, (vm_size_t)addr & CpuCacheAliasMask); + bp->b_un.b_addr = (caddr_t) (kva + off); + sz = atop(sz); + while (sz--) { + pa = pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), + (vm_offset_t)addr); + if (pa == 0) + panic("vmapbuf: null page frame"); + pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa), + VM_PROT_READ|VM_PROT_WRITE, TRUE); + addr += PAGE_SIZE; + kva += PAGE_SIZE; + } +} + +/* + * Free the io map PTEs associated with this IO operation. + * We also invalidate the TLB entries and restore the original b_addr. + */ +void +vunmapbuf(bp, len) + struct buf *bp; + vm_size_t len; +{ + register caddr_t addr = bp->b_un.b_addr; + register vm_size_t sz; + vm_offset_t kva; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + sz = round_page(len + ((int)addr & PGOFSET)); + kva = (vm_offset_t)((int)addr & ~PGOFSET); + kmem_free_wakeup(phys_map, kva, sz); + bp->b_un.b_addr = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} + + +/* + * SAVE_HINT: + * + * Saves the specified entry as the hint for + * future lookups. Performs necessary interlocks. + */ +#define SAVE_HINT(map,value) \ + simple_lock(&(map)->hint_lock); \ + (map)->hint = (value); \ + simple_unlock(&(map)->hint_lock); + + +/* + * kmem_alloc_upage: + * + * Allocate pageable memory to the kernel's address map. + * map must be "kernel_map" below. + * (Currently only used when allocating U pages). + */ +vm_offset_t +kmem_alloc_upage(map, size) + vm_map_t map; + register vm_size_t size; +{ + vm_offset_t addr; + register int result; + + + size = round_page(size); + + addr = vm_map_min(map); + result = vm_map_find_U(map, NULL, (vm_offset_t) 0, + &addr, size, TRUE); + if (result != KERN_SUCCESS) { + return(0); + } + + return(addr); +} + +/* + * vm_map_find finds an unallocated region in the target address + * map with the given length aligned on U viritual address. + * The search is defined to be first-fit from the specified address; + * the region found is returned in the same parameter. + * + */ +int +vm_map_find_U(map, object, offset, addr, length, find_space) + vm_map_t map; + vm_object_t object; + vm_offset_t offset; + vm_offset_t *addr; /* IN/OUT */ + vm_size_t length; + boolean_t find_space; +{ + register vm_offset_t start; + int result; + + start = *addr; + vm_map_lock(map); + if (find_space) { + if (vm_map_findspace_align(map, start, length, addr, 0)) { + vm_map_unlock(map); + return (KERN_NO_SPACE); + } + start = *addr; + } + result = vm_map_insert(map, object, offset, start, start + length); + vm_map_unlock(map); + return (result); +} + +/* + * Find sufficient space for `length' bytes in the given map, starting at + * `start'. The map must be locked. Returns 0 on success, 1 on no space. + */ +int +vm_map_findspace_align(map, start, length, addr, align) + register vm_map_t map; + register vm_offset_t start; + vm_size_t length; + vm_offset_t *addr; + vm_size_t align; +{ + register vm_map_entry_t entry, next; + register vm_offset_t end; + + if (start < map->min_offset) + start = map->min_offset; + if (start > map->max_offset) + return (1); + + /* + * Look for the first possible address; if there's already + * something at this address, we have to start after it. + */ + if (start == map->min_offset) { + if ((entry = map->first_free) != &map->header) + start = entry->end; + } else { + vm_map_entry_t tmp; + if (vm_map_lookup_entry(map, start, &tmp)) + start = tmp->end; + entry = tmp; + } + + /* + * Look through the rest of the map, trying to fit a new region in + * the gap between existing regions, or after the very last region. + */ + for (;; start = (entry = next)->end) { + /* + * Find the end of the proposed new region. Be sure we didn't + * go beyond the end of the map, or wrap around the address; + * if so, we lose. Otherwise, if this is the last entry, or + * if the proposed new region fits before the next entry, we + * win. + */ + start = ((start + NBPG -1) & ~(NBPG - 1)); /* Paranoia */ + if((start & CpuCacheAliasMask) <= align) { + start += align - (start & CpuCacheAliasMask); + } + else { + start = ((start + CpuCacheAliasMask) & ~CpuCacheAliasMask); + start += align; + } + + end = start + length; + if (end > map->max_offset || end < start) + return (1); + next = entry->next; + if (next == &map->header || next->start >= end) + break; + } + SAVE_HINT(map, entry); + *addr = start; + return (0); +} + +/* + * kmem_alloc_wait_align + * + * Allocates pageable memory from a sub-map of the kernel. If the submap + * has no room, the caller sleeps waiting for more memory in the submap. + * + */ +vm_offset_t +kmem_alloc_wait_align(map, size, align) + vm_map_t map; + vm_size_t size; + vm_size_t align; +{ + vm_offset_t addr; + + size = round_page(size); + + for (;;) { + /* + * To make this work for more than one map, + * use the map's lock to lock out sleepers/wakers. + */ + vm_map_lock(map); + if (vm_map_findspace_align(map, 0, size, &addr, align) == 0) + break; + /* no space now; see if we can ever get space */ + if (vm_map_max(map) - vm_map_min(map) < size) { + vm_map_unlock(map); + return (0); + } + assert_wait(map, TRUE); + vm_map_unlock(map); + thread_block(); + } + vm_map_insert(map, NULL, (vm_offset_t)0, addr, addr + size); + vm_map_unlock(map); + return (addr); +} diff --git a/sys/arch/wgrisc/wgrisc/wgrisctype.h b/sys/arch/wgrisc/wgrisc/wgrisctype.h new file mode 100644 index 00000000000..2e8f475a2dd --- /dev/null +++ b/sys/arch/wgrisc/wgrisc/wgrisctype.h @@ -0,0 +1,38 @@ +/* $OpenBSD: wgrisctype.h,v 1.1 1997/02/06 16:02:47 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * + * 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 under OpenBSD by + * Per Fogelstrom. + * 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. + * + */ + +/* + * Mother board type byte of "systype" environment variable. + */ +#define WGRISC9100 0x1 /* WGRISC 9100 R3081 board */ |