diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/arch/pc532 |
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/pc532')
102 files changed, 26074 insertions, 0 deletions
diff --git a/sys/arch/pc532/Makefile b/sys/arch/pc532/Makefile new file mode 100644 index 00000000000..56051070bd5 --- /dev/null +++ b/sys/arch/pc532/Makefile @@ -0,0 +1,32 @@ +# $NetBSD: Makefile,v 1.2 1994/10/26 08:23:50 cgd Exp $ + +# @(#)Makefile 7.3 (Berkeley) 6/9/91 + +COMM= ../net/*.[ch] ../netimp/*.[ch] ../netinet/*.[ch] ../netns/*.[ch] \ + ../netiso/*.[ch] ../netccitt/*.[ch] \ + ../kern/*.c ../ufs/*.[ch] ../nfs/*.[ch] ../vm/*.[ch] ../sys/*.h + +# Makefile for pc532 tags file + +SUBDIR= stand + +TPC532= ../pc532/tags +SPC532= ../pc532/pc532/*.[ch] ../pc532/include/*.h \ + ../pc532/dev/*.[ch] ../pc532/scsi/*.[ch] +APC532= ../pc532/pc532/*.s + +# Directories in which to place pc532 tags links +DPC532= dev include scsi + +tags: + -ctags -dtf ${TPC532} ${COMM} ${SPC532} + egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${APC532} | \ + sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \ + >> ${TPC532} + sort -o ${TPC532} ${TPC532} + +links: + -for i in ${DPC532}; do \ + cd ../$$i && rm -f tags; ln -s ../tags tags; done + +.include <bsd.prog.mk> diff --git a/sys/arch/pc532/To.Do b/sys/arch/pc532/To.Do new file mode 100644 index 00000000000..88173f4628d --- /dev/null +++ b/sys/arch/pc532/To.Do @@ -0,0 +1,40 @@ +$NetBSD: To.Do,v 1.4 1995/06/09 06:03:45 phil Exp $ + +This is the "To Do" list for NetBSD/pc532 + (Order is not in order of importance.) + +- improve scn driver (integrate mods from Phil Bunde) + +- get kernel debugger working + +- get the dp scsi driver working + +- write an aic scsi driver + +- improve copyin/out and friends + +- get gdb working (partially done) + +- ptrace syscall (?) + +- improve bim (detect a non-writeable disklabel, ...) + +- man4 man pages + +- man8 man pages + +- mods to better support ufs boot loader + +- integrate printer driver from matthias (partially done) + +- verify all devices including vn, tun, ... + +- integrate other machine independent "devices" + +- write a bim.8 + +- find or write a "usable" comm package to replace kermit for + initial downloading. + +- find out why profiling does not accumulate any time + diff --git a/sys/arch/pc532/compile/.keep_me b/sys/arch/pc532/compile/.keep_me new file mode 100644 index 00000000000..a3950d5c483 --- /dev/null +++ b/sys/arch/pc532/compile/.keep_me @@ -0,0 +1,3 @@ +$NetBSD: .keep_me,v 1.2 1994/10/26 08:23:53 cgd Exp $ + +This normally empty directory needs to be kept in the distribution. diff --git a/sys/arch/pc532/conf/DEFAULT b/sys/arch/pc532/conf/DEFAULT new file mode 100644 index 00000000000..f25774619f9 --- /dev/null +++ b/sys/arch/pc532/conf/DEFAULT @@ -0,0 +1,90 @@ +# +# DEFAULT: default install kernel +# Only has scn0-5 are configured. +# Instead of scn6/7 the lpt0/1 devices get into the kernel. +# + +machine pc532 + +maxusers 8 # estimated number of users +options TIMEZONE=0, DST=0 # time zone to read RTC in +options SWAPPAGER # paging +options VNODEPAGER,DEVPAGER # vnode and device node caching + +#options DDB # kernel debugger; recommended +#options DIAGNOSTIC # internal consistency checking +options KTRACE # system call tracing, a la ktrace(1) + +#options ACCOUNTING # process accounting +options FIFO # fifos; recommended +#options SYSVSHM # System V shared memory; broken +#options SHMMAXPGS=1024 +#options LKM # loadable kernel modules + +# compatibility options +#options COMPAT_09 # NetBSD 0.9, +#options COMPAT_10 # NetBSD 1.0, +options COMPAT_43 # and 4.3BSD +#options TCP_COMPAT_42 # TCP bug compatibility with 4.2BSD + +# file system options +#options QUOTA # file system quotas +options FFS # Berkeley fast file system +#options LFS # log-structered file system +options MFS # memory file system; uses RAM and swap +options MSDOSFS # MS-DOS file system +options CD9660 # ISO 9660 CD-ROM file system, with RR +options NULLFS # loopback file system +#options UMAPFS # NULLFS + uid and gid remapping +options UNION # union file system +#options PORTAL # /portal +options FDESC # /dev/fd +options KERNFS # /kern +options PROCFS # /proc +#options NFSSERVER # Network File System server +options NFSCLIENT # Network File System client + +# networking options +#options GATEWAY # packet forwarding +options INET # IP + ICMP + TCP + UDP +#options NS # XNS +#options ISO,TPIP # OSI +#options EON # OSI tunneling over IP +#options CCITT,LLC,HDLC # X.25 + +# pc532 specific options +#options COMDEF_SPEED=B19200 # default baud on the scn chips +options PLIP # PLIP driver in dev/lpt.c +options DEV_RTC # RTC driver in pc532/mem.c +options NO_INLINE_SPLX # don't inline splx calls + +config netbsd swap generic +options GENERIC + +membus0 at root + +ncr0 at membus? + +scsibus0 at scsi? + +sd* at scsibus? target ? lun ? # SCSI disks +st* at scsibus? target ? lun ? # SCSI tapes +cd* at scsibus? target ? lun ? # SCSI CD-ROMs + +scn0 at membus? +scn1 at membus? +scn2 at membus? +scn3 at membus? +scn4 at membus? +scn5 at membus? + +lpt0 at membus? addr 0xffc80030 irq 7 +lpt1 at membus? addr 0xffc80034 irq 6 + +pseudo-device pty 16 # pseudo-terminals +pseudo-device loop 1 # loopback network +pseudo-device vnd 2 # vnode devices +pseudo-device bpfilter 4 # packet filter +pseudo-device sl 1 # compressed SLIP +pseudo-device ppp 1 # Point-to-Point Protocol +pseudo-device tun 1 # network tunneling diff --git a/sys/arch/pc532/conf/INSTALL b/sys/arch/pc532/conf/INSTALL new file mode 100644 index 00000000000..2ae8556d6c4 --- /dev/null +++ b/sys/arch/pc532/conf/INSTALL @@ -0,0 +1,65 @@ +# $NetBSD: INSTALL,v 1.3 1995/09/29 04:16:48 phil Exp $ +# +# INSTALL -- install kernel +# +# + +# architecture type and name of kernel; REQUIRED +machine "pc532" + +# time zone RTC is expected to be set in; REQUIRED +options TIMEZONE=0, DST=0 # time zone to read RTC in +options GENERIC + +# estimated number of users +maxusers 2 + +# paging of processes, and caching vnodes and devices; REQUIRED +options SWAPPAGER +options VNODEPAGER +options DEVPAGER + +# networking options +#options INET + +# generic SCSI system +options SCSI + +# filesystems +#options FIFO +options MSDOSFS +options FFS +#options NFSCLIENT +options CD9660 + +# pc532 special options +# options PLIP +options NO_INLINE_SPLX + +config "netbsd" swap generic + +membus0 at root + +rd0 at membus? +options RD_SIZE=0x200000 + +ncr0 at membus? +scsibus0 at scsi? + +sd* at scsibus? target ? lun ? +st* at scsibus? target ? lun ? +cd* at scsibus? target ? lun ? + +scn0 at membus? +scn1 at membus? +scn2 at membus? +scn3 at membus? +#scn4 at membus? +#scn5 at membus? + +#lpt0 at membus? addr 0xffc80030 irq 7 +#lpt1 at membus? addr 0xffc80034 irq 6 + +#pseudo-device loop 1 # loopback network +#pseudo-device sl 1 # compressed SLIP +#pseudo-device ppp 1 # Point-to-Point Protocol diff --git a/sys/arch/pc532/conf/KLONDIKE b/sys/arch/pc532/conf/KLONDIKE new file mode 100644 index 00000000000..4bbf1a1998d --- /dev/null +++ b/sys/arch/pc532/conf/KLONDIKE @@ -0,0 +1,84 @@ +# $NetBSD: KLONDIKE,v 1.2 1995/09/26 20:16:01 phil Exp $ +# +# KLONDIKE: Matthias Pfaller's pc532 +# + +machine pc532 + +maxusers 8 # estimated number of users +options TIMEZONE=0, DST=0 # time zone to read RTC in +options SWAPPAGER # paging +options VNODEPAGER,DEVPAGER # vnode and device node caching + +#options DDB # kernel debugger; recommended +#options DIAGNOSTIC # internal consistency checking +options KTRACE # system call tracing, a la ktrace(1) + +#options ACCOUNTING # process accounting +options FIFO # fifos; recommended +#options SYSVSHM # System V shared memory; broken +#options SHMMAXPGS=1024 +#options LKM # loadable kernel modules + +# compatibility options +options COMPAT_43 # 4.3 system calls + +# file system options +#options QUOTA # file system quotas +options FFS # Berkeley fast file system +#options LFS # log-structered file system +options MFS # memory file system; uses RAM and swap +options MSDOSFS # MS-DOS file system +options CD9660 # ISO 9660 CD-ROM file system, with RR +options NULLFS # loopback file system +#options UMAPFS # NULLFS + uid and gid remapping +options UNION # union file system +#options PORTAL # /portal +#options FDESC # /dev/fd +options KERNFS # /kern +options PROCFS # /proc +options NFSSERVER # Network File System server +options NFSCLIENT # Network File System client + +# networking options +#options GATEWAY # packet forwarding +options INET # IP + ICMP + TCP + UDP +#options NS # XNS +#options ISO,TPIP # OSI +#options EON # OSI tunneling over IP +#options CCITT,LLC,HDLC # X.25 + +# pc532 specific options +options COMDEF_SPEED=B19200 # default baud on the scn chips +options PLIP # PLIP driver in dev/lpt.c +options DEV_RTC # RTC driver in pc532/mem.c + +config netbsd root on sd0a swap on sd0b and sd1b + +membus0 at root +#clock0 at membus? +#timer0 at membus? + +ncr0 at membus? + +scsibus0 at scsi? + +sd* at scsibus? target ? lun ? # SCSI disks +st* at scsibus? target ? lun ? # SCSI tapes +cd* at scsibus? target ? lun ? # SCSI CD-ROMs + +scn0 at membus? +scn1 at membus? +scn2 at membus? +scn3 at membus? + +lpt0 at membus? addr 0xffc80030 irq 7 +lpt1 at membus? addr 0xffc80034 irq 6 + +pseudo-device pty 16 # pseudo-terminals +pseudo-device loop 1 # loopback network +pseudo-device vnd 2 # vnode devices +#pseudo-device bpfilter 4 # packet filter +#pseudo-device sl 1 # compressed SLIP +#pseudo-device ppp 1 # Point-to-Point Protocol +#pseudo-device tun 1 # ip tunneling diff --git a/sys/arch/pc532/conf/Makefile.pc532 b/sys/arch/pc532/conf/Makefile.pc532 new file mode 100644 index 00000000000..a1fd431b9bd --- /dev/null +++ b/sys/arch/pc532/conf/Makefile.pc532 @@ -0,0 +1,159 @@ +# $NetBSD: Makefile.pc532,v 1.14 1995/09/19 23:51:40 thorpej Exp $ + +# Copyright 1990 W. Jolitz +# @(#)Makefile.i386 7.1 5/10/91 +# +# Makefile for NetBSD/532 +# +# Edited by Philip A. Nelson +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/arch/pc532/conf/``machineid'' +# after which you should do +# config machineid +# Generic makefile changes should be made in +# /sys/arch/pc532/conf/Makefile.pc532 +# after which config should be rerun for all machines. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE 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 +# + +TOUCH= touch -f -c +AS= as +LD= ld +CC= cc +CPP= cpp +AWK= awk + +S= ../../../.. +PC532= ../.. + +.s.o:; (${CPP} ${COPTS} ${PC532}/pc532/$*.s | ${AS} ${ASFLAGS} -o $*.o) + +INCLUDES= -I. -I$S -I$S/sys -I${PC532} +COPTS= ${INCLUDES} ${IDENT} -D_KERNEL +ASFLAGS= +CFLAGS= -O -Werror -fno-builtin -msb ${COPTS} + +### 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 + +NORMAL_S= (${CPP} ${COPTS} ${PROF} $< | ${AS} ${ASFLAGS} -o $*.o) +NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $< +NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< +DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< +SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o vnode_if.o ${LIBKERN} \ + ${LIBCOMPAT} +SYSTEM_DEP=Makefile ${SYSTEM_OBJS} +SYSTEM_LD_HEAD= @echo loading $@; rm -f $@ +SYSTEM_LD= @${LD} -z -T FE002000 -o $@ -X vers.o ${SYSTEM_OBJS} +SYSTEM_LD_TAIL= size $@ ; nm -n $@ > SYMMS ; chmod 755 $@ + +%OBJS + +%CFILES + +%LOAD + +clean:: + rm -f eddep *netbsd tags *.o locore.i [a-uw-z]*.s \ + errs linterrs makelinks genassym + +#lint: /tmp param.c +# @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \ +# ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \ +# grep -v 'struct/union .* never defined' | \ +# grep -v 'possible pointer alignment problem' + +locore.o: assym.h ${PC532}/pc532/locore.s \ + ${PC532}/pc532/bcopy.s ${PC532}/pc532/bzero.s + +# the following is necessary because autoconf.o depends on #if GENERIC +autoconf.o: Makefile + +# depend on network configuration +af.o uipc_proto.o locore.o: Makefile + +# depend on maxusers +assym.s machdep.o: Makefile + +# depends on KDB (cons.o also depends on GENERIC) +trap.o cons.o: Makefile + +assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \ + $S/sys/vmmeter.h \ + $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h + +assym.h: genassym + ./genassym >assym.h + +genassym: ${PC532}/pc532/genassym.c + ${CC} -static ${INCLUDES} -D_KERNEL ${IDENT} ${PARAM} \ + ${PC532}/pc532/genassym.c -o genassym + +depend: assym.h param.c vnode_if.h + sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c + sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${PC532}/pc532/genassym.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 $S/sys/param.h $S/sys/buf.h \ + ${PC532}/dev/device.h machine/icu.h + ${CC} -c ${CFLAGS} ioconf.c + +conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \ + $S/sys/tty.h $S/sys/conf.h ${PC532}/pc532/conf.c + ${CC} -traditional -c ${CFLAGS} ${PC532}/pc532/conf.c + +param.c: $S/conf/param.c + -rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${CC} -c ${CFLAGS} ${PARAM} param.c + +vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP} + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} -c vers.c + +# for config.new +newvers: + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} -c vers.c + +# This allows you to specify which "awk" you will run, i.e.: +# make AWK=nawk ... +vnode_if.c vnode_if.h : $S/kern/vnode_if.sh $S/kern/vnode_if.src + AWK=${AWK} sh $S/kern/vnode_if.sh $S/kern/vnode_if.src + +%RULES + diff --git a/sys/arch/pc532/conf/STEELHEAD b/sys/arch/pc532/conf/STEELHEAD new file mode 100644 index 00000000000..076615e0393 --- /dev/null +++ b/sys/arch/pc532/conf/STEELHEAD @@ -0,0 +1,85 @@ +# $NetBSD: STEELHEAD,v 1.9 1995/09/26 20:16:02 phil Exp $ +# +# STEELHEAD: Phil Nelson's pc532 +# +machine "pc532" + +maxusers 10 # estimated number of users +options TIMEZONE=0, DST=0 # time zone to read RTC in +options SWAPPAGER # paging +options VNODEPAGER,DEVPAGER # vnode and device node caching +#options DDB # kernel debugger; not working +#options DIAGNOSTIC # internal consistency checking + +#options ACCOUNTING # process accounting +options KTRACE # system call tracing, a la ktrace(1) +options FIFO # fifos; recommended +#options SYSVSHM # System V shared memory; broken +#options "SHMMAXPGS=1024" +#options LKM # loadable kernel modules + +# compatibility options +options "COMPAT_43" # 4.3 system calls +options "TCP_COMPAT_42" # 4.2 networking ABI +options "COMPAT_09" # NetBSD-0.9 +options "COMPAT_10" # NetBSD-1.0 + +# file system options +#options QUOTA # file system quotas +options FFS # Berkeley fast file system +#options FASTLINKS # fast symbolic links in FFS +#options MFS # memory file system; uses RAM and swap +options NFSSERVER # Network File System server +options NFSCLIENT # Network File System client +#options ISOFS # ISO 9660 CD-ROM file system, with RR +#options MSDOSFS # MS-DOS FAT file system +options FDESC # /dev/fd +options KERNFS # kernel file system; recommended + +# networking options +#options GATEWAY # packet forwarding +options INET # IP +#options NS # XNS +#options CCITT # X.25 +#options ISO # OSI +#options TPIP # ? +#options EON # ? + +# pc532 specific options +options "COMDEF_SPEED=B19200" # default baud on the scn chips +#options "RAMD_SIZE=1536000" # Size of the "boot strap ram disk" +#options "RAMD_ADR=0x400000" # Adr of the "boot strap ram disk" +options "CONFIG_NEW" # Use config.new stuff +options "DEV_RTC" # /dev/rtc access to hardware clock +options "CON_BRK_PANIC" # 3 breaks on tty0 -> panic? y/n + +config "netbsd" root on sd0 swap on sd0 and sd1 and vnd0a + +membus0 at root + +#rd0 at membus? + +ncr0 at membus? + +scsibus0 at scsi? + +sd* at scsibus? target ? lun ? # SCSI disks +st* at scsibus? target ? lun ? # SCSI tapes +#cd* at scsibus? target ? lun ? # SCSI ??? + +scn0 at membus? +scn1 at membus? +scn2 at membus? +scn3 at membus? +scn4 at membus? +scn5 at membus? +scn6 at membus? +scn7 at membus? + +pseudo-device pty 16 # pseudo-terminals +pseudo-device loop 1 # loopback network +pseudo-device bpfilter 4 # packet filter +pseudo-device sl 1 # compressed SLIP +pseudo-device ppp 1 # Point-to-Point Protocol +pseudo-device vnd 4 # Vnode devices +#pseudo-device ether # diff --git a/sys/arch/pc532/conf/files.pc532 b/sys/arch/pc532/conf/files.pc532 new file mode 100644 index 00000000000..06d6a76db93 --- /dev/null +++ b/sys/arch/pc532/conf/files.pc532 @@ -0,0 +1,80 @@ +# $NetBSD: files.pc532,v 1.15.2.1 1995/10/17 00:18:56 phil Exp $ +# +# new style config file for pc532 architecture +# + +# maxpartitions must be first item in files.${ARCH}.newconf +maxpartitions 8 + +maxusers 2 16 64 + +device membus at root {[addr = -1], [irq = -1]} + +major {vnd = 5} + +device rd at membus: disk +file arch/pc532/dev/rd.c rd needs-count +major {rd = 3} + +#device timer at membus +#device clock at membus +file arch/pc532/pc532/clock.c # clock timer + +device scn at membus: tty +file arch/pc532/dev/scn.c scn needs-flag + +device lpt at membus: ether, ifnet +file arch/pc532/dev/lpt.c lpt needs-count + +define scsi {} + +device ncr at membus: scsi +file arch/pc532/dev/ncr.c ncr needs-count +device oldncr at membus: scsi +file arch/pc532/dev/oldncr.c oldncr needs-count +device dp at membus: scsi +file arch/pc532/dev/dp.c dp needs-count +device aic at membus: scsi +file arch/pc532/dev/aic.c aic needs-count + +device scsibus at scsi {target = -1, lun = -1} + +device cd at scsibus: disk +file scsi/cd.c cd needs-flag +major {cd = 4} +device sd at scsibus: disk +file scsi/sd.c sd needs-flag +major {sd = 0} +device st at scsibus: tape +file scsi/st.c st needs-flag +major {st = 2} +device ch at scsibus: disk +file scsi/ch.c ch needs-flag +device uk at scsibus: disk +file scsi/uk.c uk needs-flag +device su at scsibus: disk +file scsi/su.c su needs-flag + +file dev/cons.c +file dev/cninit.c +file scsi/scsiconf.c scsi +file scsi/scsi_base.c scsi +file scsi/scsi_ioctl.c scsi +file arch/pc532/pc532/autoconf.c +file arch/pc532/pc532/db_disasm.c ddb +file arch/pc532/pc532/db_interface.c ddb +file arch/pc532/pc532/db_trace.c ddb +file arch/pc532/pc532/disksubr.c disk +file arch/pc532/pc532/icuinit.c +file arch/pc532/pc532/in_cksum.c inet +file arch/pc532/pc532/intr.c +file arch/pc532/pc532/machdep.c +file arch/pc532/pc532/mem.c +file arch/pc532/pc532/ns_cksum.c ns +#file arch/pc532/pc532/ntoh.s +file arch/pc532/pc532/pmap.c +file arch/pc532/pc532/process_machdep.c +file arch/pc532/pc532/random.s +file arch/pc532/pc532/sys_machdep.c +file arch/pc532/pc532/trap.c +file arch/pc532/pc532/vm_machdep.c diff --git a/sys/arch/pc532/dev/aic.c b/sys/arch/pc532/dev/aic.c new file mode 100644 index 00000000000..f0c3e022f38 --- /dev/null +++ b/sys/arch/pc532/dev/aic.c @@ -0,0 +1,137 @@ +/* $NetBSD: aic.c,v 1.4 1995/08/12 20:31:10 mycroft Exp $ */ + +/* Written by Phil Nelson for the pc532. Used source with the following + * copyrights as a model. + * + * aic.c: A Adaptec 6250 driver for the pc532. + */ +/* + * (Mostly) Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + */ + +/* + * a FEW lines in this driver come from a MACH adaptec-disk driver + * so the copyright below is included: + * + * Copyright 1990 by Open Software Foundation, + * Grenoble, FRANCE + * + * All Rights Reserved + * + * 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 and + * that both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of OSF or Open Software + * Foundation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "sys/types.h" +#include "sys/param.h" +#include "sys/systm.h" +#include "sys/errno.h" +#include "sys/ioctl.h" +#include "sys/buf.h" +#include "machine/stdarg.h" +#include "sys/proc.h" +#include "sys/user.h" +#include "sys/dkbad.h" +#include "sys/disklabel.h" +#include "scsi/scsi_all.h" +#include "scsi/scsiconf.h" + +#include "device.h" + +/* Some constants (may need to be changed!) */ +#define AIC_NSEG 16 + +int aicprobe(struct pc532_device *); +int aicattach(struct pc532_device *); +int aic_scsi_cmd(struct scsi_xfer *); +void aicminphys(struct buf *); +long int aic_adapter_info(int); + +struct scsidevs * +scsi_probe(int masunit, struct scsi_switch *sw, int physid, int type, int want); + +struct pc532_driver aicdriver = { + aicprobe, aicattach, "aic", +}; + +struct scsi_switch dp_switch = { + "aic", + aic_scsi_cmd, + aicminphys, + 0, + 0, + aic_adapter_info, + 0, 0, 0 +}; + +int aicprobe(struct pc532_device *dvp) +{ + return (0); /* All pc532s should have one, but it is not working now. */ +} + + +int aicattach(struct pc532_device *dvp) +{ + int r; + + r = scsi_attach(0, 7, &dp_switch, + &dvp->pd_drive, &dvp->pd_unit, dvp->pd_flags); + + return(r); +} + +void aicminphys(struct buf *bp) +{ + + if(bp->b_bcount > ((AIC_NSEG - 1) * NBPG)) + bp->b_bcount = ((AIC_NSEG - 1) * NBPG); + minphys(bp); +} + +long int aic_adapter_info(int unit) +{ + return (1); /* only 1 outstanding request. */ +} + + +/* Do a scsi command. */ + +struct scsi_xfer *cur_xs; + +int aic_scsi_cmd(struct scsi_xfer *xs) +{ +printf ("aic_scsi_cmd: ... \n"); + cur_xs = xs; + + return (HAD_ERROR); +} + +void aic_intr (struct intrframe frame) +{ +} diff --git a/sys/arch/pc532/dev/device.h b/sys/arch/pc532/dev/device.h new file mode 100644 index 00000000000..ed5aba7f4a0 --- /dev/null +++ b/sys/arch/pc532/dev/device.h @@ -0,0 +1,65 @@ +/* $NetBSD: device.h,v 1.2 1994/10/26 08:24:09 cgd Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + * + * @(#)isa_device.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Per device structure. + */ +struct pc532_device { + struct pc532_driver *pd_driver; + char *pd_name; /* device name */ + int pd_unit; /* unit number */ + int pd_drive; /* drive number */ + int pd_flags; /* flags needed */ + int pd_alive; /* device is present */ +}; + +/* + * Per-driver structure. + * + * Each device driver defines entries for a set of routines + * as well as an array of types which are acceptable to it. + * These are used at boot time by the configuration program. + */ +struct pc532_driver { + int (*probe)(); /* test whether device is present */ + int (*attach)(); /* setup driver for a device */ + char *name; /* device name */ +}; + +extern struct pc532_device pc532_devtab_bio[], pc532_devtab_tty[], + pc532_devtab_net[]; + diff --git a/sys/arch/pc532/dev/dp.c b/sys/arch/pc532/dev/dp.c new file mode 100644 index 00000000000..17bc9979ef0 --- /dev/null +++ b/sys/arch/pc532/dev/dp.c @@ -0,0 +1,1046 @@ +/* $NetBSD: dp.c,v 1.8 1995/08/12 20:31:11 mycroft Exp $ */ + +/* Written by Phil Nelson for the pc532. Used source with the following + * copyrights as a model. + * + * dp.c: A NCR DP8490 driver for the pc532. + */ + +/* + * (Mostly) Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + */ + +/* + * a FEW lines in this driver come from a MACH adaptec-disk driver + * so the copyright below is included: + * + * Copyright 1990 by Open Software Foundation, + * Grenoble, FRANCE + * + * All Rights Reserved + * + * 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 and + * that both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of OSF or Open Software + * Foundation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/buf.h> +#include <machine/stdarg.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/dkbad.h> +#include <sys/disklabel.h> +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> + +#include <machine/frame.h> +#include <machine/icu.h> + +#include "device.h" +#include "dpreg.h" + +#define DP_DEBUG 0 + +/* Some constants (may need to be changed!) */ +#define DP_NSEG 16 + +int dpprobe(struct pc532_device *); +int dpattach(struct pc532_device *); +int dp_scsi_cmd(struct scsi_xfer *); +void dpminphys(struct buf *); +long int dp_adapter_info(int); +void dp_intr(void); +void dp_intr_work(void); + +struct scsidevs * +scsi_probe(int masunit, struct scsi_switch *sw, int physid, int type, int want); + +struct pc532_driver dpdriver = { + dpprobe, dpattach, "dp", +}; + +struct scsi_switch dp_switch = { + "dp", + dp_scsi_cmd, + dpminphys, + 0, + 0, + dp_adapter_info, + 0, 0, 0 +}; + +/* Sense command. */ +static u_char sense_cmd[] = { 3, 0, 0, 0, 0, 0}; + +/* Do we need to initialize. */ +int dp_needs_init = 1; + +/* Do we need a reset . */ +int dp_needs_reset = 1; + +/* SCSI phase we are currently in . . . */ +int dp_scsi_phase; + +/* SCSI Driver state */ +int dp_dvr_state = DP_DVR_READY; + +/* For polled error reporting. */ +int dp_intr_retval; + +/* For counting the retries. */ +int dp_try_count; + +/* Give the interrupt routine access to the current scsi_xfer info block. */ +struct scsi_xfer *cur_xs = NULL; + +/* names of phases for debug printouts */ +const char *dp_phase_names[] = { + "DATA OUT", + "DATA IN", + "CMD", + "STATUS", + "PHASE 4", + "PHASE 5", + "MSG OUT", + "MSG IN", +}; + +/* Initial probe for a device. If it is using the dp controller, + just say yes so that attach can be the one to find the real drive. */ + +int dpprobe(struct pc532_device *dvp) +{ + /* If we call this, we need to add SPL_DP to the bio mask! */ + PL_bio |= SPL_DP; + PL_zero |= PL_bio; + + if (dp_needs_init) + dp_initialize(); + + if (dp_needs_reset) + dp_reset(); + + /* All pc532s should have one, so we don't check ! :) */ + return (1); +} + + +int dpattach(struct pc532_device *dvp) +{ + int r; + + r = scsi_attach(0, 7, &dp_switch, + &dvp->pd_drive, &dvp->pd_unit, dvp->pd_flags); + + return(r); +} + +void dpminphys(struct buf *bp) +{ + + if(bp->b_bcount > ((DP_NSEG - 1) * NBPG)) + bp->b_bcount = ((DP_NSEG - 1) * NBPG); + minphys(bp); +} + +long int dp_adapter_info(int unit) +{ + return (1); /* only 1 outstanding request. */ +} + +#if DP_DEBUG +void +dp_print_stat1(u_char stat1) +{ + printf("stat1="); + if ( stat1 & 0x80 ) printf(" /RST"); + if ( stat1 & 0x40 ) printf(" /BSY"); + if ( stat1 & 0x20 ) printf(" /REQ"); + if ( stat1 & 0x10 ) printf(" /MSG"); + if ( stat1 & 0x08 ) printf(" /CD"); + if ( stat1 & 0x04 ) printf(" /IO"); + if ( stat1 & 0x02 ) printf(" /SEL"); + if ( stat1 & 0x01 ) printf(" /DBP"); + printf("\n"); +} + +void +dp_print_stat2(u_char stat2) +{ + printf("stat2="); + if ( stat2 & 0x80 ) printf(" EDMA"); + if ( stat2 & 0x40 ) printf(" DRQ"); + if ( stat2 & 0x20 ) printf(" SPER"); + if ( stat2 & 0x10 ) printf(" INT"); + if ( stat2 & 0x08 ) printf(" PHSM"); + if ( stat2 & 0x04 ) printf(" BSY"); + if ( stat2 & 0x02 ) printf(" /ATN"); + if ( stat2 & 0x01 ) printf(" /ACK"); + printf("\n"); +} +#endif + +#if DP_DEBUG +void +dp_print_regs() +{ + u_char stat1 = RD_ADR(u_char, DP_STAT1); + u_char stat2 = RD_ADR(u_char, DP_STAT2); + dp_print_stat1(stat1); + dp_print_stat2(stat2); +} +#endif + +/* Do a scsi command. */ + +int dp_scsi_cmd(struct scsi_xfer *xs) +{ + struct iovec *iovp; + int flags; + int retval; /* Return values from functions. */ + int x; /* for splbio() & splhigh() */ + int dvr_state; + int ti_val; /* For timeouts. */ + +#if DP_DEBUG + printf("\n"); +#endif + x = splhigh(); + if (dp_dvr_state == DP_DVR_READY) + dp_dvr_state = DP_DVR_STARTED; + dvr_state = dp_dvr_state; + splx(x); + + if (dvr_state != DP_DVR_STARTED) + return (TRY_AGAIN_LATER); + + cur_xs = xs; + + /* Some initial checks. */ + flags = xs->flags; + if (!(flags & INUSE)) { +#if DP_DEBUG + printf("dp xs not in use!\n"); +#endif + xs->flags |= INUSE; + } + if (flags & ITSDONE) { +#if DP_DEBUG + printf("dp xs already done!\n"); +#endif + xs->flags &= ~ITSDONE; + } + if (dp_needs_reset || (xs->flags & SCSI_RESET)) + dp_reset(); +#if DP_DEBUG + printf ("scsi_cmd: flags=0x%x, targ=%d, lu=%d, cmdlen=%d, cmd=%x\n", + xs->flags, xs->targ, xs->lu, xs->cmdlen, xs->cmd->opcode); +#endif +#if 1 + /* we don't always get NOMASK passed in, so this hack fakes it. */ + { + if ( !initproc ) + xs->flags |= SCSI_NOMASK; + } +#endif + if (!(xs->flags & SCSI_NOMASK)) { + x = splbio(); + retval = dp_start_cmd(xs); + splx(x); + return retval; + } + /* No interrupts available! */ + retval = dp_start_cmd(xs); + if (retval != SUCCESSFULLY_QUEUED) + return retval; +#if DP_DEBUG > 1 + printf("polling for interrupts\n"); +#endif + ti_val = WAIT_MUL * xs->timeout; + while (dp_dvr_state != DP_DVR_READY) { + if (RD_ADR(u_char, DP_STAT2) & DP_S_IRQ) { + dp_intr_work(); + ti_val = WAIT_MUL * xs->timeout; + retval = dp_intr_retval; + } + if (--ti_val == 0) { + /* Software Timeout! */ + xs->error = XS_SWTIMEOUT; + dp_dvr_state = DP_DVR_READY; + retval = HAD_ERROR; + } + } + if (xs->error == XS_SWTIMEOUT) { + /* Software Timeout! */ + printf ("scsi timeout!\n"); +#if DP_DEBUG + dp_print_regs(); + printf("TCMD = 0x%x\n", RD_ADR(u_char, DP_TCMD)); +#endif + dp_reset(); + } +#if 1 + /* another hack: read cannot handle anything but SUCCESSFULLY_QUEUED */ + if (xs->cmd->opcode == 0x28) + return SUCCESSFULLY_QUEUED; +#endif + return retval; +} + +/*===========================================================================* + * dp_intr * + *===========================================================================*/ + +/* This is where a lot of the work happens! This is called in non-interrupt + mode when an interrupt would have happened. It is also the real interrupt + routine. It uses dp_dvr_state to determine the next actions along with + cur_xs->flags. */ + +void dp_intr(void) +{ + int x = splhigh(); +#if DP_DEBUG + printf("\n REAL dp_intr\n"); +#endif + dp_intr_work(); + splx(x); +} + +void dp_intr_work(void) +{ + u_char isr; + u_char new_phase; + u_char stat1; + u_char stat2; + static u_char status; + static u_char message; + int ret; + + scsi_select_ctlr (DP8490); + WR_ADR(u_char, DP_EMR_ISR, DP_EF_ISR_NEXT); + isr = RD_ADR (u_char, DP_EMR_ISR); + dp_clear_isr(); + + stat1 = RD_ADR(u_char, DP_STAT1); + new_phase = (stat1 >> 2) & 7; + +#if DP_DEBUG + printf ("dp_intr: dvr_state %d isr=0x%x new_phase = %d %s\n", + dp_dvr_state, isr, new_phase, dp_phase_names[new_phase]); +#if DP_DEBUG > 1 + dp_print_regs(); +#endif +#endif +#if 0 + /* de-assert the bus */ + WR_ADR(u_char, DP_ICMD, DP_EMODE); + /* disable dma */ + RD_ADR(u_char, DP_MODE) &= ~DP_M_DMA; +#endif + if (isr & DP_ISR_BSYERR) { +#if DP_DEBUG + printf("dp_intr: Busy error\n"); +#endif + } + if (isr & DP_ISR_EDMA) { +#if DP_DEBUG > 1 + printf("dp_intr: EDMA detected\n"); +#endif + RD_ADR(u_char, DP_MODE) &= ~DP_M_DMA; + WR_ADR(u_char, DP_ICMD, DP_EMODE); + } + if (!(isr & DP_ISR_APHS)) { +#if DP_DEBUG > 1 + printf("dp_intr: Not an APHS!\n"); + printf("dp_intr: dvr_state %d isr=0x%x (exit)\n", + dp_dvr_state, isr); +#endif + return; + } + + switch (dp_dvr_state) { + case DP_DVR_ARB: /* Next comes the command phase! */ + if (new_phase != DP_PHASE_CMD) { +#if DP_DEBUG + printf ("Phase mismatch cmd!\n"); +#endif + goto phase_mismatch; + } + dp_dvr_state = DP_DVR_CMD; + ret = dp_pdma_out(cur_xs->cmd, cur_xs->cmdlen, DP_PHASE_CMD); + dp_clear_isr(); + break; + + case DP_DVR_CMD: /* Next comes the data i/o phase if needed. */ + /* + * This state can potentially accept data in, data out, + * or status for new_phase. data in or data out could + * be skipped (new_phase is status) if an error was detected + * in the command. + */ + if (cur_xs->flags & SCSI_DATA_UIO) { + /* UIO work. */ + panic ("scsi uio"); + } + if (new_phase == DP_PHASE_DATAI) { +#if 1 + /* just a quick hack until we + can trust flags to be correct + */ + if (!cur_xs->data) { +#else + if (!(cur_xs->flags & SCSI_DATA_IN)) { +#endif +#if DP_DEBUG + printf("Phase mismatch in.\n"); +#endif + goto phase_mismatch; + } + /* expect STAT phase next */ + dp_dvr_state = DP_DVR_DATA; + ret = dp_pdma_in(cur_xs->data, cur_xs->datalen, + DP_PHASE_DATAI); + dp_clear_isr(); + break; + } + else if (new_phase == DP_PHASE_DATAO) { +#if 1 + /* just a quick hack until we + can trust flags to be correct + */ + if (!cur_xs->data) { +#else + if (!(cur_xs->flags & SCSI_DATA_OUT)) { +#endif +#if DP_DEBUG + printf("Phase mismatch out.\n"); +#endif + goto phase_mismatch; + } + /* expect STAT phase next */ + dp_dvr_state = DP_DVR_DATA; + ret = dp_pdma_out(cur_xs->data, cur_xs->datalen, + DP_PHASE_DATAO); + dp_clear_isr(); + break; + } + /* Fall through to next phase. */ + case DP_DVR_DATA: /* Next comes the stat phase */ + if (new_phase != DP_PHASE_STATUS) { +#if DP_DEBUG + printf("Phase mismatch stat.\n"); +#endif + goto phase_mismatch; + } + dp_dvr_state = DP_DVR_STAT; + dp_pdma_in(&status, 1, DP_PHASE_STATUS); + dp_clear_isr(); +#if DP_DEBUG > 1 + printf("status = 0x%x\n", status); +#endif + break; + + case DP_DVR_STAT: + if (new_phase != DP_PHASE_MSGI) { +#if DP_DEBUG + printf ("msgi phase mismatch\n"); +#endif + goto phase_mismatch; + } + dp_dvr_state = DP_DVR_MSGI; + dp_pdma_in(&message, 1, DP_PHASE_MSGI); + dp_clear_isr(); +#if DP_DEBUG > 1 + printf("message = 0x%x\n", message); +#endif +#if 0 + if (status != SCSI_OK && dp_try_count < cur_xs->retries) { + printf("dp_intr: retry: dp_try_count = %d\n", + dp_try_count); + dp_restart_cmd(); + } +#endif + break; + + default: +phase_mismatch: + /* TEMP error generation!!! */ + dp_reset(); + dp_dvr_state = DP_DVR_READY; + cur_xs->error = XS_DRIVER_STUFFUP; + dp_intr_retval = HAD_ERROR; + /* If this true interrupt code, call the done routine. */ + if (cur_xs->when_done) { + (*(cur_xs->when_done))(cur_xs->done_arg, cur_xs->done_arg2); + } + } + + if (dp_dvr_state == DP_DVR_MSGI) { +#if DP_DEBUG > 1 + printf ("dvr_stat: dp_try_count = %d\n", dp_try_count); +#endif + WR_ADR (u_char, DP_MODE, 0); /* Turn off monbsy, dma, ... */ + if (status == SCSI_OK) { + cur_xs->error = XS_NOERROR; + dp_intr_retval = COMPLETE; + } else if (status & SCSI_BUSY) { + cur_xs->error = XS_BUSY; + dp_intr_retval = HAD_ERROR; + } else if (status & SCSI_CHECK) { + /* Do a sense command. */ + cur_xs->error = XS_SENSE; + dp_intr_retval = HAD_ERROR; + dp_get_sense (cur_xs); + } + cur_xs->flags |= ITSDONE; + dp_dvr_state = DP_DVR_READY; +#if DP_DEBUG > 1 + printf("calling wakeup on 0x%x\n", cur_xs); +#endif + wakeup((caddr_t) cur_xs); + /* If this true interrupt code, call the done routine. */ + if (cur_xs->when_done) { +#if DP_DEBUG > 1 + printf("dp_intr: calling when_done 0x%x\n", cur_xs->when_done); +#endif + (*(cur_xs->when_done))(cur_xs->done_arg, cur_xs->done_arg2); + } + } +#if DP_DEBUG > 1 + printf ("exit dp_intr.\n"); +#endif +} + + +/*===========================================================================* + * dp_initialize * + *===========================================================================*/ + +dp_initialize() +{ +#if DP_DEBUG + printf("dp_initialize()\n"); +#endif + scsi_select_ctlr (DP8490); + WR_ADR (u_char, DP_ICMD, DP_EMODE); /* Set Enhanced mode */ + WR_ADR (u_char, DP_MODE, 0); /* Disable everything. */ + WR_ADR (u_char, DP_EMR_ISR, DP_EF_RESETIP); + WR_ADR (u_char, DP_EMR_ISR, DP_EF_NOP); + WR_ADR (u_char, DP_SER, 0x80); /* scsi adr 7. */ + dp_scsi_phase = DP_PHASE_NONE; + dp_needs_init = 0; +} + +/*===========================================================================* + * dp_reset * + *===========================================================================*/ + +/* + * Reset dp SCSI bus. + */ + +dp_reset() +{ + volatile int i; + int x = splbio(); + + scsi_select_ctlr (DP8490); + WR_ADR (u_char, DP_MODE, 0); /* get into harmless state */ + WR_ADR (u_char, DP_OUTDATA, 0); + WR_ADR (u_char, DP_ICMD, DP_A_RST|DP_EMODE); /* assert RST on SCSI bus */ + for (i = 55; i; --i); /* wait 25 usec */ + WR_ADR (u_char, DP_ICMD, DP_EMODE); /* deassert RST, get off bus */ + WR_ADR (u_char, DP_EMR_ISR, DP_EF_ISR_NEXT | DP_EMR_APHS); + WR_ADR (u_char, DP_EMR_ISR, DP_INT_MASK); /* set interrupt mask */ + splx(x); + for (i = 800000; i; --i); /* wait 360 msec */ + dp_needs_reset = 0; +} + +/*===========================================================================* + * dp_wait_bus_free * + *===========================================================================*/ +/* Wait for the SCSI bus to become free. Currently polled because I am + * assuming a single initiator configuration -- so this code would not be + * running if the bus were busy. + */ +int +dp_wait_bus_free() +{ + int i; + u_char stat1; + volatile int j; + + /* get into a harmless state */ + WR_ADR (u_char, DP_TCMD, 0); + WR_ADR (u_char, DP_MODE, 0); /* return to initiator mode */ + WR_ADR (u_char, DP_ICMD, DP_EMODE); /* clear SEL, disable data out */ + i = WAIT_MUL * 2000; + while (i--) { + /* Must be clear for 2 usec, so read twice */ + stat1 = RD_ADR (u_char, DP_STAT1); + if (stat1 & (DP_S_BSY | DP_S_SEL)) continue; + for (j = 5; j; j--); + stat1 = RD_ADR (u_char, DP_STAT1); + if (stat1 & (DP_S_BSY | DP_S_SEL)) continue; + return OK; + } +#if DP_DEBUG + printf("wait bus free failed\n"); + dp_print_stat1(stat1); +#endif + dp_needs_reset = 1; + return NOT_OK; +} + +/*===========================================================================* + * dp_select * + *===========================================================================*/ +/* Select SCSI device, set up for command transfer. + */ +int +dp_select(adr) +long adr; +{ + int i, stat1; + +#if DP_DEBUG > 1 + printf("dp_select(0x%x)\n", adr); +#endif + WR_ADR (u_char, DP_TCMD, 0); /* get to harmless state */ + WR_ADR (u_char, DP_MODE, 0); /* get to harmless state */ + WR_ADR (u_char, DP_OUTDATA, adr); /* SCSI bus address */ + WR_ADR (u_char, DP_ICMD, DP_A_SEL | DP_ENABLE_DB | DP_EMODE); + for (i = 0;; ++i) { /* wait for target to assert SEL */ + stat1 = RD_ADR (u_char, DP_STAT1); + if (stat1 & DP_S_BSY) break; /* select successful */ + if (i > WAIT_MUL * 2000) { /* timeout */ + u_char isr; + WR_ADR(u_char, DP_EMR_ISR, DP_EF_ISR_NEXT); + isr = RD_ADR (u_char, DP_EMR_ISR); +#if DP_DEBUG + printf ("SCSI: SELECT timeout adr %d\n", adr); + dp_print_regs(); + printf("ICMD = 0x%x isr = 0x%x\n", RD_ADR(u_char, DP_ICMD), isr); +#endif + dp_reset(); + return NOT_OK; + } + } + WR_ADR (u_char, DP_ICMD, DP_EMODE); /* clear SEL, disable data out */ + WR_ADR (u_char, DP_OUTDATA, 0); + dp_clear_isr(); + WR_ADR (u_char, DP_TCMD, 4); /* bogus phase, guarantee mismatch */ + WR_ADR (u_char, DP_MODE, DP_M_BSY | DP_M_DMA); + return OK; +} + +/*===========================================================================* + * scsi_select_ctlr + *===========================================================================*/ +/* Select a SCSI device. + */ +scsi_select_ctlr (ctlr) +int ctlr; +{ + /* May need other stuff here to syncronize between dp & aic. */ + + RD_ADR (u_char, ICU_IO) &= ~ICU_SCSI_BIT; /* i/o, not port */ + RD_ADR (u_char, ICU_DIR) &= ~ICU_SCSI_BIT; /* output */ + if (ctlr == DP8490) + RD_ADR (u_char, ICU_DATA) &= ~ICU_SCSI_BIT; /* select = 0 for 8490 */ + else + RD_ADR (u_char, ICU_DATA) |= ICU_SCSI_BIT; /* select = 1 for AIC6250 */ +} + +/*===========================================================================* + * dp_start_cmd * + *===========================================================================*/ + +int dp_start_cmd(struct scsi_xfer *xs) +{ +#if 0 + WR_ADR (u_char, DP_OUTDATA, 1 << xs->targ); /* SCSI bus address */ + WR_ADR (u_char, DP_EMR_ISR, DP_EF_ARB); + dp_dvr_state = DP_DVR_ARB; +#else + + /* This is not the "right" way to start it. We should just have the + chip do the select for us and interrupt at the end. */ + + if (!dp_wait_bus_free()) { +#if DP_DEBUG + printf("dp_start_cmd: DP DRIVER BUSY\n"); +#endif + xs->error = XS_BUSY; + return TRY_AGAIN_LATER; + } + + if (!dp_select(1 << xs->targ)) { +#if DP_DEBUG + printf("dp_start_cmd: DP DRIVER STUFFUP\n"); +#endif + xs->error = XS_DRIVER_STUFFUP; + return HAD_ERROR; + } +#endif + + /* After selection, we now wait for the APHS interrupt! */ + dp_dvr_state = DP_DVR_ARB; /* Just finished the select/arbitration */ + dp_try_count = 1; + + if (!(xs->flags & SCSI_NOMASK)) { + /* Set up the timeout! */ +#if DP_DEBUG > 1 + printf ("dp_start_cmd: dp timeouts not done\n"); +#endif + } + return SUCCESSFULLY_QUEUED; +} + +/*===========================================================================* + * dp_restart_cmd * + *===========================================================================*/ + +int dp_restart_cmd() +{ +#if 0 + WR_ADR (u_char, DP_OUTDATA, xs->targ); /* SCSI bus address */ + WR_ADR (u_char, DP_EMR_ISR, DP_EF_ARB); + dp_dvr_state = DP_DVR_ARB; +#endif + + /* This is not the "right" way to start it. We should just have the + chip do the select for us and interrupt at the end. */ + + DELAY(50); +#if DP_DEBUG + printf ("restart .. stat1=0x%x stat2=0x%x\n", RD_ADR(u_char, DP_STAT1), + RD_ADR(u_char, DP_STAT2)); +#endif + if (!dp_wait_bus_free()) { + cur_xs->error = XS_BUSY; + return; + } + +#if DP_DEBUG + printf ("restart .1 stat1=0x%x stat2=0x%x\n", RD_ADR(u_char, DP_STAT1), + RD_ADR(u_char, DP_STAT2)); + printf ("cur_xs->targ=%d\n",cur_xs->targ); +#endif + if (!dp_select (1 << cur_xs->targ)) { + cur_xs->error = XS_DRIVER_STUFFUP; + return; + } + +#if DP_DEBUG + printf ("restart .2 stat1=0x%x stat2=0x%x\n", RD_ADR(u_char, DP_STAT1), + RD_ADR(u_char, DP_STAT2)); +#endif + /* After selection, we now wait for the APHS interrupt! */ + dp_dvr_state = DP_DVR_ARB; /* Just finished the select/arbitration */ + dp_try_count++; + + if (!(cur_xs->flags & SCSI_NOMASK)) { + /* Set up the timeout! */ +#if DP_DEBUG + printf ("dp_restart_cmd: dp timeouts not done\n"); +#endif + } +} + +/*===========================================================================* + * dp_pdma_out * + *===========================================================================*/ + +/* Note: in NetBSD, the scsi dma addresses are set by the mapping hardware + to inhibit cache. There is therefore, no need to worry about cache hits + during access to dma addresses. */ + +int dp_pdma_out(char *buf, int count, int phase) +{ + int cnt; + int ret = OK; + u_int stat2; + +#if DP_DEBUG + printf("dp_pdma_out: write %d bytes\n", count); +#endif +#if DP_DEBUG > 1 + if (RD_ADR(u_char, DP_STAT2) & DP_S_IRQ) + printf("WARNING: stat2:IRQ set on call to dp_pdma_out\n"); +#endif + + /* Set it up. */ + WR_ADR(u_char, DP_TCMD, phase); + RD_ADR(u_char, DP_MODE) |= DP_M_DMA; + WR_ADR(u_char, DP_ICMD, DP_ENABLE_DB | DP_EMODE); + WR_ADR(u_char, DP_START_SEND, 0); + + /* Do the pdma: first longs, then bytes. */ + while (count > sizeof(long)) { + WR_ADR(long, DP_DMA, *(((long *)buf)++)); + count -= sizeof(long); + } + while (count-- > 1) { + WR_ADR(u_char, DP_DMA, *(buf++)); + } + + /* wait for DRQ to be asserted for the last byte, or an + * interrupt request to be signaled + */ + while (1) { + stat2 = RD_ADR(u_char, DP_STAT2); + if (stat2 & (DP_S_IRQ | DP_S_DRQ)) break; + } + + if (stat2 & DP_S_DRQ) { + WR_ADR(u_char, DP_DMA_EOP, *buf); + } + else { + /* dma error! */ +#if DP_DEBUG + printf ("dma write error!\n"); + dp_print_stat1(RD_ADR(u_char, DP_STAT1)); + dp_print_stat2(stat2); +#endif + cur_xs->error = XS_DRIVER_STUFFUP; + /* Clear dma mode, just in case, and disable the bus. */ + RD_ADR (u_char, DP_MODE) &= ~DP_M_DMA; + WR_ADR (u_char, DP_ICMD, DP_EMODE); + ret = NOT_OK; + } +#if 0 + /* Clear dma mode, just in case, and disable the bus. */ + RD_ADR (u_char, DP_MODE) &= ~DP_M_DMA; + WR_ADR (u_char, DP_ICMD, DP_EMODE); +#endif + + return ret; +} + +/*===========================================================================* + * dp_pdma_in * + *===========================================================================*/ + +/* Note: in NetBSD, the scsi dma addresses are set by the mapping hardware + to inhibit cache. There is therefore, no need to worry about cache hits + during access to dma addresses. */ + +int dp_pdma_in(char *buf, int count, int phase) +{ + int ret = OK; + int i_count = count; + u_int stat2; + u_char *dma_adr = (u_char *) DP_DMA; /* Address for last few bytes. */ + +#if DP_DEBUG > 1 + printf("dp_pdma_in: read %d bytes\n", count); +#endif + /* Set it up. */ + WR_ADR(u_char, DP_TCMD, phase); + RD_ADR(u_char, DP_MODE) |= DP_M_DMA; + WR_ADR(u_char, DP_EMR_ISR, DP_EF_START_RCV | DP_EMR_APHS); + + /* Do the pdma */ + while (count >= sizeof(long)) { + *(((long *)buf)++) = RD_ADR(long, DP_DMA); + count -= sizeof(long); + } + + while (count-- > 0) { + *(buf++) = RD_ADR(u_char, (dma_adr++)); + } + + /* Clear dma mode, just in case, and disable the bus. */ + RD_ADR(u_char, DP_MODE) &= ~DP_M_DMA; + WR_ADR(u_char, DP_ICMD, DP_EMODE); + return ret; +} + +dp_wait_for_edma() +{ + int i; + + for (i = 0; i < 1000000; ++i) { + u_char tcmd = RD_ADR(u_char, DP_TCMD); + if (tcmd & DP_TCMD_EDMA) { +#if DP_DEBUG > 1 + printf("dp_wait_for_phase: EDMA detected\n"); +#endif + RD_ADR(u_char, DP_MODE) &= ~DP_M_DMA; + WR_ADR(u_char, DP_ICMD, DP_EMODE); + return; + } + } + printf("wait for edma timeout\n"); +#if DP_DEBUG + dp_print_regs(); +#endif + panic("dp: wait for edma"); +} + +dp_wait_for_phase(u_char phase) +{ + int i; + u_char isr; + +#if DP_DEBUG > 1 + printf("wait for phase %d...", phase); +#endif + /* set the TCR register */ + WR_ADR(u_char, DP_TCMD, phase); + /* wait for phase match */ + for (i = 0; i < 1000000; ++i) { + u_char stat2 = RD_ADR(u_char, DP_STAT2); + if (stat2 & DP_S_PHASE) { +#if DP_DEBUG > 1 + printf("done\n"); +#endif + /* completely clear the isr */ + WR_ADR(u_char, DP_EMR_ISR, DP_EF_ISR_NEXT); + isr = RD_ADR (u_char, DP_EMR_ISR); + dp_clear_isr(); + return; + } + } + printf("wait for phase %d timeout\n", phase); +#if DP_DEBUG + dp_print_regs(); +#endif + panic("dp: wait for phase"); +} + +/*===========================================================================* + * dp_get_sense * + *===========================================================================*/ + +dp_get_sense (struct scsi_xfer *xs) +{ + u_char status; + u_char message; + u_char isr; + int ret; + + bzero((u_char *) &xs->sense, sizeof(xs->sense)); + + /* completely clear the isr on entry */ + WR_ADR(u_char, DP_EMR_ISR, DP_EF_ISR_NEXT); + isr = RD_ADR (u_char, DP_EMR_ISR); + dp_clear_isr(); + + RD_ADR(u_char, DP_MODE) &= ~DP_M_DMA; + WR_ADR(u_char, DP_ICMD, DP_EMODE); + +#if DP_DEBUG > 2 + printf ("sense 1: wait bus free\n"); +#endif + if (!dp_wait_bus_free()) { +#if DP_DEBUG > 2 + printf("sense 1: wait-bus-free failed\n"); +#endif + xs->error = XS_BUSY; + return; + } + +#if DP_DEBUG > 2 + printf ("sense 2: select device\n"); +#endif + if (!dp_select (1 << xs->targ)) { +#if DP_DEBUG + printf("sense 2: select failed\n"); +#endif + xs->error = XS_DRIVER_STUFFUP; + return; + } + /* completely clear the isr */ + WR_ADR(u_char, DP_EMR_ISR, DP_EF_ISR_NEXT); + isr = RD_ADR (u_char, DP_EMR_ISR); + dp_clear_isr(); + + /* send the command */ + sense_cmd[1] = xs->lu << 5; +#if 0 + sense_cmd[4] = sizeof(struct scsi_sense_data); +#else + sense_cmd[4] = 0x04; +#endif + dp_wait_for_phase(DP_PHASE_CMD); + ret = dp_pdma_out(sense_cmd, sizeof(sense_cmd), DP_PHASE_CMD); + if (ret != OK) { +#if DP_DEBUG + printf("dp_pdma_out: ret=%d\n", ret); +#endif + return; + } + + /* read sense data */ + dp_wait_for_edma(); + dp_wait_for_phase(DP_PHASE_DATAI); + ret = dp_pdma_in((u_char *) &xs->sense, sense_cmd[4], DP_PHASE_DATAI); + if (ret != OK) { +#if DP_DEBUG + printf ("dp_pdma_in: ret=%d\n", ret); +#endif + } + + /* read status */ + dp_wait_for_phase(DP_PHASE_STATUS); + ret = dp_pdma_in(&status, 1, DP_PHASE_STATUS); + if (ret != OK) { +#if DP_DEBUG + printf ("dp_pdma_in: ret=%d\n", ret); +#endif + } + + /* read message */ + dp_wait_for_phase(DP_PHASE_MSGI); + ret = dp_pdma_in(&message, 1, DP_PHASE_MSGI); + if (ret != OK) { +#if DP_DEBUG + printf ("dp_pdma_in: ret=%d\n", ret); +#endif + } + +#if DP_DEBUG + printf("sense status = 0x%x\n", status); + printf(" sense (0x%x) valid = %d code = 0x%x class = 0x%x\n", + *(u_char *) &xs->sense, + xs->sense.valid, xs->sense.error_code, xs->sense.error_class); +#endif + + if (status & SCSI_BUSY) { + xs->error = XS_BUSY; + } + WR_ADR (u_char, DP_MODE, 0); /* Turn off monbsy, dma, ... */ +} diff --git a/sys/arch/pc532/dev/dpreg.h b/sys/arch/pc532/dev/dpreg.h new file mode 100644 index 00000000000..df1af1257bd --- /dev/null +++ b/sys/arch/pc532/dev/dpreg.h @@ -0,0 +1,128 @@ +/* $NetBSD: dpreg.h,v 1.6 1994/10/26 08:24:11 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. + * + * dp.h: defines for the dp driver. + */ + +/* Most of this comes from the Minix dp driver by Bruce Culbertson. */ + +/* NCR 8490 SCSI controller registers + */ +#define DP_CTL 0xffd00000 /* base for control registers */ +#define DP_DMA 0xffe00000 /* base for data registers */ +#define DP_DMA_EOP 0xffeff000 /* SCSI DMA with EOP asserted */ +#define DP_CURDATA (DP_CTL+0) +#define DP_OUTDATA (DP_CTL+0) +#define DP_ICMD (DP_CTL+1) +#define DP_MODE (DP_CTL+2) +#define DP_TCMD (DP_CTL+3) +#define DP_STAT1 (DP_CTL+4) +#define DP_SER (DP_CTL+4) +#define DP_STAT2 (DP_CTL+5) +#define DP_START_SEND (DP_CTL+5) +#define DP_INDATA (DP_CTL+6) +#define DP_EMR_ISR (DP_CTL+7) + +/* Bits in NCR 8490 registers + */ +#define DP_A_RST 0x80 +#define DP_A_SEL 0x04 +#define DP_S_SEL 0x02 +#define DP_S_REQ 0x20 +#define DP_S_BSY 0x40 +#define DP_S_BSYERR 0x04 +#define DP_S_PHASE 0x08 +#define DP_S_IRQ 0x10 +#define DP_S_DRQ 0x40 +#define DP_TCMD_EDMA 0x80 /* true end of dma in tcmd */ +#define DP_M_DMA 0x02 +#define DP_M_BSY 0x04 +#define DP_M_EDMA 0x08 +#define DP_ENABLE_DB 0x01 +#define DP_EMODE 0x40 /* enhanced mode */ +#define DP_EF_NOP 0x00 /* enhanced functions */ +#define DP_EF_ARB 0x01 +#define DP_EF_RESETIP 0x02 +#define DP_EF_START_RCV 0x04 +#define DP_EF_ISR_NEXT 0x06 +#define DP_EMR_APHS 0x80 +#define DP_ISR_BSYERR 0x04 +#define DP_ISR_APHS 0x08 +#define DP_ISR_DPHS 0x10 +#define DP_ISR_EDMA 0x20 +#define DP_INT_MASK (~(DP_ISR_APHS | DP_ISR_BSYERR | DP_ISR_EDMA)) + +#define DP_PHASE_DATAO 0 /* Data out */ +#define DP_PHASE_DATAI 1 /* Data in */ +#define DP_PHASE_CMD 2 /* CMD out */ +#define DP_PHASE_STATUS 3 /* Status in */ +#define DP_PHASE_MSGO 6 /* Message out */ +#define DP_PHASE_MSGI 7 /* Message in */ + +#define DP_PHASE_NONE 4 /* will mismatch all phases (??) */ + +/* Driver state. Helps interrupt code decide what to do next. */ +#define DP_DVR_READY 0 +#define DP_DVR_STARTED 1 +#define DP_DVR_ARB 2 +#define DP_DVR_CMD 3 +#define DP_DVR_DATA 4 +#define DP_DVR_STAT 5 +#define DP_DVR_MSGI 6 +#define DP_DVR_SENSE 7 + +#define dp_clear_isr() /* clear 8490 interrupts */ \ + WR_ADR (u_char, DP_EMR_ISR, DP_EF_RESETIP); \ + WR_ADR (u_char, DP_EMR_ISR, DP_EF_NOP | DP_EMR_APHS); + +/* Status of interrupt routine. + */ +#define ISR_NOTDONE 0 +#define ISR_OK 1 +#define ISR_BSYERR 2 +#define ISR_RSTERR 3 +#define ISR_BADPHASE 4 +#define ISR_TIMEOUT 5 +#define ISR_DMACNTERR 6 + +#define ICU_ADR 0xfffffe00 +#define ICU_IO (ICU_ADR+20) +#define ICU_DIR (ICU_ADR+21) +#define ICU_DATA (ICU_ADR+19) +#define ICU_SCSI_BIT 0x80 + +/* Miscellaneous + */ +#define WAIT_MUL 1000 /* Estimate! .. for polling. */ + +#define OK 1 +#define NOT_OK 0 diff --git a/sys/arch/pc532/dev/lpt.c b/sys/arch/pc532/dev/lpt.c new file mode 100644 index 00000000000..9811279385f --- /dev/null +++ b/sys/arch/pc532/dev/lpt.c @@ -0,0 +1,876 @@ +/* $NetBSD: lpt.c,v 1.6 1995/09/26 20:16:06 phil Exp $ */ + +/* + * Copyright (c) 1994 Matthias Pfaller. + * Copyright (c) 1994 Poul-Henning Kamp + * 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 Matthias's parallel printer port. + * This driver is based on the i386 lpt driver and + * some IP code from Poul-Henning Kamp. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/buf.h> +#include <sys/kernel.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <sys/device.h> +#include <sys/syslog.h> +#include <sys/malloc.h> +#include <machine/cpu.h> + +#include "lpt.h" +#include "lptreg.h" + +#if defined(INET) && defined(PLIP) +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#endif + +#define LPT_INVERT (LPC_NBUSY|LPC_NERROR|LPC_NACK|LPC_ONLINE) +#define LPT_MASK (LPC_NBUSY|LPC_NERROR|LPC_NACK|LPC_NOPAPER|LPC_ONLINE) + +#define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */ +#define STEP hz/4 + +#define LPTPRI (PZERO+8) +#define LPT_BSIZE 1024 + +#if defined(INET) && defined(PLIP) +#ifndef PLIPMTU /* MTU for the plip# interfaces */ +#if defined(COMPAT_PLIP10) +#define PLIPMTU 1600 +#else +#define PLIPMTU (ETHERMTU - ifp->if_hdrlen) +#endif +#endif + +#ifndef PLIPMXSPIN1 /* DELAY factor for the plip# interfaces */ +#define PLIPMXSPIN1 2000 /* Spinning for remote intr to happen */ +#endif + +#ifndef PLIPMXSPIN2 /* DELAY factor for the plip# interfaces */ +#define PLIPMXSPIN2 6000 /* Spinning for remote handshake to happen */ +#endif + +#ifndef PLIPMXERRS /* Max errors before !RUNNING */ +#define PLIPMXERRS 20 +#endif +#ifndef PLIPMXRETRY +#define PLIPMXRETRY 20 /* Max number of retransmits */ +#endif +#ifndef PLIPRETRY +#define PLIPRETRY hz/50 /* Time between retransmits */ +#endif +#endif + +struct lpt_softc { + struct device sc_dev; + size_t sc_count; + u_char *sc_inbuf; + u_char *sc_cp; + volatile struct i8255 *sc_i8255; + int sc_irq; + u_char sc_state; +#define LPT_OPEN 0x01 /* device is open */ +#define LPT_INIT 0x02 /* waiting to initialize for open */ + + u_char sc_status; + u_char sc_flags; +#define LPT_AUTOLF 0x20 /* automatic LF on CR */ +#define LPT_NOPRIME 0x40 /* don't prime on open */ + +#if defined(INET) && defined(PLIP) + struct arpcom sc_arpcom; + u_char *sc_ifbuf; + int sc_ifierrs; /* consecutive input errors */ + int sc_ifoerrs; /* consecutive output errors */ + int sc_ifsoftint; /* i/o software interrupt */ + volatile int sc_pending; /* interrputs pending */ +#define PLIP_IPENDING 1 +#define PLIP_OPENDING 2 + +#if defined(COMPAT_PLIP10) + u_char sc_adrcksum; +#endif +#endif +}; + +#define LPTUNIT(s) (minor(s) & 0x1f) +#define LPTFLAGS(s) (minor(s) & 0xe0) + +static int lptmatch(struct device *, void *, void *aux); +static void lptattach(struct device *, struct device *, void *); +static void lptintr(struct lpt_softc *); +static int notready(u_char, struct lpt_softc *); +static void lptout(void *arg); +static int pushbytes(struct lpt_softc *); + +#if defined(INET) && defined(PLIP) +/* Functions for the plip# interface */ +static void plipattach(struct lpt_softc *,int); +static int plipioctl(struct ifnet *, u_long, caddr_t); +static void plipsoftint(struct lpt_softc *); +static void plipinput(struct lpt_softc *); +static void plipstart(struct ifnet *); +static void plipoutput(struct lpt_softc *); +#endif + +struct cfdriver lptcd = { + NULL, + "lpt", + lptmatch, + lptattach, + DV_TTY, + sizeof(struct lpt_softc), + NULL, + 0 +}; + +lptmatch(struct device *parent, void *cf, void *aux) +{ + volatile struct i8255 *i8255 = + (volatile struct i8255 *)((struct cfdata *)cf)->cf_loc[0]; + int unit = ((struct cfdata *)cf)->cf_unit; + + if (unit >= LPT_MAX) + return(0); + + if ((int) i8255 == -1) + i8255 = LPT_ADR(unit); + + i8255->port_control = LPT_PROBE_MODE; + + i8255->port_control = LPT_PROBE_CLR; + if ((i8255->port_c & LPT_PROBE_MASK) != 0) + return 0; + + i8255->port_control = LPT_PROBE_SET; + if ((i8255->port_c & LPT_PROBE_MASK) == 0) + return 0; + + i8255->port_control = LPT_PROBE_CLR; + if ((i8255->port_c & LPT_PROBE_MASK) != 0) + return 0; + + i8255->port_control = LPT_MODE; + i8255->port_a = LPA_ACTIVE | LPA_NPRIME; + + return 1; +} + +void +lptattach(struct device *parent, struct device *self, void *aux) +{ + struct lpt_softc *sc = (struct lpt_softc *) self; + volatile struct i8255 *i8255 = + (volatile struct i8255 *)self->dv_cfdata->cf_loc[0]; + + if ((sc->sc_irq = self->dv_cfdata->cf_loc[1]) == -1) + sc->sc_irq = LPT_IRQ(self->dv_unit); + + if ((int)i8255 == -1) + i8255 = LPT_ADR(self->dv_unit); + i8255->port_control = LPT_MODE; + i8255->port_a = LPA_ACTIVE | LPA_NPRIME; + i8255->port_control = LPT_IRQDISABLE; + + sc->sc_state = 0; + sc->sc_i8255 = i8255; + +#if defined(INET) && defined(PLIP) + plipattach(sc, self->dv_unit); +#endif + intr_establish(sc->sc_irq, lptintr, sc, sc->sc_dev.dv_xname, + IPL_NONE, FALLING_EDGE); + printf(" addr 0x%x, irq %d\n", (int) i8255, sc->sc_irq); +} + +/* + * Reset the printer, then wait until it's selected and not busy. + */ +int +lptopen(dev_t dev, int flag) +{ + struct lpt_softc *sc = (struct lpt_softc *) lptcd.cd_devs[LPTUNIT(dev)]; + volatile struct i8255 *i8255 = sc->sc_i8255; + u_char flags = LPTFLAGS(dev); + int error; + int spin; + + if (LPTUNIT(dev) >= NLPT || !sc) + return ENXIO; + + if (sc->sc_state) + return EBUSY; + +#if defined(INET) && defined(PLIP) + if (sc->sc_arpcom.ac_if.if_flags & IFF_UP) + return EBUSY; +#endif + + sc->sc_state = LPT_INIT; + sc->sc_flags = flags; + + if ((flags & LPT_NOPRIME) == 0) { + /* assert INIT for 100 usec to start up printer */ + i8255->port_a &= ~LPA_NPRIME; + DELAY(100); + } + + if (flags & LPT_AUTOLF) + i8255->port_a |= LPA_ALF | LPA_SELECT | LPA_NPRIME; + else + i8255->port_a = (i8255->port_a & ~LPA_ALF) + | LPA_SELECT | LPA_NPRIME; + + /* wait till ready (printer running diagnostics) */ + for (spin = 0; notready(i8255->port_c, sc); spin += STEP) { + if (spin >= TIMEOUT) { + sc->sc_state = 0; + return EBUSY; + } + + /* wait 1/4 second, give up if we get a signal */ + if (error = tsleep((caddr_t)sc, LPTPRI | PCATCH, "lptopen", + STEP) != EWOULDBLOCK) { + sc->sc_state = 0; + return error; + } + } + + sc->sc_inbuf = malloc(LPT_BSIZE, M_DEVBUF, M_WAITOK); + sc->sc_status = + sc->sc_count = 0; + sc->sc_state = LPT_OPEN; + + return 0; +} + +int +notready(u_char status, struct lpt_softc *sc) +{ + status ^= LPT_INVERT; + + if (status != sc->sc_status) { + if (status & LPC_NOPAPER) + log(LOG_NOTICE, "%s: out of paper\n", sc->sc_dev.dv_xname); + if (status & LPC_ONLINE) + log(LOG_NOTICE, "%s: offline\n", sc->sc_dev.dv_xname); + if (status & LPC_NERROR) + log(LOG_NOTICE, "%s: output error\n", sc->sc_dev.dv_xname); + if (status & LPC_NACK) + log(LOG_NOTICE, "%s: NACK low\n", sc->sc_dev.dv_xname); + if (status & LPC_NBUSY) + log(LOG_NOTICE, "%s: NBUSY low\n", sc->sc_dev.dv_xname); + sc->sc_status = status; + } + return status & LPT_MASK; +} + +void +lptout(void *arg) +{ + struct lpt_softc *sc = (struct lpt_softc *) arg; + if (sc->sc_count > 0) + sc->sc_i8255->port_control = LPT_IRQENABLE; +} + +/* + * Close the device, and free the local line buffer. + */ +lptclose(dev_t dev, int flag) +{ + struct lpt_softc *sc = (struct lpt_softc *) lptcd.cd_devs[LPTUNIT(dev)]; + + if (sc->sc_count) + (void) pushbytes(sc); + + sc->sc_i8255->port_control = LPT_IRQDISABLE; + sc->sc_state = 0; + free(sc->sc_inbuf, M_DEVBUF); + + return 0; +} + +int +pushbytes(struct lpt_softc *sc) +{ + volatile struct i8255 *i8255 = sc->sc_i8255; + int error; + + while (sc->sc_count > 0) { + i8255->port_control = LPT_IRQENABLE; + if (error = tsleep((caddr_t)sc, LPTPRI | PCATCH, + "lptwrite", 0)) + return error; + } + return 0; +} + +/* + * Copy a line from user space to a local buffer, then call pushbytes to + * get the chars moved to the output queue. + */ +lptwrite(dev_t dev, struct uio *uio) +{ + struct lpt_softc *sc = (struct lpt_softc *) lptcd.cd_devs[LPTUNIT(dev)]; + size_t n; + int error = 0; + + if (sc->sc_count) return EBUSY; + while (n = min(LPT_BSIZE, uio->uio_resid)) { + uiomove(sc->sc_cp = sc->sc_inbuf, n, uio); + sc->sc_count = n; + error = pushbytes(sc); + if (error) { + /* + * Return accurate residual if interrupted or timed + * out. + */ + uio->uio_resid += sc->sc_count; + sc->sc_count = 0; + return error; + } + } + return 0; +} + +/* + * Handle printer interrupts which occur when the printer is ready to accept + * another char. + */ +void +lptintr(struct lpt_softc *sc) +{ + volatile struct i8255 *i8255 = sc->sc_i8255; + +#if defined(INET) && defined(PLIP) + if(sc->sc_arpcom.ac_if.if_flags & IFF_UP) { + i8255->port_a &= ~LPA_ACKENABLE; + sc->sc_pending |= PLIP_IPENDING; + softintr(sc->sc_ifsoftint); + return; + } +#endif + + if ((sc->sc_state & LPT_OPEN) == 0) { + i8255->port_control = LPT_IRQDISABLE; + return; + } + + if (sc->sc_count) { + /* is printer online and ready for output? */ + if (notready(i8255->port_c, sc)) { + i8255->port_control = LPT_IRQDISABLE; + timeout(lptout, sc, STEP); + return; + } + /* send char */ + i8255->port_a &= ~LPA_ACTIVE; + i8255->port_b = *sc->sc_cp++; + i8255->port_a |= LPA_ACTIVE; + sc->sc_count--; + } + + if (sc->sc_count == 0) { + /* none, wake up the top half to get more */ + i8255->port_control = LPT_IRQDISABLE; + wakeup((caddr_t)sc); + } +} + +int +lptioctl(dev_t dev, int cmd, caddr_t data, int flag) +{ + int error = 0; + + switch (cmd) { + default: + error = EINVAL; + } + + return error; +} + +#if defined(INET) && defined(PLIP) + +static void +plipattach(struct lpt_softc *sc, int unit) +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + + sc->sc_ifbuf = NULL; + ifp->if_unit = unit; + ifp->if_name = "plip"; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + ifp->if_output = ether_output; + ifp->if_start = plipstart; + ifp->if_ioctl = plipioctl; + ifp->if_watchdog = 0; + + ifp->if_type = IFT_ETHER; + ifp->if_addrlen = 6; + ifp->if_hdrlen = 14; + ifp->if_mtu = PLIPMTU; + sc->sc_ifsoftint = intr_establish(SOFTINT, plipsoftint, sc, + sc->sc_dev.dv_xname, IPL_NET, 0); + + if_attach(ifp); +} + +/* + * Process an ioctl request. + */ +static int +plipioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct proc *p = curproc; + struct lpt_softc *sc = (struct lpt_softc *) lptcd.cd_devs[ifp->if_unit]; + volatile struct i8255 *i8255 = sc->sc_i8255; + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int s; + int error = 0; + + switch (cmd) { + + case SIOCSIFFLAGS: + if (((ifp->if_flags & IFF_UP) == 0) && + (ifp->if_flags & IFF_RUNNING)) { + ifp->if_flags &= ~IFF_RUNNING; + sc->sc_i8255->port_control = LPT_MODE; + i8255->port_a = LPA_ACTIVE | LPA_NPRIME; + if (sc->sc_ifbuf) + free(sc->sc_ifbuf, M_DEVBUF); + sc->sc_ifbuf = NULL; + } + if (((ifp->if_flags & IFF_UP)) && + ((ifp->if_flags & IFF_RUNNING) == 0)) { + if (sc->sc_state) { + error = EBUSY; + break; + } + if (!sc->sc_ifbuf) + sc->sc_ifbuf = + malloc(ifp->if_mtu + ifp->if_hdrlen, + M_DEVBUF, M_WAITOK); + ifp->if_flags |= IFF_RUNNING; + sc->sc_i8255->port_control = LPT_IRQDISABLE; + sc->sc_i8255->port_b = 0; + sc->sc_i8255->port_a |= LPA_ACKENABLE; + } + break; + + case SIOCSIFADDR: + if (ifa->ifa_addr->sa_family == AF_INET) { + if (!sc->sc_ifbuf) + sc->sc_ifbuf = + malloc(PLIPMTU + ifp->if_hdrlen, + M_DEVBUF, M_WAITOK); + sc->sc_arpcom.ac_enaddr[0] = 0xfc; + sc->sc_arpcom.ac_enaddr[1] = 0xfc; + bcopy((caddr_t)&IA_SIN(ifa)->sin_addr, + (caddr_t)&sc->sc_arpcom.ac_enaddr[2], 4); + sc->sc_arpcom.ac_ipaddr = IA_SIN(ifa)->sin_addr; +#if defined(COMPAT_PLIP10) + if (ifp->if_flags & IFF_LINK0) { + int i; + sc->sc_arpcom.ac_enaddr[0] = 0xfd; + sc->sc_arpcom.ac_enaddr[1] = 0xfd; + for (i = sc->sc_adrcksum = 0; i < 5; i++) + sc->sc_adrcksum += sc->sc_arpcom.ac_enaddr[i]; + sc->sc_adrcksum *= 2; + } +#endif + ifp->if_flags |= IFF_RUNNING | IFF_UP; +#if 0 + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + struct sockaddr_dl *sdl; + if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && + sdl->sdl_family == AF_LINK) { + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ifp->if_addrlen; + bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, + LLADDR(sdl), ifp->if_addrlen); + break; + } + } +#endif + sc->sc_i8255->port_control = LPT_IRQDISABLE; + sc->sc_i8255->port_b = 0; + sc->sc_i8255->port_a |= LPA_ACKENABLE; + arp_ifinit(&sc->sc_arpcom, ifa); + } else + error = EAFNOSUPPORT; + break; + + case SIOCAIFADDR: + case SIOCDIFADDR: + case SIOCSIFDSTADDR: + if (ifa->ifa_addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + break; + + case SIOCSIFMTU: + if ((error = suser(p->p_ucred, &p->p_acflag))) + return(error); + if (ifp->if_mtu != ifr->ifr_metric) { + ifp->if_mtu = ifr->ifr_metric; + if (sc->sc_ifbuf) { + s = splimp(); + free(sc->sc_ifbuf, M_DEVBUF); + sc->sc_ifbuf = + malloc(ifp->if_mtu + ifp->if_hdrlen, + M_DEVBUF, M_WAITOK); + splx(s); + } + } + break; + + case SIOCGIFMTU: + ifr->ifr_metric = ifp->if_mtu; + break; + + default: + error = EINVAL; + } + return (error); +} + +static void +plipsoftint(struct lpt_softc *sc) +{ + int pending = sc->sc_pending; + + while (sc->sc_pending & PLIP_IPENDING) { + pending |= sc->sc_pending; + sc->sc_pending = 0; + plipinput(sc); + } + + if (pending & PLIP_OPENDING) + plipoutput(sc); +} + +static int +plipreceive(volatile struct i8255 *i8255, u_char *buf, int len) +{ + int i; + u_char cksum = 0, c; + + while (len--) { + i = PLIPMXSPIN2; + while ((i8255->port_c & LPC_NBUSY) != 0) + if (i-- < 0) return -1; + c = i8255->port_c >> 4; + i8255->port_b = 0x11; + while ((i8255->port_c & LPC_NBUSY) == 0) + if (i-- < 0) return -1; + c |= i8255->port_c & 0xf0; + i8255->port_b = 0x01; + cksum += (*buf++ = c); + } + return(cksum); +} + +static void +plipinput(struct lpt_softc *sc) +{ + extern struct mbuf *m_devget(char *, int, int, struct ifnet *, void (*)()); + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + volatile struct i8255 *i8255 = sc->sc_i8255; + struct mbuf *m; + struct ether_header *eh; + u_char *p = sc->sc_ifbuf, minibuf[4]; + int c, i = 0, s, len, cksum; + + if (!(i8255->port_c & LPC_NACK)) { + i8255->port_a |= LPA_ACKENABLE; + ifp->if_collisions++; + return; + } + i8255->port_b = 0x01; + i8255->port_a &= ~(LPA_ACKENABLE | LPA_ACTIVE); + +#if defined(COMPAT_PLIP10) + if (ifp->if_flags & IFF_LINK0) { + if (plipreceive(i8255, minibuf, 3) < 0) goto err; + len = (minibuf[1] << 8) | minibuf[2]; + if (len > (ifp->if_mtu + ifp->if_hdrlen)) goto err; + + switch (minibuf[0]) { + case 0xfc: + p[0] = p[ 6] = ifp->ac_enaddr[0]; + p[1] = p[ 7] = ifp->ac_enaddr[1]; + p[2] = p[ 8] = ifp->ac_enaddr[2]; + p[3] = p[ 9] = ifp->ac_enaddr[3]; + p[4] = p[10] = ifp->ac_enaddr[4]; + p += 5; + if ((cksum = plipreceive(i8255, p, 1)) < 0) goto err; + p += 6; + if ((c = plipreceive(i8255, p, len - 11)) < 0) goto err; + cksum += c + sc->sc_adrcksum; + c = p[1]; p[1] = p[2]; p[2] = c; + cksum &= 0xff; + break; + case 0xfd: + if ((cksum = plipreceive(i8255, p, len)) < 0) goto err; + break; + default: + goto err; + } + } else +#endif + { + if (plipreceive(i8255, minibuf, 2) < 0) goto err; + len = (minibuf[1] << 8) | minibuf[0]; + if (len > (ifp->if_mtu + ifp->if_hdrlen)) { + log(LOG_NOTICE, "plip%d: packet > MTU\n", ifp->if_unit); + goto err; + } + if ((cksum = plipreceive(i8255, p, len)) < 0) goto err; + } + + if (plipreceive(i8255, minibuf, 1) < 0) goto err; + if (cksum != minibuf[0]) { + log(LOG_NOTICE, "plip%d: checksum error\n", ifp->if_unit); + goto err; + } + i8255->port_b = 0x00; + + s = splimp(); + if (m = m_devget(sc->sc_ifbuf, len, 0, ifp, NULL)) { + /* We assume that the header fit entirely in one mbuf. */ + eh = mtod(m, struct ether_header *); + m->m_pkthdr.len -= sizeof(*eh); + m->m_len -= sizeof(*eh); + m->m_data += sizeof(*eh); + ether_input(ifp, eh, m); + } + splx(s); + sc->sc_ifierrs = 0; + ifp->if_ipackets++; + i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE; + return; + +err: + i8255->port_b = 0x00; + + if (sc->sc_ifierrs < PLIPMXERRS) { + i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE; + } else { + /* We are not able to send receive anything for now, + * so stop wasting our time and leave the interrupt + * disabled. + */ + if (sc->sc_ifierrs == PLIPMXERRS) + log(LOG_NOTICE, "plip%d: rx hard error\n", ifp->if_unit); + i8255->port_a |= LPA_ACTIVE; + } + ifp->if_ierrors++; + sc->sc_ifierrs++; + return; +} + +static int +pliptransmit(volatile struct i8255 *i8255, u_char *buf, int len) +{ + int i; + u_char cksum = 0, c; + + while (len--) { + i = PLIPMXSPIN2; + cksum += (c = *buf++); + while ((i8255->port_c & LPC_NBUSY) == 0) + if (i-- < 0) return -1; + i8255->port_b = c & 0x0f; + i8255->port_b = c & 0x0f | 0x10; + c >>= 4; + while ((i8255->port_c & LPC_NBUSY) != 0) + if (i-- < 0) return -1; + i8255->port_b = c | 0x10; + i8255->port_b = c; + } + return(cksum); +} + +/* + * Setup output on interface. + */ +static void +plipstart(struct ifnet *ifp) +{ + struct lpt_softc *sc = (struct lpt_softc *) lptcd.cd_devs[ifp->if_unit]; + sc->sc_pending |= PLIP_OPENDING; + softintr(sc->sc_ifsoftint); +} + +static void +plipoutput(struct lpt_softc *sc) +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + volatile struct i8255 *i8255 = sc->sc_i8255; + struct mbuf *m0, *m; + u_char minibuf[4], cksum; + int len, i, s; + + if (ifp->if_flags & IFF_OACTIVE) + return; + ifp->if_flags |= IFF_OACTIVE; + + if (sc->sc_ifoerrs) + untimeout((void (*)(void *))plipoutput, sc); + + for (;;) { + s = splnet(); + IF_DEQUEUE(&ifp->if_snd, m0); + splx(s); + if (!m0) + break; + + for (len = 0, m = m0; m; m = m->m_next) + len += m->m_len; +#if defined(COMPAT_PLIP10) + if (ifp->if_flags & IFF_LINK0) { + minibuf[0] = 3; + minibuf[1] = 0xfd; + minibuf[2] = len >> 8; + minibuf[3] = len; + } else +#endif + { + minibuf[0] = 2; + minibuf[1] = len; + minibuf[2] = len >> 8; + } + + /* Trigger remote interrupt */ + i = PLIPMXSPIN1; + do { + if (sc->sc_pending & PLIP_IPENDING) { + i8255->port_b = 0x00; + sc->sc_pending = 0; + plipinput(sc); + i = PLIPMXSPIN1; + } else if (i-- < 0) + goto retry; + /* Retrigger remote interrupt */ + i8255->port_b = 0x08; + } while ((i8255->port_c & LPC_NERROR) == 0); + i8255->port_a &= ~(LPA_ACKENABLE | LPA_ACTIVE); + + if (pliptransmit(i8255, minibuf + 1, minibuf[0]) < 0) goto retry; + for (cksum = 0, m = m0; m; m = m->m_next) { + i = pliptransmit(i8255, mtod(m, u_char *), m->m_len); + if (i < 0) goto retry; + cksum += i; + } + if (pliptransmit(i8255, &cksum, 1) < 0) goto retry; + i = PLIPMXSPIN2; + while ((i8255->port_c & LPC_NBUSY) == 0) + if (i-- < 0) goto retry; + i8255->port_b = 0x00; + + ifp->if_opackets++; + ifp->if_obytes += len + 4; + sc->sc_ifoerrs = 0; + s = splimp(); + m_freem(m0); + splx(s); + i8255->port_a |= LPA_ACKENABLE; + } + i8255->port_a |= LPA_ACTIVE; + ifp->if_flags &= ~IFF_OACTIVE; + return; + +retry: + if (i8255->port_c & LPC_NACK) + ifp->if_collisions++; + else + ifp->if_oerrors++; + + ifp->if_flags &= ~IFF_OACTIVE; + i8255->port_b = 0x00; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_UP)) == (IFF_RUNNING | IFF_UP) + && sc->sc_ifoerrs < PLIPMXRETRY) { + s = splnet(); + IF_PREPEND(&ifp->if_snd, m0); + splx(s); + i8255->port_a |= LPA_ACKENABLE | LPA_ACTIVE; + timeout((void (*)(void *))plipoutput, sc, PLIPRETRY); + } else { + if (sc->sc_ifoerrs == PLIPMXRETRY) { + log(LOG_NOTICE, "plip%d: tx hard error\n", ifp->if_unit); + } + s = splimp(); + m_freem(m0); + splx(s); + i8255->port_a |= LPA_ACTIVE; + } + sc->sc_ifoerrs++; +} + +#endif diff --git a/sys/arch/pc532/dev/lptreg.h b/sys/arch/pc532/dev/lptreg.h new file mode 100644 index 00000000000..6298f1fe291 --- /dev/null +++ b/sys/arch/pc532/dev/lptreg.h @@ -0,0 +1,75 @@ +/* $NetBSD: lptreg.h,v 1.3 1995/05/16 07:30:35 phil Exp $ */ + +/* + * Copyright (c) 1994 Matthias Pfaller. + * 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 Matthias Pfaller. + * 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. + * + * lptreg.h: definitions for the lpt driver. + * + */ + +struct i8255 { + unsigned char port_a; /* Port A data (r/w) */ + unsigned char port_b; /* Port B data (r/w) */ + unsigned char port_c; /* Port C data (r/w) */ + unsigned char port_control; /* Port control (-/w) */ +}; + +/* port_a */ +#define LPA_ALF 0x01 +#define LPA_SELECT 0x02 +#define LPA_NPRIME 0x04 +#define LPA_ACKENABLE 0x08 /* Enable Ack interrupts */ +#define LPA_ACTIVE 0x10 /* Device active led */ + +/* port_c */ +#define LPC_IRQ 0x01 +#define LPC_NSTROBE 0x02 +#define LPC_NBUSY 0x08 /* Negative logic! */ +#define LPC_NERROR 0x10 +#define LPC_ONLINE 0x20 +#define LPC_NOPAPER 0x40 +#define LPC_NACK 0x80 + +/* port_control */ +#define LPT_PROBE_MODE 0x8c +#define LPT_MODE 0x8d /* Port A: Output, Mode 0 */ + /* Port B: Output, Mode 1 */ + /* Port C: Input */ +#define LPT_IRQENABLE 0x05 /* Enable LPT interrupts */ +#define LPT_IRQDISABLE 0x04 /* Disable LPT interrupts */ + +#define LPT_PROBE_MASK 0x08 +#define LPT_PROBE_SET 0x07 +#define LPT_PROBE_CLR 0x06 + + /* Default mapped address */ +#define LPT_ADR(unit) (((volatile struct i8255 *)0xFFC80030) + unit) + /* Default interrupts */ +#define LPT_IRQ(unit) (unit?IR_TTY3 - 1:IR_TTY3) +#define LPT_MAX 2 /* Maximum number of lpt interfaces*/ diff --git a/sys/arch/pc532/dev/ncr.c b/sys/arch/pc532/dev/ncr.c new file mode 100644 index 00000000000..0501972eabe --- /dev/null +++ b/sys/arch/pc532/dev/ncr.c @@ -0,0 +1,297 @@ +/* $NetBSD: ncr.c,v 1.20 1995/09/26 20:16:08 phil Exp $ */ + +/* + * Copyright (c) 1994 Matthias Pfaller. + * 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 Matthias Pfaller. + * 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. + * + * $Id: ncr.c,v 1.1 1995/10/18 08:51:17 deraadt Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/buf.h> +#include <scsi/scsi_all.h> +#include <scsi/scsi_message.h> +#include <scsi/scsiconf.h> +#include <machine/stdarg.h> + +/* + * Include the driver definitions + */ +#include "ncr5380reg.h" +#include "ncrreg.h" + +/* + * Set the various driver options + */ +#define NREQ 18 /* Size of issue queue */ +#define AUTO_SENSE 1 /* Automatically issue a request-sense */ + +#define DRNAME ncr /* used in various prints */ +#undef DBG_SEL /* Show the selection process */ +#undef DBG_REQ /* Show enqueued/ready requests */ +#undef DBG_NOWRITE /* Do not allow writes to the targets */ +#undef DBG_PIO /* Show the polled-I/O process */ +#undef DBG_INF /* Show information transfer process */ +#undef DBG_NOSTATIC /* No static functions, all in DDB trace*/ +#define DBG_PID /* Keep track of driver */ +#undef REAL_DMA /* Use DMA if sensible */ +#undef REAL_DMA_POLL 0 /* 1: Poll for end of DMA-transfer */ +#define USE_PDMA /* Use special pdma-transfer function */ + +/* + * Softc of currently active controller (a bit of fake; we only have one) + */ +static struct ncr_softc *cur_softc; + +/* + * Function decls: + */ +static int transfer_pdma __P((u_char *, u_char *, u_long *)); +static void ncr_intr __P((void *)); +static void ncr_soft_intr __P((void *)); +#define scsi_dmaok(x) 0 +#define pdma_ready() 0 +#define fair_to_keep_dma() 1 +#define claimed_dma() 1 +#define reconsider_dma() +#define ENABLE_NCR5380(sc) do { \ + scsi_select_ctlr(DP8490); \ + cur_softc = sc; \ + } while (0) + +void +delay(timeo) + int timeo; +{ + int len; + for (len=0; len < timeo * 2; len++); +} + +static int +machine_match(pdp, cdp, auxp, cfd) + struct device *pdp; + struct cfdata *cdp; + void *auxp; + struct cfdriver *cfd; +{ + if(cdp->cf_unit != 0) /* Only one unit */ + return(0); + return(1); +} + +static void +scsi_mach_init(sc) + struct ncr_softc *sc; +{ + register int i; + intr_disable(IR_SCSI1); + i = intr_establish(SOFTINT, ncr_soft_intr, sc, sc->sc_dev.dv_xname, + IPL_BIO, 0); + intr_establish(IR_SCSI1, ncr_intr, (void *)i, sc->sc_dev.dv_xname, + IPL_BIO, RISING_EDGE); + printf(" addr 0x%x, irq %d", NCR5380, IR_SCSI1); +} + +/* + * 5380 interrupt. + */ +static void +ncr_intr(softint) + void *softint; +{ + int ctrlr; + + ctrlr = scsi_select_ctlr(DP8490); + if (NCR5380->ncr_dmstat & SC_IRQ_SET) { + intr_disable(IR_SCSI1); + softintr((int)softint); + } + scsi_select_ctlr(ctrlr); +} + +static void +ncr_soft_intr(sc) + void *sc; +{ + int ctrlr = scsi_select_ctlr(DP8490); + ncr_ctrl_intr(sc); + scsi_select_ctlr(ctrlr); +} + +/* + * PDMA stuff + */ +#define movsd(from, to, n) do { \ + register int r0 __asm ("r0") = n; \ + register u_char *r1 __asm("r1") = from; \ + register u_char *r2 __asm("r2") = to; \ + __asm volatile ("movsd" \ + : "=r" (r1), "=r" (r2) \ + : "0" (r1), "1" (r2), "r" (r0) \ + : "r0", "memory" \ + ); \ + from = r1; to = r2; \ + } while (0) + +#define movsb(from, to, n) do { \ + register int r0 __asm ("r0") = n; \ + register u_char *r1 __asm("r1") = from; \ + register u_char *r2 __asm("r2") = to; \ + __asm volatile ("movsb" \ + : "=r" (r1), "=r" (r2) \ + : "0" (r1), "1" (r2), "r" (r0) \ + : "r0", "memory" \ + ); \ + from = r1; to = r2; \ + } while (0) + +#define TIMEOUT 1000000 +#define READY(dataout) do { \ + for (i = TIMEOUT; i > 0; i --) { \ + /*if (!(NCR5380->ncr_dmstat & SC_PHS_MTCH)) {*/ \ + if (NCR5380->ncr_dmstat & SC_IRQ_SET) { \ + if (dataout) NCR5380->ncr_icom &= ~SC_ADTB; \ + NCR5380->ncr_mode &= ~SC_M_DMA; \ + *count = len; \ + if ((idstat = NCR5380->ncr_idstat) & SC_S_REQ) \ + *phase = (idstat >> 2) & 7; \ + else \ + *phase = NR_PHASE; \ + return(1); \ + } \ + if (NCR5380->ncr_dmstat & SC_DMA_REQ) break; \ + delay(1); \ + } \ + if (i <= 0) panic("ncr0: pdma timeout"); \ + } while (0) + +#define byte_data ((volatile u_char *)pdma) +#define word_data ((volatile u_short *)pdma) +#define long_data ((volatile u_long *)pdma) + +#define W1(n) *byte_data = *(data + n) +#define W2(n) *word_data = *((u_short *)data + n) +#define W4(n) *long_data = *((u_long *)data + n) +#define R1(n) *(data + n) = *byte_data +#define R4(n) *((u_long *)data + n) = *long_data + +static int +transfer_pdma(phase, data, count) + u_char *phase; + u_char *data; + u_long *count; +{ + register volatile u_char *pdma = PDMA_ADDRESS; + register int len = *count, i, idstat; + + if (len < 256) { + __asm volatile ("lmr ivar0,%0" : : "g" (data)); + transfer_pio(phase, data, count, 0); + return(1); + } + NCR5380->ncr_tcom = *phase; + scsi_clr_ipend(); + if (PH_IN(*phase)) { + NCR5380->ncr_icom = 0; + NCR5380->ncr_mode = IMODE_BASE | SC_M_DMA; + NCR5380->ncr_ircv = 0; + while (len >= 256) { + if (!((u_long) data & 0xfff)) + __asm volatile ("lmr ivar0,%0" : : "g" (data)); + READY(0); + di(); + movsd((u_char *)pdma, data, 64); + len -= 256; + ei(); + } + if (len) { + di(); + while (len) { + READY(0); + R1(0); + data++; + len--; + } + ei(); + } + } else { + NCR5380->ncr_mode = IMODE_BASE | SC_M_DMA; + NCR5380->ncr_icom = SC_ADTB; + NCR5380->ncr_dmstat = SC_S_SEND; + while (len >= 256) { + /* The second ready is to + * compensate for DMA-prefetch. + * Since we adjust len only at + * the end of the block, there + * is no need to correct the + * residue. + */ + READY(1); + di(); + W1(0); READY(1); W1(1); W2(1); + data += 4; + movsd(data, (u_char *)pdma, 63); + ei(); + len -= 256; + } + if (len) { + READY(1); + di(); + while (len) { + W1(0); + READY(1); + data++; + len--; + } + ei(); + } + i = TIMEOUT; + while (((NCR5380->ncr_dmstat & (SC_DMA_REQ|SC_PHS_MTCH)) + == SC_PHS_MTCH) && --i); + if (!i) + printf("ncr0: timeout waiting for SC_DMA_REQ.\n"); + *byte_data = 0; + } + +ncr_timeout_error: + NCR5380->ncr_mode &= ~SC_M_DMA; + if((idstat = NCR5380->ncr_idstat) & SC_S_REQ) + *phase = (idstat >> 2) & 7; + else + *phase = NR_PHASE; + *count = len; + return(1); +} + +/* + * Last but not least... Include the general driver code + */ +#include "ncr5380.c" diff --git a/sys/arch/pc532/dev/ncr5380.c b/sys/arch/pc532/dev/ncr5380.c new file mode 100644 index 00000000000..cbc267873c7 --- /dev/null +++ b/sys/arch/pc532/dev/ncr5380.c @@ -0,0 +1,1907 @@ +/* $NetBSD: ncr5380.c,v 1.5 1995/10/10 08:08:01 phil Exp $ */ + +/* + * Copyright (c) 1995 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. + */ + + +#ifdef DBG_NOSTATIC +# define static +#endif +#ifdef DBG_SEL +# define DBG_SELPRINT(a,b) printf(a,b) +#else +# define DBG_SELPRINT(a,b) +#endif +#ifdef DBG_PIO +# define DBG_PIOPRINT(a,b,c) printf(a,b,c) +#else +# define DBG_PIOPRINT(a,b,c) +#endif +#ifdef DBG_INF +# define DBG_INFPRINT(a,b,c) a(b,c) +#else +# define DBG_INFPRINT(a,b,c) +#endif +#ifdef DBG_PID + static char *last_hit = NULL, *olast_hit = NULL; +# define PID(a) olast_hit = last_hit; last_hit = a; +#else +# define PID(a) +#endif + +/* + * Bit mask of targets you want debugging to be shown + */ +u_char dbg_target_mask = 0x7f; + +/* + * Set bit for target when parity checking must be disabled. + * My (LWP) Maxtor 7245S seems to generate parity errors on about 50% + * of all transfers while the data is correct!? + */ +u_char ncr5380_no_parchk = 0xff; + +/* + * This is the default sense-command we send. + */ +static u_char sense_cmd[] = { + REQUEST_SENSE, 0, 0, 0, sizeof(struct scsi_sense_data), 0 +}; + +/* + * True if the main co-routine is running + */ +static volatile int main_running = 0; + +/* + * Mask of targets selected + */ +static u_char busy; + +static void ncr5380_minphys(struct buf *bp); +static int ncr5380_scsi_cmd(struct scsi_xfer *xs); +static int ncr5380_show_scsi_cmd(struct scsi_xfer *xs); + +struct scsi_adapter ncr5380_switch = { + ncr5380_scsi_cmd, /* scsi_cmd() */ + ncr5380_minphys, /* scsi_minphys() */ + 0, /* open_target_lu() */ + 0 /* close_target_lu() */ +}; + +struct scsi_device ncr5380_dev = { + NULL, /* use default error handler */ + NULL, /* do not have a start functio */ + NULL, /* have no async handler */ + NULL /* Use default done routine */ +}; + + +static SC_REQ req_queue[NREQ]; +static SC_REQ *free_head = NULL; /* Free request structures */ + + +/* + * Inline functions: + */ + +/* + * Determine the size of a SCSI command. + */ +extern __inline__ int command_size(opcode) +u_char opcode; +{ + switch ((opcode >> 4) & 0xf) { + case 0: + case 1: + return (6); + case 2: + case 3: + return (10); + } + return (12); +} + + +/* + * Wait for request-line to become active. When it doesn't return 0. + * Otherwise return != 0. + * The timeouts in the 'wait_req_*' functions are arbitrary and rather + * large. In 99% of the invocations nearly no timeout is needed but in + * some cases (especially when using my tapedrive, a Tandberg 3600) the + * device is busy internally and the first SCSI-phase will be delayed. + */ +extern __inline__ int wait_req_true(void) +{ + int timeout = 25000; + + while (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) && --timeout) + delay(1); + return (GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ); +} + +/* + * Wait for request-line to become inactive. When it doesn't return 0. + * Otherwise return != 0. + */ +extern __inline__ int wait_req_false(void) +{ + int timeout = 25000; + + while ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) && --timeout) + delay(1); + return (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ)); +} + +extern __inline__ void ack_message() +{ + SET_5380_REG(NCR5380_ICOM, 0); +} + +extern __inline__ void nack_message(SC_REQ *reqp) +{ + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + reqp->msgout = MSG_ABORT; +} + +extern __inline__ void finish_req(SC_REQ *reqp) +{ + int sps; + struct scsi_xfer *xs = reqp->xs; + +#ifdef REAL_DMA + /* + * If we bounced, free the bounce buffer + */ + if (reqp->dr_flag & DRIVER_BOUNCING) + free_bounceb(reqp->bounceb); +#endif /* REAL_DMA */ +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, "DONE"); +#endif +#ifdef DBG_ERR_RET + if (reqp->xs->error != 0) + show_request(reqp, "ERR_RET"); +#endif + + /* + * Return request to free-q + */ + sps = splbio(); + reqp->next = free_head; + free_head = reqp; + splx(sps); + + xs->flags |= ITSDONE; + scsi_done(xs); +} + +/* + * Auto config stuff.... + */ +int ncr_cprint __P((void *auxp, char *)); +void ncr_attach __P((struct device *, struct device *, void *)); +int ncr_match __P((struct device *, struct cfdata *, void *)); + +/* + * Tricks to make driver-name configurable + */ +#define CFNAME(n) __CONCAT(n,cd) +#define CFSTRING(n) __STRING(n) + +struct cfdriver CFNAME(DRNAME) = { + NULL, CFSTRING(DRNAME), (cfmatch_t)ncr_match, ncr_attach, + DV_DULL, sizeof(struct ncr_softc), NULL, 0 }; + +int +ncr_match(pdp, cdp, auxp) +struct device *pdp; +struct cfdata *cdp; +void *auxp; +{ + return (machine_match(pdp, cdp, auxp, &CFNAME(DRNAME))); +} + +void +ncr_attach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + struct ncr_softc *sc; + int i; + + sc = (struct ncr_softc *)dp; + + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = 7; + sc->sc_link.adapter = &ncr5380_switch; + sc->sc_link.device = &ncr5380_dev; + sc->sc_link.openings = NREQ - 1; + + /* + * bitmasks + */ + sc->sc_noselatn = 0; + sc->sc_selected = 0; + + /* + * Initialize machine-type specific things... + */ + scsi_mach_init(sc); + printf("\n"); + + /* + * Initialize request queue freelist. + */ + for (i = 0; i < NREQ; i++) { + req_queue[i].next = free_head; + free_head = &req_queue[i]; + } + + /* + * Initialize the host adapter + */ + scsi_idisable(); + ENABLE_NCR5380(sc); + SET_5380_REG(NCR5380_ICOM, 0); + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_TCOM, 0); + SET_5380_REG(NCR5380_IDSTAT, 0); + scsi_ienable(); + + /* + * attach all scsi units on us + */ + config_found(dp, &sc->sc_link, ncr_cprint); +} + +/* + * print diag if name is NULL else just extra + */ +int +ncr_cprint(auxp, name) +void *auxp; +char *name; +{ + if (name == NULL) + return (UNCONF); + return (QUIET); +} +/* + * End of auto config stuff.... + */ + +/* + * Carry out a request from the high level driver. + */ +static int +ncr5380_scsi_cmd(struct scsi_xfer *xs) +{ + int sps; + SC_REQ *reqp; + int flags = xs->flags; + + /* + * We do not queue RESET commands + */ + if (flags & SCSI_RESET) { + scsi_reset(xs->sc_link->adapter_softc); + return (COMPLETE); + } + + /* + * Get a request block + */ + sps = splbio(); + if ((reqp = free_head) == 0) { + splx(sps); + return (TRY_AGAIN_LATER); + } + free_head = reqp->next; + reqp->next = NULL; + splx(sps); + + /* + * Initialize our private fields + */ + reqp->dr_flag = (flags & SCSI_POLL) ? DRIVER_NOINT : 0; + reqp->phase = NR_PHASE; + reqp->msgout = MSG_NOOP; + reqp->status = SCSGOOD; + reqp->link = NULL; + reqp->xs = xs; + reqp->targ_id = xs->sc_link->target; + reqp->targ_lun = xs->sc_link->lun; + reqp->xdata_ptr = (u_char*)xs->data; + reqp->xdata_len = xs->datalen; + bcopy(xs->cmd, &reqp->xcmd, sizeof(struct scsi_generic)); + reqp->xcmd.bytes[0] |= reqp->targ_lun << 5; + + /* + * Sanity check on flags... + */ + if (flags & ITSDONE) { + ncr_tprint(reqp, "scsi_cmd: command already done.....\n"); + xs->flags &= ~ITSDONE; + } + if (!(flags & INUSE)) { + ncr_tprint(reqp, "scsi_cmd: command not in use.....\n"); + xs->flags |= ~INUSE; + } + +#ifdef REAL_DMA + /* + * Check if DMA can be used on this request + */ + if (scsi_dmaok(reqp)) + reqp->dr_flag |= DRIVER_DMAOK; +#endif /* REAL_DMA */ + + /* + * Insert the command into the issue queue. Note that 'REQUEST SENSE' + * commands are inserted at the head of the queue since any command + * will clear the existing contingent allegience condition and the sense + * data is only valid while the condition exists. + * When possible, link the command to a previous command to the same + * target. This is not very sensible when AUTO_SENSE is not defined! + * Interrupts are disabled while we are fiddling with the issue-queue. + */ + sps = splbio(); + if ((issue_q == NULL) || (reqp->xcmd.opcode == REQUEST_SENSE)) { + reqp->next = issue_q; + issue_q = reqp; + } + else { + SC_REQ *tmp, *link; + + tmp = issue_q; + link = NULL; + do { + if (!link && (tmp->targ_id == reqp->targ_id) && !tmp->link) + link = tmp; + } while (tmp->next && (tmp = tmp->next)); + tmp->next = reqp; +#ifdef AUTO_SENSE + if (link) { + link->link = reqp; + link->xcmd.bytes[link->xs->cmdlen-1] |= 1; + } +#endif + } + splx(sps); + +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, (reqp->xcmd.opcode == REQUEST_SENSE) ? + "HEAD":"TAIL"); +#endif + + run_main(xs->sc_link->adapter_softc); + + if (xs->flags & SCSI_POLL) + return (COMPLETE); /* We're booting */ + return (SUCCESSFULLY_QUEUED); +} + +#define MIN_PHYS 65536 /*BARF!!!!*/ +static void +ncr5380_minphys(struct buf *bp) +{ + if (bp->b_bcount > MIN_PHYS) + bp->b_bcount = MIN_PHYS; + minphys(bp); +} +#undef MIN_PHYS + +static int +ncr5380_show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *) xs->cmd; + int i = 0; + + if (!(xs->flags & SCSI_RESET)) { + printf("(%d:%d:%d,0x%x)-", xs->sc_link->scsibus, + xs->sc_link->target, xs->sc_link->lun, xs->sc_link->flags); + while (i < xs->cmdlen) { + if (i) + printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else { + printf("(%d:%d:%d)-RESET-\n", + xs->sc_link->scsibus,xs->sc_link->target, xs->sc_link->lun); + } +} + +/* + * The body of the driver. + */ +static void +scsi_main(sc) +struct ncr_softc *sc; +{ + SC_REQ *req, *prev; + int itype; + int sps; + + /* + * While running in the driver SCSI-interrupts are disabled. + */ + scsi_idisable(); + ENABLE_NCR5380(sc); + + PID("scsi_main1"); + for (;;) { + sps = splbio(); + if (!connected) { + /* + * Check if it is fair keep any exclusive access to DMA + * claimed. If not, stop queueing new jobs so the discon_q + * will be eventually drained and DMA can be given up. + */ + if (!fair_to_keep_dma()) + goto main_exit; + + /* + * Search through the issue-queue for a command + * destined for a target that isn't busy. + */ + prev = NULL; + for (req=issue_q; req != NULL; prev = req, req = req->next) { + if (!(busy & (1 << req->targ_id))) { + /* + * Found one, remove it from the issue queue + */ + if (prev == NULL) + issue_q = req->next; + else prev->next = req->next; + req->next = NULL; + break; + } + } + + /* + * When a request has just ended, we get here before an other + * device detects that the bus is free and that it can + * reconnect. The problem is that when this happens, we always + * baffle the device because our (initiator) id is higher. This + * can cause a sort of starvation on slow devices. So we check + * for a pending reselection here. + * Note that 'connected' will be non-null if the reselection + * succeeds. + */ + if ((GET_5380_REG(NCR5380_IDSTAT) & (SC_S_SEL|SC_S_IO)) + == (SC_S_SEL|SC_S_IO)){ + if (req != NULL) { + req->next = issue_q; + issue_q = req; + } + splx(sps); + + reselect(sc); + scsi_clr_ipend(); + goto connected; + } + + /* + * The host is not connected and there is no request + * pending, exit. + */ + if (req == NULL) { + PID("scsi_main2"); + goto main_exit; + } + + /* + * Re-enable interrupts before handling the request. + */ + splx(sps); + +#ifdef DBG_REQ + if (dbg_target_mask & (1 << req->targ_id)) + show_request(req, "TARGET"); +#endif + /* + * We found a request. Try to connect to the target. If the + * initiator fails arbitration, the command is put back in the + * issue queue. + */ + if (scsi_select(req, 0)) { + sps = splbio(); + req->next = issue_q; + issue_q = req; + splx(sps); +#ifdef DBG_REQ + if (dbg_target_mask & (1 << req->targ_id)) + ncr_tprint(req, "Select failed\n"); +#endif + } + } + else splx(sps); +connected: + if (connected) { + /* + * If the host is currently connected but a 'real-dma' transfer + * is in progress, the 'end-of-dma' interrupt restarts main. + * So quit. + */ + sps = splbio(); + if (connected && (connected->dr_flag & DRIVER_IN_DMA)) { + PID("scsi_main3"); + goto main_exit; + } + splx(sps); + + /* + * Let the target guide us through the bus-phases + */ + while (information_transfer() == -1) + ; + } + } + /* NEVER TO REACH HERE */ + panic("ncr5380-SCSI: not designed to come here"); + +main_exit: + /* + * We enter here with interrupts disabled. We are about to exit main + * so interrupts should be re-enabled. Because interrupts are edge + * triggered, we could already have missed the interrupt. Therefore + * we check the IRQ-line here and re-enter when we really missed a + * valid interrupt. + */ + PID("scsi_main4"); + scsi_ienable(); + SET_5380_REG(NCR5380_IDSTAT, SC_HOST_ID); + if (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) { + if ((itype = check_intr(sc)) != INTR_SPURIOUS) { + scsi_idisable(); + splx(sps); + + if (itype == INTR_RESEL) + reselect(sc); +#ifdef REAL_DMA + else dma_ready(); +#else + else { + if (pdma_ready()) + goto connected; + panic("Got DMA interrupt without DMA"); + } +#endif + scsi_clr_ipend(); + goto connected; + } + } + reconsider_dma(); + + main_running = 0; + splx(sps); + PID("scsi_main5"); +} + +#ifdef REAL_DMA +/* + * The SCSI-DMA interrupt. + * This interrupt can only be triggered when running in non-polled DMA + * mode. When DMA is not active, it will be silently ignored, it is usually + * to late because the EOP interrupt of the controller happens just a tiny + * bit earlier. It might become usefull when scatter/gather is implemented, + * because in that case only part of the DATAIN/DATAOUT transfer is taken + * out of a single buffer. + */ +static void +ncr_dma_intr(sc) +struct ncr_softc *sc; +{ + SC_REQ *reqp; + int dma_done; + + PID("ncr_dma_intr"); + if ((reqp = connected) && (reqp->dr_flag & DRIVER_IN_DMA)) { + scsi_idisable(); + if (!(dma_done = dma_ready())) { + transfer_dma(reqp, reqp->phase, 0); + return; + } + run_main(sc); + } +} +#endif /* REAL_DMA */ + +/* + * The SCSI-controller interrupt. This interrupt occurs on reselections and + * at the end of non-polled DMA-interrupts. It is assumed to be called from + * the machine-dependent hardware interrupt. + */ +static void +ncr_ctrl_intr(sc) +struct ncr_softc *sc; +{ + int itype; + int dma_done; + + while (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) { + scsi_idisable(); + if ((itype = check_intr(sc)) != INTR_SPURIOUS) { + if (itype == INTR_RESEL) + reselect(sc); + else { +#ifdef REAL_DMA + if (!(dma_done = dma_ready())) { + transfer_dma(connected, connected->phase, 0); + return; + } +#else + if (pdma_ready()) + return; + panic("Got DMA interrupt without DMA\n"); +#endif + } + scsi_clr_ipend(); + } + run_main(sc); + return; + } + PID("ncr_ctrl_intr1"); +} + +/* + * Initiate a connection path between the host and the target. The function + * first goes into arbitration for the SCSI-bus. When this succeeds, the target + * is selected and an 'IDENTIFY' message is send. + * Returns -1 when the arbitration failed. Otherwise 0 is returned. When + * the target does not respond (to either selection or 'MESSAGE OUT') the + * 'done' function is executed. + * The result code given by the driver can be influenced by setting 'code' + * to a non-zero value. This is the case when 'select' is called by abort. + */ +static int +scsi_select(reqp, code) +SC_REQ *reqp; +{ + u_long timeout; + u_char tmp[1]; + u_char phase; + u_long cnt; + int sps; + u_int8_t atn_flag; + u_int8_t targ_bit; + struct ncr_softc *sc; + + sc = reqp->xs->sc_link->adapter_softc; + DBG_SELPRINT ("Starting arbitration\n", 0); + PID("scsi_select1"); + + sps = splbio(); + + /* + * Prevent a race condition here. If a reslection interrupt occurred + * between the decision to pick a new request and the call to select, + * we abort the selection. + * Interrupts are lowered when the 5380 is setup to arbitrate for the + * bus. + */ + if (connected || (GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY)) { + splx(sps); + PID("scsi_select2"); + return (-1); + } + + /* + * Set phase bits to 0, otherwise the 5380 won't drive the bus during + * selection. + */ + SET_5380_REG(NCR5380_TCOM, 0); + SET_5380_REG(NCR5380_ICOM, 0); + + /* + * Arbitrate for the bus. + */ + SET_5380_REG(NCR5380_DATA, SC_HOST_ID); + SET_5380_REG(NCR5380_MODE, SC_ARBIT); + + splx(sps); + + cnt = 10000; + while (!(GET_5380_REG(NCR5380_ICOM) & SC_AIP) && --cnt) + delay(1); + + if (!(GET_5380_REG(NCR5380_ICOM) & SC_AIP)) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + delay(1); + PID("scsi_select3"); + + if (GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) { + /* + * Damn, we have a connected target that we don't know + * of. Some targets seem to respond to a selection + * AFTER the selection-timeout. Try to get the target + * into the Message-out phase so we can send an ABORT + * message. We try to avoid resetting the SCSI-bus! + */ + if (!reach_msg_out(sc, sizeof(struct scsi_generic))) { + u_long len = 1; + u_char phase = PH_MSGOUT; + u_char msg = MSG_ABORT; + + transfer_pio(&phase, &msg, &len, 0); + } + else if (GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) + scsi_reset(sc); + } + PID("scsi_select4"); + return (-1); + } + + /* The arbitration delay is 2.2 usecs */ + delay(3); + + /* + * Check the result of the arbitration. If we failed, return -1. + */ + if (GET_5380_REG(NCR5380_ICOM) & SC_LA) { + /* + * The spec requires that we should read the data register to + * check for higher id's and check the SC_LA again. + */ + tmp[0] = GET_5380_REG(NCR5380_DATA); + if (GET_5380_REG(NCR5380_ICOM) & SC_LA) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + DBG_SELPRINT ("Arbitration lost,deassert SC_ARBIT\n",0); + PID("scsi_select5"); + return (-1); + } + } + SET_5380_REG(NCR5380_ICOM, SC_A_SEL | SC_A_BSY); + if (GET_5380_REG(NCR5380_ICOM) & SC_LA) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + DBG_SELPRINT ("Arbitration lost, deassert SC_A_SEL\n", 0); + PID("scsi_select6"); + return (-1); + } + /* Bus settle delay + Bus clear delay = 1.2 usecs */ + delay(2); + DBG_SELPRINT ("Arbitration complete\n", 0); + + targ_bit = 1 << reqp->targ_id; + + /* + * Now that we won the arbitration, start the selection. + */ + SET_5380_REG(NCR5380_DATA, SC_HOST_ID | targ_bit); + + if (sc->sc_noselatn & targ_bit) + atn_flag = 0; + else + atn_flag = SC_A_ATN; + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after the selection. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_BSY | SC_A_SEL | atn_flag | SC_ADTB); + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + + /* + * Turn off reselection interrupts + */ + SET_5380_REG(NCR5380_IDSTAT, 0); + + /* + * Reset BSY. The delay following it, surpresses a glitch in the + * 5380 which causes us to see our own BSY signal instead of that of + * the target. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_SEL | atn_flag | SC_ADTB); + delay(1); + + /* + * Wait for the target to react, the specs call for a timeout of + * 250 ms. + */ + cnt = 25000 /* 250 */; + while (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) && --cnt) + delay(10); + + if (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY)) { + /* + * There is no reaction from the target, start the selection + * timeout procedure. We release the databus but keep SEL + * asserted. After that we wait a 'selection abort time' (200 + * usecs) and 2 deskew delays (90 ns) and check BSY again. + * When BSY is asserted, we assume the selection succeeded, + * otherwise we release the bus. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_SEL | SC_A_ATN); + delay(201); + if (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY)) { + SET_5380_REG(NCR5380_ICOM, 0); + reqp->xs->error = code ? code : XS_SELTIMEOUT; + DBG_SELPRINT ("Target %d not responding to sel\n", + reqp->targ_id); + finish_req(reqp); + PID("scsi_select7"); + return (0); + } + } + SET_5380_REG(NCR5380_ICOM, atn_flag); + + DBG_SELPRINT ("Target %d responding to select.\n", reqp->targ_id); + + /* + * The SCSI-interrupts are disabled while a request is being handled. + */ + scsi_idisable(); + + /* + * If we did not request ATN, then don't try to send IDENTIFY. + */ + if (atn_flag == 0) { + reqp->phase = PH_CMD; + goto identify_failed; + } + + /* + * Here we prepare to send an 'IDENTIFY' message. + * Allow disconnect only when interrups are allowed. + */ + tmp[0] = MSG_IDENTIFY(reqp->targ_lun, + (reqp->dr_flag & DRIVER_NOINT) ? 0 : 0); + cnt = 1; + phase = PH_MSGOUT; + + /* + * Since we followed the SCSI-spec and raised ATN while SEL was true + * but before BSY was false during the selection, a 'MESSAGE OUT' + * phase should follow. Unfortunately, this does not happen on + * all targets (Asante ethernet devices, for example), so we must + * check the actual mode if the message transfer fails--if the + * new phase is PH_CMD and has never been successfully selected + * w/ATN in the past, then we assume that it is an old device + * that doesn't support select w/ATN. + */ + if (transfer_pio(&phase, tmp, &cnt, 0) || cnt) { + + if ((phase == PH_CMD) && !(sc->sc_selected & targ_bit)) { + DBG_SELPRINT ("Target %d: not responding to ATN.\n", + reqp->targ_id); + sc->sc_noselatn |= targ_bit; + reqp->phase = PH_CMD; + goto identify_failed; + } + + DBG_SELPRINT ("Target %d: failed to send identify\n", + reqp->targ_id); + /* + * Try to disconnect from the target. We cannot leave + * it just hanging here. + */ + if (!reach_msg_out(sc, sizeof(struct scsi_generic))) { + u_long len = 1; + u_char phase = PH_MSGOUT; + u_char msg = MSG_ABORT; + + transfer_pio(&phase, &msg, &len, 0); + } + else scsi_reset(sc); + + SET_5380_REG(NCR5380_ICOM, 0); + reqp->xs->error = code ? code : XS_DRIVER_STUFFUP; + finish_req(reqp); + PID("scsi_select8"); + return (0); + } + reqp->phase = PH_MSGOUT; + +identify_failed: + sc->sc_selected |= targ_bit; + +#ifdef notyet /* LWP: Do we need timeouts in the driver? */ + /* + * Command is connected, start timer ticking. + */ + ccb_p->xtimeout = ccb_p->timeout + Lbolt; +#endif + + connected = reqp; + busy |= targ_bit; + PID("scsi_select9"); + return (0); +} + +/* + * Return codes: + * -1: quit main, trigger on interrupt + * 0: keep on running main. + */ +static int +information_transfer() +{ + SC_REQ *reqp = connected; + u_char tmp, phase; + u_long len; + + PID("info_transf1"); + /* + * Clear pending interrupts from 5380-chip. + */ + scsi_clr_ipend(); + + /* + * We only have a valid SCSI-phase when REQ is asserted. Something + * is deadly wrong when BSY has dropped. + */ + tmp = GET_5380_REG(NCR5380_IDSTAT); + + if (!(tmp & SC_S_BSY)) { + busy &= ~(1 << reqp->targ_id); + connected = NULL; + reqp->xs->error = XS_BUSY; + finish_req(reqp); + PID("info_transf2"); + return (0); + } + + if (tmp & SC_S_REQ) { + phase = (tmp >> 2) & 7; + if (phase != reqp->phase) { + reqp->phase = phase; + DBG_INFPRINT(show_phase, reqp, phase); + } + } + else return (-1); + + switch (phase) { + case PH_DATAOUT: + +#ifdef DBG_NOWRITE + ncr_tprint(reqp, "NOWRITE set -- write attempt aborted."); + reqp->msgout = MSG_ABORT; + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + return (-1); +#endif /* DBG_NOWRITE */ + /* + * If this is the first write using DMA, fill + * the bounce buffer. + */ + if (reqp->xdata_ptr == reqp->xs->data) { /* XXX */ + if (reqp->dr_flag & DRIVER_BOUNCING) + bcopy(reqp->xdata_ptr, reqp->bounceb, reqp->xdata_len); + } + + case PH_DATAIN: +#ifdef REAL_DMA + if (reqp->dr_flag & DRIVER_DMAOK) { + int poll = REAL_DMA_POLL|(reqp->dr_flag & DRIVER_NOINT); + transfer_dma(reqp, phase, poll); + if (!poll) + return (0); + } + else +#endif + { + PID("info_transf3"); + len = reqp->xdata_len; +#ifdef USE_PDMA + if (transfer_pdma(&phase, reqp->xdata_ptr, &len) == 0) + return (0); +#else + transfer_pio(&phase, reqp->xdata_ptr, &len, 0); +#endif + reqp->xdata_ptr += reqp->xdata_len - len; + reqp->xdata_len = len; + } + return (-1); + case PH_MSGIN: + /* + * We only expect single byte messages here. + */ + len = 1; + transfer_pio(&phase, &tmp, &len, 1); + reqp->message = tmp; + return (handle_message(reqp, tmp)); + case PH_MSGOUT: + len = 1; + transfer_pio(&phase, &reqp->msgout, &len, 0); + if (reqp->msgout == MSG_ABORT) { + busy &= ~(1 << reqp->targ_id); + connected = NULL; + reqp->xs->error = XS_DRIVER_STUFFUP; + finish_req(reqp); + PID("info_transf4"); + return (0); + } + reqp->msgout = MSG_NOOP; + return (-1); + case PH_CMD : + len = command_size(reqp->xcmd.opcode); + transfer_pio(&phase, (u_char *)&reqp->xcmd, &len, 0); + PID("info_transf5"); + return (-1); + case PH_STATUS: + len = 1; + transfer_pio(&phase, &tmp, &len, 0); + reqp->status = tmp; + PID("info_transf6"); + return (-1); + default : + ncr_tprint(reqp, "Unknown phase\n"); + } + PID("info_transf7"); + return (-1); +} + +/* + * Handle the message 'msg' send to us by the target. + * Return values: + * 0 : The current command has completed. + * -1 : Get on to the next phase. + */ +static int +handle_message(reqp, msg) +SC_REQ *reqp; +u_int msg; +{ + int sps; + + PID("hmessage1"); + switch (msg) { + /* + * Linking lets us reduce the time required to get + * the next command to the device, skipping the arbitration + * and selection time. In the current implementation, + * we merely have to start the next command pointed + * to by 'next_link'. + */ + case MSG_LINK_CMD_COMPLETE: + case MSG_LINK_CMD_COMPLETEF: + if (reqp->link == NULL) { + ncr_tprint(reqp, "No link for linked command"); + nack_message(reqp); + PID("hmessage2"); + return (-1); + } + ack_message(); + reqp->xs->error = 0; + +#ifdef AUTO_SENSE + if (check_autosense(reqp, 0) == -1) + return (-1); +#endif /* AUTO_SENSE */ + +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp->link, "LINK"); +#endif + connected = reqp->link; + finish_req(reqp); + PID("hmessage3"); + return (-1); + case MSG_ABORT: + case MSG_CMDCOMPLETE: + ack_message(); + connected = NULL; + busy &= ~(1 << reqp->targ_id); + if (!(reqp->dr_flag & DRIVER_AUTOSEN)) { + reqp->xs->resid = reqp->xdata_len; + reqp->xs->error = 0; + } + +#ifdef AUTO_SENSE + if (check_autosense(reqp, 0) == -1) { + PID("hmessage4"); + return (0); + } +#endif /* AUTO_SENSE */ + + finish_req(reqp); + PID("hmessage5"); + return (0); + case MSG_MESSAGE_REJECT: + ack_message(); + PID("hmessage6"); + return (-1); + case MSG_DISCONNECT: + ack_message(); +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, "DISCON"); +#endif + sps = splbio(); + connected = NULL; + reqp->next = discon_q; + discon_q = reqp; + splx(sps); + PID("hmessage7"); + return (0); + case MSG_SAVEDATAPOINTER: + case MSG_RESTOREPOINTERS: + /* + * We save pointers implicitely at disconnect. + * So we can ignore these messages. + */ + ack_message(); + PID("hmessage8"); + return (-1); + case MSG_EXTENDED: + nack_message(reqp); + PID("hmessage9"); + return (-1); + default: + ncr_tprint(reqp, "Unkown message %x\n", msg); + return (-1); + } + PID("hmessage10"); + return (-1); +} + +/* + * Handle reselection. If a valid reconnection occurs, connected + * points at the reconnected command. The command is removed from the + * disconnected queue. + */ +static void +reselect(sc) +struct ncr_softc *sc; +{ + u_char phase; + u_long len; + u_char msg; + u_char target_mask; + int abort = 0; + SC_REQ *tmp, *prev; + + PID("reselect1"); + target_mask = GET_5380_REG(NCR5380_DATA) & ~SC_HOST_ID; + + /* + * At this point, we have detected that our SCSI-id is on the bus, + * SEL is true and BSY was false for at least one bus settle + * delay (400 ns.). + * We must assert BSY ourselves, until the target drops the SEL signal. + * The SCSI-spec specifies no maximum time for this, so we have to + * choose something long enough to suit all targets. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_BSY); + len = 1000; + while ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_SEL) && (len > 0)) { + delay(1); + len--; + } + if (GET_5380_REG(NCR5380_IDSTAT) & SC_S_SEL) { + /* Damn SEL isn't dropping */ + scsi_reset(sc); + return; + } + + SET_5380_REG(NCR5380_ICOM, 0); + + /* + * Get the expected identify message. + */ + phase = PH_MSGIN; + len = 1; + transfer_pio(&phase, &msg, &len, 0); + if (len || !MSG_ISIDENTIFY(msg)) { + ncr_aprint(sc, "Expecting IDENTIFY, got 0x%x\n", msg); + abort = 1; + } + else { + /* + * Find the command reconnecting + */ + for (tmp = discon_q, prev = NULL; tmp; prev = tmp, tmp = tmp->next){ + if (target_mask == (1 << tmp->targ_id)) { + if (prev) + prev->next = tmp->next; + else discon_q = tmp->next; + tmp->next = NULL; + break; + } + } + if (tmp == NULL) { + ncr_aprint(sc, "No disconnected job for targetmask %x\n", + target_mask); + abort = 1; + } + } + if (abort) { + msg = MSG_ABORT; + len = 1; + phase = PH_MSGOUT; + + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + transfer_pio(&phase, &msg, &len, 0); + } + else { + connected = tmp; +#ifdef DBG_REQ + if (dbg_target_mask & (1 << tmp->targ_id)) + show_request(tmp, "RECON"); +#endif + } + PID("reselect2"); +} + +/* + * Transfer data in a given phase using programmed I/O. + * Returns -1 when a different phase is entered without transferring the + * maximum number of bytes, 0 if all bytes transferred or exit is in the same + * phase. + */ +static int +transfer_pio(phase, data, len, dont_drop_ack) +u_char *phase; +u_char *data; +u_long *len; +int dont_drop_ack; +{ + u_int cnt = *len; + u_char ph = *phase; + u_char tmp, new_icom; + + DBG_PIOPRINT ("SCSI: transfer_pio start: phase: %d, len: %d\n", ph,cnt); + PID("tpio1"); + SET_5380_REG(NCR5380_TCOM, ph); + do { + if (!wait_req_true()) { + DBG_PIOPRINT ("SCSI: transfer_pio: missing REQ\n", 0, 0); + break; + } + if (((GET_5380_REG(NCR5380_IDSTAT) >> 2) & 7) != ph) { + DBG_PIOPRINT ("SCSI: transfer_pio: phase mismatch\n", 0, 0); + break; + } + if (PH_IN(ph)) { + *data++ = GET_5380_REG(NCR5380_DATA); + SET_5380_REG(NCR5380_ICOM, SC_A_ACK); + if ((cnt == 1) && dont_drop_ack) + new_icom = SC_A_ACK; + else new_icom = 0; + } + else { + SET_5380_REG(NCR5380_DATA, *data++); + + /* + * The SCSI-standard suggests that in the 'MESSAGE OUT' phase, + * the initiator should drop ATN on the last byte of the + * message phase after REQ has been asserted for the handshake + * but before the initiator raises ACK. + */ + if (!( (ph == PH_MSGOUT) && (cnt > 1) )) { + SET_5380_REG(NCR5380_ICOM, SC_ADTB); + SET_5380_REG(NCR5380_ICOM, SC_ADTB | SC_A_ACK); + new_icom = 0; + } + else { + SET_5380_REG(NCR5380_ICOM, SC_ADTB | SC_A_ATN); + SET_5380_REG(NCR5380_ICOM, SC_ADTB|SC_A_ATN|SC_A_ACK); + new_icom = SC_A_ATN; + } + } + if (!wait_req_false()) { + DBG_PIOPRINT ("SCSI: transfer_pio - REQ not dropping\n", 0, 0); + break; + } + SET_5380_REG(NCR5380_ICOM, new_icom); + + } while (--cnt); + + if ((tmp = GET_5380_REG(NCR5380_IDSTAT)) & SC_S_REQ) + *phase = (tmp >> 2) & 7; + else *phase = NR_PHASE; + *len = cnt; + DBG_PIOPRINT ("SCSI: transfer_pio done: phase: %d, len: %d\n", + *phase, cnt); + PID("tpio2"); + if (!cnt || (*phase == ph)) + return (0); + return (-1); +} + +#ifdef REAL_DMA +/* + * Start a DMA-transfer on the device using the current pointers. + * If 'poll' is true, the function busy-waits until DMA has completed. + */ +static void +transfer_dma(reqp, phase, poll) +SC_REQ *reqp; +u_int phase; +int poll; +{ + int dma_done; + u_char mbase = 0; + int sps; + +again: + PID("tdma1"); + + /* + * We should be in phase, otherwise we are not allowed to + * drive the bus. + */ + SET_5380_REG(NCR5380_TCOM, phase); + + /* + * Defer interrupts until DMA is fully running. + */ + sps = splbio(); + + /* + * Clear pending interrupts and parity errors. + */ + scsi_clr_ipend(); + + if (!poll) { + /* + * Enable SCSI interrupts and set IN_DMA flag, set 'mbase' + * to the interrupts we want enabled. + */ + scsi_ienable(); + reqp->dr_flag |= DRIVER_IN_DMA; + mbase = SC_E_EOPI | SC_MON_BSY; + } + else scsi_idisable(); + mbase |= IMODE_BASE | SC_M_DMA; + scsi_dma_setup(reqp, phase, mbase); + + splx(sps); + + if (poll) { + /* + * On polled-dma transfers, we wait here until the + * 'end-of-dma' condition occurs. + */ + poll_edma(reqp); + if (!(dma_done = dma_ready())) + goto again; + } + PID("tdma2"); +} + +/* + * Check results of a DMA data-transfer. + */ +static int +dma_ready() +{ + SC_REQ *reqp = connected; + int dmstat, is_edma; + long bytes_left, bytes_done; + + is_edma = get_dma_result(reqp, &bytes_left); + dmstat = GET_5380_REG(NCR5380_DMSTAT); + + /* + * Check if the call is sensible and not caused by any spurious + * interrupt. + */ + if (!is_edma && !(dmstat & (SC_END_DMA|SC_BSY_ERR)) + && (dmstat & SC_PHS_MTCH) ) { + ncr_tprint(reqp, "dma_ready: spurious call" + "(dm:%x,last_hit: %s)\n", +#ifdef DBG_PID + dmstat, last_hit); +#else + dmstat, "unknown"); +#endif + return (0); + } + + /* + * Clear all (pending) interrupts. + */ + scsi_clr_ipend(); + + /* + * Update various transfer-pointers/lengths + */ + bytes_done = reqp->dm_cur->dm_count - bytes_left; + + if ((reqp->dr_flag & DRIVER_BOUNCING) && (PH_IN(reqp->phase))) { + /* + * Copy the bytes read until now from the bounce buffer + * to the 'real' destination. Flush the data-cache + * before copying. + */ + PCIA(); + bcopy(reqp->bouncerp, reqp->xdata_ptr, bytes_done); + reqp->bouncerp += bytes_done; + } + + reqp->xdata_ptr = &reqp->xdata_ptr[bytes_done]; /* XXX */ + reqp->xdata_len -= bytes_done; /* XXX */ + if ((reqp->dm_cur->dm_count -= bytes_done) == 0) + reqp->dm_cur++; + else reqp->dm_cur->dm_addr += bytes_done; + + if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) { + if (!(ncr5380_no_parchk & (1 << reqp->targ_id))) + /* XXX: Should be parity error ???? */ + reqp->xs->error = XS_DRIVER_STUFFUP; + } + + /* + * DMA mode should always be reset even when we will continue with the + * next chain. + */ + SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA); + + + if ((dmstat & SC_BSY_ERR) || !(dmstat & SC_PHS_MTCH) + || (reqp->dm_cur > reqp->dm_last) || (reqp->xs->error)) { + + /* + * Tell interrupt functions DMA mode has ended. + */ + reqp->dr_flag &= ~DRIVER_IN_DMA; + + /* + * Clear mode and icom + */ + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + + if (dmstat & SC_BSY_ERR) { + if (!reqp->xs->error) + reqp->xs->error = XS_BUSY; + finish_req(reqp); + PID("dma_ready1"); + return (1); + } + + if (reqp->xs->error != 0) { +ncr_tprint(reqp, "dma-ready: code = %d\n", reqp->xs->error); /* LWP */ + reqp->msgout = MSG_ABORT; + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + } + PID("dma_ready2"); + return (1); + } + return (0); +} +#endif /* REAL_DMA */ + +static int +check_autosense(reqp, linked) +SC_REQ *reqp; +int linked; +{ + int sps; + + /* + * If we not executing an auto-sense and the status code + * is request-sense, we automatically issue a request + * sense command. + */ + PID("cautos1"); + if (!(reqp->dr_flag & DRIVER_AUTOSEN)) { + if (reqp->status == SCSCHKC) { + bcopy(sense_cmd, &reqp->xcmd, sizeof(sense_cmd)); + reqp->xdata_ptr = (u_char *)&reqp->xs->sense; + reqp->xdata_len = sizeof(reqp->xs->sense); + reqp->dr_flag |= DRIVER_AUTOSEN; + reqp->dr_flag &= ~DRIVER_DMAOK; + if (!linked) { + sps = splbio(); + reqp->next = issue_q; + issue_q = reqp; + splx(sps); + } + else reqp->xcmd.bytes[4] |= 1; + +#ifdef DBG_REQ + bzero(reqp->xdata_ptr, reqp->xdata_len); + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, "AUTO-SENSE"); +#endif + PID("cautos2"); + return (-1); + } + } + else { + /* + * An auto-sense has finished + */ + if ((reqp->status & SCSMASK) != SCSGOOD) + reqp->xs->error = XS_DRIVER_STUFFUP; /* SC_E_AUTOSEN; */ + else reqp->xs->error = XS_SENSE; + reqp->status = SCSCHKC; + } + PID("cautos3"); + return (0); +} + +static int +reach_msg_out(sc, len) +struct ncr_softc *sc; +u_long len; +{ + u_char phase; + u_char data; + + ncr_aprint(sc, "Trying to reach Message-out phase\n"); + if ((phase = GET_5380_REG(NCR5380_IDSTAT)) & SC_S_REQ) + phase = (phase >> 2) & 7; + else return (-1); + ncr_aprint(sc, "Trying to reach Message-out phase, now: %d\n", phase); + if (phase == PH_MSGOUT) + return (0); + + SET_5380_REG(NCR5380_TCOM, phase); + + do { + if (!wait_req_true()) + break; + if (((GET_5380_REG(NCR5380_IDSTAT) >> 2) & 7) != phase) + break; + if (PH_IN(phase)) { + data = GET_5380_REG(NCR5380_DATA); + SET_5380_REG(NCR5380_ICOM, SC_A_ACK | SC_A_ATN); + } + else { + SET_5380_REG(NCR5380_DATA, 0); + SET_5380_REG(NCR5380_ICOM, SC_ADTB|SC_A_ACK|SC_A_ATN); + } + if (!wait_req_false()) + break; + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + } while (--len); + + if ((phase = GET_5380_REG(NCR5380_IDSTAT)) & SC_S_REQ) { + phase = (phase >> 2) & 7; + if (phase == PH_MSGOUT) { + ncr_aprint(sc, "Message-out phase reached.\n"); + return (0); + } + } + return (-1); +} + +static void +scsi_reset(sc) +struct ncr_softc *sc; +{ + SC_REQ *tmp, *next; + int sps; + + ncr_aprint(sc, "Resetting SCSI-bus\n"); + + PID("scsi_reset1"); + sps = splbio(); + SET_5380_REG(NCR5380_ICOM, SC_A_RST); + delay(1); + SET_5380_REG(NCR5380_ICOM, 0); + + /* + * None of the jobs in the discon_q will ever be reconnected, + * notify this to the higher level code. + */ + for (tmp = discon_q; tmp ;) { + next = tmp->next; + tmp->next = NULL; + tmp->xs->error = XS_TIMEOUT; + busy &= ~(1 << tmp->targ_id); + finish_req(tmp); + tmp = next; + } + discon_q = NULL; + + /* + * The current job will never finish either. + * The problem is that we can't finish the job because an instance + * of main is running on it. Our best guess is that the job is currently + * doing REAL-DMA. In that case 'dma_ready()' should correctly finish + * the job because it detects BSY-loss. + */ + if (tmp = connected) { + if (tmp->dr_flag & DRIVER_IN_DMA) { + tmp->xs->error = XS_DRIVER_STUFFUP; +#ifdef REAL_DMA + dma_ready(); +#endif + } + } + splx(sps); + PID("scsi_reset2"); +} + +/* + * Check validity of the IRQ set by the 5380. If the interrupt is valid, + * the appropriate action is carried out (reselection or DMA ready) and + * INTR_RESEL or INTR_DMA is returned. Otherwise a console notice is written + * and INTR_SPURIOUS is returned. + */ +static int +check_intr(sc) +struct ncr_softc *sc; +{ + SC_REQ *reqp; + + if ((GET_5380_REG(NCR5380_IDSTAT) & (SC_S_SEL|SC_S_IO)) + ==(SC_S_SEL|SC_S_IO)) + return (INTR_RESEL); + else { + if ((reqp = connected) && (reqp->dr_flag & DRIVER_IN_DMA)){ + reqp->dr_flag &= ~DRIVER_IN_DMA; + return (INTR_DMA); + } + } + scsi_clr_ipend(); + printf("-->"); + scsi_show(); + ncr_aprint(sc, "Spurious interrupt.\n"); + return (INTR_SPURIOUS); +} + +#ifdef REAL_DMA +/* + * Check if DMA can be used for this request. This function also builds + * the dma-chain. + */ +static int +scsi_dmaok(reqp) +SC_REQ *reqp; +{ + u_long phy_buf; + u_long phy_len; + void *req_addr; + u_long req_len; + struct dma_chain *dm; + + /* + * Initialize locals and requests' DMA-chain. + */ + req_len = reqp->xdata_len; + req_addr = (void*)reqp->xdata_ptr; + dm = reqp->dm_cur = reqp->dm_last = reqp->dm_chain; + dm->dm_count = dm->dm_addr = 0; + reqp->dr_flag &= ~DRIVER_BOUNCING; + + /* + * Do not accept zero length DMA. + */ + if (req_len == 0) + return (0); + + /* + * LWP: I think that this restriction is not strictly nessecary. + */ + if ((req_len & 0x1) || ((u_int)req_addr & 0x3)) + return (0); + + /* + * Build the DMA-chain. + */ + dm->dm_addr = phy_buf = kvtop(req_addr); + while (req_len) { + if (req_len < (phy_len = NBPG - ((u_long)req_addr & PGOFSET))) + phy_len = req_len; + + req_addr += phy_len; + req_len -= phy_len; + dm->dm_count += phy_len; + + if (req_len) { + u_long tmp = kvtop(req_addr); + + if ((phy_buf + phy_len) != tmp) { + if (wrong_dma_range(reqp, dm)) { + if (reqp->dr_flag & DRIVER_BOUNCING) + goto bounceit; + return (0); + } + + if (++dm >= &reqp->dm_chain[MAXDMAIO]) { + ncr_tprint(reqp,"dmaok: DMA chain too long!\n"); + return (0); + } + dm->dm_count = 0; + dm->dm_addr = tmp; + } + phy_buf = tmp; + } + } + if (wrong_dma_range(reqp, dm)) { + if (reqp->dr_flag & DRIVER_BOUNCING) + goto bounceit; + return (0); + } + reqp->dm_last = dm; + return (1); + +bounceit: + if ((reqp->bounceb = alloc_bounceb(reqp->xdata_len)) == NULL) { + /* + * If we can't get a bounce buffer, forget DMA + */ + reqp->dr_flag &= ~DRIVER_BOUNCING; + return(0); + } + /* + * Initialize a single DMA-range containing the bounced request + */ + dm = reqp->dm_cur = reqp->dm_last = reqp->dm_chain; + dm->dm_addr = kvtop(reqp->bounceb); + dm->dm_count = reqp->xdata_len; + reqp->bouncerp = reqp->bounceb; + + return (1); +} +#endif /* REAL_DMA */ + +static void +run_main(sc) +struct ncr_softc *sc; +{ + int sps = splbio(); + + if (!main_running) { + /* + * If shared resources are required, claim them + * before entering 'scsi_main'. If we can't get them + * now, assume 'run_main' will be called when the resource + * becomes available. + */ + if (!claimed_dma()) { + splx(sps); + return; + } + main_running = 1; + splx(sps); + scsi_main(sc); + } + else splx(sps); +} + +/* + * Prefix message with full target info. + */ +static void +ncr_tprint(SC_REQ *reqp, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sc_print_addr(reqp->xs->sc_link); + printf("%r", fmt, ap); + va_end(ap); +} + +/* + * Prefix message with adapter info. + */ +static void +ncr_aprint(struct ncr_softc *sc, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + printf("%s : %r", sc->sc_dev.dv_xname, fmt, ap); + va_end(ap); +} +/**************************************************************************** + * Start Debugging Functions * + ****************************************************************************/ +static void +show_data_sense(xs) +struct scsi_xfer *xs; +{ + u_char *p1, *p2; + int i; + int sz; + + p1 = (u_char *) xs->cmd; + p2 = (u_char *)&xs->sense; + if(*p2 == 0) + return; /* No(n)sense */ + printf("cmd[%d,%d]: ", xs->cmdlen, sz = command_size(*p1)); + for (i = 0; i < sz; i++) + printf("%x ", p1[i]); + printf("\nsense: "); + for (i = 0; i < sizeof(xs->sense); i++) + printf("%x ", p2[i]); + printf("\n"); +} + +static void +show_request(reqp, qtxt) +SC_REQ *reqp; +char *qtxt; +{ + printf("REQ-%s: %d %x[%d] cmd[0]=%x S=%x M=%x R=%x resid=%d %s\n", + qtxt, reqp->targ_id, reqp->xdata_ptr, reqp->xdata_len, + reqp->xcmd.opcode, reqp->status, reqp->message, + reqp->xs->error, reqp->xs->resid, reqp->link ? "L":""); + if (reqp->status == SCSCHKC) + show_data_sense(reqp->xs); +} + +static char *sig_names[] = { + "PAR", "SEL", "I/O", "C/D", "MSG", "REQ", "BSY", "RST", + "ACK", "ATN", "LBSY", "PMATCH", "IRQ", "EPAR", "DREQ", "EDMA" +}; + +static void +show_signals(dmstat, idstat) +u_char dmstat, idstat; +{ + u_short tmp, mask; + int i, j, need_pipe; + + tmp = idstat | ((dmstat & 3) << 8); + printf("Bus signals (%02x/%02x): ", idstat, dmstat & 3); + for (mask = 1, j = need_pipe = 0; mask <= tmp; mask <<= 1, j++) { + if (tmp & mask) + printf("%s%s", need_pipe++ ? "|" : "", sig_names[j]); + } + printf("\nDma status (%02x): ", dmstat); + for (mask = 4, j = 10, need_pipe = 0; mask <= dmstat; mask <<= 1, j++) { + if (dmstat & mask) + printf("%s%s", need_pipe++ ? "|" : "", sig_names[j]); + } + printf("\n"); +} + +scsi_show() +{ + SC_REQ *tmp; + int sps = splhigh(); + u_char idstat, dmstat; + +#ifndef DBG_PID + #define last_hit "" + #define olast_hit "" +#endif + + for (tmp = issue_q; tmp; tmp = tmp->next) + show_request(tmp, "ISSUED"); + for (tmp = discon_q; tmp; tmp = tmp->next) + show_request(tmp, "DISCONNECTED"); + if (connected) + show_request(connected, "CONNECTED"); + idstat = GET_5380_REG(NCR5380_IDSTAT); + dmstat = GET_5380_REG(NCR5380_DMSTAT); + show_signals(dmstat, idstat); + if (connected) + printf("phase = %d, ", connected->phase); + printf("busy:%x, last_hit:%s, olast_hit:%s spl:%04x\n", busy, + last_hit, olast_hit, sps); + + splx(sps); +} diff --git a/sys/arch/pc532/dev/ncr5380reg.h b/sys/arch/pc532/dev/ncr5380reg.h new file mode 100644 index 00000000000..783013af418 --- /dev/null +++ b/sys/arch/pc532/dev/ncr5380reg.h @@ -0,0 +1,258 @@ +/* $NetBSD: ncr5380reg.h,v 1.3 1995/09/26 20:16:13 phil Exp $ */ + +/* + * Copyright (c) 1995 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 _NCR5380REG_H +#define _NCR5380REG_H +/* + * NCR5380 common interface definitions. + */ + +/* + * Register numbers: (first argument to GET/SET_5380_REG ) + */ +#define NCR5380_DATA 0 /* Data register */ +#define NCR5380_ICOM 1 /* Initiator command register */ +#define NCR5380_MODE 2 /* Mode register */ +#define NCR5380_TCOM 3 /* Target command register */ +#define NCR5380_IDSTAT 4 /* Bus status register */ +#define NCR5380_DMSTAT 5 /* DMA status register */ +#define NCR5380_TRCV 6 /* Target receive register */ +#define NCR5380_IRCV 7 /* Initiator receive register */ + +/* + * Definitions for Initiator command register. + */ +#define SC_A_RST 0x80 /* RW - Assert RST */ +#define SC_TEST 0x40 /* W - Test mode */ +#define SC_AIP 0x40 /* R - Arbitration in progress */ +#define SC_LA 0x20 /* R - Lost arbitration */ +#define SC_A_ACK 0x10 /* RW - Assert ACK */ +#define SC_A_BSY 0x08 /* RW - Assert BSY */ +#define SC_A_SEL 0x04 /* RW - Assert SEL */ +#define SC_A_ATN 0x02 /* RW - Assert ATN */ +#define SC_ADTB 0x01 /* RW - Assert Data To Bus */ + +/* + * Definitions for mode register + */ +#define SC_B_DMA 0x80 /* RW - Block mode DMA (not on TT!) */ +#define SC_T_MODE 0x40 /* RW - Target mode */ +#define SC_E_PAR 0x20 /* RW - Enable parity check */ +#define SC_E_PARI 0x10 /* RW - Enable parity interrupt */ +#define SC_E_EOPI 0x08 /* RW - Enable End Of Process Interrupt */ +#define SC_MON_BSY 0x04 /* RW - Monitor BSY */ +#define SC_M_DMA 0x02 /* RW - Set DMA mode */ +#define SC_ARBIT 0x01 /* RW - Arbitrate */ + +/* + * Definitions for tcom register + */ +#define SC_LBS 0x80 /* RW - Last Byte Send (not on TT!) */ +#define SC_A_REQ 0x08 /* RW - Assert REQ */ +#define SC_A_MSG 0x04 /* RW - Assert MSG */ +#define SC_A_CD 0x02 /* RW - Assert C/D */ +#define SC_A_IO 0x01 /* RW - Assert I/O */ + +/* + * Definitions for idstat register + */ +#define SC_S_RST 0x80 /* R - RST is set */ +#define SC_S_BSY 0x40 /* R - BSY is set */ +#define SC_S_REQ 0x20 /* R - REQ is set */ +#define SC_S_MSG 0x10 /* R - MSG is set */ +#define SC_S_CD 0x08 /* R - C/D is set */ +#define SC_S_IO 0x04 /* R - I/O is set */ +#define SC_S_SEL 0x02 /* R - SEL is set */ +#define SC_S_PAR 0x01 /* R - Parity bit */ + +/* + * Definitions for dmastat register + */ +#define SC_END_DMA 0x80 /* R - End of DMA */ +#define SC_DMA_REQ 0x40 /* R - DMA request */ +#define SC_PAR_ERR 0x20 /* R - Parity error */ +#define SC_IRQ_SET 0x10 /* R - IRQ is active */ +#define SC_PHS_MTCH 0x08 /* R - Phase Match */ +#define SC_BSY_ERR 0x04 /* R - Busy error */ +#define SC_ATN_STAT 0x02 /* R - State of ATN line */ +#define SC_ACK_STAT 0x01 /* R - State of ACK line */ +#define SC_S_SEND 0x00 /* W - Start DMA output */ + +#define SC_CLINT { /* Clear interrupts */ \ + int i = GET_5380_REG(NCR5380_IRCV); \ + } + + +/* + * Definition of SCSI-bus phases. The values are determined by signals + * on the SCSI-bus. DO NOT CHANGE! + * The values must be used to index the pointers in SCSI-PARMS. + */ +#define NR_PHASE 8 +#define PH_DATAOUT 0 +#define PH_DATAIN 1 +#define PH_CMD 2 +#define PH_STATUS 3 +#define PH_RES1 4 +#define PH_RES2 5 +#define PH_MSGOUT 6 +#define PH_MSGIN 7 + +#define PH_OUT(phase) (!(phase & 1)) /* TRUE if output phase */ +#define PH_IN(phase) (phase & 1) /* TRUE if input phase */ + +/* + * Id of Host-adapter + */ +#define SC_HOST_ID 0x80 + +/* + * Base setting for 5380 mode register + */ +#define IMODE_BASE SC_E_PAR + +/* + * SCSI completion status codes, should move to sys/scsi/???? + */ +#define SCSMASK 0x1e /* status code mask */ +#define SCSGOOD 0x00 /* good status */ +#define SCSCHKC 0x02 /* check condition */ +#define SCSBUSY 0x08 /* busy status */ +#define SCSCMET 0x04 /* condition met / good */ + +/* + * Return values of check_intr() + */ +#define INTR_SPURIOUS 0 +#define INTR_RESEL 2 +#define INTR_DMA 3 + +struct ncr_softc { + struct device sc_dev; + struct scsi_link sc_link; + + /* + * Some (pre-SCSI2) devices don't support select with ATN. + * If the device responds to select with ATN by going into + * command phase (ignoring ATN), then we flag it in the + * following bitmask. + * We also keep track of which devices have been selected + * before. This allows us to not even try raising ATN if + * the target doesn't respond to it the first time. + */ + u_int8_t sc_noselatn; + u_int8_t sc_selected; +}; + +/* + * Max. number of dma-chains per request + */ +#define MAXDMAIO (MAXPHYS/NBPG + 1) + +/* + * Some requests are not contiguous in physical memory. We need to break them + * up into contiguous parts for DMA. + */ +struct dma_chain { + u_int dm_count; + u_long dm_addr; +}; + +/* + * Define our issue, free and disconnect queue's. + */ +typedef struct req_q { + struct req_q *next; /* next in free, issue or discon queue */ + struct req_q *link; /* next linked command to execute */ + struct scsi_xfer *xs; /* request from high-level driver */ + u_short dr_flag; /* driver state */ + u_char phase; /* current SCSI phase */ + u_char msgout; /* message to send when requested */ + u_char targ_id; /* target for command */ + u_char targ_lun; /* lun for command */ + u_char status; /* returned status byte */ + u_char message; /* returned message byte */ + u_char *bounceb; /* allocated bounce buffer */ + u_char *bouncerp; /* bounce read-pointer */ + struct dma_chain dm_chain[MAXDMAIO]; + struct dma_chain *dm_cur; /* current dma-request */ + struct dma_chain *dm_last; /* last dma-request */ + long xdata_len; /* length of transfer */ + u_char *xdata_ptr; /* virtual address of transfer */ + struct scsi_generic xcmd; /* command to execute */ +} SC_REQ; + +/* + * Values for dr_flag: + */ +#define DRIVER_IN_DMA 0x01 /* Non-polled DMA activated */ +#define DRIVER_AUTOSEN 0x02 /* Doing automatic sense */ +#define DRIVER_NOINT 0x04 /* We are booting: no interrupts */ +#define DRIVER_DMAOK 0x08 /* DMA can be used on this request */ +#define DRIVER_BOUNCING 0x10 /* Using the bounce buffer */ + +/* XXX: Should go to ncr5380var.h */ +static SC_REQ *issue_q = NULL; /* Commands waiting to be issued*/ +static SC_REQ *discon_q = NULL; /* Commands disconnected */ +static SC_REQ *connected = NULL; /* Command currently connected */ + +/* + * Function decls: + */ +static int transfer_pio __P((u_char *, u_char *, u_long *, int)); +static int wait_req_true __P((void)); +static int wait_req_false __P((void)); +static int scsi_select __P((SC_REQ *, int)); +static int handle_message __P((SC_REQ *, u_int)); +static void ack_message __P((void)); +static void nack_message __P((SC_REQ *)); +static int information_transfer __P((void)); +static void reselect __P((struct ncr_softc *)); +static int dma_ready __P((void)); +static void transfer_dma __P((SC_REQ *, u_int, int)); +static int check_autosense __P((SC_REQ *, int)); +static int reach_msg_out __P((struct ncr_softc *, u_long)); +static int check_intr __P((struct ncr_softc *)); +static void scsi_reset __P((struct ncr_softc *)); +static int scsi_dmaok __P((SC_REQ *)); +static void run_main __P((struct ncr_softc *)); +static void scsi_main __P((struct ncr_softc *)); +static void ncr_ctrl_intr __P((struct ncr_softc *)); +static void ncr_dma_intr __P((struct ncr_softc *)); +static void ncr_tprint __P((SC_REQ *, char *, ...)); +static void ncr_aprint __P((struct ncr_softc *, char *, ...)); + +static void show_request __P((SC_REQ *, char *)); +static void show_phase __P((SC_REQ *, int)); +static void show_signals __P((u_char, u_char)); + +#endif /* _NCR5380REG_H */ diff --git a/sys/arch/pc532/dev/ncr_5380.h b/sys/arch/pc532/dev/ncr_5380.h new file mode 100644 index 00000000000..4d209f5671f --- /dev/null +++ b/sys/arch/pc532/dev/ncr_5380.h @@ -0,0 +1,145 @@ +/* $NetBSD: ncr_5380.h,v 1.4 1995/08/25 07:30:37 phil 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. + */ +/* + * File: scsi_5380.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 5/91 + * + * Defines for the NCR 5380 (SCSI chip), aka Am5380 + * + * Modified for the pc532 by Phil Nelson. 1/94 + */ + +/* + * Register map + */ + +typedef struct { + volatile unsigned char sci_data; /* r: Current data */ +#define sci_odata sci_data /* w: Out data */ + + volatile unsigned char sci_icmd; /* rw: Initiator command */ + + volatile unsigned char sci_mode; /* rw: Mode */ + + volatile unsigned char sci_tcmd; /* rw: Target command */ + + volatile unsigned char sci_bus_csr; /* r: Bus Status */ +#define sci_sel_enb sci_bus_csr /* w: Select enable */ + + volatile unsigned char sci_csr; /* r: Status */ +#define sci_dma_send sci_csr /* w: Start dma send data */ + + volatile unsigned char sci_idata; /* r: Input data */ +#define sci_trecv sci_idata /* w: Start dma receive, target */ + + volatile unsigned char sci_iack; /* r: Interrupt Acknowledge */ +#define sci_irecv sci_iack /* w: Start dma receive, initiator */ +} sci_regmap_t; + + +/* + * Initiator command register + */ + +#define SCI_ICMD_DATA 0x01 /* rw: Assert data bus */ +#define SCI_ICMD_ATN 0x02 /* rw: Assert ATN signal */ +#define SCI_ICMD_SEL 0x04 /* rw: Assert SEL signal */ +#define SCI_ICMD_BSY 0x08 /* rw: Assert BSY signal */ +#define SCI_ICMD_ACK 0x10 /* rw: Assert ACK signal */ +#define SCI_ICMD_LST 0x20 /* r: Lost arbitration */ +#define SCI_ICMD_DIFF SCI_ICMD_LST /* w: Differential cable */ +#define SCI_ICMD_AIP 0x40 /* r: Arbitration in progress */ +#define SCI_ICMD_TEST SCI_ICMD_AIP /* w: Test mode */ +#define SCI_ICMD_RST 0x80 /* rw: Assert RST signal */ + + +/* + * Mode register + */ + +#define SCI_MODE_ARB 0x01 /* rw: Start arbitration */ +#define SCI_MODE_DMA 0x02 /* rw: Enable DMA xfers */ +#define SCI_MODE_MONBSY 0x04 /* rw: Monitor BSY signal */ +#define SCI_MODE_DMA_IE 0x08 /* rw: Enable DMA complete interrupt */ +#define SCI_MODE_PERR_IE 0x10 /* rw: Interrupt on parity errors */ +#define SCI_MODE_PAR_CHK 0x20 /* rw: Check parity */ +#define SCI_MODE_TARGET 0x40 /* rw: Target mode (Initiator if 0) */ +#define SCI_MODE_BLOCKDMA 0x80 /* rw: Block-mode DMA handshake (MBZ) */ + + +/* + * Target command register + */ + +#define SCI_TCMD_IO 0x01 /* rw: Assert I/O signal */ +#define SCI_TCMD_CD 0x02 /* rw: Assert C/D signal */ +#define SCI_TCMD_MSG 0x04 /* rw: Assert MSG signal */ +#define SCI_TCMD_PHASE_MASK 0x07 /* r: Mask for current bus phase */ +#define SCI_TCMD_REQ 0x08 /* rw: Assert REQ signal */ +#define SCI_TCMD_LAST_SENT 0x80 /* ro: Last byte was xferred + * (not on 5380/1) */ + +#define SCI_PHASE(x) SCSI_PHASE(x) + +/* + * Current (SCSI) Bus status + */ + +#define SCI_BUS_DBP 0x01 /* r: Data Bus parity */ +#define SCI_BUS_SEL 0x02 /* r: SEL signal */ +#define SCI_BUS_IO 0x04 /* r: I/O signal */ +#define SCI_BUS_CD 0x08 /* r: C/D signal */ +#define SCI_BUS_MSG 0x10 /* r: MSG signal */ +#define SCI_BUS_REQ 0x20 /* r: REQ signal */ +#define SCI_BUS_BSY 0x40 /* r: BSY signal */ +#define SCI_BUS_RST 0x80 /* r: RST signal */ + +#define SCI_CUR_PHASE(x) SCSI_PHASE((x)>>2) + +/* + * Bus and Status register + */ + +#define SCI_CSR_ACK 0x01 /* r: ACK signal */ +#define SCI_CSR_ATN 0x02 /* r: ATN signal */ +#define SCI_CSR_DISC 0x04 /* r: Disconnected (BSY==0) */ +#define SCI_CSR_PHASE_MATCH 0x08 /* r: Bus and SCI_TCMD match */ +#define SCI_CSR_INT 0x10 /* r: Interrupt request */ +#define SCI_CSR_PERR 0x20 /* r: Parity error */ +#define SCI_CSR_DREQ 0x40 /* r: DMA request */ +#define SCI_CSR_DONE 0x80 /* r: DMA count is zero */ + + +/* icu scsi chip switching */ + +#define ICU_ADR 0xfffffe00 +#define ICU_IO (ICU_ADR+20) +#define ICU_DIR (ICU_ADR+21) +#define ICU_DATA (ICU_ADR+19) +#define ICU_SCSI_BIT 0x80 diff --git a/sys/arch/pc532/dev/ncr_defs.h b/sys/arch/pc532/dev/ncr_defs.h new file mode 100644 index 00000000000..952661c3b54 --- /dev/null +++ b/sys/arch/pc532/dev/ncr_defs.h @@ -0,0 +1,57 @@ +/* $NetBSD: ncr_defs.h,v 1.4 1995/08/25 07:30:39 phil Exp $ */ + +/*- + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * 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 Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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 _SCSI_DEFS_H +#define _SCSI_DEFS_H + +#define SCSI_PHASE_DATA_OUT 0x0 +#define SCSI_PHASE_DATA_IN 0x1 +#define SCSI_PHASE_CMD 0x2 +#define SCSI_PHASE_STATUS 0x3 +#define SCSI_PHASE_UNSPEC1 0x4 +#define SCSI_PHASE_UNSPEC2 0x5 +#define SCSI_PHASE_MESSAGE_OUT 0x6 +#define SCSI_PHASE_MESSAGE_IN 0x7 + +#define SCSI_PHASE(x) ((x)&0x7) + +/* These should be fixed up. */ + +#define SCSI_RET_SUCCESS 0 +#define SCSI_RET_RETRY 1 +#define SCSI_RET_DEVICE_DOWN 2 +#define SCSI_RET_COMMAND_FAIL 3 + +#endif diff --git a/sys/arch/pc532/dev/ncrreg.h b/sys/arch/pc532/dev/ncrreg.h new file mode 100644 index 00000000000..41c371ba231 --- /dev/null +++ b/sys/arch/pc532/dev/ncrreg.h @@ -0,0 +1,62 @@ +/* $NetBSD: ncrreg.h,v 1.2 1995/08/25 07:30:40 phil Exp $ */ + +/* + * Copyright (c) 1994 Matthias Pfaller. + * 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 Matthias Pfaller. + * 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. + * + * $Id: ncrreg.h,v 1.1 1995/10/18 08:51:18 deraadt Exp $ + */ + +#ifndef _NCRREG_H +#define _NCRREG_H + +#define PDMA_ADDRESS ((volatile u_char *) 0xffe00000) +#define NCR5380 ((volatile struct ncr5380 *) 0xffd00000) + +struct ncr5380 { + volatile u_char regs[8]; /* use only the odd bytes */ +}; + +#define ncr_data regs[0] /* Data register */ +#define ncr_icom regs[1] /* Initiator command register */ +#define ncr_mode regs[2] /* Mode register */ +#define ncr_tcom regs[3] /* Target command register */ +#define ncr_idstat regs[4] /* Bus status register */ +#define ncr_dmstat regs[5] /* DMA status register */ +#define ncr_trcv regs[6] /* Target receive register */ +#define ncr_ircv regs[7] /* Initiator receive register */ + +#define GET_5380_REG(rnum) NCR5380->regs[rnum] +#define SET_5380_REG(rnum,val) (NCR5380->regs[rnum] = val) +#define scsi_ienable() intr_enable(IR_SCSI1) +#define scsi_idisable() intr_disable(IR_SCSI1) +#define scsi_clr_ipend() do { \ + int i = GET_5380_REG(NCR5380_IRCV); \ + } while (0) + +#endif /* _NCRREG_H */ diff --git a/sys/arch/pc532/dev/oldncr.c b/sys/arch/pc532/dev/oldncr.c new file mode 100644 index 00000000000..24b95d104a4 --- /dev/null +++ b/sys/arch/pc532/dev/oldncr.c @@ -0,0 +1,953 @@ +/* $NetBSD: oldncr.c,v 1.2 1995/08/27 04:07:54 phil Exp $ */ + +/* + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * 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 Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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. + */ + +/* Modified for use with the pc532 by Phil Nelson, June 94. */ + +#define PSEUDO_DMA 1 + +static int ncr_debug=1; + +#include <sys/types.h> +#include <sys/malloc.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/buf.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/device.h> +#include <scsi/scsi_all.h> +#include <scsi/scsi_debug.h> +#include <scsi/scsiconf.h> + +#include <machine/icu.h> + +#include "ncr_defs.h" +#include "ncr_5380.h" + +#define NCR5380 DP8490 + +#define SCI_PHASE_DISC 0 /* sort of ... */ +#define SCI_CLR_INTR(regs) {register int temp = regs->sci_iack;} +#define SCI_ACK(ptr,phase) (ptr)->sci_tcmd = (phase) +#define SCSI_TIMEOUT_VAL 10000000 +#define WAIT_FOR_NOT_REQ(ptr) { \ + int scsi_timeout = SCSI_TIMEOUT_VAL; \ + while ( ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ + ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ + ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("scsi timeout--WAIT_FOR_NOT_REQ---ncr.c, \ + line %d.\n", __LINE__); \ + goto scsi_timeout_error; \ + } \ + } + +#define WAIT_FOR_REQ(ptr) { \ + int scsi_timeout = SCSI_TIMEOUT_VAL; \ + while ( (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("scsi timeout--WAIT_FOR_REQ---ncr.c, \ + line %d.\n", __LINE__); \ + goto scsi_timeout_error; \ + } \ + } +#define WAIT_FOR_BSY(ptr) { \ + int scsi_timeout = SCSI_TIMEOUT_VAL; \ + while ((((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("scsi timeout--WAIT_FOR_BSY---ncr.c, \ + line %d.\n", __LINE__); \ + goto scsi_timeout_error; \ + } \ + } + +#ifdef DDB +int Debugger(); +#else +#define Debugger() panic("Should call Debugger here (mac/dev/ncr.c).") +#endif + +typedef unsigned long int physaddr; +typedef sci_regmap_t sci_padded_regmap_t; + +#define NNCR5380 1 + +struct ncr5380_softc { + struct device sc_dev; + struct scsi_link sc_link; +}; + +/* From the mapping of the pc532 address space. See pc532/machdep.c */ +static volatile sci_padded_regmap_t *ncr = (sci_regmap_t *) 0xffd00000; +static volatile long *sci_4byte_addr= (long *) 0xffe00000; +static volatile u_char *sci_1byte_addr=(u_char *) 0xffe00000; + +static void ncr5380_minphys(struct buf *bp); +static int ncr5380_scsi_cmd(struct scsi_xfer *xs); + +static int ncr5380_show_scsi_cmd(struct scsi_xfer *xs); +static int ncr5380_reset_target(int adapter, int target); +static int ncr5380_poll(int adapter, int timeout); +static int ncr5380_send_cmd(struct scsi_xfer *xs); + +extern void ncr5380_intr(int adapter); +extern void spinwait(int); + +static int scsi_gen(int adapter, int id, int lun, + struct scsi_generic *cmd, int cmdlen, + void *databuf, int datalen); +static int scsi_group0(int adapter, int id, int lun, + int opcode, int addr, int len, + int flags, caddr_t databuf, int datalen); + +static char scsi_name[] = "ncr"; + +struct scsi_adapter ncr5380_switch = { + ncr5380_scsi_cmd, /* scsi_cmd() */ + ncr5380_minphys, /* scsi_minphys() */ + 0, /* open_target_lu() */ + 0 /* close_target_lu() */ +}; + +/* This is copied from julian's bt driver */ +/* "so we have a default dev struct for our link struct." */ +struct scsi_device ncr_dev = { + NULL, /* Use default error handler. */ + NULL, /* have a queue, served by this (?) */ + NULL, /* have no async handler. */ + NULL /* Use default "done" routine. */ +}; + +extern int matchbyname(); +static int ncrprobe(); +static void ncrattach(); + +struct cfdriver oldncrcd = + { NULL, "ncr", ncrprobe, ncrattach, + DV_DULL, sizeof(struct ncr5380_softc), NULL, 0 }; + +static int +ncrprobe(parent, self, aux) + struct device *parent, *self; + void *aux; +{ +/* int unit = cf->cf_unit; */ + struct ncr5380_softc *ncr5380 = (void *)self; + +#if 0 +DELETE THIS ???? + if (unit >= NNCR5380) { + printf("ncr5380attach: unit %d more than %d configured.\n", + unit+1, NNCR5380); + return 0; + } + ncr5380 = malloc(sizeof(struct ncr5380_data), M_TEMP, M_NOWAIT); + if (!ncr5380) { + printf("ncr5380attach: Can't malloc.\n"); + return 0; + } + + bzero(ncr5380, sizeof(*ncr5380)); + ncr5380data[unit] = ncr5380; +#endif + + /* If we call this, we need to add SPL_DP to the bio mask! */ + /* PL_bio |= SPL_DP; Not yet ... no interrupts */ + + return 1; +} + +static void +ncrattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + register volatile sci_padded_regmap_t *regs = ncr; + struct ncr5380_softc *ncr5380 = (void *)self; + int r; + + ncr5380->sc_link.adapter_softc = ncr5380; +/* ncr5380->sc_link.scsibus = 0; */ + ncr5380->sc_link.adapter_target = 7; + ncr5380->sc_link.adapter = &ncr5380_switch; + ncr5380->sc_link.device = &ncr_dev; + ncr5380->sc_link.openings = 1; + + printf("\n"); + + config_found(self, &(ncr5380->sc_link), NULL); +} + +#define MIN_PHYS 65536 /*BARF!!!!*/ +static void +ncr5380_minphys(struct buf *bp) +{ + if (bp->b_bcount > MIN_PHYS) { + printf("Uh-oh... ncr5380_minphys setting bp->b_bcount = %x.\n", MIN_PHYS); + bp->b_bcount = MIN_PHYS; + } + minphys(bp); +} +#undef MIN_PHYS + +static int +ncr5380_scsi_cmd(struct scsi_xfer *xs) +{ + int flags, s, r; + + flags = xs->flags; + if (xs->bp) flags |= (SCSI_NOSLEEP); + if ( flags & ITSDONE ) { + printf("Already done?"); + xs->flags &= ~ITSDONE; + } + if ( ! ( flags & INUSE ) ) { + printf("Not in use?"); + xs->flags |= INUSE; + } + + if ( flags & SCSI_RESET ) { + printf("flags & SCSIRESET.\n"); + s = splbio(); + ncr5380_reset_target(xs->sc_link->scsibus, + xs->sc_link->target); + splx(s); + return(COMPLETE); + } + + xs->resid = 0; /* Default value? */ + r = ncr5380_send_cmd(xs); + xs->flags |= ITSDONE; + scsi_done(xs); + switch(r) { + case COMPLETE: case SUCCESSFULLY_QUEUED: + r = SUCCESSFULLY_QUEUED; + if (xs->flags&SCSI_POLL) + r = COMPLETE; + break; + default: + break; + } + return r; +} + +static int +ncr5380_show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *) xs->cmd; + int i = 0; + + if ( ! ( xs->flags & SCSI_RESET ) ) { + printf("ncr5380(%d:%d:%d)-", + xs->sc_link->scsibus, xs->sc_link->target, xs->sc_link->lun); + while (i < xs->cmdlen) { + if (i) printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } else { + printf("ncr5380(%d:%d:%d)-RESET-\n", + xs->sc_link->scsibus, xs->sc_link->target, xs->sc_link->lun); + } +} + +/* + * Actual chip control. + */ + +void +delay(int timeo) +{ + int len; + for (len=0;len<timeo*2;len++); +} + +#if 0 +extern void +spinwait(int ms) +{ + while (ms--) + delay(500); +} +#endif + +extern void +ncr5380_intr(int adapter) +{ + register volatile sci_padded_regmap_t *regs = ncr; + + SCI_CLR_INTR(regs); + regs->sci_mode = 0x00; +} + +extern int +scsi_irq_intr(void) +{ + register volatile sci_padded_regmap_t *regs = ncr; + +/* if (regs->sci_csr != SCI_CSR_PHASE_MATCH) + printf("scsi_irq_intr called (not just phase match -- " + "csr = 0x%x, bus_csr = 0x%x).\n", + regs->sci_csr, regs->sci_bus_csr); + ncr5380_intr(0); */ + return 1; +} + +extern int +scsi_drq_intr(void) +{ +/* printf("scsi_drq_intr called.\n"); */ +/* ncr5380_intr(0); */ + return 1; +} + +static int +ncr5380_reset_target(int adapter, int target) +{ + register volatile sci_padded_regmap_t *regs = ncr; + int dummy; + + scsi_select_ctlr (DP8490); + regs->sci_icmd = SCI_ICMD_TEST; + regs->sci_icmd = SCI_ICMD_TEST | SCI_ICMD_RST; + delay(2500); + regs->sci_icmd = 0; + + regs->sci_mode = 0; + regs->sci_tcmd = SCI_PHASE_DISC; + regs->sci_sel_enb = 0; + + SCI_CLR_INTR(regs); + SCI_CLR_INTR(regs); +} + + +static int +ncr5380_send_cmd(struct scsi_xfer *xs) +{ + int s, i, sense; + +#if 0 + ncr5380_show_scsi_cmd(xs); +#endif + s = splbio(); + sense = scsi_gen( xs->sc_link->scsibus, xs->sc_link->target, + xs->sc_link->lun, xs->cmd, xs->cmdlen, + xs->data, xs->datalen ); + splx(s); + switch (sense) { + case 0x00: + xs->error = XS_NOERROR; + return (COMPLETE); + case 0x02: /* Check condition */ + for (i = 10; i; i--) { + s = splbio(); + sense = scsi_group0(xs->sc_link->scsibus, + xs->sc_link->target, + xs->sc_link->lun, + 0x3, 0x0, + sizeof(struct scsi_sense_data), + 0, (caddr_t) &(xs->sense), + sizeof(struct scsi_sense_data)); + splx(s); + if (sense == 0) break; + if (sense == 8 + && (xs->flags & SCSI_NOSLEEP) == 0) + tsleep((caddr_t)&lbolt, PRIBIO, "ncrbusy", 0); + } + if (!i) + printf("ncr(%d:%d): Sense failed (dev busy)\n", + xs->sc_link->target, xs->sc_link->lun); + xs->error = XS_SENSE; + return COMPLETE; + case 0x08: /* Busy */ + xs->error = XS_BUSY; + return COMPLETE; + default: + xs->error = XS_DRIVER_STUFFUP; + return COMPLETE; + } +} + +static int +select_target(register volatile sci_padded_regmap_t *regs, + u_char myid, u_char tid, int with_atn) +{ + register u_char bid, icmd; + int ret = SCSI_RET_RETRY; + + if ((regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) && + (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) && + (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL))) + return ret; + + /* for our purposes.. */ + myid = 1 << myid; + tid = 1 << tid; + + regs->sci_sel_enb = 0; /*myid; we don't want any interrupts. */ + regs->sci_tcmd = 0; /* get into a harmless state */ + regs->sci_mode = 0; /* get into a harmless state */ + + regs->sci_odata = myid; + regs->sci_mode = SCI_MODE_ARB; +/* regs->sci_mode |= SCI_MODE_ARB; */ + /* AIP might not set if BSY went true after we checked */ + for (bid = 0; bid < 20; bid++) /* 20usec circa */ + if (regs->sci_icmd & SCI_ICMD_AIP) + break; + if ((regs->sci_icmd & SCI_ICMD_AIP) == 0) { + goto lost; + } + + spinwait(2); /* 2.2us arb delay */ + + if (regs->sci_icmd & SCI_ICMD_LST) { + goto lost; + } + + regs->sci_mode &= ~SCI_MODE_PAR_CHK; + bid = regs->sci_data; + + if ((bid & ~myid) > myid) { + goto lost; + } + if (regs->sci_icmd & SCI_ICMD_LST) { + goto lost; + } + + /* Won arbitration, enter selection phase now */ + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); + icmd |= (with_atn ? (SCI_ICMD_SEL|SCI_ICMD_ATN) : SCI_ICMD_SEL); + icmd |= SCI_ICMD_BSY; + regs->sci_icmd = icmd; + + if (regs->sci_icmd & SCI_ICMD_LST) { + goto nosel; + } + + /* XXX a target that violates specs might still drive the bus XXX */ + /* XXX should put our id out, and after the delay check nothi XXX */ + /* XXX ng else is out there. XXX */ + + delay(0); + + regs->sci_tcmd = 0; + regs->sci_odata = myid | tid; + regs->sci_sel_enb = 0; + +/* regs->sci_mode &= ~SCI_MODE_ARB; 2 deskew delays, too */ + regs->sci_mode = 0; /* 2 deskew delays, too */ + + icmd |= SCI_ICMD_DATA; + icmd &= ~(SCI_ICMD_BSY); + + regs->sci_icmd = icmd; + + /* bus settle delay, 400ns */ + delay(2); /* too much (was 2) ? */ + +/* regs->sci_mode |= SCI_MODE_PAR_CHK; */ + + { + register int timeo = 2500;/* 250 msecs in 100 usecs chunks */ + while ((regs->sci_bus_csr & SCI_BUS_BSY) == 0) { + if (--timeo > 0) { + delay(100); + } else { + goto nodev; + } + } + } + + icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL); + regs->sci_icmd = icmd; +/* regs->sci_sel_enb = myid;*/ /* looks like we should NOT have it */ + return SCSI_RET_SUCCESS; +nodev: + ret = SCSI_RET_DEVICE_DOWN; + regs->sci_sel_enb = myid; +nosel: + icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL|SCI_ICMD_ATN); + regs->sci_icmd = icmd; +lost: + regs->sci_mode = 0; + + return ret; +} + +sci_data_out(regs, phase, count, data) + register sci_padded_regmap_t *regs; + unsigned char *data; +{ + register unsigned char icmd; + register int cnt=0; + + /* ..checks.. */ + + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); +loop: + if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) + return cnt; + + WAIT_FOR_REQ(regs); + icmd |= SCI_ICMD_DATA; + regs->sci_icmd = icmd; + regs->sci_odata = *data++; + icmd |= SCI_ICMD_ACK; + regs->sci_icmd = icmd; + + icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_ACK); + WAIT_FOR_NOT_REQ(regs); + regs->sci_icmd = icmd; + ++cnt; + if (--count > 0) + goto loop; +scsi_timeout_error: + return cnt; +} + +sci_data_in(regs, phase, count, data) + register sci_padded_regmap_t *regs; + unsigned char *data; +{ + register unsigned char icmd; + register int cnt=0; + + /* ..checks.. */ + + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); + +loop: + if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) + return cnt; + + WAIT_FOR_REQ(regs); + *data++ = regs->sci_data; + icmd |= SCI_ICMD_ACK; + regs->sci_icmd = icmd; + + icmd &= ~SCI_ICMD_ACK; + WAIT_FOR_NOT_REQ(regs); + regs->sci_icmd = icmd; + ++cnt; + if (--count > 0) + goto loop; + +scsi_timeout_error: + return cnt; +} + +static int +command_transfer(register volatile sci_padded_regmap_t *regs, + int maxlen, u_char *data, u_char *status, u_char *msg) +{ + int xfer=0, phase; + +/* printf("command_transfer called for 0x%x.\n", *data); */ + + regs->sci_icmd = 0; + + while (1) { + + WAIT_FOR_REQ(regs); + + phase = SCI_CUR_PHASE(regs->sci_bus_csr); + + switch (phase) { + case SCSI_PHASE_CMD: + SCI_ACK(regs,SCSI_PHASE_CMD); + xfer += sci_data_out(regs, SCSI_PHASE_CMD, + maxlen, data); + return xfer; + case SCSI_PHASE_DATA_IN: + printf("Data in phase in command_transfer?\n"); + return 0; + case SCSI_PHASE_DATA_OUT: + printf("Data out phase in command_transfer?\n"); + return 0; + case SCSI_PHASE_STATUS: + SCI_ACK(regs,SCSI_PHASE_STATUS); + printf("status in command_transfer.\n"); + sci_data_in(regs, SCSI_PHASE_STATUS, + 1, status); + break; + case SCSI_PHASE_MESSAGE_IN: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); + printf("msgin in command_transfer.\n"); + sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, + 1, msg); + break; + case SCSI_PHASE_MESSAGE_OUT: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); + sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, + 1, msg); + break; + default: + printf("Unexpected phase 0x%x in " + "command_transfer().\n", phase); +scsi_timeout_error: + return xfer; + break; + } + } +} + +static int +data_transfer(register volatile sci_padded_regmap_t *regs, + int maxlen, u_char *data, u_char *status, u_char *msg) +{ + int retlen = 0, xfer, phase; + + regs->sci_icmd = 0; + + *status = 0; + + while (1) { + + WAIT_FOR_REQ(regs); + + phase = SCI_CUR_PHASE(regs->sci_bus_csr); + + switch (phase) { + case SCSI_PHASE_CMD: + printf("Command phase in data_transfer().\n"); + return retlen; + case SCSI_PHASE_DATA_IN: + SCI_ACK(regs,SCSI_PHASE_DATA_IN); +#if PSEUDO_DMA + xfer = sci_pdma_in(regs, SCSI_PHASE_DATA_IN, + maxlen, data); +#else + xfer = sci_data_in(regs, SCSI_PHASE_DATA_IN, + maxlen, data); +#endif + retlen += xfer; + maxlen -= xfer; + break; + case SCSI_PHASE_DATA_OUT: + SCI_ACK(regs,SCSI_PHASE_DATA_OUT); +#if PSEUDO_DMA + xfer = sci_pdma_out(regs, SCSI_PHASE_DATA_OUT, + maxlen, data); +#else + xfer = sci_data_out(regs, SCSI_PHASE_DATA_OUT, + maxlen, data); +#endif + retlen += xfer; + maxlen -= xfer; + break; + case SCSI_PHASE_STATUS: + SCI_ACK(regs,SCSI_PHASE_STATUS); + sci_data_in(regs, SCSI_PHASE_STATUS, + 1, status); + break; + case SCSI_PHASE_MESSAGE_IN: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); + sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, + 1, msg); + if (*msg == 0) { + return retlen; + } else { + printf( "message 0x%x in " + "data_transfer.\n", *msg); + } + break; + case SCSI_PHASE_MESSAGE_OUT: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); + sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, + 1, msg); + break; + default: + printf( "Unexpected phase 0x%x in " + "data_transfer().\n", phase); +scsi_timeout_error: + return retlen; + break; + } + } +} + +static int +scsi_request(register volatile sci_padded_regmap_t *regs, + int target, int lun, u_char *cmd, int cmdlen, + char *databuf, int datalen, int *sent, int *ret) +{ +/* Returns 0 on success, -1 on internal error, or the status byte */ + int cmd_bytes_sent, r; + u_char stat, msg, c; + + *sent = 0; + scsi_select_ctlr (DP8490); + + if ( ( r = select_target(regs, 7, target, 1) ) != SCSI_RET_SUCCESS) { + *ret = r; + SCI_CLR_INTR(regs); + switch (r) { + case SCSI_RET_RETRY: + return 0x08; + default: + printf("select_target(target %d, lun %d) failed(%d).\n", + target, lun, r); + case SCSI_RET_DEVICE_DOWN: + return -1; + } + } + + c = 0x80 | lun; + + if ((cmd_bytes_sent = command_transfer(regs, cmdlen, + (u_char *) cmd, &stat, &c)) + != cmdlen) { + SCI_CLR_INTR(regs); + *ret = SCSI_RET_COMMAND_FAIL; + printf("Data underrun sending CCB (%d bytes of %d, sent).\n", + cmd_bytes_sent, cmdlen); + return -1; + } + + *sent=data_transfer(regs, datalen, (u_char *)databuf, + &stat, &msg); + + *ret = 0; + + return stat; +} + +static int +scsi_gen(int adapter, int id, int lun, struct scsi_generic *cmd, + int cmdlen, void *databuf, int datalen) +{ + register volatile sci_padded_regmap_t *regs = ncr; + int i,j,sent,ret; + + cmd->bytes[0] |= ((u_char) lun << 5); + + i = scsi_request(regs, id, lun, (u_char *) cmd, cmdlen, + databuf, datalen, &sent, &ret); + + return i; +} + +static int +scsi_group0(int adapter, int id, int lun, int opcode, int addr, int len, + int flags, caddr_t databuf, int datalen) +{ + register volatile sci_padded_regmap_t *regs = ncr; + unsigned char cmd[6]; + int i,j,sent,ret; + + cmd[0] = opcode; /* Operation code */ + cmd[1] = (lun << 5) | ((addr >> 16) & 0x1F); /* Lun & MSB of addr */ + cmd[2] = (addr >> 8) & 0xFF; /* addr */ + cmd[3] = addr & 0xFF; /* LSB of addr */ + cmd[4] = len; /* Allocation length */ + cmd[5] = flags; /* Link/Flag */ + + i = scsi_request(regs, id, lun, cmd, 6, databuf, datalen, &sent, &ret); + + return i; +} + +/* pseudo-dma action */ + +#if PSEUDO_DMA + +#define TIMEOUT 1000000 +#define READY(poll) \ + i = TIMEOUT; \ + while ((regs->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) \ + !=(SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) \ + if ( !(regs->sci_csr & SCI_CSR_PHASE_MATCH) \ + || !(regs->sci_bus_csr & SCI_BUS_BSY) \ + || (i-- < 0) ) { \ + printf("ncr.c: timeout counter = %d, len = %d count=%d (count-len %d).\n", \ + i, len,count,count-len); \ + printf("ncr_debug = %d, 1=out, 2=in",ncr_debug); \ + /*dump_regs();*/ \ + if (poll && !(regs->sci_csr & SCI_CSR_PHASE_MATCH)) { \ + regs->sci_icmd &= ~SCI_ICMD_DATA; \ + len--; \ + } else { \ + regs->sci_mode &= ~SCI_MODE_DMA; \ + } \ + return count-len; \ + } + +#define W1 *byte_data = *data++ +#define W4 *long_data = *((long*)data)++ + +sci_pdma_out(regs, phase, count, data) + register volatile sci_padded_regmap_t *regs; + int phase; + int count; + u_char *data; +{ + register volatile long *long_data = sci_4byte_addr; + register volatile u_char *byte_data = sci_1byte_addr; + register int len = count, i; + +ncr_debug=1; + + if (count < 128) + return sci_data_out(regs, phase, count, data); + + WAIT_FOR_BSY(regs); + regs->sci_mode |= SCI_MODE_DMA; + regs->sci_icmd |= SCI_ICMD_DATA; + regs->sci_dma_send = 0; + + while ( len >= 64 ) { + READY(1); W1; READY(1); W1; READY(1); W1; READY(1); W1; + READY(1); + W4;W4;W4; W4;W4;W4;W4; W4;W4;W4;W4; W4;W4;W4;W4; + len -= 64; + } + while (len) { + READY(1); + W1; + len--; + } + i = TIMEOUT; + while ( ((regs->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) + == SCI_CSR_PHASE_MATCH) && --i); + if (!i) + printf("ncr.c:%d: timeout waiting for SCI_CSR_DREQ.\n", __LINE__); + *byte_data = 0; +scsi_timeout_error: + regs->sci_mode &= ~SCI_MODE_DMA; + return count-len; +} + +#undef W1 +#undef W4 + +#define R4 *((long *)data)++ = *long_data +#define R1 *data++ = *byte_data + +sci_pdma_in(regs, phase, count, data) + register volatile sci_padded_regmap_t *regs; + int phase; + int count; + u_char *data; +{ + register volatile long *long_data = sci_4byte_addr; + register volatile u_char *byte_data = sci_1byte_addr; + register int len = count, i; + +ncr_debug=2; + if (count < 128) + return sci_data_in(regs, phase, count, data); + +/* printf("Called sci_pdma_in(0x%x, 0x%x, %d, 0x%x.\n", regs, phase, count, data); */ + + WAIT_FOR_BSY(regs); + regs->sci_mode |= SCI_MODE_DMA; + regs->sci_icmd |= SCI_ICMD_DATA; + regs->sci_irecv = 0; + + while (len >= 1024) { + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 128 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 256 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 384 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 512 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 640 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 768 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 896 */ + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /*1024 */ + len -= 1024; + } + while (len >= 128) { + READY(0); + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; + R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 128 */ + len -= 128; + } + while (len) { + READY(0); + R1; + len--; + } +scsi_timeout_error: + regs->sci_mode &= ~SCI_MODE_DMA; + return count - len; +} +#undef R4 +#undef R1 +#endif + +/* Some stuff from dp.c ... */ + + +#if 0 +/* Select a SCSI device. + */ +int scsi_select_ctlr (int ctlr) +{ + /* May need other stuff here to syncronize between dp & aic. */ + + RD_ADR (u_char, ICU_IO) &= ~ICU_SCSI_BIT; /* i/o, not port */ + RD_ADR (u_char, ICU_DIR) &= ~ICU_SCSI_BIT; /* output */ + if (ctlr == NCR5380) + RD_ADR (u_char, ICU_DATA) &= ~ICU_SCSI_BIT; /* select = 0 for 8490 */ + else + RD_ADR (u_char, ICU_DATA) |= ICU_SCSI_BIT; /* select = 1 for AIC6250 */ +} +#endif diff --git a/sys/arch/pc532/dev/rd.c b/sys/arch/pc532/dev/rd.c new file mode 100644 index 00000000000..1b54557f7d9 --- /dev/null +++ b/sys/arch/pc532/dev/rd.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 1995 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 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. + * + * $Id: rd.c,v 1.1 1995/10/18 08:51:18 deraadt Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/conf.h> + +static int rdmatch(struct device *parent, void *cf, void *aux); +static void rdattach(struct device *parent, struct device *self, void *aux); + +struct cfdriver rdcd = { + NULL, + "rd", + rdmatch, + rdattach, + DV_DISK, + sizeof(struct device), + NULL, + 0 +}; + +#if !defined(RD_SIZE) +# define RD_SIZE 0x200000 +#endif + +u_char ram_disk[RD_SIZE] = "Ramdiskorigin"; + +static int +rdmatch(parent, cf, aux) + struct device *parent; + void *cf, *aux; +{ + return(((struct cfdata *)cf)->cf_unit == 0); +} + +static void +rdattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + printf(" addr 0x%x, size 0x%x\n", ram_disk, RD_SIZE); +} + + +/* operational routines */ + +int +rdopen(dev, flags, devtype, p) + dev_t dev; + int flags, devtype; + struct proc *p; +{ + if (minor(dev) == 0) + return(0); + else + return(ENXIO); +} + +int +rdclose(dev, flags, devtype, p) + dev_t dev; + int flags, devtype; + struct proc *p; +{ + return(0); +} + +int +rdioctl(dev, cmd, addr, flag, p) + dev_t dev; + u_long cmd; + int flag; + caddr_t addr; + struct proc *p; +{ + return(ENOTTY); +} + +int +rdsize(dev) + dev_t dev; +{ + if (minor(dev) == 0) + return(RD_SIZE / DEV_BSIZE); + else + return(0); +} + +int +rddump(dev, blkno, va, size) + dev_t dev; + daddr_t blkno; + caddr_t va; + size_t size; +{ + return(ENXIO); +} + +void +rdstrategy(bp) + struct buf *bp; +{ + int loc, size; + char *adr; + + if (minor(bp->b_dev) == 0) + loc = bp->b_blkno * DEV_BSIZE; + else { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + return; + } + size = bp->b_bcount; + adr = (char *) bp->b_un.b_addr; + if (loc + size > sizeof(ram_disk)) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + return; + } + if (bp->b_flags & B_READ) + bcopy(&ram_disk[loc], adr, size); + else + bcopy(adr, &ram_disk[loc], size); + biodone(bp); +} + +int +rdread(dev, uio) + dev_t dev; + struct uio *uio; +{ + return(physio(rdstrategy, NULL, dev, B_READ, minphys, uio)); +} + +int +rdwrite(dev, uio) + dev_t dev; + struct uio *uio; +{ + return(physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio)); +} diff --git a/sys/arch/pc532/dev/scn.c b/sys/arch/pc532/dev/scn.c new file mode 100644 index 00000000000..1b391b8c022 --- /dev/null +++ b/sys/arch/pc532/dev/scn.c @@ -0,0 +1,1119 @@ +/* $NetBSD: scn.c,v 1.22 1995/09/26 20:16:17 phil Exp $ */ + +/* + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 + */ + +#include "scn.h" + +#if NSCN > 0 + +/* #define KERN_MORE */ + +/* The pc532 has 4 duarts! */ +#define NLINES 8 + +/* + * scn2681 driver for the pc532. Phil Nelson Feb 8, 1993 + * + */ +#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 <dev/cons.h> + +#include <machine/icu.h> + +#include "scnreg.h" + +#include "sl.h" + +struct scn_softc { + struct device scn_dev; + struct tty *scn_tty; + struct rs232_s scn_line; + char scn_swflags; +#define SCN_SW_SOFTCAR 0x01 +#define SCN_SW_CLOCAL 0x02 +#define SCN_SW_CRTSCTS 0x04 +}; + +int scnprobe __P((struct device *, void *, void *)); +void scnattach __P((struct device *, struct device *, void *)); +int scnintr __P((int)); +int scnparam __P((struct tty *, struct termios *)); +void scnstart __P((struct tty *)); +int scnopen __P((dev_t, int, int, struct proc *)); +int scnclose __P((dev_t, int, int, struct proc *)); + +struct cfdriver scncd = + { NULL, "scn", scnprobe, scnattach, + DV_TTY, sizeof(struct scn_softc), NULL, 0 }; + +/* int scnsoftCAR; +int scn_active; To Be Deleted ... */ +int scnconsole = SCN_CONSOLE; +int scnconsinit = 0; +int scndefaultrate = TTYDEF_SPEED; +int scnmajor; + +struct duart_info uart[(NLINES+1)/2]; +/* struct rs232_s line[NLINES]; + struct tty *scn_tty[NLINES]; To be deleted. */ + +struct speedtab scnspeedtab[] = { + 0, 0x40, /* code for line-hangup */ + 50, 0x00, + 75, 0x10, + 110, 0x21, + 134, 0x22, + 150, 0x13, + 200, 0x03, + 300, 0x24, + 600, 0x25, + 1050, 0x07, + 1200, 0x26, + 1800, 0x1a, + 2000, 0x17, + 2400, 0x28, + 4800, 0x29, + 7200, 0x0a, + 9600, 0x2b, + 19200, 0x1c, + 38400, 0x0c, + 57600, 0x60, /* An illegal speed....? */ + -1, -1 +}; + +#define getspeedcode(sp,val) \ + { int i=0; \ + while (scnspeedtab[i].sp_speed != -1 && \ + scnspeedtab[i].sp_speed != sp) \ + i++; \ + val = scnspeedtab[i].sp_code; \ + } + +/* Unit is 0-7. Other parts of the minor number are things like + hardware cts/rts handshaking. (XXX how?) */ + +#define UNIT(x) (minor(x) & 0x7) + +/* Which uart is the device on? */ +#define UART(x) (UNIT(x) >> 1) + +extern struct tty *constty; + +#ifdef KGDB +#include "machine/remote-sl.h" + +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + + +/* Debug routine to print out the rs line structures. */ +void print_rs (struct rs232_s *rs) +{ + printf ("\nline frame overrun parity break\n"); + printf ("tty%1d state=%2x f=%2d o=%2d p=%2d b=%2d in=%x, out=%x grp=%d\n", + rs->unit, rs->framing_errors, rs->overrun_errors, + rs->parity_errors, rs->break_interrupts, + rs->uart->i_speed[rs->a_or_b], rs->uart->o_speed[rs->a_or_b], + rs->uart->speed_grp); +} + + +/*==========================================================================* + * scn_config * + *==========================================================================*/ +static +int scn_config(unit, in_speed, out_speed, parity, stop_bits, data_bits ) +int unit; /* which rs line */ +int in_speed; /* input speed: 110, 300, 1200, etc */ +int out_speed; /* output speed: 110, 300, 1200, etc */ +int parity; /* some parity */ +int stop_bits; /* 2 (110 baud) or 1 (other speeds) */ +int data_bits; /* 5, 6, 7, or 8 */ +{ +/* Set various line control parameters for RS232 I/O. */ + + register struct rs232_s *rs; + char mr1_val, mr2_val; + int sp_grp, sp_both; + char set_speed; /* Non zero if we need to set the speed. */ + char a_or_b; /* Used for ease of access. */ + int in_code; + int out_code; + int x; + + /* Get the speed codes. */ + getspeedcode(in_speed,in_code); + getspeedcode(out_speed,out_code); + + /* Check for speed errors. */ + if (in_code == -1 || out_code == -1) + return (EINVAL); + + /* Set up rs pointer. */ + if (unit >= scncd.cd_ndevs) + return ENXIO; + rs = &((struct scn_softc *)scncd.cd_devs[unit])->scn_line; + a_or_b = rs->a_or_b; + + /* Check out the Speeds. There are two groups of speeds. If the new + speeds are not in the same group, or the other line is not the same + speed of the other group, do not change the speeds. Also, if the + in speed and the out speed are in different groups, use the in speed. */ + + set_speed = FALSE; + if ( (in_code != rs->uart->i_code[a_or_b]) + || (out_code != rs->uart->o_code[a_or_b])) { + + /* We need to set the speeds .*/ + set_speed = TRUE; + + if ( ((in_code & LC_SP_GRP) != (out_code & LC_SP_GRP)) + && (((in_code | out_code) & LC_SP_BOTH) != 1) ) { + /* Input speed and output speed are different groups. */ + return (EINVAL); + } + + sp_grp = ((in_code | out_code) & LC_SP_GRP)>>4; + sp_both = in_code & out_code & LC_SP_BOTH; + + /* Check for compatibility and set the uart values */ + if (sp_both) + sp_grp = rs->uart->speed_grp; + else + if ((sp_grp != rs->uart->speed_grp) + && !(rs->uart->i_code[1-a_or_b] & rs->uart->o_code[1-a_or_b] + & LC_SP_BOTH)) { + /* Can't change group, don`t change the speed rates. */ + return (EINVAL); + } + rs->uart->i_code[a_or_b] = in_code; + rs->uart->o_code[a_or_b] = out_code; + rs->uart->i_speed[a_or_b] = in_speed; + rs->uart->o_speed[a_or_b] = out_speed; + } + + /* Lock out interrupts while setting the parameters. (Just for safety.) + */ + x=spltty(); + WR_ADR (u_char, rs->cmd_port, CMD_MR1); + mr1_val = RD_ADR (u_char, rs->mr_port); + mr2_val = RD_ADR (u_char, rs->mr_port); + if ((((mr1_val & 0xe0) | parity | data_bits) != mr1_val) || + (((mr2_val & 0xf0) | stop_bits) != mr2_val)) { + WR_ADR (u_char, rs->cmd_port, CMD_MR1); + WR_ADR (u_char, rs->mr_port, (mr1_val & 0xe0) | parity | data_bits); + WR_ADR (u_char, rs->mr_port, (mr2_val & 0xf0) | stop_bits); + } + if (set_speed) { + if (rs->uart->speed_grp != sp_grp) { + /* Change the group! */ + rs->uart->speed_grp = sp_grp; + WR_ADR (u_char, rs->acr_port, (sp_grp << 7) | rs->uart->acr_int_bits); + } + WR_ADR (u_char, rs->speed_port, ((in_code & 0x0f) << 4) + | (out_code & 0x0f)); + } + DELAY(96000/out_speed); + + splx(x); + return (0); +} + + +scnprobe(parent, cf, aux) + struct device *parent; + void *cf; + void *aux; +{ + int unit = ((struct cfdata *)cf)->cf_unit; + + if (unit >= NLINES) { + return(0); /* dev is "not working." */ + } else { + return(1); /* dev is "working." */ + } +} + +void +scnattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + static char scnints[4] = { IR_TTY0, IR_TTY1, IR_TTY2, IR_TTY3 }; + struct scn_softc *sc = (void *) self; + struct tty *tp; + u_char unit = sc->scn_dev.dv_unit; + u_char duart = unit >> 1; + register struct rs232_s *rs = &sc->scn_line; + int x; + int speed; + long line_base; + long uart_base; + long scn_first_adr; + + if (unit == 0) DELAY(5); /* Let the output go out.... */ + + sc->scn_swflags |= SCN_SW_SOFTCAR; + + /* Record unit number, uart, channel a_or_b. */ + rs->unit = unit; + rs->uart = &uart[unit >> 1]; + rs->a_or_b = unit % 2; + + /* Establish interrupt vector */ + if (rs->a_or_b == 0) { + /* Arg 0 is special, so we must pass "unit + 1" */ + intr_establish(scnints[unit >> 1], (void (*)(void *))scnintr, + (void *)(unit + 1), sc->scn_dev.dv_xname, IPL_TTY, FALLING_EDGE); + } + + /* Precalculate port numbers for speed. Magic numbers in the code (once). */ + scn_first_adr = SCN_FIRST_MAP_ADR; /* to get around a gcc bug. */ + line_base = scn_first_adr + LINE_SZ * unit; + uart_base = scn_first_adr + UART_SZ * duart; + rs->xmit_port = DATA_ADR; + rs->recv_port = DATA_ADR; + rs->mr_port = MR_ADR; + rs->stat_port = STAT_ADR; + rs->speed_port = SPEED_ADR; + rs->cmd_port = CMD_ADR; + rs->acr_port = ACR_ADR; + rs->ip_port = IP_ADR; + rs->opset_port = SET_OP_ADR; + rs->opclr_port = CLR_OP_ADR; + + /* Initialize error counts */ + rs->framing_errors = 0; + rs->overrun_errors = 0; + rs->parity_errors = 0; + rs->break_interrupts = 0; + + /* Set up the hardware to a base state, in particular + * o reset transmitter and receiver + * o set speeds and configurations + * o receiver interrupts only (RxRDY and BREAK) + */ + + x = spltty(); + istop(rs); /* CTS off... */ + + WR_ADR (u_char, rs->cmd_port, CMD_DIS_RX | CMD_DIS_TX); + WR_ADR (u_char, rs->cmd_port, CMD_RESET_RX); + WR_ADR (u_char, rs->cmd_port, CMD_RESET_TX); + WR_ADR (u_char, rs->cmd_port, CMD_RESET_ERR); + WR_ADR (u_char, rs->cmd_port, CMD_RESET_BRK); + WR_ADR (u_char, rs->cmd_port, CMD_MR1); + WR_ADR (u_char, rs->mr_port, 0); /* No receiver control of RTS. */ + WR_ADR (u_char, rs->mr_port, 0); +#if 1 + if (unit != 0) { + WR_ADR (u_char, rs->mr_port, 0x80); /* Enable receiver control of RTS */ + WR_ADR (u_char, rs->mr_port, 0x10); /* Enable CTS transmitter control */ + } +#endif + + /* Initialize the uart structure if this is channel A. */ + if (rs->a_or_b == 0) { + /* uart ports */ + rs->uart->isr_port = ISR_ADR; + rs->uart->imr_port = IMR_ADR; + rs->uart->ipcr_port = IPCR_ADR; + rs->uart->opcr_port = OPCR_ADR; + + /* Disable all interrupts. */ + WR_ADR (u_char, rs->uart->imr_port, 0); + rs->uart->imr_int_bits = 0; + + /* Output port config */ + WR_ADR (u_char, rs->uart->opcr_port, 0); + + /* Speeds... */ + rs->uart->speed_grp = 1; + rs->uart->acr_int_bits = 0; + /* Set initial speed to an illegal code that can be changed to + any other baud. */ + rs->uart->i_code[0] = rs->uart->o_code[0] = + rs->uart->i_code[1] = rs->uart->o_code[1] = 0x2f; + rs->uart->i_speed[0] = rs->uart->o_speed[0] = + rs->uart->i_speed[1] = rs->uart->o_speed[1] = 0x0; + } + +#if 0 + rs->uart->acr_int_bits |= ACR_CTS << rs->a_or_b; /* Set CTS int */ +#endif + WR_ADR (u_char, rs->acr_port, + (rs->uart->speed_grp << 7) | rs->uart->acr_int_bits); + scn_config(unit, scndefaultrate, scndefaultrate, + LC_NONE, LC_STOP1, LC_BITS8); + + /* Turn on the Rx and Tx. */ + WR_ADR (u_char, rs->cmd_port, CMD_ENA_RX | CMD_ENA_TX); + + /* Set up the interrupts. */ + rs->uart->imr_int_bits + |= (/*IMR_RX_INT | IMR_TX_INT |*/ unit?IMR_BRK_INT:0) << (4*rs->a_or_b) | IMR_IP_INT; + WR_ADR (u_char, rs->uart->imr_port, rs->uart->imr_int_bits); + + splx(x); + +#ifdef KGDB + if (kgdb_dev == makedev(scnmajor, unit+1)) { + if (scnconsole == unit) + kgdb_dev = -1; /* can't debug over console port */ + else { + (void) scninit(unit, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("scn%d: ", unit); + kgdb_connect(1); + } else + printf("scn%d: kgdb enabled\n", unit); + } + } +#endif + + /* print the device number... */ + printf (" addr 0x%x\n", line_base); +} + +/* ARGSUSED */ +scnopen(dev_t dev, int flag, int mode, struct proc *p) +{ + struct scn_softc *sc; + register struct tty *tp; + register int unit = UNIT(dev); + register struct rs232_s *rs; + int error = 0; + int x; + + /* Set up rs pointer. */ + if (unit >= scncd.cd_ndevs) + return ENXIO; + sc = scncd.cd_devs[unit]; + if (!sc) + return ENXIO; + rs = &sc->scn_line; + + x = spltty(); + + if(!sc->scn_tty) { + tp = sc->scn_tty = ttymalloc(); + } else + tp = sc->scn_tty; + + tp->t_oproc = scnstart; + tp->t_param = scnparam; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + if (sc->scn_swflags & SCN_SW_CLOCAL) + tp->t_cflag |= CLOCAL; + if (sc->scn_swflags & SCN_SW_CRTSCTS) + tp->t_cflag |= CRTSCTS; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = scndefaultrate; + scnparam(tp, &tp->t_termios); + ttsetwater(tp); + + /* Turn on DTR and RTS. */ + istart(rs); + rx_ints_on (rs); + + /* Carrier? XXX fix more like i386 */ + if ((sc->scn_swflags & SCN_SW_SOFTCAR) || get_dcd(rs)) + tp->t_state |= TS_CARR_ON; + } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(x); + return (EBUSY); + } + + /* wait for carrier if necessary */ + if ((flag & O_NONBLOCK) == 0) + while ((tp->t_cflag & CLOCAL) == 0 && + (tp->t_state & TS_CARR_ON) == 0) { + tp->t_state |= TS_WOPEN; + error = ttysleep(tp, (caddr_t)&tp->t_rawq, + TTIPRI | PCATCH, ttopen, 0); + if (error) { + /* XXX should turn off chip if we're the + only waiter */ + splx(x); + return error; + } + } + splx(x); + + return (*linesw[tp->t_line].l_open)(dev, tp); +} + +/*ARGSUSED*/ +scnclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + register int unit = UNIT(dev); + struct scn_softc *sc = scncd.cd_devs[unit]; + register struct tty *tp = sc->scn_tty; + register struct rs232_s *rs = &sc->scn_line; + + (*linesw[tp->t_line].l_close)(tp, flag); +#ifdef KGDB + /* do not disable interrupts if debugging */ + if (kgdb_dev != makedev(scnmajor, unit)) +#endif + if ((tp->t_state&TS_ISOPEN) == 0) + rx_ints_off (rs); + if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || + (tp->t_state&TS_ISOPEN) == 0) { + WR_ADR (u_char, rs->opclr_port, DTR_BIT << rs->a_or_b); + DELAY (10); + WR_ADR (u_char, rs->opset_port, DTR_BIT << rs->a_or_b); + } + ttyclose(tp); +#if 0 + if ((tp->t_state&TS_ISOPEN) == 0) { + ttyfree(tp); + sc->scn_tty = (struct tty *)NULL; + } +#endif + return(0); +} + +scnread(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + register struct scn_softc *sc = scncd.cd_devs[UNIT(dev)]; + register struct tty *tp = sc->scn_tty; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +scnwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + register struct scn_softc *sc = scncd.cd_devs[UNIT(dev)]; + register struct tty *tp = sc->scn_tty; + + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +struct tty * +scntty(dev) + dev_t dev; +{ + register struct scn_softc *sc = scncd.cd_devs[UNIT(dev)]; + register struct tty *tp = sc->scn_tty; + + return (tp); +} + +void cts_int (struct rs232_s *rs, struct tty *tp) +{ +} + +#if 0 +scnintr(int uart_no) +{ + int line0 = uart_no << 1; + int line1 = (uart_no << 1)+1; + + register struct scn_softc *sc0 = scncd.cd_devs[line0]; + register struct scn_softc *sc1 = scncd.cd_devs[line1]; + + register struct tty *tp0 = sc0->scn_tty; + register struct tty *tp1 = sc1->scn_tty; + + register struct rs232_s *rs0 = &sc0->scn_line; + register struct rs232_s *rs1 = &sc1->scn_line; + + register struct duart_info *uart = rs0->uart; + + char rs_work = TRUE; + + u_char rs_stat; + u_char rs_ipcr; + u_char ch; + + + rs_stat = RD_ADR(u_char, uart->isr_port); + printf ("scnintr, rs_stat = 0x%x\n", rs_stat); + + if (rs_stat & IMR_BRK_INT) { + /* A break interrupt! */ + rs0->lstatus = RD_ADR(u_char, rs0->stat_port); + printf ("lstatus = 0x%x\n", rs0->lstatus); + if (rs0->lstatus & SR_BREAK) { + ++rs0->break_interrupts; + RD_ADR(u_char, rs0->recv_port); /* Toss zero character. */ + rs_stat &= ~IMR_RX_INT; + } + WR_ADR (u_char, rs0->cmd_port, CMD_RESET_BRK); + rs0->lstatus = RD_ADR(u_char, rs0->stat_port); + printf ("lstatus = 0x%x\n", rs0->lstatus); + } + if (rs_stat & IMR_RX_INT) { + ch = RD_ADR(u_char, rs0->recv_port); + printf ("input ch = \"%c\"\n", ch); + } +} +/* Change this for real interrupts! */ +_scnintr(int uart_no) + +#else + +/* Change this for real interrupts! */ +scnintr(int line1) +#endif +{ + register struct scn_softc *sc0 = scncd.cd_devs[line1 - 1]; + register struct scn_softc *sc1 = scncd.cd_devs[line1]; + + register struct tty *tp0 = sc0->scn_tty; + register struct tty *tp1 = sc1->scn_tty; + + register struct rs232_s *rs0 = &sc0->scn_line; + register struct rs232_s *rs1 = &sc1->scn_line; + + register struct duart_info *uart = rs0->uart; + + char rs_work = TRUE; + + u_char rs_stat; + u_char rs_ipcr; + u_char ch; + +#ifdef CON_BRK_PANIC + u_char nr_brk = 0; +#endif + + while (rs_work) { + /* Loop to pick up ALL pending interrupts for device. + */ + rs_work = FALSE; + rs_stat = RD_ADR(u_char, uart->isr_port); +/* if (rs_stat & ~(IMR_TX_INT | IMR_TXB_INT)) printf ("scn intr rs_stat = 0x%x\n", rs_stat); */ + if ((rs_stat & IMR_TX_INT) && (tp0 != NULL) + && (tp0->t_state & TS_BUSY)) { + /* output char done. */ + tp0->t_state &= ~(TS_BUSY|TS_FLUSH); + tx_ints_off(rs0); + if (tp0->t_line) + (*linesw[tp0->t_line].l_start)(tp0); + else + scnstart(tp0); + rs_work = TRUE; + } + if (rs_stat & IMR_BRK_INT && (tp0 != NULL)) { + /* A break interrupt! */ + rs0->lstatus = RD_ADR(u_char, rs0->stat_port); + if (rs0->lstatus & SR_BREAK) { + ++rs0->break_interrupts; + RD_ADR(u_char, rs0->recv_port); /* Toss zero character. */ + rs_stat &= ~IMR_RX_INT; + } + WR_ADR (u_char, rs0->cmd_port, CMD_RESET_BRK); + rs_work = TRUE; +#ifdef CON_BRK_PANIC + if (line1 == 1 && (rs0->lstatus & SR_BREAK)) { + if (++nr_brk >= 3) { + char c; + printf("\r\nDo you want a dump (y/n)? "); + do + c = cngetc(); + while (c != 'y' && c != 'n'); + printf("%c\r\n", c); + if (c == 'y') { + panic("Panic Button"); + } + } + } +#endif + } + if (rs_stat & IMR_RX_INT && (tp0 != NULL)) { + ch = RD_ADR(u_char, rs0->recv_port); + if (tp0->t_state & TS_ISOPEN) + (*linesw[tp0->t_line].l_rint)(ch, tp0); + rs_work = TRUE; +#ifdef CON_BRK_PANIC + if (line1 == 1) nr_brk = 0; +#endif + } + if ((rs_stat & IMR_TXB_INT) && (tp1 != NULL) + && (tp1->t_state & TS_BUSY)) { + /* output char done. */ + tp1->t_state &= ~(TS_BUSY|TS_FLUSH); + tx_ints_off(rs1); + if (tp1->t_line) + (*linesw[tp1->t_line].l_start)(tp1); + else + scnstart(tp1); + rs_work = TRUE; + } + if (rs_stat & IMR_BRKB_INT && (tp1 != NULL)) { + /* A break interrupt! */ + rs1->lstatus = RD_ADR(u_char, rs1->stat_port); + if (rs1->lstatus & SR_BREAK) { + ++rs1->break_interrupts; + RD_ADR(u_char, rs1->recv_port); /* Toss zero character. */ + rs_stat &= ~IMR_RXB_INT; + } + WR_ADR (u_char, rs1->cmd_port, CMD_RESET_BRK); + rs_work = TRUE; + } + if (rs_stat & IMR_RXB_INT && (tp1 != NULL)) { + ch = RD_ADR(u_char, rs1->recv_port); + if (tp1->t_state & TS_ISOPEN) + (*linesw[tp1->t_line].l_rint)(ch, tp1); + rs_work = TRUE; + } + if (rs_stat & IMR_IP_INT) { + rs_work = TRUE; + rs_ipcr = RD_ADR (u_char, uart->ipcr_port); +#if 0 + /* RTS/CTS stuff! */ + if (rs_ipcr & IPCR_CTS) + cts_int(rs0, tp0); + if (rs_ipcr & (IPCR_CTS << 1)) + cts_int(rs1, tp1); +#endif +#if 0 + if (rs_ipcr & ACR_DCD) + dcd_int(rs0, tp0); + if (rs_ipcr & (ACR_DCD << 1)) + dcd_int(rs1, tp1); +#endif + } + } +} + + +scnioctl(dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + register int unit = UNIT(dev); + register struct scn_softc *sc = scncd.cd_devs[unit]; + register struct tty *tp = sc->scn_tty; + register struct rs232_s *rs = &sc->scn_line; + register scn; + register int error; + + 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: + WR_ADR(u_char, rs->cmd_port, CMD_START_BRK); + break; + + case TIOCCBRK: + WR_ADR (u_char, rs->cmd_port, CMD_STOP_BRK); + break; + + case TIOCSDTR: + WR_ADR(u_char, rs->opset_port, + (DTR_BIT | RTS_BIT) << rs->a_or_b); + break; + + case TIOCCDTR: + WR_ADR(u_char, rs->opclr_port, + (DTR_BIT | RTS_BIT) << rs->a_or_b); + break; + + case TIOCMSET: +/* (void) scnmctl(dev, *(int *)data, DMSET); */ + rs->scn_bits = *(long *)data; + break; + + case TIOCMBIS: +/* (void) scnmctl(dev, *(int *)data, DMBIS); */ + rs->scn_bits |= *(int *)data; + break; + + case TIOCMBIC: +/* (void) scnmctl(dev, *(int *)data, DMBIC); */ + rs->scn_bits &= ~(*(int *)data); + break; + + case TIOCMGET: +/* *(int *)data = scnmctl(dev, 0, DMGET); */ + *(int *)data = rs->scn_bits; + break; + +/* 386 case TIOCGFLAGS: { + int bits = 0; + + if (sc->sc_swflags & COM_SW_SOFTCAR) + bits |= TIOCFLAG_SOFTCAR; + if (sc->sc_swflags & COM_SW_CLOCAL) + bits |= TIOCFLAG_CLOCAL; + if (sc->sc_swflags & COM_SW_CRTSCTS) + bits |= TIOCFLAG_CRTSCTS; + if (sc->sc_swflags & COM_SW_MDMBUF) + bits |= TIOCFLAG_MDMBUF; + + *(int *)data = bits; + break; + } + case TIOCSFLAGS: { + int userbits, driverbits = 0; + + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return(EPERM); + + userbits = *(int *)data; + if ((userbits & TIOCFLAG_SOFTCAR) || + (sc->sc_hwflags & COM_HW_CONSOLE)) + driverbits |= COM_SW_SOFTCAR; + if (userbits & TIOCFLAG_CLOCAL) + driverbits |= COM_SW_CLOCAL; + if (userbits & TIOCFLAG_CRTSCTS) + driverbits |= COM_SW_CRTSCTS; + if (userbits & TIOCFLAG_MDMBUF) + driverbits |= COM_SW_MDMBUF; + + sc->sc_swflags = driverbits; + break; + } +*/ + default: + return (ENOTTY); + } + return (0); +} + +scnparam(tp, t) + register struct tty *tp; + register struct termios *t; +{ + int cflag = t->c_cflag; + int unit = UNIT(tp->t_dev); + register struct scn_softc *sc = scncd.cd_devs[unit]; + int parity = LC_NONE, + stop_bits = LC_STOP1, + data_bits = LC_BITS8; + int error; + struct rs232_s *rs = &sc->scn_line; + + /* Is this a hang up? */ + if (t->c_ospeed == B0) { + WR_ADR (u_char, rs->opclr_port, DTR_BIT << rs->a_or_b); + DELAY (10); + WR_ADR (u_char, rs->opset_port, DTR_BIT << rs->a_or_b); + return(0); + } + + /* Parity? */ + if (cflag&PARENB) { + if ((cflag&PARODD) == 0) + parity = LC_EVEN; + else + parity = LC_ODD; + } + + /* Stop bits. */ + if (cflag&CSTOPB) + stop_bits = LC_STOP1; + + /* Data bits. */ + switch (cflag&CSIZE) { + case CS5: + data_bits = LC_BITS5; break; + case CS6: + data_bits = LC_BITS6; break; + case CS7: + data_bits = LC_BITS7; break; + case CS8: + data_bits = LC_BITS8; break; + } + + error = scn_config (unit, t->c_ispeed, t->c_ospeed, parity, stop_bits, + data_bits); + + /* If successful, copy to tty */ + if (!error) { + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = cflag; + } + + return (error); +} + +void +scnstart(tp) + register struct tty *tp; +{ + int s, c; + int unit = UNIT(tp->t_dev); + register struct scn_softc *sc = scncd.cd_devs[unit]; + struct rs232_s *rs = &sc->scn_line; + + s = spltty(); + if (tp->t_state & (TS_BUSY|TS_TTSTOP)) + goto out; + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (tp->t_state&TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + if (tp->t_outq.c_cc == 0) + goto out; + tp->t_state |= TS_BUSY; + if (tx_rdy(rs)) { + c = getc(&tp->t_outq); + WR_ADR(u_char, rs->xmit_port, c); + tx_ints_on(rs); + } +out: + splx(s); +} + +/* + * Stop output on a line. + */ +/*ARGSUSED*/ +scnstop(tp, flag) + register struct tty *tp; +{ + register int s; + + s = spltty(); + if (tp->t_state & TS_BUSY) { + if ((tp->t_state&TS_TTSTOP)==0) + tp->t_state |= TS_FLUSH; + } + splx(s); +} + +/* + * Following are all routines needed for SCN to act as console + */ + +scncnprobe(cp) + struct consdev *cp; +{ + /* locate the major number */ + for (scnmajor = 0; scnmajor < nchrdev; scnmajor++) + if (cdevsw[scnmajor].d_open == scnopen) + break; + + /* make sure hardware exists? XXX */ + + /* initialize required fields */ + cp->cn_dev = makedev(scnmajor, SCN_CONSOLE); + cp->cn_pri = CN_NORMAL; + return 1; +} + +scncninit(cp) + struct consdev *cp; +{ +#if 0 + int unit = UNIT(cp->cn_dev); + + scninit(unit, scndefaultrate); + scnconsole = unit; + scnconsinit = 1; +#endif +} + +scninit(unit, rate) + int unit, rate; +{ +#if 0 + register int scn; + int s; + short stat; + +#ifdef lint + stat = unit; if (stat) return; +#endif + scn = scn_addr[unit]; + s = splhigh(); + outb(com+com_cfcr, CFCR_DLAB); + rate = ttspeedtab(comdefaultrate, comspeedtab); + outb(com+com_data, rate & 0xFF); + outb(com+com_ier, rate >> 8); + outb(com+com_cfcr, CFCR_8BITS); + outb(com+com_ier, IER_ERXRDY | IER_ETXRDY); + outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); + stat = inb(com+com_iir); + splx(s); +#endif +} + +#if 0 +int +scnselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + register struct tty *tp = scn_tty[UNIT(dev)]; + int nread; + int s = spltty(); + struct proc *selp; + + switch (rw) { + + case FREAD: + nread = ttnread(tp); + if (nread > 0 || + ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) + goto win; + selrecord(p, &tp->t_rsel); + break; + + case FWRITE: + if (tp->t_outq.c_cc <= tp->t_lowat) + goto win; + selrecord(p, &tp->t_wsel); + break; + } + splx(s); + return (0); + win: + splx(s); + return (1); +} +#endif + + +/* So the kernel can write in unmapped mode! */ +int _mapped = 0; + +/* + * Console kernel input character routine. + */ + +char +scncngetc(dev_t dev) +{ + char c; + int x = spltty(); + WR_ADR (u_char, SCN_FIRST_MAP_ADR + 14, (RTS_BIT | DTR_BIT)); + while (0 == (RD_ADR (u_char, SCN_CON_MAP_STAT) & SR_RX_RDY)); + c = RD_ADR(u_char, SCN_CON_MAP_DATA); + splx(x); + return c; +} + +/* pc532 does not turn off console polling. */ +char +scncnpollc(dev_t dev, int on) +{ +} + + +/* + * Console kernel output character routine. + */ + +/* A simple kernel level "more" for debugging output. */ +#ifdef KERN_MORE +int ___lines = 0; +#endif + +scncnputc (dev_t dev, char c) +{ + int x = spltty(); + + if (c == '\n') scncnputc(dev,'\r'); + if (_mapped) { + while (0 == (RD_ADR (u_char, SCN_CON_MAP_STAT) & SR_TX_RDY)); + WR_ADR (u_char, SCN_CON_MAP_DATA, c); + while (0 == (RD_ADR (u_char, SCN_CON_MAP_STAT) & SR_TX_RDY)); + RD_ADR(u_char, SCN_CON_MAP_ISR); + } else { + while (0 == (RD_ADR (u_char, SCN_CON_STAT) & SR_TX_RDY)); + WR_ADR (u_char, SCN_CON_DATA, c); + while (0 == (RD_ADR (u_char, SCN_CON_STAT) & SR_TX_RDY)); + RD_ADR(u_char, SCN_CON_ISR); + } +#ifdef KERN_MORE + if (c == '\n' && ___lines >= 0) + { + if (++___lines == 22) { + ___lines = 0; + scncnputc(dev,'m');scncnputc(dev,'o');scncnputc(dev,'r'); + scncnputc(dev,'e');scncnputc(dev,':');scncnputc(dev,' '); + scncngetc(dev); + scncnputc(dev,'\n'); + } + } +#endif + splx(x); +} + +#endif diff --git a/sys/arch/pc532/dev/scnreg.h b/sys/arch/pc532/dev/scnreg.h new file mode 100644 index 00000000000..569ce9c5db7 --- /dev/null +++ b/sys/arch/pc532/dev/scnreg.h @@ -0,0 +1,209 @@ +/* $NetBSD: scnreg.h,v 1.5 1994/10/26 08:24:19 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. + * + * scnreg.h: definitions for the scn serial driver. + */ + +/* Constants. */ +#ifdef COMDEF_SPEED +#undef TTYDEF_SPEED +#define TTYDEF_SPEED COMDEF_SPEED /* default baud rate */ +#endif + +#define SCN_FIRST_ADR 0x28000000 /* address of first RS232 port */ +#define SCN_FIRST_MAP_ADR 0xFFC80000 /* mapped address of first port */ + +#define SCN_SIZE 0x8 /* address space for port */ + +#define SCN_CONSOLE 0 /* minor number of console */ + +#define SCN_CON_MAP_STAT 0xFFC80001 /* raw addresses for console */ +#define SCN_CON_MAP_DATA 0xFFC80003 /* Mapped .... */ +#define SCN_CON_MAP_ISR 0xFFC80005 + +#define SCN_CON_STAT 0x28000001 /* raw addresses for console */ +#define SCN_CON_DATA 0x28000003 /* Unmapped .... */ +#define SCN_CON_ISR 0x28000005 + + +/* SCN2691 registers, values. */ +#define LINE_SZ 0x08 +#define UART_SZ 0x10 +#define MR_ADR (line_base+0) +#define STAT_ADR (line_base+1) +#define SPEED_ADR (line_base+1) +#define CMD_ADR (line_base+2) +#define DATA_ADR (line_base+3) +#define IPCR_ADR (uart_base+4) +#define ACR_ADR (uart_base+4) +#define ISR_ADR (uart_base+5) +#define IMR_ADR (uart_base+5) +#define IP_ADR (uart_base+13) +#define OPCR_ADR (uart_base+13) +#define SET_OP_ADR (uart_base+14) +#define CLR_OP_ADR (uart_base+15) + +/* Data Values */ +#define LC_ODD 0x04 +#define LC_EVEN 0x00 +#define LC_NONE 0x10 +#define LC_STOP1 0x07 +#define LC_STOP2 0x0f +#define LC_BITS5 0x00 +#define LC_BITS6 0x01 +#define LC_BITS7 0x02 +#define LC_BITS8 0x03 +#define LC_CHARS 0x03 +#define LC_CHARS_SHIFT 0x08 +#define LC_SP_GRP 0x10 +#define LC_SP_BOTH 0x20 + +#define RTS_BIT 0x1 +#define CTS_BIT 0x1 +#define DTR_BIT 0x4 +#define DCD_BIT 0x4 + +/* CR (command) register values. */ +#define CMD_ENA_RX 0x01 +#define CMD_DIS_RX 0x02 +#define CMD_ENA_TX 0x04 +#define CMD_DIS_TX 0x08 +#define CMD_MR1 0x10 +#define CMD_RESET_RX 0x20 +#define CMD_RESET_TX 0x30 +#define CMD_RESET_ERR 0x40 +#define CMD_RESET_BRK 0x50 +#define CMD_START_BRK 0x60 +#define CMD_STOP_BRK 0x70 + +/* SR register */ +#define SR_RX_RDY 0x01 +#define SR_TX_RDY 0x04 +#define SR_BREAK 0x80 +#define SR_FRAME 0x40 +#define SR_PARITY 0x20 +#define SR_OVERRUN 0x10 + +/* Output port configuration. */ +#define OPCR_CONFIG 0x00 + +/* Input port interrupt config. */ +#define ACR_CTS 0x01 +#define ACR_DCD 0x04 +#define IPCR_CTS 0x10 +#define IPCR_DCD 0x40 + +/* Interrupt configurations. */ +#define IMR_IP_INT 0x80 +#define IMR_BRK_INT 0x04 +#define IMR_RX_INT 0x02 +#define IMR_TX_INT 0x01 +#define IMR_BRKB_INT 0x40 +#define IMR_RXB_INT 0x20 +#define IMR_TXB_INT 0x10 + +/* If we need a delay.... */ +#define DELAY(x) {int i; for (i=0; i<x*10000; i++); } + +#define istart(rs) \ + (WR_ADR(u_char, rs->opset_port, (RTS_BIT | DTR_BIT) << (rs)->a_or_b)) + +#define istop(rs) \ + (WR_ADR(u_char, rs->opclr_port, RTS_BIT << (rs)->a_or_b)) + +#define get_dcd(rs) \ + (RD_ADR(u_char, rs->ip_port) & (DCD_BIT << (1-rs->a_or_b))) + +#define tx_rdy(rs) \ + (RD_ADR(u_char, rs->stat_port) & SR_TX_RDY) + +/* Interrupts on and off. */ +#define tx_ints_off(rs) \ + { rs->uart->imr_int_bits &= ~((IMR_TX_INT) << (4*rs->a_or_b)); \ + WR_ADR (u_char, rs->uart->imr_port, rs->uart->imr_int_bits); } + +#define tx_ints_on(rs) \ + { rs->uart->imr_int_bits |= (IMR_TX_INT) << (4*rs->a_or_b); \ + WR_ADR (u_char, rs->uart->imr_port, rs->uart->imr_int_bits); } + +#define rx_ints_off(rs) \ + { rs->uart->imr_int_bits &= ~((IMR_RX_INT) << (4*rs->a_or_b)); \ + WR_ADR (u_char, rs->uart->imr_port, rs->uart->imr_int_bits); } + +#define rx_ints_on(rs) \ + { rs->uart->imr_int_bits |= (IMR_RX_INT) << (4*rs->a_or_b); \ + WR_ADR (u_char, rs->uart->imr_port, rs->uart->imr_int_bits); } + +/* Structure definitions. */ +typedef unsigned long port_t; + +/* The DUART description table */ +struct duart_info { + char i_speed[2], o_speed[2]; /* Channel A and B speeds. */ + char i_code[2], o_code[2]; /* Channel A and B speeds. */ + char speed_grp; /* ACR bit 7 */ + char acr_int_bits; /* ACR bits 0-6 */ + char imr_int_bits; /* IMR bits current set. */ + + port_t isr_port; + port_t imr_port; + port_t ipcr_port; + port_t opcr_port; +}; + +/* RS232 device structure, one per device. */ +struct rs232_s { + int unit; /* unit number of this line (base 0) */ + struct duart_info *uart; /* pointer to uart struct */ + char a_or_b; /* 0 => A, 1 => B */ + + long scn_bits; /* Temp! for TIOCM ... */ + + port_t xmit_port; /* i/o ports */ + port_t recv_port; + port_t mr_port; + port_t stat_port; /* sra or srb */ + port_t speed_port; /* csra or csrb */ + port_t cmd_port; /* cra or crb */ + port_t acr_port; + port_t ip_port; + port_t opset_port; + port_t opclr_port; + + unsigned char lstatus; /* last line status */ + unsigned framing_errors; /* error counts (no reporting yet) */ + unsigned overrun_errors; + unsigned parity_errors; + unsigned break_interrupts; + +}; + diff --git a/sys/arch/pc532/include/ansi.h b/sys/arch/pc532/include/ansi.h new file mode 100644 index 00000000000..4251db0c798 --- /dev/null +++ b/sys/arch/pc532/include/ansi.h @@ -0,0 +1,74 @@ +/* $NetBSD: ansi.h,v 1.6 1994/10/26 08:24:21 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/pc532/include/asm.h b/sys/arch/pc532/include/asm.h new file mode 100644 index 00000000000..fbb3a42206a --- /dev/null +++ b/sys/arch/pc532/include/asm.h @@ -0,0 +1,116 @@ +/* $NetBSD: asm.h,v 1.5 1994/10/26 08:24:22 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + * File: asm.h + * Author: Johannes Helander, Tero Kivinen, Tatu Ylonen + * Modified by Phil Nelson for NetBSD. + * Modified by Matthias Pfaller for PIC. + * Helsinki University of Technology 1992. + */ + +#ifndef _MACHINE_ASM_H_ +#define _MACHINE_ASM_H_ + +#ifdef __STDC__ +#define CAT(a, b) a ## b +#define EX(x) _ ## x +#define LEX(x) _ ## x ## : +#else +#define CAT(a, b) a/**/b +#define EX(x) _/**/x +#define LEX(x) _/**/x/**/: +#endif + +#define FRAME enter [],0 +#define EMARF exit [] + +#if 1 /* DEBUG */ +#define DFRAME FRAME +#define DEMARF EMARF +#else +#define DFRAME +#define DEMARF +#endif + +#define S_ARG0 4(sp) +#define S_ARG1 8(sp) +#define S_ARG2 12(sp) +#define S_ARG3 16(sp) + +#define B_ARG0 8(fp) +#define B_ARG1 12(fp) +#define B_ARG2 16(fp) +#define B_ARG3 20(fp) + +#define ALIGN 0 + +#ifdef PIC +#define PIC_PROLOGUE \ + sprd sb,tos; \ + addr __GLOBAL_OFFSET_TABLE_(pc),r1; \ + lprd sb,r1 +#define PIC_EPILOGUE \ + lprd sb,tos +#define PIC_GOT(x) 0(x(sb)) + +#define PIC_S_ARG0 8(sp) +#define PIC_S_ARG1 12(sp) +#define PIC_S_ARG2 16(sp) +#define PIC_S_ARG3 20(sp) +#else +#define PIC_PROLOGUE +#define PIC_EPILOGUE +#define PIC_GOT(x) x(pc) + +#define PIC_S_ARG0 4(sp) +#define PIC_S_ARG1 8(sp) +#define PIC_S_ARG2 12(sp) +#define PIC_S_ARG3 16(sp) +#endif + +#ifdef PROF +#define MC1 .data; 1:; .long 0; .text +#define MC2 addr 1b(pc),r0; bsr mcount +#else +#define MC1 +#define MC2 +#endif + +#define DECL(x) MC1; .globl x; .type x,@function; .align ALIGN; CAT(x,:); MC2 + +#define ENTRY(x) DECL(EX(x)) +#define Entry(x) DECL(EX(x)) +#define ASENTRY(x) DECL(x) +#define ASMSTR .asciz + +#define SVC svc + +#endif diff --git a/sys/arch/pc532/include/cdefs.h b/sys/arch/pc532/include/cdefs.h new file mode 100644 index 00000000000..eb5deb6adbd --- /dev/null +++ b/sys/arch/pc532/include/cdefs.h @@ -0,0 +1,35 @@ +/* $NetBSD: cdefs.h,v 1.2 1995/03/23 20:10:38 jtc Exp $ */ + +/* + * Written by J.T. Conklin <jtc@wimsey.com> 01/17/95. + * Public domain. + */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#ifdef __STDC__ +#define _C_LABEL(x) _STRING(_ ## x) +#else +#define _C_LABEL(x) _STRING(_/**/x) +#endif + +#ifdef __GNUC__ +#ifdef __STDC__ +#define __indr_reference(sym,alias) \ + __asm__(".stabs \"_" #alias "\",11,0,0,0"); \ + __asm__(".stabs \"_" #sym "\",1,0,0,0") +#define __warn_references(sym,msg) \ + __asm__(".stabs \"" msg "\",30,0,0,0"); \ + __asm__(".stabs \"_" #sym "\",1,0,0,0") +#else +#define __indr_reference(sym,alias) \ + __asm__(".stabs \"_/**/alias\",11,0,0,0"); \ + __asm__(".stabs \"_/**/sym\",1,0,0,0") +#define __warn_references(sym,msg) \ + __asm__(".stabs msg,30,0,0,0"); \ + __asm__(".stabs \"_/**/sym\",1,0,0,0") +#endif +#endif + +#endif /* !_MACHINE_CDEFS_H_ */ diff --git a/sys/arch/pc532/include/cpu.h b/sys/arch/pc532/include/cpu.h new file mode 100644 index 00000000000..454bca5c00e --- /dev/null +++ b/sys/arch/pc532/include/cpu.h @@ -0,0 +1,119 @@ +/* $NetBSD: cpu.h,v 1.12 1995/06/28 02:55:56 cgd Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)cpu.h 5.4 (Berkeley) 5/9/91 + */ + +#ifndef _MACHINE_CPU_H_ +#define _MACHINE_CPU_H_ +/* + * Definitions unique to ns532 cpu support. + * + * modified from 386 code for the pc532 by Phil Nelson (12/92) + */ + +#include "machine/psl.h" +#include "machine/frame.h" + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define cpu_swapin(p) /* nothing */ +#define cpu_set_init_frame(p,fp) (p)->p_md.md_regs = fp +#define cpu_swapout(p) panic("cpu_swapout: can't get here"); + +/* XXX needed? PAN + * function vs. inline configuration; + * these are defined to get generic functions + * rather than inline or machine-dependent implementations + */ +#define NEED_MINMAX /* need {,i,l,ul}{min,max} functions */ +#define NEED_FFS /* need ffs function */ +#define NEED_BCMP /* need bcmp function */ +#define NEED_STRLEN /* need strlen function */ + +/* + * Arguments to hardclock, softclock and gatherstats + * encapsulate the previous machine state in an opaque + * clockframe; for now, use generic intrframe. + */ + +#define clockframe intrframe + +#define CLKF_USERMODE(framep) ((framep)->if_psr & PSR_USR) +#define CLKF_BASEPRI(framep) ((framep)->if_pl == imask[IPL_ZERO]) +#define CLKF_PC(framep) ((framep)->if_pc) +#define CLKF_INTR(frame) (0) /* XXX should have an interrupt stack */ + +#ifdef _KERNEL +#include <machine/icu.h> +#endif + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +int want_resched; /* resched() was called */ +#define need_resched() (want_resched = 1, setsoftast()) + +/* + * Give a profiling tick to the current process from the softclock + * interrupt. On the pc532, request an ast to send us through trap(), + * marking the proc as needing a profiling tick. + */ +#define profile_tick(p, framep) ((p)->p_flag |= P_OWEUPC, setsoftast()) +#define need_proftick(p) ((p)->p_flag |= P_OWEUPC, setsoftast()) + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) setsoftast() + +/* + * 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 diff --git a/sys/arch/pc532/include/db_machdep.h b/sys/arch/pc532/include/db_machdep.h new file mode 100644 index 00000000000..a20ea5465d0 --- /dev/null +++ b/sys/arch/pc532/include/db_machdep.h @@ -0,0 +1,131 @@ +/* $NetBSD: db_machdep.h,v 1.3 1994/10/26 08:24:24 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * HISTORY + * 11-May-92 Tero Kivinen (kivinen) at Helsinki University of Technology + * Created. + * + */ +/* + * File: ns532/db_machdep.h + * Author: Tero Kivinen, Helsinki University of Technology 1992. + * + * Machine-dependent defines for kernel debugger. + * + * modified by Phil Nelson for inclusion in 532bsd. + * + */ + +#ifndef _MACHINE_DB_MACHDEP_H_ +#define _MACHINE_DB_MACHDEP_H_ + +/* #include <mach/ns532/vm_types.h> */ +/* #include <mach/ns532/vm_param.h> */ +#include <vm/vm_prot.h> +#include <vm/vm_param.h> +#include <vm/vm_inherit.h> +#include <vm/lock.h> + +/* #include <ns532/thread.h> /* for thread_status */ +#include <machine/frame.h> /* For struct trapframe */ + +#include <machine/psl.h> +#include <machine/trap.h> + +typedef vm_offset_t db_addr_t; /* address - unsigned */ +typedef int db_expr_t; /* expression - signed */ + +typedef struct ns532_saved_state db_regs_t; +db_regs_t ddb_regs; /* register state */ +#define DDB_REGS (&ddb_regs) + +#define PC_REGS(regs) ((db_addr_t)(regs)->pc) + +#define BKPT_INST 0xf2 /* breakpoint instruction */ +#define BKPT_SIZE (1) /* size of breakpoint inst */ +#define BKPT_SET(inst) (BKPT_INST) + +/* #define FIXUP_PC_AFTER_BREAK ddb_regs.pc -= 1; */ + +#define db_clear_single_step(regs) ((regs)->psr &= ~PSR_T) +#define db_set_single_step(regs) ((regs)->psr |= PSR_T) + +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPT) +#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) + +#define I_BSR 0x02 +#define I_JSR 0x7f /* and low 3 bits of next byte are 0x6 */ +#define I_RET 0x12 +#define I_RETT 0x42 +#define I_RETI 0x52 + +#define inst_trap_return(ins) (((ins)&0xff) == I_RETT || \ + ((ins)&0xff) == I_RETI) +#define inst_return(ins) (((ins)&0xff) == I_RET) +#define inst_call(ins) (((ins)&0xff) == I_BSR || \ + (((ins)&0xff) == I_JSR && \ + ((ins)&0x0700) == 0x0600)) + +#define inst_load(ins) 0 +#define inst_store(ins) 0 + +extern int db_active_ipl; + +/* access capability and access macros */ + +#define DB_ACCESS_LEVEL 2 /* access any space */ +#define DB_CHECK_ACCESS(addr,size,task) \ + db_check_access(addr,size,task) +#define DB_PHYS_EQ(task1,addr1,task2,addr2) \ + db_phys_eq(task1,addr1,task2,addr2) +#define DB_VALID_KERN_ADDR(addr) \ + ((addr) >= VM_MIN_KERNEL_ADDRESS && \ + (addr) < VM_MAX_KERNEL_ADDRESS) +#define DB_VALID_ADDRESS(addr,user) \ + ((!(user) && DB_VALID_KERN_ADDR(addr)) || \ + ((user) && (addr) < VM_MIN_KERNEL_ADDRESS)) + +boolean_t db_check_access(/* vm_offset_t, int, task_t */); +boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */); + +/* macros for printing OS server dependent task name */ + +#define DB_TASK_NAME(task) db_task_name(task) +#define DB_TASK_NAME_TITLE "COMMAND " +#define DB_TASK_NAME_LEN 23 +#define DB_NULL_TASK_NAME "? " + +void db_task_name(/* task_t */); + +/* macro for checking if a thread has used floating point */ + +#define db_thread_fp_used(thread) ((thread)->pcb->fps && (thread)->pcb->fps->valid) + +#endif diff --git a/sys/arch/pc532/include/disklabel.h b/sys/arch/pc532/include/disklabel.h new file mode 100644 index 00000000000..0142c9807e4 --- /dev/null +++ b/sys/arch/pc532/include/disklabel.h @@ -0,0 +1,46 @@ +/* $NetBSD: disklabel.h,v 1.1 1994/10/14 18:27:14 cgd Exp $ */ + +/* + * Copyright (c) 1994 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_DISKLABEL_H_ +#define _MACHINE_DISKLABEL_H_ + +#define LABELSECTOR 0 /* sector containing label */ +#define LABELOFFSET 64 /* offset of label in sector */ +#define MAXPARTITIONS 8 /* number of partitions */ +#define RAW_PART 2 /* raw partition: xx?c */ + +/* Just a dummy */ +struct cpu_disklabel { + int cd_dummy; /* must have one element. */ +}; + +#endif /* _MACHINE_DISKLABEL_H_ */ diff --git a/sys/arch/pc532/include/endian.h b/sys/arch/pc532/include/endian.h new file mode 100644 index 00000000000..a9d8cb4d942 --- /dev/null +++ b/sys/arch/pc532/include/endian.h @@ -0,0 +1,127 @@ +/* $NetBSD: endian.h,v 1.8 1995/06/18 07:13:46 phil Exp $ */ + +/* + * Copyright (c) 1987, 1991 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 7.8 (Berkeley) 4/3/91 + */ + +#ifndef _PC532_ENDIAN_H_ +#define _PC532_ENDIAN_H_ + +/* + * 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, ns32000 */ +#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 + +#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 + + +#ifdef __GNUC__ + +#define __byte_swap_long_variable(x) \ +({ register unsigned long __x = (x); \ + __asm ("rotw 8,%1; rotd 16,%1; rotw 8,%1" \ + : "=r" (__x) \ + : "0" (__x)); \ + __x; }) + +#define __byte_swap_word_variable(x) \ +({ register unsigned short __x = (x); \ + __asm ("rotw 8,%1" \ + : "=r" (__x) \ + : "0" (__x)); \ + __x; }) + + +#ifdef __OPTIMIZE__ + +#define __byte_swap_long_constant(x) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#define __byte_swap_word_constant(x) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) +#define __byte_swap_long(x) \ + (__builtin_constant_p((x)) ? \ + __byte_swap_long_constant(x) : __byte_swap_long_variable(x)) +#define __byte_swap_word(x) \ + (__builtin_constant_p((x)) ? \ + __byte_swap_word_constant(x) : __byte_swap_word_variable(x)) + +#else /* __OPTIMIZE__ */ + +#define __byte_swap_long(x) __byte_swap_long_variable(x) +#define __byte_swap_word(x) __byte_swap_word_variable(x) + +#endif /* __OPTIMIZE__ */ + +#define ntohl(x) __byte_swap_long(x) +#define ntohs(x) __byte_swap_word(x) +#define htonl(x) __byte_swap_long(x) +#define htons(x) __byte_swap_word(x) + +#endif /* __GNUC__ */ + + +/* + * Macros for network/external number representation conversion. + */ +#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 /* _POSIX_SOURCE */ + +#endif /* _PC532_ENDIAN_H_ */ diff --git a/sys/arch/pc532/include/exec.h b/sys/arch/pc532/include/exec.h new file mode 100644 index 00000000000..ecbac2d452f --- /dev/null +++ b/sys/arch/pc532/include/exec.h @@ -0,0 +1,50 @@ +/* $NetBSD: exec.h,v 1.7 1994/10/26 08:24:26 cgd Exp $ */ + +/* + * Copyright (c) 1993 Paul Kranenburg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PC532_EXEC_H_ +#define _PC532_EXEC_H_ + +#define __LDPGSZ 4096 + +/* Relocation format. */ +struct relocation_info_pc532 { + int r_address; /* offset in text or data segment */ + unsigned int r_symbolnum : 22, /* ordinal number of add symbol */ + r_copy : 1, /* run time copy */ + r_relative : 1, /* load address relative */ + r_pcrel : 1, /* 1 if value should be pc-relative */ + r_length : 2, /* log base 2 of value's width */ + r_extern : 1, /* 1 if need to add symbol to value */ + r_jmptable : 1, /* relocate to jump table */ + r_disp : 2, /* ns32k data type */ + r_baserel : 1; /* linkage table relative */ +}; +#define relocation_info relocation_info_pc532 + +#endif /* _PC532_EXEC_H_ */ diff --git a/sys/arch/pc532/include/float.h b/sys/arch/pc532/include/float.h new file mode 100644 index 00000000000..740e82785d6 --- /dev/null +++ b/sys/arch/pc532/include/float.h @@ -0,0 +1,80 @@ +/* $NetBSD: float.h,v 1.7 1995/06/20 20:45:48 jtc Exp $ */ + +/* + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 7.1 (Berkeley) 5/8/90 + */ + +#ifndef _PC532_FLOAT_H_ +#define _PC532_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.2250738585072014E-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157E+308 +#define DBL_MAX_10_EXP 308 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP + +#endif /* _PC532_FLOAT_H_ */ diff --git a/sys/arch/pc532/include/frame.h b/sys/arch/pc532/include/frame.h new file mode 100644 index 00000000000..674f8eb7d5d --- /dev/null +++ b/sys/arch/pc532/include/frame.h @@ -0,0 +1,110 @@ +/* $NetBSD: frame.h,v 1.4 1994/10/26 08:24:28 cgd Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)frame.h 5.2 (Berkeley) 1/18/91 + */ + +#ifndef _MACHINE_FRAME_H_ +#define _MACHINE_FRAME_H_ + +#include <sys/signal.h> +#include <machine/reg.h> + +/* + * System stack frames. + */ + +/* + * Exception/Trap Stack Frame + */ + +struct trapframe { + long tf_msr; /* For abt. 0 for others. */ + long tf_tear; /* For abt. 0 for others. */ + long tf_trapno; + long tf_reg[8]; /* R7 - R0 from enter */ + long tf_usp; + long tf_sb; + long tf_fp; /* From enter */ + /* below portion defined in 532 hardware */ + long tf_pc; + u_short tf_mod; /* Not used in direct excption mode. */ + u_short tf_psr; +}; + +/* Interrupt stack frame */ + +struct intrframe { + long if_vec; + long if_pl; /* the "processor level" for clock. */ + long if_reg[8]; /* R7 - R0 from enter */ + long if_usp; + long if_sb; + long if_fp; /* From enter */ + /* below portion defined in 532 hardware */ + long if_pc; + u_short if_mod; /* Not used in direct excption mode. */ + u_short if_psr; +}; + +/* + * System Call Stack Frame + */ + +struct syscframe { + long sf_reg[8]; /* R7 - R0 from enter */ + long sf_usp; + long sf_sb; + long sf_fp; /* From enter */ + /* below portion defined in 532 hardware */ + long sf_pc; + u_short sf_mod; /* Not used in direct excption mode. */ + u_short sf_psr; +}; + +/* + * Signal frame + */ +struct sigframe { + int sf_signum; + int sf_code; + struct sigcontext *sf_scp; + sig_t sf_handler; + struct sigcontext sf_sc; +} ; + +#endif diff --git a/sys/arch/pc532/include/icu.h b/sys/arch/pc532/include/icu.h new file mode 100644 index 00000000000..e669036e5d1 --- /dev/null +++ b/sys/arch/pc532/include/icu.h @@ -0,0 +1,134 @@ +/* $NetBSD: icu.h,v 1.5 1995/08/25 07:52:18 phil 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. + * + * icu.h + */ + +/* icu.h: defines for use with the ns32532 icu. */ + +#ifndef _MACHINE_ICU_H_ +#define _MACHINE_ICU_H_ + +/* We don't use vector interrupts, but make it right anyway */ +#define VEC_ICU 0x10 + +/* The address of the ICU! */ +#define ICU_ADR 0xfffffe00 + +/* ICU clock speed. */ +#define ICU_CLK_HZ 3686400/4 /* raw ICU clock speed */ + +/* ICU registers + */ +#define HVCT 0 +#define SVCT 1 +#define ELTG 2 +#define TPL 4 +#define IPND 6 +#define ISRV 8 +#define IMSK 10 +#define CSRC 12 +#define FPRT 14 +#define MCTL 16 +#define OCASN 17 +#define CIPTR 18 +#define PDAT 19 +#define IPS 20 +#define PDIR 21 +#define CCTL 22 +#define CICTL 23 +#define LCSV 24 +#define HCSV 26 +#define LCCV 28 +#define HCCV 30 + +/* Byte and Word access to ICU registers + */ +#define ICUB(n) *((unsigned char *)(ICU_ADR + n)) +#define ICUW(n) *((unsigned short *)(ICU_ADR + n)) + +#ifndef LOCORE +/* Interrupt trigger modes + */ +enum {HIGH_LEVEL, LOW_LEVEL, RISING_EDGE, FALLING_EDGE} int_modes; +#endif /* !LOCORE */ + +/* Hardware interrupt request lines. + */ +#define IR_CLK 2 /* highest priority */ +#define IR_SCSI0 5 /* Adaptec 6250 */ +#define IR_SCSI1 4 /* NCR DP8490 */ +#define IR_TTY0 13 +#define IR_TTY0RDY 12 +#define IR_TTY1 11 +#define IR_TTY1RDY 10 +#define IR_TTY2 9 +#define IR_TTY2RDY 8 +#define IR_TTY3 7 +#define IR_TTY3RDY 6 + +/* edge polarity + * 0 0 falling edge + * 0 1 rising edge + * 1 0 low level + * 1 1 high level + * + */ +#define IEDGE 0 +#define IPOLARITY 0 + +#define ints_off bicpsrw PSR_I +#define ints_on bispsrw PSR_I + +/* SCSI controllers */ +#define AIC6250 0 +#define DP8490 1 +#define ICU_SCSI_BIT 0x80 + +#ifndef LOCORE +/* + * Select a SCSI controller. + */ +static __inline int +scsi_select_ctlr(int ctlr) +{ + int old; + + old = (ICUB(PDAT) & ICU_SCSI_BIT) == 0; + if (ctlr == DP8490) + ICUB(PDAT) &= ~ICU_SCSI_BIT; /* select = 0 for 8490 */ + else + ICUB(PDAT) |= ICU_SCSI_BIT; /* select = 1 for AIC6250 */ + return(old); +} +#endif /* !LOCORE */ +#endif /* _MACHINE_ICU_H_ */ diff --git a/sys/arch/pc532/include/ieeefp.h b/sys/arch/pc532/include/ieeefp.h new file mode 100644 index 00000000000..58a853dfa72 --- /dev/null +++ b/sys/arch/pc532/include/ieeefp.h @@ -0,0 +1,19 @@ +/* + * Written by J.T. Conklin, Apr 28, 1995 + * Public domain. + */ + +#ifndef _PC532_IEEEFP_H_ +#define _PC532_IEEEFP_H_ + +/* defined just to keep prototypes in machine independant header happy. */ +typedef int fp_except; + +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 /* _PC532_IEEEFP_H_ */ diff --git a/sys/arch/pc532/include/jmpbuf.h b/sys/arch/pc532/include/jmpbuf.h new file mode 100644 index 00000000000..4b477c7a3b5 --- /dev/null +++ b/sys/arch/pc532/include/jmpbuf.h @@ -0,0 +1,53 @@ +/* $NetBSD: jmpbuf.h,v 1.3 1994/10/26 08:24:30 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. + * + * + * machine/setjmp.h : for support of the library routines. + */ + +#ifndef _MACHINE_JMPBUF_H_ +#define _MACHINE_JMPBUF_H_ + +/* These are byte offsets into the jmp buffer. */ + +#define JMP_BUF_R3 0 +#define JMP_BUF_R4 4 +#define JMP_BUF_R5 8 +#define JMP_BUF_R6 12 +#define JMP_BUF_R7 16 +#define JMP_BUF_PC 20 +#define JMP_BUF_SP 24 +#define JMP_BUF_FP 28 +#define JMP_BUF_SB 32 +#define JMP_BUF_SIGMASK 36 + +#endif diff --git a/sys/arch/pc532/include/limits.h b/sys/arch/pc532/include/limits.h new file mode 100644 index 00000000000..4c53bb0489f --- /dev/null +++ b/sys/arch/pc532/include/limits.h @@ -0,0 +1,84 @@ +/* $NetBSD: limits.h,v 1.7 1994/10/26 08:24:31 cgd Exp $ */ + +/* + * Copyright (c) 1988 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 7.2 (Berkeley) 6/28/90 + */ + +#define CHAR_BIT 8 /* number of bits in a char */ +#define MB_LEN_MAX 1 /* no multibyte characters */ + +#define SCHAR_MIN (-0x7f-1) /* min value for a signed char */ +#define SCHAR_MAX 0x7f /* max value for a signed char */ + +#define UCHAR_MAX 0xff /* max value for an unsigned char */ +#define CHAR_MAX 0x7f /* max value for a char */ +#define CHAR_MIN (-0x7f-1) /* min value for a char */ + +#define USHRT_MAX 0xffff /* max value for an unsigned short */ +#define SHRT_MAX 0x7fff /* max value for a short */ +#define SHRT_MIN (-0x7fff-1) /* min value for a short */ + +#define UINT_MAX 0xffffffff /* max value for an unsigned int */ +#define INT_MAX 0x7fffffff /* max value for an int */ +#define INT_MIN (-0x7fffffff-1) /* min value for an int */ + +#define ULONG_MAX 0xffffffffUL /* max value for an unsigned long */ +#define LONG_MAX 0x7fffffff /* max value for a long */ +#define LONG_MIN (-0x7fffffff-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 */ + +#define UQUAD_MAX 0xffffffffffffffffULL /* max unsigned quad */ +#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */ +#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */ + +#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_MIN 2.2250738585072014E-308 +#define DBL_MAX 1.7976931348623157E+308 + +#define FLT_DIG 6 +#define FLT_MAX 3.40282347E+38F +#define FLT_MIN 1.17549435E-38F +#endif diff --git a/sys/arch/pc532/include/mtpr.h b/sys/arch/pc532/include/mtpr.h new file mode 100644 index 00000000000..c487c474e9f --- /dev/null +++ b/sys/arch/pc532/include/mtpr.h @@ -0,0 +1,3 @@ +/* $NetBSD: mtpr.h,v 1.3 1994/10/26 08:24:32 cgd Exp $ */ + +/* EMPTY */ diff --git a/sys/arch/pc532/include/param.h b/sys/arch/pc532/include/param.h new file mode 100644 index 00000000000..2be9a2d4889 --- /dev/null +++ b/sys/arch/pc532/include/param.h @@ -0,0 +1,169 @@ +/* $NetBSD: param.h,v 1.12 1995/06/26 06:56:05 cgd Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)param.h 5.8 (Berkeley) 6/28/91 + */ + +/* + * Machine dependent constants for NS 32532. + * + * Derived from the i386 param.h by Phil Nelson. + * + */ + +#ifndef _MACHINE_PARAM_H_ +#define _MACHINE_PARAM_H_ + +#ifdef _KERNEL +#include <machine/cpu.h> +#endif + +#define MACHINE "pc532" +#define MACHINE_ARCH "ns32k" +#define MID_MACHINE MID_NS32532 + +/* + * 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 (sizeof(int) - 1) +#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/(sizeof (struct pte))) + +#define NBPDR (1024*NBPG) /* bytes/page dir */ +#define PDROFSET (NBPDR-1) /* byte offset into page dir */ +#define PDRSHIFT 22 /* LOG2(NBPDR) */ + +#define KERNBASE 0xFE000000 /* start of kernel virtual */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define DEV_BSIZE 512 +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define BLKDEV_IOSIZE 4096 /* Was 2048 (pan) */ +#define MAXPHYS (64 * 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 USPACE (UPAGES * NBPG) + +/* + * 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. + */ +#ifndef MSIZE +#define MSIZE 128 /* size of an mbuf */ +#endif /* MSIZE */ + +#ifndef MCLSHIFT +#define MCLSHIFT 11 /* convert bytes to m_buf clusters */ +#endif /* MCLSHIFT */ +#define MCLBYTES (1 << MCLSHIFT) /* size of a m_buf cluster */ +#define MCLOFSET (MCLBYTES - 1) /* offset within a m_buf cluster */ + +#ifndef NMBCLUSTERS +#define NMBCLUSTERS 512 /* map size, max cluster allocation */ +#endif + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (2048*1024/CLBYTES) +#endif + +/* + * Some macros for units conversion + */ + +/* pages ("clicks") to disk blocks */ +#define ctod(x) ((x) << (PGSHIFT - DEV_BSHIFT)) +#define dtoc(x) ((x) >> (PGSHIFT - DEV_BSHIFT)) + +/* clicks 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 will be if we + * add an entry to cdevsw/bdevsw for that purpose. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE)) + + +/* + * Mach derived conversion macros + */ +#define ns532_round_pdr(x) ((((unsigned)(x)) + NBPDR - 1) & ~(NBPDR-1)) +#define ns532_trunc_pdr(x) ((unsigned)(x) & ~(NBPDR-1)) +#define ns532_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1)) +#define ns532_trunc_page(x) ((unsigned)(x) & ~(NBPG-1)) +#define ns532_btod(x) ((unsigned)(x) >> PDRSHIFT) +#define ns532_dtob(x) ((unsigned)(x) << PDRSHIFT) +#define ns532_btop(x) ((unsigned)(x) >> PGSHIFT) +#define ns532_ptob(x) ((unsigned)(x) << PGSHIFT) + +#ifndef _KERNEL +#define DELAY(n) { volatile int N = (n); while (--N > 0); } +#endif + +/* Macros to read and write from absolute addresses. */ + +#define WR_ADR(type,adr,val) (*((volatile type *)(adr))=(val)) +#define RD_ADR(type,adr) (*((volatile type *)(adr))) + +#endif diff --git a/sys/arch/pc532/include/pcb.h b/sys/arch/pc532/include/pcb.h new file mode 100644 index 00000000000..e9ed77517f0 --- /dev/null +++ b/sys/arch/pc532/include/pcb.h @@ -0,0 +1,98 @@ +/* $NetBSD: pcb.h,v 1.6 1995/03/28 18:18:24 jtc Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)pcb.h 5.10 (Berkeley) 5/12/91 + */ + +#ifndef _MACHINE_PCB_H_ +#define _MACHINE_PCB_H_ + +/* + * PC 532 process control block + * + * Phil Nelson, 12/8/92 + * + */ + +/* The registers as pushed from a trap/interrupt with the + exception of USP and SB, and they are placed by software. */ +struct on_stack { + long pcb_reg[8]; /* R7 - R0 from enter */ + long pcb_usp; /* User stack pointer, by software. */ + long pcb_sb; /* Static Base pointer, by software. */ + long pcb_fp; /* From enter */ + long pcb_pc; /* From the trap/interrupt */ + u_short pcb_mod; /* in direct exception mode. */ + u_short pcb_psr; +}; + +struct pcb { + /* Put in a pointer to the trap/interrupt frame. */ + struct on_stack *pcb_onstack; + + /* Floating point stuff */ + long pcb_fsr; /* fpu status reg */ + double pcb_freg[8]; /* F0 - F7 */ + + /* Saved during a "swtch" */ + + long pcb_ksp; /* Kernel stack -- sp0. */ + long pcb_kfp; /* Kernel fp. */ + long pcb_ptb; /* ptb0 */ + long pcb_pl; /* "processor level" */ + +/* + * Software pcb (extension) + */ + u_short pcb_flags; /* Used? PAN */ + caddr_t pcb_onfault; /* copyin/out fault recovery */ +}; + +/* + * The pcb is augmented with machine-dependent additional data for + * core dumps. For the pc532, there is nothing to add. + */ +struct md_coredump { + long md_pad[8]; +}; + + +#ifdef _KERNEL +struct pcb *curpcb; /* our current running pcb */ +#endif + +#endif diff --git a/sys/arch/pc532/include/pmap.h b/sys/arch/pc532/include/pmap.h new file mode 100644 index 00000000000..5e198f27d3e --- /dev/null +++ b/sys/arch/pc532/include/pmap.h @@ -0,0 +1,241 @@ +/* $NetBSD: pmap.h,v 1.7 1995/05/11 16:53:07 jtc Exp $ */ + +/* + * Copyright (c) 1991 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 William Jolitz of UUNET Technologies 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. + * + * @(#)pmap.h 7.4 (Berkeley) 5/12/91 + */ + +/* + * Derived from hp300 version by Mike Hibler, this version by William + * Jolitz uses a recursive map [a pde points to the page directory] to + * map the page tables using the pagetables themselves. This is done to + * reduce the impact on kernel virtual memory for lots of sparse address + * space, and to reduce the cost of memory to each process. + * + * from hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90 + */ + +#ifndef _MACHINE_PMAP_H_ +#define _MACHINE_PMAP_H_ + +/* + * 532 page table entry and page table directory + * Phil Nelson, 12/92 + * + * modified from the 386 stuff by W.Jolitz, 8/89 + */ + +struct pde /* First level PTE */ +{ +unsigned long + pd_v:1, /* valid bit */ + pd_prot:2, /* access control */ + pd_mbz1:4, /* reserved, must be zero */ + pd_u:1, /* hardware maintained 'used' bit */ + pd_mbz2:1, /* reserved, must be zero */ + :3, /* reserved for software */ + pd_pfnum:20; /* physical page frame number of pte's*/ +}; + +#define PD_MASK 0xffc00000 /* page directory address bits */ +#define PT_MASK 0x003ff000 /* page table address bits */ +#define PD_SHIFT 22 /* page directory address shift */ +#define PG_SHIFT 12 /* page table address shift */ + +struct pte +{ +unsigned int + pg_v:1, /* valid bit */ + pg_prot:2, /* access control */ + pg_mbz1:3, /* reserved, must be zero */ + pg_nc:1, /* 'uncacheable page' bit */ + pg_u:1, /* hardware maintained 'used' bit */ + pg_m:1, /* hardware maintained modified bit */ + pg_w:1, /* software, wired down page */ + :2, /* software (unused) */ + pg_pfnum:20; /* physical page frame number */ +}; + +#define PG_V 0x00000001 +#define PG_RO 0x00000000 +#define PG_RW 0x00000002 +#define PG_u 0x00000004 +#define PG_PROT 0x00000006 /* all protection bits . */ +#define PG_W 0x00000200 /* Wired bit (user def) */ +#define PG_N 0x00000040 /* Non-cacheable */ +#define PG_M 0x00000100 +#define PG_U 0x00000080 +#define PG_FRAME 0xfffff000 + + +#define PG_NOACC 0 +#define PG_KR 0x00000000 +#define PG_KW 0x00000002 +#define PG_URKR 0x00000004 +#define PG_URKW 0x00000004 +#define PG_UW 0x00000006 + +/* Garbage for current bastardized pager that assumes a hp300 */ +#define PG_NV 0 +#define PG_CI 0 + +/* + * Page Protection Exception bits + */ + +#define PGEX_TEX 0x03 /* Which exception. */ +#define PGEX_DDT 0x04 /* Data direction: 0 => read */ +#define PGEX_UST 0x08 /* user/super 0 => supervisor */ +#define PGEX_STT 0xf0 /* CPU status. */ + +#define PGEX_P PGEX_TEX /* Protection violation vs. not present */ +#define PGEX_W PGEX_DDT /* during a Write cycle */ +#define PGEX_U PGEX_UST /* access from User mode (UPL) */ + +typedef struct pde pd_entry_t; /* page directory entry */ +typedef struct pte pt_entry_t; /* Mach page table entry */ + +/* + * One page directory, shared between + * kernel and user modes. + */ +#define NS532_PAGE_SIZE NBPG +#define NS532_PDR_SIZE NBPDR + +#define NS532_KPDES 8 /* KPT page directory size */ +#define NS532_UPDES NBPDR/sizeof(struct pde)-8 /* UPT page directory size */ + +#define UPTDI 0x3f6 /* ptd entry for u./kernel&user stack */ +#define PTDPTDI 0x3f7 /* ptd entry that points to ptd! */ +#define KPTDI_FIRST 0x3f8 /* start of kernel virtual pde's */ +#define KPTDI_LAST 0x3ff /* last of kernel virtual pde's */ + +/* + * Address of current and alternate address space page table maps + * and directories. + */ +#ifdef _KERNEL +extern struct pte PTmap[], APTmap[], Upte; +extern struct pde PTD[], APTD[], PTDpde, APTDpde, Upde; +extern pt_entry_t *Sysmap; + +extern int IdlePTD; /* physical address of "Idle" state directory */ +#endif + +/* + * virtual address to page table entry and + * to physical address. Likewise for alternate address space. + * Note: these work recursively, thus vtopte of a pte will give + * the corresponding pde that in turn maps it. + */ +#define vtopte(va) (PTmap + ns532_btop(va)) +#define kvtopte(va) vtopte(va) +#define ptetov(pt) (ns532_ptob(pt - PTmap)) +#define vtophys(va) (ns532_ptob(vtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET)) +#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS) + +#define avtopte(va) (APTmap + ns532_btop(va)) +#define ptetoav(pt) (NS532_ptob(pt - APTmap)) +#define avtophys(va) (ns532_ptob(avtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET)) + +/* + * macros to generate page directory/table indicies + */ + +#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT) +#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT) + +/* + * Pmap stuff + */ + +struct pmap { + pd_entry_t *pm_pdir; /* KVA of page directory */ + boolean_t pm_pdchanged; /* pdir changed */ + short pm_dref; /* page directory ref count */ + short pm_count; /* pmap reference count */ + simple_lock_data_t pm_lock; /* lock on pmap */ + struct pmap_statistics pm_stats; /* pmap statistics */ + long pm_ptpages; /* more stats: PT pages */ +}; + +typedef struct pmap *pmap_t; + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmapp, pcbp) \ + if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \ + (pcbp)->pcb_ptb = \ + pmap_extract(pmap_kernel(),(vm_offset_t)(pmapp)->pm_pdir); \ + if ((pmapp) == &curproc->p_vmspace->vm_pmap) \ + _load_ptb0((pcbp)->pcb_ptb); \ + (pmapp)->pm_pdchanged = FALSE; \ + } + +#define PMAP_DEACTIVATE(pmapp, pcbp) + +/* + * 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. + */ +typedef struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + pmap_t pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + int pv_flags; /* flags */ +} *pv_entry_t; + +#define PV_ENTRY_NULL ((pv_entry_t) 0) + +#define PV_CI 0x01 /* all entries must be cache inhibited */ +#define PV_PTPAGE 0x02 /* entry maps a page table page */ + +#ifdef _KERNEL + +pv_entry_t pv_table; /* array of entries, one per page */ +struct pmap kernel_pmap_store; + +#define pa_index(pa) atop(pa - vm_first_phys) +#define pa_to_pvh(pa) (&pv_table[pa_index(pa)]) + +#define pmap_kernel() (&kernel_pmap_store) +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) + +#endif /* _KERNEL */ + +#endif diff --git a/sys/arch/pc532/include/proc.h b/sys/arch/pc532/include/proc.h new file mode 100644 index 00000000000..c4a53bfb776 --- /dev/null +++ b/sys/arch/pc532/include/proc.h @@ -0,0 +1,48 @@ +/* $NetBSD: proc.h,v 1.4 1994/10/26 08:24:37 cgd Exp $ */ + +/* + * Copyright (c) 1991 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. + * + * @(#)proc.h 7.1 (Berkeley) 5/15/91 + */ + +#ifndef _MACHINE_PROC_H_ +#define _MACHINE_PROC_H_ + +/* + * Machine-dependent part of the proc structure for the pc532. + */ +struct mdproc { + int *md_regs; /* pointer to regs on the stack */ +}; + +#endif diff --git a/sys/arch/pc532/include/profile.h b/sys/arch/pc532/include/profile.h new file mode 100644 index 00000000000..5f8490ad786 --- /dev/null +++ b/sys/arch/pc532/include/profile.h @@ -0,0 +1,70 @@ +/* $NetBSD: profile.h,v 1.4 1995/03/28 18:18:30 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. + * + * @(#)profile.h 8.1 (Berkeley) 6/11/93 + */ + +/* pc532 version, 5/15/94. + */ + +#define _MCOUNT_DECL static inline void _mcount + +#define MCOUNT \ +extern void mcount() asm("mcount"); \ +void \ +mcount() \ +{ \ + int selfpc, frompcindex; \ + /* \ + * find the return address for mcount, \ + * and the return address for mcount's caller. \ + * \ + * selfpc = pc pushed by mcount call \ + */ \ + asm("movd 4(fp),%0" : "=r" (selfpc)); \ + /* \ + * frompcindex = pc pushed by call into self. \ + */ \ + asm("movd 4(0(fp)),%0" : "=r" (frompcindex)); \ + _mcount(frompcindex, selfpc); \ +} + +#ifdef _KERNEL +/* + * Note that we assume splhigh() and splx() cannot call mcount() + * recursively. + */ +#define MCOUNT_ENTER s = splhigh() +#define MCOUNT_EXIT splx(s) +#endif /* _KERNEL */ diff --git a/sys/arch/pc532/include/psl.h b/sys/arch/pc532/include/psl.h new file mode 100644 index 00000000000..e9bbaca6d68 --- /dev/null +++ b/sys/arch/pc532/include/psl.h @@ -0,0 +1,240 @@ +/* $NetBSD: psl.h,v 1.13 1995/09/26 20:16:21 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)psl.h 5.2 (Berkeley) 1/18/91 + */ + +#ifndef _MACHINE_PSL_H_ +#define _MACHINE_PSL_H_ + +/* + * 32532 processor status longword. + */ +#define PSL_C 0x00000001 /* carry bit */ +#define PSL_T 0x00000002 /* trace enable bit */ +#define PSL_L 0x00000004 /* less bit */ +#define PSL_V 0x00000010 /* overflow bit */ +#define PSL_F 0x00000020 /* flag bit */ +#define PSL_Z 0x00000040 /* zero bit */ +#define PSL_N 0x00000080 /* negative bit */ + +#define PSL_USER 0x00000100 /* User mode bit */ +#define PSL_US 0x00000200 /* User stack mode bit */ +#define PSL_P 0x00000400 /* Prevent TRC trap */ +#define PSL_I 0x00000800 /* interrupt enable bit */ + +#define PSL_USERSET (PSL_USER | PSL_US | PSL_I) +#define PSL_USERSTATIC (PSL_USER | PSL_US | PSL_I) + +/* The PSR versions ... */ +#define PSR_USR PSL_USER + +#ifdef _KERNEL +#include <machine/icu.h> +/* + * Interrupt levels + */ +#define IPL_NONE -1 +#define IPL_ZERO 0 /* level 0 */ +#define IPL_BIO 1 /* block I/O */ +#define IPL_NET 2 /* network */ +#define IPL_TTY 3 /* terminal */ +#define IPL_CLOCK 4 /* clock */ +#define IPL_IMP 5 /* memory allocation */ +#define NIPL 6 /* number of interrupt priority levels */ +#define IPL_NAMES {"zero", "bio", "net", "tty", "clock", "imp"} + +/* + * Preassigned software interrupts + */ +#define SOFTINT 16 +#define SIR_CLOCK (SOFTINT+0) +#define SIR_CLOCKMASK (1 << SIR_CLOCK) +#define SIR_NET (SOFTINT+1) +#define SIR_NETMASK ((1 << SIR_NET) | SIR_CLOCKMASK) +#define SIR_ALLMASK 0xffff0000 + +#ifndef LOCORE +/* + * Structure of the software interrupt table + */ +struct iv { + void (*iv_vec)(); + void *iv_arg; + int iv_cnt; + char *iv_use; +}; + +extern unsigned int imask[], Cur_pl, idisabled, sirpending, astpending; +extern void intr_init(); +extern void check_sir(); +extern int intr_establish(int, void (*)(), void *, char *, int, int); +extern struct iv ivt[]; + +/* + * Disable/Enable CPU-Interrupts + */ +#define di() /* Removing the nop will give you *BIG* trouble */ \ + __asm __volatile("bicpsrw 0x800 ; nop" : : : "cc") +#define ei() __asm __volatile("bispsrw 0x800" : : : "cc") + +/* + * Globaly disable/enable specific interrupts + * (overriding spl0) + */ +#define intr_disable(ir) do { \ + di(); \ + ICUW(IMSK) = Cur_pl | (idisabled |= (1 << ir)); \ + ei(); \ + } while(0) + +#define intr_enable(ir) do { \ + di(); \ + ICUW(IMSK) = Cur_pl | (idisabled &= ~(1 << ir)); \ + ei(); \ + } while(0) + +/* + * Add a mask to Cur_pl, and return the old value of Cur_pl. + */ +#if !defined(NO_INLINE_SPLX) || defined(DEFINE_SPLX) +# ifndef NO_INLINE_SPLX +static __inline +# endif +int +splraise(register int ncpl) +{ + register int ocpl; + di(); + ocpl = Cur_pl; + ncpl |= ocpl; + ICUW(IMSK) = ncpl | idisabled; + Cur_pl = ncpl; + ei(); + return(ocpl); +} + +/* + * Restore a value to Cur_pl (unmasking interrupts). + * + * NOTE: We go to the trouble of returning the old value of cpl for + * the benefit of some splsoftclock() callers. This extra work is + * usually optimized away by the compiler. + */ +# ifndef DEFINE_SPLX +static +# endif +# ifndef NO_INLINE_SPLX +__inline +# endif +int +splx(register int ncpl) +{ + register int ocpl; + di(); + ocpl = Cur_pl; + ICUW(IMSK) = ncpl | idisabled; + Cur_pl = ncpl; + if (sirpending && ncpl == imask[IPL_ZERO]) { + Cur_pl |= SIR_ALLMASK; + check_sir(); + Cur_pl = ncpl; + } + ei(); + return (ocpl); +} + +/* + * This special version of splx returns with interrupts disabled. + */ +# ifdef DEFINE_SPLX +int +splx_di(register int ncpl) +{ + register int ocpl; + di(); + ocpl = Cur_pl; + ICUW(IMSK) = ncpl | idisabled; + Cur_pl = ncpl; + if (sirpending && ncpl == imask[IPL_ZERO]) { + Cur_pl |= SIR_ALLMASK; + check_sir(); + Cur_pl = ncpl; + } + return (ocpl); +} +# endif +#endif + +/* + * Hardware interrupt masks + */ +#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() splx(SIR_CLOCKMASK|imask[IPL_ZERO]) +#define splsoftnet() splraise(SIR_NETMASK) + +/* + * Miscellaneous + */ +#define splhigh() splraise(-1) +#define spl0() splx(imask[IPL_ZERO]) +#define splnone() spl0() + +/* + * Software interrupt registration + */ +#define softintr(n) (sirpending |= (1 << (n))) +#define setsoftast() (astpending = 1) +#define setsoftclock() softintr(SIR_CLOCK) +#define setsoftnet() softintr(SIR_NET) + +#endif /* !LOCORE */ +#endif /* _KERNEL */ + +#endif /* _MACHINE_PSL_H_ */ diff --git a/sys/arch/pc532/include/ptrace.h b/sys/arch/pc532/include/ptrace.h new file mode 100644 index 00000000000..395182d4bc4 --- /dev/null +++ b/sys/arch/pc532/include/ptrace.h @@ -0,0 +1,40 @@ +/* $NetBSD: ptrace.h,v 1.6 1995/07/28 08:00:17 phil Exp $ */ + +/* + * Copyright (c) 1993 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 withough 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. + */ + +/* + * pc532-dependent ptrace definitions + */ +#define PT_STEP (PT_FIRSTMACH + 0) +#define PT_GETREGS (PT_FIRSTMACH + 1) +#define PT_SETREGS (PT_FIRSTMACH + 2) +#define PT_GETFPREGS (PT_FIRSTMACH + 3) +#define PT_SETFPREGS (PT_FIRSTMACH + 4) diff --git a/sys/arch/pc532/include/reg.h b/sys/arch/pc532/include/reg.h new file mode 100644 index 00000000000..49c87ea3967 --- /dev/null +++ b/sys/arch/pc532/include/reg.h @@ -0,0 +1,96 @@ +/* $NetBSD: reg.h,v 1.10 1995/08/29 22:40:59 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)reg.h 5.5 (Berkeley) 1/18/91 + */ + +/* Modified for the pc532... 2/1/93 by Phil Nelson + */ + +#ifndef _MACHINE_REG_H_ +#define _MACHINE_REG_H_ + +/* + * Location of the users' stored + * registers within appropriate frame of 'trap' and 'syscall', relative to + * base of stack frame. + * Normal usage is u.u_ar0[XX] in kernel. + */ + +/* When referenced during a trap/exception and a syscall, + registers are at these offsets from p-p_regs*/ + +#define REG_R0 (7) +#define REG_R1 (6) +#define REG_R2 (5) +#define REG_R3 (4) +#define REG_R4 (3) +#define REG_R5 (2) +#define REG_R6 (1) +#define REG_R7 (0) + +#define REG_SP (8) +#define REG_SB (9) +#define REG_FP (10) +#define REG_PC (11) +#define REG_PSR (12) + +/* The reg struct .. in the order of above. */ + +struct reg { + int r_r7; + int r_r6; + int r_r5; + int r_r4; + int r_r3; + int r_r2; + int r_r1; + int r_r0; + + int r_sp; + int r_sb; + int r_fp; + int r_pc; + short r_mod; + short r_psr; +}; + +struct fpreg { + int r_fsr; + double r_freg[8]; +}; +#endif /* _MACHINE_REG_H_ */ diff --git a/sys/arch/pc532/include/setjmp.h b/sys/arch/pc532/include/setjmp.h new file mode 100644 index 00000000000..5a080a0ab7c --- /dev/null +++ b/sys/arch/pc532/include/setjmp.h @@ -0,0 +1,7 @@ +/* $NetBSD: setjmp.h,v 1.1 1994/12/20 10:37:01 cgd Exp $ */ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + */ + +#define _JBLEN 10 /* size, in longs, of a jmp_buf */ diff --git a/sys/arch/pc532/include/signal.h b/sys/arch/pc532/include/signal.h new file mode 100644 index 00000000000..810bfd6c45a --- /dev/null +++ b/sys/arch/pc532/include/signal.h @@ -0,0 +1,68 @@ +/* $NetBSD: signal.h,v 1.5 1995/01/10 19:01:36 jtc Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989, 1991 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. + * + * @(#)signal.h 7.16 (Berkeley) 3/17/91 + */ + +#ifndef _MACHINE_SIGNAL_H_ +#define _MACHINE_SIGNAL_H_ + +typedef int sig_atomic_t; + +#ifndef _ANSI_SOURCE +/* + * Get the "code" values + */ +#include <machine/trap.h> + +/* + * 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_sp; /* sp to restore */ + int sc_fp; /* fp to restore */ + int sc_sb; /* sb to restore */ + int sc_pc; /* pc to restore */ + int sc_ps; /* psl to restore */ + int sc_reg[8]; /* The registers */ +}; + +#endif /* !_ANSI_SOURCE */ +#endif /* !_MACHINE_SIGNAL_H_ */ diff --git a/sys/arch/pc532/include/stdarg.h b/sys/arch/pc532/include/stdarg.h new file mode 100644 index 00000000000..32a97df670c --- /dev/null +++ b/sys/arch/pc532/include/stdarg.h @@ -0,0 +1,61 @@ +/* $NetBSD: stdarg.h,v 1.9 1995/03/28 18:18:36 jtc Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)stdarg.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _PC532_STDARG_H_ +#define _PC532_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 += __va_promote(type), ap - __va_promote(type)))[0] +#endif + +#define va_end(ap) ((void) 0) + +#endif /* !_PC532_STDARG_H_ */ diff --git a/sys/arch/pc532/include/trap.h b/sys/arch/pc532/include/trap.h new file mode 100644 index 00000000000..034423fa8ea --- /dev/null +++ b/sys/arch/pc532/include/trap.h @@ -0,0 +1,91 @@ +/* $NetBSD: trap.h,v 1.3 1994/10/26 08:24:44 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ns532/trap.h + * Author: Tatu Ylonen, Helsinki University of Technology 1992. + * Modified for NetBSD by Phil Nelson + * Hardware trap vectors for ns532. + */ + +#ifndef _MACHINE_TRAP_H_ +#define _MACHINE_TRAP_H_ + +#define T_NVI 0 /* non-vectored interrupt */ +#define T_NMI 1 /* non-maskable interrupt */ +#define T_ABT 2 /* abort */ +#define T_SLAVE 3 /* coprocessor trap */ +#define T_ILL 4 /* illegal operation in user mode */ +#define T_SVC 5 /* supervisor call */ +#define T_DVZ 6 /* divide by zero */ +#define T_FLG 7 /* flag instruction */ +#define T_BPT 8 /* breakpoint instruction */ +#define T_TRC 9 /* trace trap */ +#define T_UND 10 /* undefined instruction */ +#define T_RBE 11 /* restartable bus error */ +#define T_NBE 12 /* non-restartable bus error */ +#define T_OVF 13 /* integer overflow trap */ +#define T_DBG 14 /* debug trap */ +#define T_RESERVED 15 /* reserved */ + +/* Not a real trap. */ +#define T_WATCHPOINT 17 /* watchpoint */ + +/* To allow for preemption */ +#define T_INTERRUPT 18 /* trap code from interrupt! */ + +/* To include system/user mode in the trap information. */ +#define T_USER 32 + +#define PARRDU_PHYS 0x28000040 /* Read parity error */ +#define PARCLU_PHYS 0x28000050 /* Clear parity error */ + +#define PARRDU_VM 0xFFC80040 /* Read parity error */ +#define PARCLU_VM 0xFFC80050 /* Clear parity error */ + +/* memory management status register bits and meanings. */ +#define MSR_STT 0xf0 /* CPU status. */ +#define STT_SEQ_INS 0x80 /* Sequential instruction fetch */ +#define STT_NSQ_INS 0x90 /* Non-sequential instruction fetch */ +#define STT_DATA 0xa0 /* Data transfer */ +#define STT_RMW 0xb0 /* Read/modify/write */ +#define STT_REA 0xc0 /* Read for effective address */ + +#define MSR_UST 0x08 /* User/supervisor */ +#define UST_USER 0x08 /* User mode is 1. Super = 0 */ + +#define MSR_DDT 0x04 /* Data Direction */ +#define DDT_WRITE 0x04 /* Write is 1. Read is 0 */ + +#define MSR_TEX 0x03 /* Exception kind. */ +#define TEX_PTE1 0x01 /* First level PTE invalid */ +#define TEX_PTE2 0x02 /* Second level PTE invalid */ +#define TEX_PROT 0x03 /* Protection violation */ + +#endif diff --git a/sys/arch/pc532/include/types.h b/sys/arch/pc532/include/types.h new file mode 100644 index 00000000000..c048c9ae906 --- /dev/null +++ b/sys/arch/pc532/include/types.h @@ -0,0 +1,74 @@ +/* $NetBSD: types.h,v 1.11 1995/08/25 07:52:20 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 7.5 (Berkeley) 3/9/91 + */ + +#ifndef _MACHINE_TYPES_H_ +#define _MACHINE_TYPES_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[6]; +} 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; +typedef long long int64_t; +typedef unsigned long long u_int64_t; + +typedef int32_t register_t; + +#define __SWAP_BROKEN + +#endif /* _MACHTYPES_H_ */ diff --git a/sys/arch/pc532/include/varargs.h b/sys/arch/pc532/include/varargs.h new file mode 100644 index 00000000000..5aedb16124f --- /dev/null +++ b/sys/arch/pc532/include/varargs.h @@ -0,0 +1,68 @@ +/* $NetBSD: varargs.h,v 1.8 1995/03/28 18:18:40 jtc Exp $ */ + +/*- + * Copyright (c) 1990, 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 _PC532_VARARGS_H_ +#define _PC532_VARARGS_H_ + +#include <machine/ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define va_dcl int va_alist; + +#define __va_promote(type) \ + (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int)) + +#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 += __va_promote(type), ap - __va_promote(type)))[0] +#endif + +#define va_end(ap) ((void) 0) + +#endif /* !_PC532_VARARGS_H_ */ diff --git a/sys/arch/pc532/include/vmparam.h b/sys/arch/pc532/include/vmparam.h new file mode 100644 index 00000000000..cee95ebf38a --- /dev/null +++ b/sys/arch/pc532/include/vmparam.h @@ -0,0 +1,230 @@ +/* $NetBSD: vmparam.h,v 1.6 1995/02/14 18:52:29 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)vmparam.h 5.9 (Berkeley) 5/12/91 + */ + +#ifndef _MACHINE_VMPARAM_H_ +#define _MACHINE_VMPARAM_H_ + +/* + * Machine dependent constants for 532. + */ + +/* + * Virtual address space arrangement. On 532, both user and kernel + * share the address space, not unlike the vax. + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. Immediately above the user stack + * resides the user structure, which is UPAGES long and contains the + * kernel stack. + * + * Immediately after the user structure is the page table map, and then + * kernal address space. + */ +#define USRTEXT 0x1000 /* For NetBSD... */ +#define USRSTACK 0xFDBFE000 +#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */ +#define LOWPAGES 0 +#define HIGHPAGES UPAGES + +/* + * Virtual memory related constants, all in bytes + */ +#define MAXTSIZ (16*1024*1024) /* max text size */ +#ifndef DFLDSIZ +#define DFLDSIZ (24*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (128*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (1*1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ (8*1024*1024) /* 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. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ +#define DMTEXT 1024 /* swap allocation for text */ + +/* + * Sizes of the system and user portions of the system page table. + */ +#define SYSPTSIZE (2*NPTEPG) +#define USRPTSIZE (2*NPTEPG) + +/* + * Size of User Raw I/O map + */ +#define USRIOSIZE 64 + +/* + * 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. + * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17 + * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) } + */ +#define SAFERSS 8 /* 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 KLMAX*CLSIZE must be <= DMMIN in dmap.h. + */ + +#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) + +/* + * KLSDIST is the advance or retard of the fifo reclaim for sequential + * processes data space. + */ +#define KLSDIST 3 /* klusters advance/retard for seq. fifo */ + +#if 0 +/* + * 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 + * minfree is 64k bytes, but at most 1/2 of desfree + */ +#define LOTSFREE (512 * 1024) +#define LOTSFREEFRACT 4 +#define DESFREE (200 * 1024) +#define DESFREEFRACT 8 +#define MINFREE (64 * 1024) +#define MINFREEFRACT 2 +#endif + +/* + * 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 + +#define mapin(pte, v, pfnum, prot) \ + {(*(int *)(pte) = ((pfnum)<<PGSHIFT) | (prot)) ; } + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0xFDBFE000) +#define UPT_MIN_ADDRESS ((vm_offset_t)0xFDC00000) +#define UPT_MAX_ADDRESS ((vm_offset_t)0xFDFF7000) +#define VM_MAX_ADDRESS UPT_MAX_ADDRESS +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xFDFF7000) +#define UPDT VM_MIN_KERNEL_ADDRESS +#define KPT_MIN_ADDRESS ((vm_offset_t)0xFDFF8000) +#define KPT_MAX_ADDRESS ((vm_offset_t)0xFDFFF000) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFF7FF000) + +/* 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) + +/* # of kernel PT pages (initial only, can grow dynamically) */ +#define VM_KERNEL_PT_PAGES ((vm_size_t)2) /* XXX: SYSPTSIZE */ + +/* pcb base */ +#define pcbb(p) ((u_int)(p)->p_addr) + +#endif diff --git a/sys/arch/pc532/pc532/autoconf.c b/sys/arch/pc532/pc532/autoconf.c new file mode 100644 index 00000000000..7be020147c3 --- /dev/null +++ b/sys/arch/pc532/pc532/autoconf.c @@ -0,0 +1,229 @@ +/* $NetBSD: autoconf.c,v 1.15 1995/09/26 20:16:23 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)autoconf.c 7.1 (Berkeley) 5/9/91 + */ + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time and initializes the vba + * device tables and the memory controller monitoring. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ + +#include <sys/param.h> +#include <sys/disklabel.h> +#include <sys/conf.h> +#include <sys/systm.h> +#include <sys/reboot.h> +#include <sys/buf.h> +#include <sys/malloc.h> +#include <sys/device.h> + +/* + * The following several variables are related to + * the configuration process, and are used in initializing + * the machine. + */ + +int dkn; /* number of iostat dk numbers assigned so far */ +extern int cold; /* cold start flag initialized in locore.s */ + +/* + * Determine i/o configuration for a machine. + */ +configure() +{ + extern int safepri; + int i; + static char *ipl_names[] = IPL_NAMES; + + /* Start the clocks. */ + startrtclock(); + + /* Find out what the hardware configuration looks like! */ + if (config_rootfound("membus", "membus") == 0) + panic ("No mem bus found!"); + + for (i = 0; i < NIPL; i++) + printf("%s%s=%x", i?", ":"", ipl_names[i], imask[i]); + printf("\n"); + + safepri = imask[IPL_ZERO]; + spl0(); + +#if GENERIC + if ((boothowto & RB_ASKNAME) == 0) + setroot(); + setconf(); +#else + setroot(); +#endif + + /* + * Configure swap area and related system + * parameter based on device(s) used. + */ + swapconf(); + dumpconf(); + cold = 0; +} + +/* + * Configure swap space and related parameters. + */ +swapconf() +{ + register struct swdevt *swp; + register int nblks; + extern int Maxmem; + + + for (swp = swdevt; swp->sw_dev > 0; swp++) + { + unsigned d = major(swp->sw_dev); + + if (d >= nblkdev) break; + if (bdevsw[d].d_psize) { + nblks = (*bdevsw[d].d_psize)(swp->sw_dev); + if (nblks > 0 && + (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) + swp->sw_nblks = nblks; + else + swp->sw_nblks = 0; + } + swp->sw_nblks = ctod(dtoc(swp->sw_nblks)); + + } +} + +#define DOSWAP /* change swdevt and dumpdev */ +u_long bootdev = 0; /* should be dev_t, but not until 32 bits */ + +static char devname[][2] = { + 's','d', /* 0 = sd */ + 's','w', /* 1 = sw */ + 's','t', /* 2 = st */ + 'r','d', /* 3 = rd */ + 'c','d', /* 4 = cd */ +}; + +/* + * 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. + */ +setroot() +{ + int majdev, mindev, unit, part, adaptor; + dev_t temp, orootdev; + struct swdevt *swp; + + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) + return; + majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; + if (majdev > sizeof(devname) / sizeof(devname[0])) + return; + adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; + part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; + unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; + mindev = (unit * MAXPARTITIONS) + part; + orootdev = rootdev; + rootdev = makedev(majdev, mindev); + /* + * If the original rootdev is the same as the one + * just calculated, don't need to adjust the swap configuration. + */ + if (rootdev == orootdev) + return; + printf("changing root device to %c%c%d%c\n", + devname[majdev][0], devname[majdev][1], + unit, part + 'a'); + +#ifdef DOSWAP + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (majdev == major(swp->sw_dev) && + (mindev / MAXPARTITIONS) + == (minor(swp->sw_dev) / MAXPARTITIONS)) { + 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; +#endif +} + +/* mem bus stuff */ + +static int membusprobe(); +static void membusattach(); + +struct cfdriver membuscd = + { NULL, "membus", membusprobe, membusattach, + DV_DULL, sizeof(struct device), NULL, 0 }; + +static int +membusprobe(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + return (strcmp(cf->cf_driver->cd_name, "membus") == 0); +} + +static void +membusattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + printf ("\n"); + while (config_found(self, NULL, NULL)) + ; +} diff --git a/sys/arch/pc532/pc532/bcopy.s b/sys/arch/pc532/pc532/bcopy.s new file mode 100644 index 00000000000..134743ae74e --- /dev/null +++ b/sys/arch/pc532/pc532/bcopy.s @@ -0,0 +1,85 @@ +/* $NetBSD: bcopy.s,v 1.5 1995/08/29 22:37:41 phil Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ns532/bcopy.s + * Author: Tatu Ylonen, Jukka Virtanen + * Helsinki University of Technology 1992. + */ + +#include <machine/asm.h> + + .text + +/* ovbcopy (from, to, bcount) -- does overlapping stuff */ + +ENTRY(bcopy) +ENTRY(ovbcopy) + DFRAME + movd B_ARG0,r1 /* from */ + movd B_ARG1,r2 /* to */ + cmpd r2, r1 + bls common /* safe to do standard thing */ + movd B_ARG2,r0 /* bcount */ + addd r1, r0 /* add to start of from */ + cmpd r2, r0 + bhs common /* safe to do standard thing */ + +/* Must do a reverse copy (and assume that the start is on a + word boundry . . . so we move the "remaining" bytes first) */ + + movd B_ARG2, r0 /* bcount */ + addqd -1, r0 + addd r0, r1 + addd r0, r2 + addqd 1, r0 + andd 3, r0 + movsb b /* move bytes backwards */ + addqd -3, r1 /* change to double pointer */ + addqd -3, r2 /* ditto */ + movd B_ARG2, r0 + lshd -2,r0 + movsd b /* move words backwards */ + DEMARF + ret 0 + +/* bcopy(from, to, bcount) -- non overlapping */ + +/* ENTRY(bcopy) -- same as ovbcopy until furthur notice.... */ + DFRAME + movd B_ARG0,r1 /* from */ + movd B_ARG1,r2 /* to */ +common: movd B_ARG2,r0 /* bcount */ + lshd -2,r0 + movsd /* move words */ + movd B_ARG2,r0 + andd 3,r0 + movsb /* move bytes */ + DEMARF + ret 0 diff --git a/sys/arch/pc532/pc532/bzero.s b/sys/arch/pc532/pc532/bzero.s new file mode 100644 index 00000000000..22a1e87efdd --- /dev/null +++ b/sys/arch/pc532/pc532/bzero.s @@ -0,0 +1,99 @@ +/* $NetBSD: bzero.s,v 1.2 1994/10/26 08:24:51 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ns532/bzero.s + * Author: Tero Kivinen, Helsinki University of Technology 1992. + * + * $Id: bzero.s,v 1.1 1995/10/18 08:51:21 deraadt Exp $ + */ + +#include <machine/asm.h> + +/* + * bzero(char * addr, unsigned int length) + */ + + .text +Entry(blkclr) +ENTRY(bzero) + DFRAME + movd B_ARG0,r1 /* addr */ + movd B_ARG1,r2 /* length */ + movd r1,r0 /* align addr */ + andd 3,r0 + cmpqd 0,r0 + beq wstart /* already aligned */ + negd r0,r0 + addqd 4,r0 + cmpd r0,r2 + bhi bytes /* not enough data to align */ +b1loop: movqb 0,0(r1) /* zero bytes */ + addqd 1,r1 + addqd -1,r2 + acbd -1,r0,b1loop +wstart: movd r2,r0 /* length */ + lshd -6,r0 + cmpqd 0,r0 + beq phase2 +w1loop: movqd 0,0(r1) /* zero words */ + movqd 0,4(r1) + movqd 0,8(r1) + movqd 0,12(r1) + movqd 0,16(r1) + movqd 0,20(r1) + movqd 0,24(r1) + movqd 0,28(r1) + movqd 0,32(r1) + movqd 0,36(r1) + movqd 0,40(r1) + movqd 0,44(r1) + movqd 0,48(r1) + movqd 0,52(r1) + movqd 0,56(r1) + movqd 0,60(r1) + addd 64,r1 + acbd -1,r0,w1loop +phase2: movd r2,r0 /* length */ + andd 63,r0 + lshd -2,r0 + cmpqd 0,r0 + beq bytes +w2loop: movqd 0,0(r1) + addqd 4,r1 + acbd -1,r0,w2loop +bytes: movd r2,r0 /* length */ + andd 3,r0 + cmpqd 0,r0 + beq done +bloop: movqb 0,0(r1) /* zero bytes */ + addqd 1,r1 + acbb -1,r0,bloop +done: DEMARF + ret 0 diff --git a/sys/arch/pc532/pc532/clock.c b/sys/arch/pc532/pc532/clock.c new file mode 100644 index 00000000000..81bcc8f8353 --- /dev/null +++ b/sys/arch/pc532/pc532/clock.c @@ -0,0 +1,253 @@ +/* $NetBSD: clock.c,v 1.11 1995/05/16 07:30:46 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + * + */ + +/* + * Primitive clock interrupt routines. + * + * Improved by Phil Budne ... 10/17/94. + * Pulled over code from i386/isa/clock.c (Matthias Pfaller 12/03/94). + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/systm.h> + +#include <machine/icu.h> + +void spinwait __P((int)); + +void +startrtclock() +{ + int timer = (ICU_CLK_HZ) / hz; + + /* Write the timer values to the ICU. */ + WR_ADR (unsigned short, ICU_ADR + HCSV, timer); + WR_ADR (unsigned short, ICU_ADR + HCCV, timer); + + /* Establish interrupt vector */ + intr_establish(IR_CLK, hardclock, NULL, "clock", IPL_CLOCK, + FALLING_EDGE); +} + +void +cpu_initclocks() +{ + /* enable clock interrupt */ + WR_ADR (unsigned char, ICU_ADR +CICTL, 0x30); +} + +void +spinwait(int millisecs) +{ + DELAY(5000 * millisecs); +} + +DELAY(n) +{ + volatile int N = (n); + while (--N > 0) + ; +} + +void +setstatclockrate(int dummy) +{ + printf ("setstatclockrate\n"); +} + + +static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static int +yeartoday(year) + int year; +{ + + return((year % 4) ? 365 : 366); +} + +int +hexdectodec(n) + char n; +{ + + return(((n >> 4) & 0x0F) * 10 + (n & 0x0F)); +} + +char +dectohexdec(n) + int n; +{ + + return((char)(((n / 10) << 4) & 0xF0) | ((n % 10) & 0x0F)); +} + +static int timeset; +struct rtc_st { + unsigned char rtc_csec; + unsigned char rtc_sec; + unsigned char rtc_min; + unsigned char rtc_hr; + unsigned char rtc_dow; + unsigned char rtc_dom; + unsigned char rtc_mon; + unsigned char rtc_yr; +}; + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +void +inittodr(base) + time_t base; +{ + /* + * We ignore the suggested time for now and go for the RTC + * clock time stored in the CMOS RAM. + */ + struct rtc_st rtclk; + time_t n; + int csec, sec, min, hr, dom, mon, yr; + int i, days = 0; + int s; + extern int have_rtc; + + timeset = 1; + if (!have_rtc) { + time.tv_sec = base; + return; + } + + rw_rtc((unsigned char *)&rtclk, 0); + + csec = hexdectodec(rtclk.rtc_csec); + sec = hexdectodec(rtclk.rtc_sec); + min = hexdectodec(rtclk.rtc_min); + hr = hexdectodec(rtclk.rtc_hr); + dom = hexdectodec(rtclk.rtc_dom); + mon = hexdectodec(rtclk.rtc_mon); + yr = hexdectodec(rtclk.rtc_yr); + yr = (yr < 70) ? yr + 100 : yr; + + /* + * Check to see if it was really the rtc + * by checking for bad date info. + */ + if (sec > 59 || min > 59 || hr > 23 || dom > 31 || mon > 12) { + printf("inittodr: No clock found\n"); + time.tv_sec = base; + return; + } + + n = sec + 60 * min + 3600 * hr; + n += (dom - 1) * 3600 * 24; + + if (yeartoday(yr) == 366) + month[1] = 29; + for (i = mon - 2; i >= 0; i--) + days += month[i]; + month[1] = 28; + for (i = 70; i < yr; i++) + days += yeartoday(i); + n += days * 3600 * 24; + + n += tz.tz_minuteswest * 60; + if (tz.tz_dsttime) + n -= 3600; + s = splclock(); + time.tv_sec = n; + time.tv_usec = csec * 10000; + splx(s); +} + +/* + * Reset the clock. + */ +void +resettodr() +{ + struct rtc_st rtclk; + time_t n; + int diff, i, j; + int s; + + /* + * We might have been called by boot() due to a crash early + * on. Don't reset the clock chip in this case. + */ + if (!timeset) + return; + + diff = tz.tz_minuteswest * 60; + if (tz.tz_dsttime) + diff -= 3600; + + s = splclock(); + n = (time.tv_sec - diff) % (3600 * 24); /* hrs+mins+secs */ + rtclk.rtc_csec = dectohexdec(time.tv_usec / 10000); + rtclk.rtc_sec = dectohexdec(n%60); + n /= 60; + rtclk.rtc_min = dectohexdec(n%60); + rtclk.rtc_hr = dectohexdec(n/60); + + n = (time.tv_sec - diff) / (3600 * 24); /* days */ + splx(s); + rtclk.rtc_dow = (n + 4) % 7; /* 1/1/70 is Thursday */ + + for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j)) + n -= i; + + rtclk.rtc_yr = dectohexdec(j - 1900); + + if (i == 366) + month[1] = 29; + for (i = 0; n >= month[i]; i++) + n -= month[i]; + month[1] = 28; + rtclk.rtc_mon = dectohexdec(++i); + + rtclk.rtc_dom = dectohexdec(++n); + + rw_rtc((unsigned char *)&rtclk, 1); +} diff --git a/sys/arch/pc532/pc532/conf.c b/sys/arch/pc532/pc532/conf.c new file mode 100644 index 00000000000..6898e20f64b --- /dev/null +++ b/sys/arch/pc532/pc532/conf.c @@ -0,0 +1,223 @@ +/* $NetBSD: conf.c,v 1.26 1995/09/26 20:16:25 phil Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 7.9 (Berkeley) 5/28/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/conf.h> +#include <sys/vnode.h> + +int ttselect __P((dev_t, int, struct proc *)); + +#include "sd.h" +bdev_decl(sd); +bdev_decl(sw); +#include "st.h" +bdev_decl(st); +#include "rd.h" +bdev_decl(rd); +#include "cd.h" +bdev_decl(cd); +#include "vnd.h" +bdev_decl(vnd); +#include "ccd.h" +bdev_decl(ccd); + +struct bdevsw bdevsw[] = +{ + bdev_disk_init(NSD,sd), /* 0: SCSI disk */ + bdev_swap_init(1,sw), /* 1: swap pseudo-device */ + bdev_tape_init(NST,st), /* 2: SCSI tape */ + bdev_disk_init(NRD,rd), /* 3: ram disk */ + bdev_disk_init(NCD,cd), /* 4: SCSI CD-ROM */ + bdev_disk_init(NVND,vnd), /* 5: vnode disk driver */ + bdev_disk_init(NCCD,ccd), /* 6: concatenated disk driver */ +}; +int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]); + +/* 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, 0} + +cdev_decl(cn); +cdev_decl(ctty); +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); +cdev_decl(sd); +cdev_decl(sw); +#include "pty.h" +#define ptstty ptytty +#define ptsioctl ptyioctl +cdev_decl(pts); +#define ptctty ptytty +#define ptcioctl ptyioctl +cdev_decl(ptc); +cdev_decl(log); +#include "scn.h" +cdev_decl(scn); +cdev_decl(rd); +cdev_decl(st); +cdev_decl(fd); +cdev_decl(cd); +cdev_decl(vnd); +cdev_decl(ccd); +#include "bpfilter.h" +cdev_decl(bpf); +#include "tun.h" +cdev_decl(tun); +#include "lpt.h" +cdev_decl(lpt); + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_ctty_init(1,ctty), /* 1: controlling terminal */ + cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */ + cdev_disk_init(NSD,sd), /* 3: SCSI disk */ + cdev_swap_init(1,sw), /* 4: /dev/drum (swap device) */ + cdev_tty_init(NPTY,pts), /* 5: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 6: pseudo-tty master */ + cdev_log_init(1,log), /* 7: /dev/klog */ + cdev_tty_init(NSCN,scn), /* 8: serial ports */ + cdev_disk_init(NRD,rd), /* 9: RAM disk */ + cdev_tape_init(NST,st), /* 10: SCSI tape */ + cdev_fd_init(1,fd), /* 11: file descriptor pseudo-device */ + cdev_disk_init(NCD,cd), /* 12: SCSI CD-ROM */ + cdev_disk_init(NVND,vnd), /* 13: vnode disk driver */ + cdev_bpftun_init(NBPFILTER,bpf),/* 14: Berkeley packet filter */ + cdev_bpftun_init(NTUN,tun), /* 15: network tunnel */ + cdev_notdef(), /* 16 */ + cdev_lpt_init(NLPT, lpt), /* 17: Centronics */ + cdev_disk_init(NCCD,ccd), /* 18: concatenated disk driver */ +}; +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); + +/* + * Returns true if dev is /dev/mem or /dev/kmem. + */ +iskmemdev(dev) + dev_t dev; +{ + + return (major(dev) == mem_no && minor(dev) < 2); +} + +/* + * Returns true if dev is /dev/zero. + */ +iszerodev(dev) + dev_t dev; +{ + + return (major(dev) == mem_no && minor(dev) == 12); +} + +static int chrtoblktbl[] = { + /* XXXX This needs to be dynamic for LKMs. */ + /*VCHR*/ /*VBLK*/ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ 0, + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ NODEV, + /* 9 */ 3, + /* 10 */ 2, + /* 11 */ NODEV, + /* 12 */ 4, + /* 13 */ 5, + /* 14 */ NODEV, + /* 15 */ NODEV, + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ 6 +}; + +/* + * Convert a character device number to a block device number. + */ +chrtoblk(dev) + dev_t dev; +{ + int blkmaj; + + if (major(dev) >= nchrdev) + return (NODEV); + blkmaj = chrtoblktbl[major(dev)]; + if (blkmaj == NODEV) + return (NODEV); + return (makedev(blkmaj, minor(dev))); +} + +/* + * 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(scn); + +struct consdev constab[] = { +#if NSCN > 0 + cons_init(scn), +#endif + { 0 }, +}; diff --git a/sys/arch/pc532/pc532/db_disasm.c b/sys/arch/pc532/pc532/db_disasm.c new file mode 100644 index 00000000000..71336343565 --- /dev/null +++ b/sys/arch/pc532/pc532/db_disasm.c @@ -0,0 +1,1899 @@ +/* $NetBSD: db_disasm.c,v 1.2 1994/10/26 08:24:55 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * Copyright (c) 1992 Bob Krause, Bruce Culbertson + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY AND BOB + * KRAUSE AND BRUCE CULBERTSON ALLOW FREE USE OF THIS SOFTWARE IN ITS + * "AS IS" CONDITION. CARNEGIE MELLON AND HELSINKI UNIVERSITY OF + * TECHNOLOGY AND BOB KRAUSE AND BRUCE CULBERTSON DISCLAIM ANY + * LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE + * USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * From Bruce Culbertson's and Bob Krause's ROM monitor for the pc532 + * adapted to pc532 Mach by Tero Kivinen and Tatu Ylonen at Helsinki + * University of Technology. + */ + +/* + * Adapted for 532bsd (386bsd port) by Phil Nelson. + * + * Not yet complete! + * + */ + +#define STATIC static + +/* #include <mach/boolean.h> */ +#include <machine/db_machdep.h> +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <ddb/db_variables.h> +#include <machine/pmap.h> +#include <vm/vm_map.h> +/* #include <kern/thread.h> */ + +struct operand { + int o_mode; /* address mode */ + int o_reg0; /* first register */ + int o_reg1; /* second register */ + long o_disp0; /* first displacment value */ + long o_disp1; /* second displacement value */ + int o_iscale; /* scaled indexing factor */ + int o_ireg; /* scaled indexing register */ +}; + +struct insn { + int i_format; /* instruction format */ + int i_op; /* operation code */ + char i_monic[8]; /* mneumonic string */ + unsigned char i_iol; /* integer operand length */ + struct operand i_opr[4]; /* operands */ +}; + +/* Addressing modes (not the same format as in a machine instruction) */ +#define AMODE_NONE 0 /* operand not used by instruction */ +#define AMODE_REG 1 /* register */ +#define AMODE_RREL 2 /* register relative */ +#define AMODE_MREL 3 /* memory relative */ +#define AMODE_IMM 4 /* immediate */ +#define AMODE_ABS 5 /* absolute */ +#define AMODE_EXT 6 /* external */ +#define AMODE_TOS 7 /* top of stack */ +#define AMODE_MSPC 8 /* memory space */ +#define AMODE_REGLIST 9 /* a register list */ +#define AMODE_QUICK 10 /* quick integer (-8 .. +7) */ +#define AMODE_INVALID 11 /* invalid address mode found */ +#define AMODE_AREG 12 /* CPU dedicated register */ +#define AMODE_BLISTB 13 /* byte length bit list */ +#define AMODE_BLISTW 14 /* word length bit list */ +#define AMODE_BLISTD 15 /* double-word length bit list */ +#define AMODE_SOPT 16 /* options in string instructions */ +#define AMODE_CFG 17 /* configuration bits */ +#define AMODE_MREG 18 /* memory management register */ +#define AMODE_CINV 19 /* cache invalidate options */ + +/* Instruction types */ +#define ITYPE_FMT0 0 +#define ITYPE_FMT1 1 +#define ITYPE_FMT2 2 +#define ITYPE_FMT3 3 +#define ITYPE_FMT4 4 +#define ITYPE_FMT5 5 +#define ITYPE_FMT6 6 +#define ITYPE_FMT7 7 +#define ITYPE_FMT8 8 +#define ITYPE_FMT9 9 +#define ITYPE_NOP 10 +#define ITYPE_FMT11 11 +#define ITYPE_FMT12 12 +#define ITYPE_UNDEF 13 +#define ITYPE_FMT14 14 +#define ITYPE_FMT15 15 + +/* Table to determine the 'condition' field of an instruction */ +STATIC +char cond_table[16][3] = { + "eq", /* equal */ + "ne", /* not equal */ + "cs", /* carry set */ + "cc", /* carry clear */ + "hi", /* higher */ + "ls", /* lower or same */ + "gt", /* greater than */ + "le", /* less than or equal */ + "fs", /* flag set */ + "fc", /* flag clear */ + "lo", /* lower */ + "hs", /* higher or same */ + "lt", /* less than */ + "ge", /* greater than or equal */ + "r", /* unconditional branch */ + "??" /* never branch (nop) */ +}; + +#define IOL(x) (((x)&0x3) + 1) +#define IOL_BYTE 1 /* Byte (8-bits) */ +#define IOL_WORD 2 /* Word (16-bits) */ +#define IOL_NONE 3 /* Does not apply */ +#define IOL_DOUBLE 4 /* Double Word (32-bits) */ + +STATIC +char iol_table[5][2] = { + "?", /* Should never appear */ + "b", /* byte */ + "w", /* word */ + "?", /* undefined */ + "d" /* double word */ +}; + +STATIC +char fol_table[2][2] = { + "l", /* long floating-point */ + "f" /* standard floating-point */ +}; + +STATIC +char scale_table[5][2] = { + "?", /* no scaled indexing */ + "b", /* byte */ + "w", /* word */ + "d", /* double-word */ + "q" /* quad-word */ +}; + +STATIC +char cfg_table[4][2] = { + "i", /* vectored interrupt enable */ + "f", /* floating point enable */ + "m", /* memory management enable */ + "c" /* custom slave enable */ +}; + +STATIC +char sopt_table[8][4] = { + "", /* no options */ + "b", /* backward */ + "w", /* while match */ + "b,w", /* backward, while match */ + "?", /* undefined */ + "b,?", /* undefined */ + "u", /* until match */ + "b,u" /* backward, until match */ +}; + +#define AREG_US 0x0 /* user stack */ +#define AREG_FP 0x8 /* frame pointer */ +#define AREG_SP 0x9 /* stack pointer */ +#define AREG_SB 0xa /* static base */ +#define AREG_PSR 0xd /* processor status register */ +#define AREG_INTBASE 0xe /* interrupt base */ +#define AREG_MOD 0xf /* module */ + +/* Floating-point operand length field masks */ +#define FOL_SINGLE 0x1 /* Single Precision (32-bits) */ +#define FOL_DOUBLE 0x0 /* Double Precision (64-bits) */ + +#define FMT0_COND(x) (((x)&0xf0)>>4) /* Condition code for fmt 0 */ +#define FMT1_OP(x) (((x)&0xf0)>>4) /* Op code for fmt 1 */ +#define FMT2_OP(x) (((x)&0x70)>>4) /* Op code for fmt 2 */ +#define FMT2_COND(x, y) (((x)>>7) + (((y)&0x80)<<1)) /* Condition code for fmt 2 */ +#define FMT3_OP(x) ((x)&0x7) /* bits 2-4 of fmt 3 op code */ +#define FMT4_OP(x) (((x)&0x3c)>>2) /* Op code for fmt 4 */ +#define FMT5_OP(x) (((x)&0x3c)>>2) /* op code for fmt 5 */ +#define FMT6_OP(x) (((x)&0x3c)>>2) /* op code for fmt 6 */ +#define FMT7_OP(x) (((x)&0x3c)>>2) /* op code for fmt 7 */ +#define FMT8_OP(x, y) ((((x)&0xc0)>>6) + ((y)&0x4)) +#define FMT8_REG(x) (((x)&0x38)>>3) /* register operand for fmt 8 */ +#define FMT8_SU 1 /* register value -> movsu */ +#define FMT8_US 3 /* register value -> movus */ +#define FMT9_OP(x) (((x)&0x38)>>3) /* op code for fmt 9 */ +#define FMT9_F(x) (((x)&0x4)>>2) /* float type for fmt 9 */ +#define FMT11_OP(x) (((x)&0x3c)>>2) /* op code for fmt 11 */ +#define FMT12_OP(x) (((x)&0x3c)>>2) /* op code for fmt 12 */ +#define FMT11_F(x) ((x)&01) /* float type for fmt 11 */ +#define FMT12_F(x) ((x)&01) /* float type for fmt 12 */ +#define FMT14_OP(x) (((x)&0x3c)>>2) /* op code for fmt 14 */ + +#define GEN_R0 0 /* register 0 */ +#define GEN_R1 1 /* register 1 */ +#define GEN_R2 2 /* register 2 */ +#define GEN_R3 3 /* register 3 */ +#define GEN_R4 4 /* register 4 */ +#define GEN_R5 5 /* register 5 */ +#define GEN_R6 6 /* register 6 */ +#define GEN_R7 7 /* register 7 */ +#define GEN_RR0 8 /* register 0 relative */ +#define GEN_RR1 9 /* register 1 relative */ +#define GEN_RR2 10 /* register 2 relative */ +#define GEN_RR3 11 /* register 3 relative */ +#define GEN_RR4 12 /* register 4 relative */ +#define GEN_RR5 13 /* register 5 relative */ +#define GEN_RR6 14 /* register 6 relative */ +#define GEN_RR7 15 /* register 7 relative */ +#define GEN_FRMR 16 /* frame memory relative */ +#define GEN_SPMR 17 /* stack memory relative */ +#define GEN_SBMR 18 /* static memory relative */ +#define GEN_RES 19 /* reserved for future use */ +#define GEN_IMM 20 /* immediate */ +#define GEN_ABS 21 /* absolute */ +#define GEN_EXT 22 /* external */ +#define GEN_TOS 23 /* top of stack */ +#define GEN_FRM 24 /* frame memory */ +#define GEN_SPM 25 /* stack memory */ +#define GEN_SBM 26 /* static memory */ +#define GEN_PCM 27 /* program memory */ +#define GEN_SIB 28 /* scaled index, bytes */ +#define GEN_SIW 29 /* scaled index, words */ +#define GEN_SID 30 /* scaled index, double words */ +#define GEN_SIQ 31 /* scaled index, quad words */ + +STATIC +unsigned char fmttab[128] = { +/* This is really an array of 256 nibbles. The index is the first + * byte of an instruction opcode. The value in the array is the + * instruction format corresponding to that first byte. + * + * group 1st byte insn format insn type + */ +(4+ /* 00000000 format 4 add .b */ +(4*16)), /* 00000001 format 4 add .w */ +(1+ /* 00000010 format 1 bsr */ +(4*16)), /* 00000011 format 4 add .l */ +(4+ /* 00000100 format 4 cmp .b */ +(4*16)), /* 00000101 format 4 cmp .w */ +(13+ /* 00000110 format 19 undefined */ +(4*16)), /* 00000111 format 4 cmp .l */ +(4+ /* 00001000 format 4 bic .b */ +(4*16)), /* 00001001 format 4 bic .w */ +(0+ /* 00001010 format 0 beq */ +(4*16)), /* 00001011 format 4 bic .w */ +(2+ /* 00001100 format 2 addq .b */ +(2*16)), /* 00001101 format 2 addq .w */ +(5+ /* 00001110 format 5 */ +(2*16)), /* 00001111 format 2 addq .l */ +(4+ /* 00010000 format 4 addc .b */ +(4*16)), /* 00010001 format 4 addc .w */ +(1+ /* 00010010 format 1 ret */ +(4*16)), /* 00010011 format 4 addc .l */ +(4+ /* 00010100 format 4 mov .b */ +(4*16)), /* 00010101 format 4 mov .w */ +(15+ /* 00010110 format 15 */ +(4*16)), /* 00010111 format 4 mov .l */ +(4+ /* 00011000 format 4 or .b */ +(4*16)), /* 00011001 format 4 or .w */ +(0+ /* 00011010 format 0 bne */ +(4*16)), /* 00011011 format 4 or .l */ +(2+ /* 00011100 format 2 cmpq .b */ +(2*16)), /* 00011101 format 2 cmpq .w */ +(14+ /* 00011110 format 14 */ +(2*16)), /* 00011111 format 2 cmpq .l */ +(4+ /* 00100000 format 4 sub .b */ +(4*16)), /* 00100001 format 4 sub .w */ +(1+ /* 00100010 format 1 cxp */ +(4*16)), /* 00100011 format 4 sub .l */ +(4+ /* 00100100 format 4 addr .b */ +(4*16)), /* 00100101 format 4 addr .w */ +(13+ /* 00100110 format 19 undefined */ +(4*16)), /* 00100111 format 4 addr .l */ +(4+ /* 00101000 format 4 and .b */ +(4*16)), /* 00101001 format 4 and .w */ +(0+ /* 00101010 format 0 bcs */ +(4*16)), /* 00101011 format 4 and .l */ +(2+ /* 00101100 format 2 spr .b */ +(2*16)), /* 00101101 format 2 spr .w */ +(8+ /* 00101110 format 8 */ +(2*16)), /* 00101111 format 2 spr .l */ +(4+ /* 00110000 format 4 subc .b */ +(4*16)), /* 00110001 format 4 subc .w */ +(1+ /* 00110010 format 1 rxp */ +(4*16)), /* 00110011 format 4 subc .l */ +(4+ /* 00110100 format 4 tbit .b */ +(4*16)), /* 00110101 format 4 tbit .w */ +(15+ /* 00110110 format 15 */ +(4*16)), /* 00110111 format 4 tbit .l */ +(4+ /* 00111000 format 4 xor .b */ +(4*16)), /* 00111001 format 4 xor .w */ +(0+ /* 00111010 format 0 bcc */ +(4*16)), /* 00111011 format 4 xor .l */ +(2+ /* 00111100 format 2 scond .b */ +(2*16)), /* 00111101 format 2 scond .w */ +(9+ /* 00111110 format 9 */ +(2*16)), /* 00111111 format 2 scond .l */ +(4+ /* 01000000 format 4 add .b */ +(4*16)), /* 01000001 format 4 add .w */ +(1+ /* 01000010 format 1 rett */ +(4*16)), /* 01000011 format 4 add .l */ +(4+ /* 01000100 format 4 cmp .b */ +(4*16)), /* 01000101 format 4 cmp .w */ +(13+ /* 01000110 format 19 undefined */ +(4*16)), /* 01000111 format 4 cmp .l */ +(4+ /* 01001000 format 4 bic .b */ +(4*16)), /* 01001001 format 4 bic .w */ +(0+ /* 01001010 format 0 bhi */ +(4*16)), /* 01001011 format 4 bic .l */ +(2+ /* 01001100 format 2 acb .b */ +(2*16)), /* 01001101 format 2 acb .w */ +(6+ /* 01001110 format 6 */ +(2*16)), /* 01001111 format 2 acb .l */ +(4+ /* 01010000 format 4 addc .b */ +(4*16)), /* 01010001 format 4 addc .w */ +(1+ /* 01010010 format 1 reti */ +(4*16)), /* 01010011 format 4 addc .l */ +(4+ /* 01010100 format 4 mov .b */ +(4*16)), /* 01010101 format 4 mov .w */ +(15+ /* 01010110 format 15 */ +(4*16)), /* 01010111 format 4 mov .l */ +(4+ /* 01011000 format 4 or .b */ +(4*16)), /* 01011001 format 4 or .w */ +(0+ /* 01011010 format 0 bis */ +(4*16)), /* 01011011 format 4 or .l */ +(2+ /* 01011100 format 2 movq .b */ +(2*16)), /* 01011101 format 2 movq .w */ +(13+ /* 01011110 format 16 undefined */ +(2*16)), /* 01011111 format 2 movq .l */ +(4+ /* 01100000 format 4 sub .b */ +(4*16)), /* 01100001 format 4 sub .w */ +(1+ /* 01100010 format 1 save */ +(4*16)), /* 01100011 format 4 sub .l */ +(4+ /* 01100100 format 4 addr .b */ +(4*16)), /* 01100101 format 4 addr .w */ +(13+ /* 01100110 format 19 undefined */ +(4*16)), /* 01100111 format 4 addr .l */ +(4+ /* 01101000 format 4 and .b */ +(4*16)), /* 01101001 format 4 and .w */ +(0+ /* 01101010 format 0 bgt */ +(4*16)), /* 01101011 format 4 and .l */ +(2+ /* 01101100 format 2 lpr .b */ +(2*16)), /* 01101101 format 2 lpr .w */ +(8+ /* 01101110 format 8 */ +(2*16)), /* 01101111 format 2 lpr .l */ +(4+ /* 01110000 format 4 subc .b */ +(4*16)), /* 01110001 format 4 subc .w */ +(1+ /* 01110010 format 1 restore */ +(4*16)), /* 01110011 format 4 subc .l */ +(4+ /* 01110100 format 4 tbit .b */ +(4*16)), /* 01110101 format 4 tbit .w */ +(15+ /* 01110110 format 15 */ +(4*16)), /* 01110111 format 4 tbit .l */ +(4+ /* 01111000 format 4 xor .b */ +(4*16)), /* 01111001 format 4 xor .w */ +(0+ /* 01111010 format 0 ble */ +(4*16)), /* 01111011 format 4 xor .l */ +(3+ /* 01111100 format 3 */ +(3*16)), /* 01111101 format 3 */ +(13+ /* 01111110 format 10 undefined */ +(3*16)), /* 01111111 format 3 */ +(4+ /* 10000000 format 4 add .b */ +(4*16)), /* 10000001 format 4 add .w */ +(1+ /* 10000010 format 1 enter */ +(4*16)), /* 10000011 format 4 add .l */ +(4+ /* 10000100 format 4 cmp .b */ +(4*16)), /* 10000101 format 4 cmp .w */ +(13+ /* 10000110 format 19 undefined */ +(4*16)), /* 10000111 format 4 cmp .l */ +(4+ /* 10001000 format 4 bic .b */ +(4*16)), /* 10001001 format 4 bic .w */ +(0+ /* 10001010 format 0 bfs */ +(4*16)), /* 10001011 format 4 bic .l */ +(2+ /* 10001100 format 2 addq .b */ +(2*16)), /* 10001101 format 2 addq .w */ +(13+ /* 10001110 format 18 undefined */ +(2*16)), /* 10001111 format 2 addq .l */ +(4+ /* 10010000 format 4 addc .b */ +(4*16)), /* 10010001 format 4 addc .w */ +(1+ /* 10010010 format 1 exit */ +(4*16)), /* 10010011 format 4 addc .l */ +(4+ /* 10010100 format 4 mov .b */ +(4*16)), /* 10010101 format 4 mov .w */ +(15+ /* 10010110 format 15 */ +(4*16)), /* 10010111 format 4 mov .l */ +(4+ /* 10011000 format 4 or .b */ +(4*16)), /* 10011001 format 4 or .w */ +(0+ /* 10011010 format 0 bfc */ +(4*16)), /* 10011011 format 4 or .l */ +(2+ /* 10011100 format 2 cmpq .b */ +(2*16)), /* 10011101 format 2 cmpq .w */ +(13+ /* 10011110 format 13 undefined */ +(2*16)), /* 10011111 format 2 cmpq .l */ +(4+ /* 10100000 format 4 sub .b */ +(4*16)), /* 10100001 format 4 sub .w */ +(10+ /* 10100010 format 1 nop */ +(4*16)), /* 10100011 format 4 sub .l */ +(4+ /* 10100100 format 4 addr .b */ +(4*16)), /* 10100101 format 4 addr .w */ +(13+ /* 10100110 format 19 undefined */ +(4*16)), /* 10100111 format 4 addr .l */ +(4+ /* 10101000 format 4 and .b */ +(4*16)), /* 10101001 format 4 and .w */ +(0+ /* 10101010 format 0 blo */ +(4*16)), /* 10101011 format 4 and .l */ +(2+ /* 10101100 format 2 spr .b */ +(2*16)), /* 10101101 format 2 spr .w */ +(8+ /* 10101110 format 8 */ +(2*16)), /* 10101111 format 2 spr .l */ +(4+ /* 10110000 format 4 subc .b */ +(4*16)), /* 10110001 format 4 subc .w */ +(1+ /* 10110010 format 1 wait */ +(4*16)), /* 10110011 format 4 subc .l */ +(4+ /* 10110100 format 4 tbit .b */ +(4*16)), /* 10110101 format 4 tbit .w */ +(15+ /* 10110110 format 15 */ +(4*16)), /* 10110111 format 4 tbit .l */ +(4+ /* 10111000 format 4 xor .b */ +(4*16)), /* 10111001 format 4 xor .w */ +(0+ /* 10111010 format 0 bhs */ +(4*16)), /* 10111011 format 4 xor .l */ +(2+ /* 10111100 format 2 scond .b */ +(2*16)), /* 10111101 format 2 scond .w */ +(11+ /* 10111110 format 11 */ +(2*16)), /* 10111111 format 2 scond .l */ +(4+ /* 11000000 format 4 add .b */ +(4*16)), /* 11000001 format 4 add .w */ +(1+ /* 11000010 format 1 dia */ +(4*16)), /* 11000011 format 4 add .l */ +(4+ /* 11000100 format 4 cmp .b */ +(4*16)), /* 11000101 format 4 cmp .w */ +(13+ /* 11000110 format 19 undefined */ +(4*16)), /* 11000111 format 4 cmp .l */ +(4+ /* 11001000 format 4 bic .b */ +(4*16)), /* 11001001 format 4 bic .w */ +(0+ /* 11001010 format 0 blt */ +(4*16)), /* 11001011 format 4 bic .l */ +(2+ /* 11001100 format 2 acb .b */ +(2*16)), /* 11001101 format 2 acb .w */ +(7+ /* 11001110 format 7 */ +(2*16)), /* 11001111 format 2 acb .l */ +(4+ /* 11010000 format 4 addc .b */ +(4*16)), /* 11010001 format 4 addc .w */ +(1+ /* 11010010 format 1 flag */ +(4*16)), /* 11010011 format 4 addc .l */ +(4+ /* 11010100 format 4 mov .b */ +(4*16)), /* 11010101 format 4 mov .w */ +(15+ /* 11010110 format 15 */ +(4*16)), /* 11010111 format 4 mov .l */ +(4+ /* 11011000 format 4 or .b */ +(4*16)), /* 11011001 format 4 or .w */ +(0+ /* 11011010 format 0 bqt */ +(4*16)), /* 11011011 format 4 or .l */ +(2+ /* 11011100 format 2 movq .b */ +(2*16)), /* 11011101 format 2 movq .w */ +(13+ /* 11011110 format 17 undefined */ +(2*16)), /* 11011111 format 2 movq .l */ +(4+ /* 11100000 format 4 sub .b */ +(4*16)), /* 11100001 format 4 sub .w */ +(1+ /* 11100010 format 1 svc */ +(4*16)), /* 11100011 format 4 sub .l */ +(4+ /* 11100100 format 4 addr .b */ +(4*16)), /* 11100101 format 4 addr .w */ +(13+ /* 11100110 format 19 undefined */ +(4*16)), /* 11100111 format 4 addr .l */ +(4+ /* 11101000 format 4 and .b */ +(4*16)), /* 11101001 format 4 and .w */ +(0+ /* 11101010 format 0 b */ +(4*16)), /* 11101011 format 4 and .l */ +(2+ /* 11101100 format 2 lpr .b */ +(2*16)), /* 11101101 format 2 lpr .w */ +(8+ /* 11101110 format 8 */ +(2*16)), /* 11101111 format 2 lpr .l */ +(4+ /* 11110000 format 4 subc .b */ +(4*16)), /* 11110001 format 4 subc .w */ +(1+ /* 11110010 format 1 bpt */ +(4*16)), /* 11110011 format 4 subc .l */ +(4+ /* 11110100 format 4 tbit .b */ +(4*16)), /* 11110101 format 4 tbit .w */ +(15+ /* 11110110 format 15 */ +(4*16)), /* 11110111 format 4 tbit .l */ +(4+ /* 11111000 format 4 xor .b */ +(4*16)), /* 11111001 format 4 xor .w */ +(10+ /* 11111010 format 0 nop */ +(4*16)), /* 11111011 format 4 xor .l */ +(13+ /* 11111100 format 3 undefined */ +(13*16)), /* 11111101 format 3 undefined */ +((12+ /* 11111110 format 12 new 532 */ +13*16)) }; /* 11111111 format 3 undefined */ + +STATIC +char fmt1_table[16][8] = { + "bsr", /* branch to subroutine */ + "ret", /* return from subroutine */ + "cxp", /* call external procedure */ + "rxp", /* return from external procedure */ + "rett", /* return from trap */ + "reti", /* return from interrupt */ + "save", /* save general purpose registers */ + "restore", /* restore general purpose registers */ + "enter", /* enter new procedure context */ + "exit", /* exit procedure context */ + "nop", /* no operation */ + "wait", /* wait fro interrupt */ + "dia", /* diagnose */ + "flag", /* flag trap */ + "svc", /* supervisor call trap */ + "bpt" /* breakpoint trap */ +}; + +#define FMT1_BSR 0x0 /* branch to subroutine */ +#define FMT1_RET 0x1 /* return from subroutine */ +#define FMT1_CXP 0x2 /* call external procedure */ +#define FMT1_RXP 0x3 /* return from external procedure */ +#define FMT1_RETT 0x4 /* return from trap */ +#define FMT1_RETI 0x5 /* return from interrupt */ +#define FMT1_SAVE 0x6 /* save general purpose registers */ +#define FMT1_RESTORE 0x7 /* restore general purpose registers */ +#define FMT1_ENTER 0x8 /* enter new procedure context */ +#define FMT1_EXIT 0x9 /* exit procedure context */ +#define FMT1_NOP 0xa /* no operation */ +#define FMT1_WAIT 0xb /* wait fro interrupt */ +#define FMT1_DIA 0xc /* diagnose */ +#define FMT1_FLAG 0xd /* flag trap */ +#define FMT1_SVC 0xe /* supervisor call trap */ +#define FMT1_BPT 0xf /* breakpoint trap */ + +STATIC +char fmt2_table[7][5] = { + "addq", /* add quick */ + "cmpq", /* compare quick */ + "spr", /* save processor register */ + "s", /* save condition as boolean */ + "acb", /* add, compare and branch */ + "movq", /* move quick */ + "lpr" /* load processor register */ +}; + +#define FMT2_ADDQ 0x0 /* add quick */ +#define FMT2_CMPQ 0x1 /* compare quick */ +#define FMT2_SPR 0x2 /* store processr oregister */ +#define FMT2_SCOND 0x3 /* save condition as boolean */ +#define FMT2_ACB 0x4 /* add, compare and branch */ +#define FMT2_MOVQ 0x5 /* move quick */ +#define FMT2_LPR 0x6 /* load processor register */ + +STATIC +char fmt3_table[8][7] = { + "cxpd", /* call external procedure with descriptor */ + "bicpsr", /* bit clear in PSR */ + "jump", /* jump */ + "bispsr", /* bit set in PSR */ + "??3??", /* UNDEFINED */ + "adjsp", /* adjust stack pointer */ + "jsr", /* jump to subroutine */ + "case" /* case branch */ +}; + +#define FMT3_CXPD 0x0 /* call external procedure with descriptor */ +#define FMT3_BICPSR 0x1 /* bit clear in PSR */ +#define FMT3_JUMP 0x2 /* jump */ +#define FMT3_BISPSR 0x3 /* bit set in PSR */ +#define FMT3_UNDEF 0x4 /* UNDEFINED */ +#define FMT3_ADJSP 0x5 /* adjust stack pointer */ +#define FMT3_JSR 0x6 /* jump to subroutine */ +#define FMT3_CASE 0x7 /* case branch */ + +STATIC +char fmt4_table[16][5] = { + "add", /* add */ + "cmp", /* compare */ + "bic", /* bit clear */ + "?4?", /* UNDEFINED */ + "addc", /* add with carry */ + "mov", /* move */ + "or", /* or */ + "?4?", /* UNDEFINED */ + "sub", /* subtract */ + "addr", /* compute effective address */ + "and", /* and */ + "?4?", /* UNDEFINED */ + "subc", /* subtract with carry */ + "tbit", /* test bit */ + "xor", /* exclusive or */ + "?4?" /* UNDEFINED */ +}; + +#define FMT4_ADD 0x0 /* add */ +#define FMT4_CMP 0x1 /* compare */ +#define FMT4_BIC 0x2 /* bit clear */ +#define FMT4_ADDC 0x4 /* add with carry */ +#define FMT4_MOV 0x5 /* move */ +#define FMT4_OR 0x6 /* or */ +#define FMT4_SUB 0x8 /* subtract */ +#define FMT4_ADDR 0x9 /* compute effective address */ +#define FMT4_AND 0xa /* and */ +#define FMT4_SUBC 0xc /* subtract with carry */ +#define FMT4_TBIT 0xd /* test bit */ +#define FMT4_XOR 0xe /* exclusive or */ + +STATIC +char fmt5_table[4][7] = { + "movs", /* move string */ + "cmps", /* compare string */ + "setcfg", /* set configuration register */ + "skps" /* skip string */ +}; + +#define FMT5_MOVS 0x0 /* move string */ +#define FMT5_CMPS 0x1 /* compare string */ +#define FMT5_SETCFG 0x2 /* set configuration register */ +#define FMT5_SKPS 0x3 /* skip string */ + +STATIC +char fmt6_table[16][6] = { + "rot", /* rotate */ + "ash", /* arithmetic shift */ + "cbit", /* clear bit */ + "cbiti", /* clear bit interlocked */ + "??6??", /* undefined */ + "lsh", /* logical shift */ + "sbit", /* set bit */ + "sbiti", /* set bit interlocked */ + "neg", /* negate */ + "not", /* not */ + "??6??", /* undefined */ + "subp", /* subtract packed decimal */ + "abs", /* absolute value */ + "com", /* complement */ + "ibit", /* invert bit */ + "addp" /* add packed decimal */ +}; + +#define FMT6_ROT 0x0 /* rotate */ +#define FMT6_ASH 0x1 /* arithmetic shift */ +#define FMT6_CBIT 0x2 /* clear bit */ +#define FMT6_CBITI 0x3 /* clear bit interlocked */ +#define FMT6_UNDEF1 0x4 /* undefined */ +#define FMT6_LSH 0x5 /* logical shift */ +#define FMT6_SBIT 0x6 /* s#define FMT6_NOT 0x9 /* not */ +#define FMT6_UNDEF2 0xa /* undefined */ +#define FMT6_SUBP 0xb /* subtract packed decimal */ +#define FMT6_ABS 0xc /* absolute value */ +#define FMT6_COM 0xd /* complement */ +#define FMT6_IBIT 0xe /* invert bit */ +#define FMT6_ADDP 0xf /* add packed decimal */ + +STATIC +char fmt7_table[16][7] = { + "movm", /* move multiple */ + "cmpm", /* compare multiple */ + "inss", /* insert field short */ + "exts", /* extract field short */ + "movxb", /* move with sign-extention byte to word */ + "movzb", /* move with zero-extention byte to word */ + "movz", /* move with zero extention i to double */ + "movx", /* move with sign-extention i to double */ + "mul", /* multiply */ + "mei", /* multiply extended integer */ + "?7?", /* undefined */ + "dei", /* divide extended integer */ + "quo", /* quotient */ + "rem", /* remainder */ + "mod", /* modulus */ + "div" /* divide */ +}; + +#define FMT7_MOVM 0x0 /* move multiple */ +#define FMT7_CMPM 0x1 /* compare multiple */ +#define FMT7_INSS 0x2 /* insert field short */ +#define FMT7_EXTS 0x3 /* extract field short */ +#define FMT7_MOVXBW 0x4 /* move with sign-extention byte to word */ +#define FMT7_MOVZBW 0x5 /* move with zero-extention byte to word */ +#define FMT7_MOVZD 0x6 /* move with zero extention i to double */ +#define FMT7_MOVXD 0x7 /* move with sign-extention i to double */ +#define FMT7_MUL 0x8 /* multiply */ +#define FMT7_MEI 0x9 /* multiply extended integer */ +#define FMT7_UNDEF 0xa /* undefined */ +#define FMT7_DEI 0xb /* divide extended integer */ +#define FMT7_QUO 0xc /* quotient */ +#define FMT7_REM 0xd /* remainder */ +#define FMT7_MOD 0xe /* modulus */ +#define FMT7_DIV 0xf /* divide */ + +STATIC +char fmt8_table[8][6] = { + "ext", /* extract field */ + "cvtp", /* convert to bit pointer */ + "ins", /* insert field */ + "check", /* bounds check */ + "index", /* calculate index */ + "ffs", /* find first set bit */ + "mov", /* move supervisor to/from user space */ + "??8??" /* undefined */ +}; + +#define FMT8_EXT 0x0 /* extract field */ +#define FMT8_CVTP 0x1 /* convert to bit pointer */ +#define FMT8_INS 0x2 /* insert field */ +#define FMT8_CHECK 0x3 /* bounds check */ +#define FMT8_INDEX 0x4 /* calculate index */ +#define FMT8_FFS 0x5 /* find first set bit */ +#define FMT8_MOV 0x6 /* move supervisor to/from user space */ +#define FMT8_UNDEF 0x7 /* undefined */ + +STATIC +char fmt9_table[8][6] = { + "mov", /* move converting integer to floating point */ + "lfsr", /* load floating-point status register */ + "movlf", /* move long floating to floating */ + "movfl", /* move floating to long floating */ + "round", /* round floating to integer */ + "trunc", /* truncate floating to integer */ + "sfsr", /* store floating-point status register */ + "floor" /* floor floating to integer */ +}; + +#define FMT9_MOV 0x0 /* move converting integer to floating point */ +#define FMT9_LFSR 0x1 /* load floating-point status register */ +#define FMT9_MOVLF 0x2 /* move long floating to floating */ +#define FMT9_MOVFL 0x3 /* move floating to long floating */ +#define FMT9_ROUND 0x4 /* round floating to integer */ +#define FMT9_TRUNC 0x5 /* truncate floating to integer */ +#define FMT9_SFSR 0x6 /* store floating-point status register */ +#define FMT9_FLOOR 0x7 /* floor floating to integer */ + +#define NOP 0xff; /* catch all nop instruction */ + +STATIC +char fmt11_table[16][4] = { + "add", /* add floating */ + "mov", /* move floating */ + "cmp", /* compare floating */ + "?f?", /* undefined */ + "sub", /* subtract floating */ + "neg", /* negate floating */ + "?f?", /* undefined */ + "?f?", /* undefined */ + "div", /* divide floating */ + "?f?", /* undefined */ + "?f?", /* undefined */ + "?f?", /* undefined */ + "mul", /* multiply floating */ + "abs", /* absolute value floating */ + "?f?", /* undefined */ + "?f?" /* undefined */ +}; + +STATIC +char fmt12_table[16][6] = { + "?f?", /* 0 undefined */ + "?f?", /* 1 undefined */ + "poly", /* 2 */ + "dot", /* 3 */ + "scalb", /* 4 */ + "logb", /* 5 */ + "?f?", /* 6 undefined */ + "?f?", /* 7 undefined */ + "?f?", /* 8 undefined */ + "?f?", /* 9 undefined */ + "?f?", /* 10 undefined */ + "?f?", /* 11 undefined */ + "?f?", /* 12 undefined */ + "?f?", /* 13 undefined */ + "?f?", /* 14 undefined */ + "?f?", /* 15 undefined */ +}; + +#define FMT11_ADD 0x0 /* add floating */ +#define FMT11_MOV 0x1 /* move floating */ +#define FMT11_CMP 0x2 /* compare floating */ +#define FMT11_UNDEF1 0x3 /* undefined */ +#define FMT11_SUB 0x4 /* subtract floating */ +#define FMT11_NEG 0x5 /* negate floating */ +#define FMT11_UNDEF2 0x6 /* undefined */ +#define FMT11_UNDEF3 0x7 /* undefined */ +#define FMT11_DIV 0x8 /* divide floating */ +#define FMT11_UNDEF4 0x9 /* undefined */ +#define FMT11_UNDEF5 0xa /* undefined */ +#define FMT11_UNDEF6 0xb /* undefined */ +#define FMT11_MUL 0xc /* multiply floating */ +#define FMT11_ABS 0xd /* absolute value floating */ +#define FMT11_UNDEF7 0xe /* undefined */ +#define FMT11_UNDEF8 0xf /* undefined */ + +#define FMT12_POLY 2 +#define FMT12_DOT 3 +#define FMT12_SCALB 4 +#define FMT12_LOGB 5 + +STATIC +char fmt14_table[][6] = { + "rdval", /* validate address for reading */ + "wrval", /* validate address for writing */ + "lmr", /* load memory managemnet register */ + "smr", /* store memory management register */ + "???", + "???", + "???", + "???", + "???", + "cinv", +}; + +#define FMT14_RDVAL 0x0 /* validate address for reading */ +#define FMT14_WRVAL 0x1 /* validate address for writing */ +#define FMT14_LMR 0x2 /* load memory managemnet register */ +#define FMT14_SMR 0x3 /* store memory management register */ +#define FMT14_CINV 0x9 /* cache invalidate */ + +/* + * These are indices into regTable. Keep in sync! + */ +#define REG_R0 0 /* General Register 0 */ +#define REG_F0 8 /* Floating Point 0 */ +#define REG_PC 32 /* Program counter */ +#define REG_USP (REG_PC+1) +#define REG_ISP (REG_PC+2) +#define REG_FP (REG_PC+3) +#define REG_SB (REG_PC+4) +#define REG_INTBASE (REG_PC+5) +#define REG_MOD (REG_PC+6) +#define REG_PSR (REG_PC+7) +#define REG_UPSR (REG_PC+8) +#define REG_DCR (REG_PC+9) +#define REG_DSR (REG_PC+10) +#define REG_CAR (REG_PC+11) +#define REG_BPC (REG_PC+12) +#define REG_CFG (REG_PC+13) + +#define REG_PTB0 46 +#define REG_PTB1 (REG_PTB0+1) +#define REG_IVAR0 (REG_PTB0+2) +#define REG_IVAR1 (REG_PTB0+3) +#define REG_TEAR (REG_PTB0+4) +#define REG_MCR (REG_PTB0+5) +#define REG_MSR (REG_PTB0+6) + +#define REG_FSR 53 +#define REG_SP (REG_FSR+1) +#define REG_NIL (REG_FSR+2) + +struct regTable { + char *name; +}; + +STATIC +struct regTable regTable[] = { + {"r0"}, /* General Register 0 */ + {"r1"}, /* General Register 1 */ + {"r2"}, /* General Register 2 */ + {"r3"}, /* General Register 3 */ + {"r4"}, /* General Register 4 */ + {"r5"}, /* General Register 5 */ + {"r6"}, /* General Register 6 */ + {"r7"}, /* General Register 7 */ + {"f0"}, /* Floating Point 0 */ + {"f1"}, /* Floating Point 1 */ + {"f2"}, /* Floating Point 2 */ + {"f3"}, /* Floating Point 3 */ + {"f4"}, /* Floating Point 4 */ + {"f5"}, /* Floating Point 5 */ + {"f6"}, /* Floating Point 6 */ + {"f7"}, /* Floating Point 7 */ + {"l1l"}, /* Floating Point L1 */ + {"l1h"}, /* Floating Point L1 */ + {"l3l"}, /* Floating Point L3 */ + {"l3h"}, /* Floating Point L3 */ + {"l5l"}, /* Floating Point L5 */ + {"l5h"}, /* Floating Point L5 */ + {"l7l"}, /* Floating Point L7 */ + {"l7h"}, /* Floating Point L7 */ + {"l0"}, + {"l1"}, + {"l2"}, + {"l3"}, + {"l4"}, + {"l5"}, + {"l6"}, + {"l7"}, + {"pc"}, /* Program counter */ + {"usp"}, /* 532 */ + {"isp"}, /* 532 */ + {"fp"}, /* Frame Pointer */ + {"sb"}, /* Static Base */ + {"intbase"}, /* Interrupt Base */ + {"mod"}, /* Module Register */ + {"psr"}, /* Processor Status */ + {"upsr"}, /* Processor Status */ + {"dcr"}, /* 532 */ + {"dsr"}, /* 532 */ + {"car"}, /* 532 */ + {"bpc"}, /* 532 */ + {"cfg"}, /* 532 */ + {"ptb0"}, /* Page Table Base 0 */ + {"ptb1"}, /* Page Table Base 1 */ + {"ivar0"}, /* 532 */ + {"ivar1"}, /* 532 */ + {"tear"}, /* 532 */ + {"mcr"}, /* 532 */ + {"msr"}, /* Memory Management Status */ + {"fsr"}, /* Floating Point Status */ + {"sp"}, /* x(x(sp)) adr mode */ + {"???"}, /* unknown reg */ +}; + +#define REGTABLESZ ((sizeof regTable) / (sizeof (struct regTable))) + +#define GetShort(x, y) ((((x) & 0x80) >> 7) + (((y) & 0x7) << 1)) +#define GetGen0(x) (((x) & 0xf8) >> 3) +#define GetGen1(x,y) ((((x) & 0xc0) >> 6) + (((y) & 0x7) << 2)) +#define GetGenSI(x) (int)((((x) & 0x1c) == 0x1c) ? (((x) & 0x3) + 1) : 0) +#define ScaledFields(input, reg, gen) \ + ((reg) = ((input) & 0x7), \ + (gen) = (((input) & 0xf8) >> 3)) + +STATIC unsigned char cpuRegTable [] = { + REG_UPSR, REG_DCR, REG_BPC, REG_DSR, + REG_CAR, REG_NIL, REG_NIL, REG_NIL, + REG_FP, REG_SP, REG_SB, REG_USP, + REG_CFG, REG_PSR, REG_INTBASE, REG_MOD, +}; + +STATIC unsigned char mmuRegTable [] = { + REG_NIL, REG_NIL, REG_NIL, REG_NIL, + REG_NIL, REG_NIL, REG_NIL, REG_NIL, + REG_NIL, REG_MCR, REG_MSR, REG_TEAR, + REG_PTB0, REG_PTB1,REG_IVAR0, REG_IVAR1, +}; + +void db_reverseBits(); + +#define get_byte(l,t) ((unsigned char) db_get_task_value(l, 1, FALSE, t)) + +void db_formatOperand(operand, loc, task) + struct operand *operand; + db_addr_t loc; + task_t task; +{ + int need_comma, i, mask, textlen; + + switch (operand->o_mode) { + + case AMODE_REG: + case AMODE_AREG: + case AMODE_MREG: + db_printf("%s", regTable[operand->o_reg0].name); + break; + + case AMODE_MREL: + db_task_printsym((db_addr_t) operand->o_disp1, + DB_STGY_ANY, task); + db_printf("("); + db_task_printsym((db_addr_t) operand->o_disp0, + DB_STGY_ANY, task); + db_printf("(%s))",regTable[operand->o_reg0].name); + break; + + case AMODE_QUICK: + case AMODE_IMM: + db_task_printsym((db_addr_t) operand->o_disp0, + DB_STGY_ANY, task); + break; + + case AMODE_ABS: + db_printf("@"); + db_task_printsym((db_addr_t) operand->o_disp0, + DB_STGY_ANY, task); + break; + + case AMODE_EXT: + db_printf("ext(%ld)", operand->o_disp0); + if (operand->o_disp1) + db_printf("+%ld", operand->o_disp1); + break; + + case AMODE_TOS: + db_printf("tos"); + break; + + case AMODE_RREL: + case AMODE_MSPC: + db_task_printsym((db_addr_t) operand->o_disp0, + DB_STGY_XTRN, task); + db_printf("(%s)",regTable[operand->o_reg0].name); + break; + + case AMODE_REGLIST: + db_printf("["); + need_comma = 0; + for (i = 0; i < 8; i++) { + mask = (1<<i); + if (operand->o_reg0&mask) { + if (need_comma) + db_printf(","); + db_printf("r%d", i); + need_comma = 1; + } + } + db_printf("]"); + break; + + case AMODE_BLISTB: + i = 7; + goto bitlist; + + case AMODE_BLISTW: + i = 15; + goto bitlist; + + case AMODE_BLISTD: + i = 31; + +bitlist: + db_printf("B'"); + for (; i >= 0; i--, textlen++) { + mask = (1<<i); + if (operand->o_disp0&mask) + db_printf("1"); + else + db_printf("0"); + } + break; + + case AMODE_SOPT: + i = operand->o_disp0>>1; + db_printf("%s", sopt_table[i]); + break; + + case AMODE_CFG: + db_printf("["); + need_comma = 0; + for (i = 0;i < 3;i++) { + mask = 1<<i; + if (operand->o_disp0&mask) { + if (need_comma) + db_printf(","); + db_printf("%s",cfg_table[i]); + need_comma = 1; + } + } + db_printf("]"); + break; + + case AMODE_CINV: + { /* print cache invalidate flags */ + char *p; + int i, need_comma = 0; + + for (i = 4, p = "AID"; i; i >>= 1, ++p) + if (i & operand->o_disp0) { + if (need_comma) + db_printf(","); + db_printf("%c",*p); + need_comma = 1; + } + } + break; + + case AMODE_INVALID: + db_printf("?"); + break; + } + if (operand->o_iscale) { + db_printf("[r%d:", operand->o_ireg); + db_printf("%s]",scale_table[operand->o_iscale]); + } +} + +void db_formatAsm(insn, loc, task, altfmt) + struct insn *insn; + db_addr_t loc; + task_t task; + boolean_t altfmt; +{ + int i, j; + + db_printf("%s\t", &insn->i_monic[0]); + + for (i = 0; i < 4 && insn->i_opr[i].o_mode != AMODE_NONE; i++) { + if (i != 0) { + db_printf(","); + } + db_formatOperand(&insn->i_opr[i], loc, task); + } + j = 0; + for (i = 0; i < 4 && insn->i_opr[i].o_mode != AMODE_NONE; i++) { + if (insn->i_opr[i].o_mode == AMODE_MSPC || + insn->i_opr[i].o_mode == AMODE_RREL) { + register struct db_variable *regp; + db_expr_t value; + + if (strcmp(db_regs->name, "pc") == 0) { + value = loc; + } else { + if (!altfmt) { + continue; + } + for (regp = db_regs; regp < db_eregs; regp++) { + if (strcmp(regp->name, + regTable[insn-> + i_opr[i].o_reg0]. + name) == 0) { + break; + } + } + db_read_write_variable(regp, &value, + DB_VAR_GET, 0); + } + if (j != 0) { + db_printf(","); + } else { + db_printf("\t<"); + } + db_task_printsym((db_addr_t) + insn->i_opr[i].o_disp0 + value, + DB_STGY_XTRN, task); + j++; + } + } + if (j != 0) { + db_printf(">"); + } +} + +void db_initInsn (insn) + struct insn *insn; +{ + insn->i_opr[0].o_mode = AMODE_NONE; + insn->i_opr[0].o_iscale = 0; + insn->i_opr[1].o_mode = AMODE_NONE; + insn->i_opr[1].o_iscale = 0; + insn->i_opr[2].o_mode = AMODE_NONE; + insn->i_opr[2].o_iscale = 0; + insn->i_opr[3].o_mode = AMODE_NONE; + insn->i_opr[3].o_iscale = 0; +} + +int db_disp(loc, result, task) + db_addr_t loc; + long *result; + task_t task; +{ + unsigned int b; + + b = get_byte(loc, task); + if (!(b & 0x80)) { /* one byte */ + *result = ((b & 0x40) ? 0xffffffc0L : 0) | (b & 0x3f); + return(1); + } else if (!(b & 0x40)) { /* two byte */ + *result = + ((b & 0x20) ? 0xffffe000L : 0) | ((b & 0x1f) << 8); + b = get_byte(loc + 1, task); + *result |= b; + return 2; + } else { /* four byte */ + *result = + ((b & 0x20) ? 0xe0000000L : 0) | /* bug fix 8/28 */ + ((b & 0x1f) << 24); /* bug fix 7/21 */ + b = get_byte(loc + 1, task); + *result |= (b << 16); + b = get_byte(loc + 2, task); + *result |= (b << 8); + b = get_byte(loc + 3, task); + *result |= b; + return(4); + } +} + +int db_decode_operand(loc, byte, operand, iol, task) + db_addr_t loc; + unsigned char byte; + struct operand *operand; + unsigned char iol; + task_t task; +{ + register int i, consumed = 0; + unsigned long value; + + switch (byte) { + + case GEN_R0: + case GEN_R1: + case GEN_R2: + case GEN_R3: + case GEN_R4: + case GEN_R5: + case GEN_R6: + case GEN_R7: + operand->o_mode = AMODE_REG; + operand->o_reg0 = REG_R0 + byte; + break; + + case GEN_RR0: + case GEN_RR1: + case GEN_RR2: + case GEN_RR3: + case GEN_RR4: + case GEN_RR5: + case GEN_RR6: + case GEN_RR7: + operand->o_mode = AMODE_RREL; + operand->o_reg0 = REG_R0 + (byte&0x7); + goto one_disp; + + case GEN_FRMR: + operand->o_reg0 = REG_FP; + operand->o_mode = AMODE_MREL; + goto two_disp; + + case GEN_SPMR: + operand->o_reg0 = REG_SP; + operand->o_mode = AMODE_MREL; + goto two_disp; + + case GEN_SBMR: + operand->o_reg0 = REG_SB; + operand->o_mode = AMODE_MREL; + goto two_disp; + + case GEN_IMM: + operand->o_mode = AMODE_IMM; + /* fix to sign extend */ + value = (get_byte(loc, task) & 0x80)? 0xffffffff: 0; + for (i = 0; i < iol; i++) { + value = (value << 8) + get_byte(loc + i, task); + } + operand->o_disp0 = value; + consumed = iol; + break; + + case GEN_ABS: + operand->o_mode = AMODE_ABS; + goto one_disp; + + case GEN_EXT: + operand->o_mode = AMODE_EXT; + goto two_disp; + + case GEN_TOS: + operand->o_mode = AMODE_TOS; + break; + + case GEN_FRM: + operand->o_mode = AMODE_MSPC; + operand->o_reg0 = REG_FP; + goto one_disp; + + case GEN_SPM: + operand->o_mode = AMODE_MSPC; + operand->o_reg0 = REG_SP; + goto one_disp; + + case GEN_SBM: + operand->o_mode = AMODE_MSPC; + operand->o_reg0 = REG_SB; + goto one_disp; + + case GEN_PCM: + operand->o_mode = AMODE_MSPC; + operand->o_reg0 = REG_PC; + goto one_disp; + + default: + operand->o_mode = AMODE_INVALID; + break; + +two_disp: + consumed = db_disp(loc, &operand->o_disp0, task); + consumed += db_disp(loc + consumed, &operand->o_disp1, task); + break; + +one_disp: + consumed = db_disp(loc, &operand->o_disp0, task); + break; + } + return(consumed); +} + +int db_gen(insn, loc, mask, byte0, byte1, task) + struct insn *insn; + db_addr_t loc; + int mask; /* 1 to get gen1, 2 to get gen2 */ + unsigned char byte0, byte1; + task_t task; +{ + int opr = 0, opr2, consumed = 0; + unsigned char gen0, gen1; + + gen0 = GetGen0(byte1); /* mask and shift gen fields */ + gen1 = GetGen1(byte0, byte1); /* gen0 is really 1, gen1 is 2 */ + + while (insn->i_opr[opr].o_mode != AMODE_NONE) + opr++; + + if (mask & 0x1) { + if (insn->i_opr[opr].o_iscale = GetGenSI(gen0)) { + ScaledFields(get_byte(loc, task), + insn->i_opr[opr].o_ireg, gen0); + consumed++; + } + opr2 = opr + 1; + } else { + opr2 = opr; + } + + if (mask & 0x2 && + (insn->i_opr[opr2].o_iscale = GetGenSI(gen1))) { + ScaledFields(get_byte(loc + consumed, task), + insn->i_opr[opr2].o_ireg, gen1); + consumed++; + } + + if (mask & 0x1) { + consumed += db_decode_operand(loc + consumed, gen0, + &insn->i_opr[opr], insn->i_iol, + task); + } + if (mask & 0x2) { + consumed += db_decode_operand(loc + consumed, gen1, + &insn->i_opr[opr2], insn->i_iol, + task); + } + return(consumed); +} + +int db_dasm_ns32k(insn, loc, task) + struct insn *insn; + db_addr_t loc; /* start addr of this insn */ + task_t task; +{ + unsigned char byte0, byte1, byte2; + int i, j; + int consumed; + + insn->i_iol = IOL_NONE; /* Don't assume any operand length */ + byte0 = get_byte(loc, task); /* look at first byte in insn */ + consumed = 1; + i = byte0 / 2; /* get index into fmttab */ + if (byte0 % 2) + j = ((fmttab[i] & 0xf0) >> 4); + else + j = (fmttab[i]) & 0x0f; + + insn->i_format = j; /* set insn type */ + + switch (j) { + case ITYPE_FMT0: + insn->i_op = FMT0_COND(byte0); /* condition code field */ + insn->i_monic[0] = 'b'; + insn->i_monic[1] = cond_table[insn->i_op][0]; + insn->i_monic[2] = cond_table[insn->i_op][1]; + insn->i_monic[3] = '\0'; + insn->i_opr[0].o_mode = AMODE_IMM; /* MSPC implied */ + insn->i_opr[0].o_reg0 = REG_PC; + consumed += db_disp(loc + consumed, &insn->i_opr[0].o_disp0, + task); + insn->i_opr[0].o_disp0 += loc; + break; + + case ITYPE_FMT1: + insn->i_op = FMT1_OP(byte0); + strcpy(insn->i_monic, fmt1_table[insn->i_op]); + switch (insn->i_op) { + case FMT1_CXP: + case FMT1_RXP: + case FMT1_RET: + case FMT1_RETT: + insn->i_opr[0].o_mode = AMODE_IMM; + consumed += db_disp(loc + consumed, + &insn->i_opr[0].o_disp0, task); + break; + + case FMT1_BSR: + insn->i_opr[0].o_mode = AMODE_IMM; /* MSPC implied */ + insn->i_opr[0].o_reg0 = REG_PC; + consumed += db_disp(loc + consumed, + &insn->i_opr[0].o_disp0, task); + insn->i_opr[0].o_disp0 += loc; + break; + + case FMT1_SAVE: + case FMT1_RESTORE: + case FMT1_ENTER: + case FMT1_EXIT: + insn->i_opr[0].o_mode = AMODE_REGLIST; + insn->i_opr[0].o_reg0 = get_byte(loc + consumed, task); + consumed++; + if (insn->i_op == FMT1_EXIT || + insn->i_op == FMT1_RESTORE) /* WBC bug fix */ + db_reverseBits (&(insn->i_opr[0].o_reg0)); + if (insn->i_op == FMT1_ENTER) { + /* MSPC implied */ + insn->i_opr[1].o_mode = AMODE_IMM; + insn->i_opr[1].o_reg0 = REG_PC; + consumed += db_disp(loc + consumed, + &insn->i_opr[1].o_disp0, + task); + } + break; + } + break; + + case ITYPE_FMT2: + byte1 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT2_OP(byte0); + insn->i_iol = IOL(byte0); + i = GetShort(byte0, byte1); + strcpy(insn->i_monic, fmt2_table[insn->i_op]); + switch (insn->i_op) { + + case FMT2_SCOND: + strcat(insn->i_monic, cond_table[i]); + break; + + case FMT2_ADDQ: + case FMT2_CMPQ: + case FMT2_ACB: + case FMT2_MOVQ: + if (i&0x08) { /* negative quick value */ + insn->i_opr[0].o_disp0 = i; + insn->i_opr[0].o_disp0 |= 0xfffffff0; + } else { + insn->i_opr[0].o_disp0 = i; + } + insn->i_opr[0].o_mode = AMODE_QUICK; + break; + + case FMT2_LPR: + case FMT2_SPR: + insn->i_opr[0].o_reg0 = cpuRegTable [i]; + insn->i_opr[0].o_mode = AMODE_AREG; + break; + } + consumed += db_gen(insn, loc + consumed, 0x1, 0, byte1, task); + strcat(insn->i_monic, iol_table[insn->i_iol]); + if (insn->i_op == FMT2_ACB) { + consumed += db_disp(loc + consumed, + &insn->i_opr[2].o_disp0, task); + insn->i_opr[2].o_disp0 += loc; + insn->i_opr[2].o_mode = AMODE_IMM; + } + break; + + case ITYPE_FMT3: + insn->i_format = ITYPE_FMT3; + byte1 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT3_OP(byte1); + insn->i_iol = IOL(byte0); + strcpy(insn->i_monic, fmt3_table[insn->i_op]); + consumed += db_gen(insn, loc + consumed, 0x1, 0, byte1, task); + switch (insn->i_op) { + + case FMT3_CXPD: + case FMT3_JUMP: + case FMT3_JSR: + if (insn->i_iol != IOL_DOUBLE) + insn->i_format = ITYPE_UNDEF; + break; + + case FMT3_BICPSR: + case FMT3_BISPSR: + if (insn->i_iol == IOL_DOUBLE) { + insn->i_format = ITYPE_UNDEF; + break; + } + if (insn->i_opr[0].o_mode == AMODE_IMM) { + if (insn->i_iol == IOL_BYTE) + insn->i_opr[0].o_mode = AMODE_BLISTB; + else + insn->i_opr[0].o_mode = AMODE_BLISTW; + } + /* fall through */ + + case FMT3_CASE: + case FMT3_ADJSP: + strcat(insn->i_monic, iol_table[insn->i_iol]); + break; + + case FMT3_UNDEF: + insn->i_format = ITYPE_UNDEF; + break; + + } + break; + + case ITYPE_FMT4: + byte1 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT4_OP(byte0); + insn->i_iol = IOL(byte0); + strcpy(insn->i_monic, fmt4_table[insn->i_op]); + consumed += db_gen(insn, loc + consumed, 0x3, byte0, + byte1, task); + if (insn->i_op == FMT4_ADDR) { + if (insn->i_iol != IOL_DOUBLE) + insn->i_format = ITYPE_UNDEF; + } + else + strcat(insn->i_monic, iol_table[insn->i_iol]); + break; + + case ITYPE_FMT5: + byte1 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT5_OP(byte1); + if (insn->i_op > FMT5_SKPS) { + insn->i_format = ITYPE_UNDEF; + break; + } + strcpy(insn->i_monic, fmt5_table[insn->i_op]); + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_opr[0].o_disp0 = GetShort(byte1, byte2); + insn->i_iol = IOL(byte1); + switch (insn->i_op) { + + case FMT5_MOVS: + case FMT5_CMPS: + case FMT5_SKPS: + if (insn->i_opr[0].o_disp0&0x1) + strcat(insn->i_monic, "t"); + else + strcat(insn->i_monic, + iol_table[insn->i_iol]); + insn->i_opr[0].o_mode = AMODE_SOPT; + break; + + case FMT5_SETCFG: + insn->i_opr[0].o_mode = AMODE_CFG; + break; + } + break; + + case ITYPE_FMT6: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT6_OP(byte1); + insn->i_iol = IOL(byte1); + strcpy(insn->i_monic, fmt6_table[insn->i_op]); + strcat(insn->i_monic, iol_table[insn->i_iol]); + if (insn->i_op == FMT6_ROT || + insn->i_op == FMT6_ASH || + insn->i_op == FMT6_LSH) + { + insn->i_iol = 1; /* shift and rotate special case */ + } + if (insn->i_op == FMT6_UNDEF1 || + insn->i_op == FMT6_UNDEF2) { + insn->i_format = ITYPE_UNDEF; + break; + } + consumed += db_gen(insn, loc + consumed, 0x3, byte1, byte2, + task); + break; + + case ITYPE_FMT7: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT7_OP(byte1); + strcpy(insn->i_monic, fmt7_table[insn->i_op]); + insn->i_iol = IOL(byte1); + strcat(insn->i_monic, iol_table[insn->i_iol]); + consumed += db_gen(insn, loc + consumed, 0x3, byte1, byte2, + task); + switch (insn->i_op) { + + case FMT7_MOVM: + case FMT7_CMPM: + consumed += db_disp(loc + consumed, + &insn->i_opr[2].o_disp0, task); + /* WBC bug fix */ + insn->i_opr[2].o_mode = AMODE_IMM; + break; + + case FMT7_INSS: + case FMT7_EXTS: + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_opr[2].o_disp0 = ((byte2&0xe0)>>5); + insn->i_opr[2].o_mode = AMODE_IMM; + insn->i_opr[3].o_disp0 = ((byte2&0x1f) + 1); + insn->i_opr[3].o_mode = AMODE_IMM; + break; + + case FMT7_MOVZD: + case FMT7_MOVXD: + strcat(insn->i_monic, "d"); + break; + + case FMT7_UNDEF: + insn->i_format = ITYPE_UNDEF; + break; + } + break; + + case ITYPE_FMT8: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT8_OP(byte0, byte1); + strcpy(insn->i_monic, fmt8_table[insn->i_op]); + insn->i_iol = IOL(byte1); + switch (insn->i_op) { + + case FMT8_MOV: + if (FMT8_REG(byte1) == FMT8_SU) + strcat(insn->i_monic, "su"); + else if (FMT8_REG(byte1) == FMT8_US) + strcat(insn->i_monic, "us"); + else + strcat(insn->i_monic, "??"); + /* fall through */ + + case FMT8_EXT: + case FMT8_INS: + case FMT8_CHECK: + case FMT8_INDEX: + case FMT8_FFS: + strcat(insn->i_monic, iol_table[insn->i_iol]); + /* fall through */ + + case FMT8_CVTP: + if (insn->i_op != FMT8_FFS && insn->i_op != FMT8_MOV) { + insn->i_opr[0].o_reg0 = + REG_R0 + FMT8_REG(byte1); + insn->i_opr[0].o_mode = AMODE_REG; + } + consumed += db_gen(insn, loc + consumed, 0x3, byte1, + byte2, task); + if (insn->i_op == FMT8_EXT || + insn->i_op == FMT8_INS) { + consumed += db_disp(loc + consumed, + &insn->i_opr[3].o_disp0, + task); + insn->i_opr[3].o_mode = AMODE_IMM; + } + break; + + default: + insn->i_format = ITYPE_UNDEF; + break; + } + break; + + case ITYPE_FMT9: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT9_OP(byte1); + strcpy(insn->i_monic, fmt9_table[insn->i_op]); + insn->i_iol = IOL(byte1); + i = FMT9_F(byte1); + switch (insn->i_op) { + + case FMT9_MOV: + strcat(insn->i_monic, iol_table[insn->i_iol]); + strcat(insn->i_monic, fol_table[i]); + consumed += db_gen(insn, loc + consumed, 0x3, byte1, + byte2, task); + if (insn->i_opr[1].o_mode == AMODE_REG) + insn->i_opr[1].o_reg0 = + REG_F0 + (insn->i_opr[1].o_reg0 - REG_R0); + break; + + case FMT9_LFSR: + consumed += db_gen(insn, loc + consumed, 0x1, + byte1, byte2, task); + break; + + case FMT9_SFSR: + consumed += db_gen(insn, loc + consumed, 0x2, + byte1, byte2, task); + break; + + case FMT9_MOVLF: + case FMT9_MOVFL: + consumed += db_gen(insn, loc + consumed, 0x3, byte1, + byte2, task); + if (insn->i_opr[0].o_mode == AMODE_REG) + insn->i_opr[0].o_reg0 = + REG_F0 + (insn->i_opr[0].o_reg0 - REG_R0); + if (insn->i_opr[1].o_mode == AMODE_REG) + insn->i_opr[1].o_reg0 = + REG_F0 + (insn->i_opr[1].o_reg0 - REG_R0); + break; + + case FMT9_ROUND: + case FMT9_TRUNC: + case FMT9_FLOOR: + strcat(insn->i_monic, fol_table[i]); + strcat(insn->i_monic, iol_table[insn->i_iol]); + consumed += db_gen(insn, loc + consumed, 0x3, byte1, + byte2, task); + if (insn->i_opr[0].o_mode == AMODE_REG) + insn->i_opr[0].o_reg0 = + REG_F0 + (insn->i_opr[0].o_reg0 - REG_R0); + break; + } + break; + + case ITYPE_NOP: + insn->i_op = NOP; + strcpy(insn->i_monic, "nop"); + break; + + case ITYPE_FMT11: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT11_OP(byte1); + switch (insn->i_op) { + + case FMT11_ADD: + case FMT11_MOV: + case FMT11_CMP: + case FMT11_SUB: + case FMT11_NEG: + case FMT11_DIV: + case FMT11_MUL: + case FMT11_ABS: + strcpy(insn->i_monic, fmt11_table[insn->i_op]); + strcat(insn->i_monic, fol_table[FMT11_F(byte1)]); + consumed += db_gen(insn, loc + consumed, 0x3, byte1, + byte2, task); + if (insn->i_opr[0].o_mode == AMODE_REG) + insn->i_opr[0].o_reg0 = + REG_F0 + (insn->i_opr[0].o_reg0 - REG_R0); + if (insn->i_opr[1].o_mode == AMODE_REG) + insn->i_opr[1].o_reg0 = + REG_F0 + (insn->i_opr[1].o_reg0 - REG_R0); + break; + + default: + insn->i_format = ITYPE_UNDEF; + break; + + } + break; + + case ITYPE_FMT12: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT12_OP(byte1); + switch (insn->i_op) { + + case FMT12_POLY: + case FMT12_DOT: + case FMT12_SCALB: + case FMT12_LOGB: + strcpy(insn->i_monic, fmt12_table[insn->i_op]); + strcat(insn->i_monic, fol_table[FMT12_F(byte1)]); + consumed += db_gen(insn, loc + consumed, 0x3, byte1, + byte2, task); + if (insn->i_opr[0].o_mode == AMODE_REG) + insn->i_opr[0].o_reg0 = + REG_F0 + (insn->i_opr[0].o_reg0 - REG_R0); + if (insn->i_opr[1].o_mode == AMODE_REG) + insn->i_opr[1].o_reg0 = + REG_F0 + (insn->i_opr[1].o_reg0 - REG_R0); + break; + + default: + insn->i_format = ITYPE_UNDEF; + break; + + } + break; + + case ITYPE_UNDEF: + strcpy(insn->i_monic, "???"); + break; + + case ITYPE_FMT14: + byte1 = get_byte(loc + consumed, task); + consumed++; + byte2 = get_byte(loc + consumed, task); + consumed++; + insn->i_op = FMT14_OP(byte1); + insn->i_iol = 4; + strcpy(insn->i_monic, fmt14_table[insn->i_op]); + switch (insn->i_op) { + + case FMT14_CINV: + insn->i_opr[0].o_disp0 = GetShort(byte1, byte2); + insn->i_opr[0].o_mode = AMODE_CINV; + consumed += db_gen(insn, loc + consumed, 0x1, + byte1/* was 0*/, byte2, task); + break; + + case FMT14_LMR: + case FMT14_SMR: + insn->i_opr[0].o_reg0 = + mmuRegTable[GetShort(byte1, byte2)]; + insn->i_opr[0].o_mode = AMODE_REG; + /* fall through */ + + case FMT14_RDVAL: + case FMT14_WRVAL: + consumed += db_gen(insn, loc + consumed, 0x1, + byte1/* was 0*/, byte2, task); + break; + } + break; + + default: + insn->i_format = ITYPE_UNDEF; + strcpy(insn->i_monic, "???"); + break; + } + return(consumed); +} + +/* + * Reverse the order of the bits in the LS byte of *ip. + */ +void db_reverseBits (ip) + int *ip; +{ + int i, src, dst; + + src = *ip; + dst = 0; + for (i = 0; i < 8; ++i) { + dst = (dst << 1) | (src & 1); + src >>= 1; + } + *ip = dst; +} + +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +db_addr_t +db_disasm(loc, altfmt, task) + db_addr_t loc; + boolean_t altfmt; + task_t task; +{ + int ate; + struct insn insn; + + db_initInsn(&insn); + ate = db_dasm_ns32k(&insn, loc, task); + if (altfmt) { + int i; + + for(i = 0; i < ate; i++) { + db_printf("%02x", + db_get_task_value(loc + i, 1, FALSE, + task) & 0xff); + } + if (i < 4) + db_printf("\t"); + db_printf("\t"); + } + db_formatAsm(&insn, loc, task, altfmt); + db_printf("\n"); + return loc + ate; +} diff --git a/sys/arch/pc532/pc532/db_interface.c b/sys/arch/pc532/pc532/db_interface.c new file mode 100644 index 00000000000..f22be4739fa --- /dev/null +++ b/sys/arch/pc532/pc532/db_interface.c @@ -0,0 +1,436 @@ +/* $NetBSD: db_interface.c,v 1.3 1995/04/10 13:15:43 mycroft Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ns532/db_interface.c + * Author: Tero Kivinen, Helsinki University of Technology 1992. + * + * Interface to new kernel debugger. + */ + +#include <sys/reboot.h> +#include <vm/pmap.h> + +#include <ns532/thread.h> +#include <ns532/db_machdep.h> +#include <ns532/trap.h> +#include <ns532/setjmp.h> +#include <ns532/machparam.h> +#include <mach/vm_param.h> +#include <vm/vm_map.h> +#include <kern/thread.h> +#include <kern/task.h> +#include <ddb/db_task_thread.h> + +int db_active = 0; + +/* + * Received keyboard interrupt sequence. + */ +void +kdb_kbd_trap(regs) + struct ns532_saved_state *regs; +{ + if (db_active == 0) { + printf("\n\nkernel: keyboard interrupt\n"); + kdb_trap(-1, 0, regs); + } +} + +extern char * trap_type[]; +extern int TRAP_TYPES; + +/* + * Print trap reason. + */ +void +kdbprinttrap(type, code) + int type, code; +{ + printf("kernel: "); + if (type > TRAP_TYPES) + printf("type %d", type); + else + printf("%s", trap_type[type]); + printf(" trap, code=%x\n", code); +} + +/* + * kdb_trap - field a TRACE or BPT trap + */ + +extern jmp_buf_t *db_recover; + +int db_active_ipl; + +kdb_trap(type, code, regs) + int type, code; + register struct ns532_saved_state *regs; +{ + int s; + + s = splsched(); + db_active_ipl = s; + + switch (type) { + case T_BPT: /* breakpoint */ + case T_WATCHPOINT: /* watchpoint */ + case T_TRC: /* trace step */ + case T_DBG: /* hardware debug trap */ + case -1: /* keyboard interrupt */ + break; + + default: + if (db_recover) { + db_printf("Caught "); + if (type > TRAP_TYPES) + db_printf("type %d", type); + else + db_printf("%s", trap_type[type]); + db_printf(" trap, code = %x, pc = %x\n", + code, regs->pc); + db_error(""); + /*NOTREACHED*/ + } + kdbprinttrap(type, code); + } + + /* Should switch to kdb's own stack here. */ + + ddb_regs = *regs; + + db_active++; + cnpollc(TRUE); + db_task_trap(type, code, (DDB_REGS->psr & PSR_U) == 0); + cnpollc(FALSE); + db_active--; + + if ((type = T_BPT) && + (db_get_task_value(PC_REGS(DDB_REGS), BKPT_SIZE, FALSE, TASK_NULL) + == BKPT_INST)) + PC_REGS(DDB_REGS) += BKPT_SIZE; + + *regs = ddb_regs; + (void) splx(s); + return (1); +} + +int +db_user_to_kernel_address(task, addr, kaddr, flag) + task_t task; + vm_offset_t addr; + unsigned *kaddr; + int flag; +{ + register pt_entry_t *ptp; + + ptp = pmap_pte(task->map->pmap, addr); + if (ptp == PT_ENTRY_NULL || (*ptp & NS532_PTE_VALID) == 0) { + if (flag) { + db_printf("\nno memory is assigned to address %08x\n", + addr); + db_error(0); + /* NOTREACHED */ + } + return(-1); + } + *kaddr = (unsigned)ptetokv(*ptp) + (addr & (NS532_PGBYTES-1)); + return(0); +} + +/* + * Read bytes from kernel address space for debugger. + */ + +void +db_read_bytes(addr, size, data, task) + vm_offset_t addr; + register int size; + register char *data; + task_t task; +{ + register char *src; + register int n; + unsigned kern_addr; + + src = (char *)addr; + if (addr >= VM_MIN_KERNEL_ADDRESS || task == TASK_NULL) { + if (task == TASK_NULL) + task = db_current_task(); + while (--size >= 0) { + if (addr++ < VM_MIN_KERNEL_ADDRESS && + task == TASK_NULL) { + db_printf("\nbad address %x\n", addr); + db_error(0); + /* NOTREACHED */ + } + *data++ = *src++; + } + return; + } + while (size > 0) { + if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0) + return; + src = (char *)kern_addr; + n = ns532_trunc_page(addr + NS532_PGBYTES) - addr; + if (n > size) + n = size; + size -= n; + addr += n; + while (--n >= 0) + *data++ = *src++; + } +} + +/* + * Write bytes to kernel address space for debugger. + */ +void +db_write_bytes(addr, size, data, task) + vm_offset_t addr; + register int size; + register char *data; + task_t task; +{ + register char *dst; + + register pt_entry_t *ptep0 = 0; + pt_entry_t oldmap0 = 0; + vm_offset_t addr1; + register pt_entry_t *ptep1 = 0; + pt_entry_t oldmap1 = 0; + extern char etext; + void db_write_bytes_user_space(); + + if ((addr < VM_MIN_KERNEL_ADDRESS) ^ + ((addr + size) <= VM_MIN_KERNEL_ADDRESS)) { + db_error("\ncannot write data into mixed space\n"); + /* NOTREACHED */ + } + if (addr < VM_MIN_KERNEL_ADDRESS) { + if (task) { + db_write_bytes_user_space(addr, size, data, task); + return; + } else if (db_current_task() == TASK_NULL) { + db_printf("\nbad address %x\n", addr); + db_error(0); + /* NOTREACHED */ + } + } + + if (addr >= VM_MIN_KERNEL_ADDRESS && + addr <= (vm_offset_t)&etext) + { + ptep0 = pmap_pte(pmap_kernel(), addr); + oldmap0 = *ptep0; + *ptep0 |= NS532_PTE_WRITE; + + addr1 = ns532_trunc_page(addr + size - 1); + if (ns532_trunc_page(addr) != addr1) { + /* data crosses a page boundary */ + + ptep1 = pmap_pte(pmap_kernel(), addr1); + oldmap1 = *ptep1; + *ptep1 |= NS532_PTE_WRITE; + } + _flush_tlb(); + } + + dst = (char *)addr; + + while (--size >= 0) { + *dst++ = *data++; + _flush_instruction_cache_addr(dst); + } + + if (ptep0) { + *ptep0 = oldmap0; + if (ptep1) { + *ptep1 = oldmap1; + } + _flush_tlb(); + } +} + +void +db_write_bytes_user_space(addr, size, data, task) + vm_offset_t addr; + register int size; + register char *data; + task_t task; +{ + register char *dst; + register n; + unsigned kern_addr; + + while (size > 0) { + if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0) + return; + dst = (char *)kern_addr; + n = ns532_trunc_page(addr+NS532_PGBYTES) - addr; + if (n > size) + n = size; + size -= n; + addr += n; + while (--n >= 0) + *dst++ = *data++; + } +} + +boolean_t +db_check_access(addr, size, task) + vm_offset_t addr; + register int size; + task_t task; +{ + register n; + unsigned kern_addr; + + if (addr >= VM_MIN_KERNEL_ADDRESS) { + if (kernel_task == TASK_NULL) + return(TRUE); + task = kernel_task; + } else if (task == TASK_NULL) { + if (current_thread() == THREAD_NULL) + return(FALSE); + task = current_thread()->task; + } + while (size > 0) { + if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0) + return(FALSE); + n = ns532_trunc_page(addr+NS532_PGBYTES) - addr; + if (n > size) + n = size; + size -= n; + addr += n; + } + return(TRUE); +} + +boolean_t +db_phys_eq(task1, addr1, task2, addr2) + task_t task1; + vm_offset_t addr1; + task_t task2; + vm_offset_t addr2; +{ + unsigned kern_addr1, kern_addr2; + + if (addr1 >= VM_MIN_KERNEL_ADDRESS || addr2 >= VM_MIN_KERNEL_ADDRESS) + return(FALSE); + if ((addr1 & (NS532_PGBYTES-1)) != (addr2 & (NS532_PGBYTES-1))) + return(FALSE); + if (task1 == TASK_NULL) { + if (current_thread() == THREAD_NULL) + return(FALSE); + task1 = current_thread()->task; + } + if (db_user_to_kernel_address(task1, addr1, &kern_addr1, 0) < 0 + || db_user_to_kernel_address(task2, addr2, &kern_addr2) < 0) + return(FALSE); + return(kern_addr1 == kern_addr2); +} + +#define DB_USER_STACK_ADDR (VM_MIN_KERNEL_ADDRESS) +#define DB_NAME_SEARCH_LIMIT (DB_USER_STACK_ADDR-(NS532_PGBYTES*3)) + +static int +db_search_null(task, svaddr, evaddr, skaddr, flag) + task_t task; + unsigned *svaddr; + unsigned evaddr; + unsigned *skaddr; + int flag; +{ + register unsigned vaddr; + register unsigned *kaddr; + + kaddr = (unsigned *)*skaddr; + for (vaddr = *svaddr; vaddr > evaddr; vaddr -= sizeof(unsigned)) { + if (vaddr % NS532_PGBYTES == 0) { + vaddr -= sizeof(unsigned); + if (db_user_to_kernel_address(task, vaddr, + skaddr, 0) < 0) + return(-1); + kaddr = (unsigned *)*skaddr; + } else { + vaddr -= sizeof(unsigned); + kaddr--; + } + if ((*kaddr == 0) ^ (flag == 0)) { + *svaddr = vaddr; + *skaddr = (unsigned)kaddr; + return(0); + } + } + return(-1); +} + +void +db_task_name(task) + task_t task; +{ + register char *p; + register n; + unsigned vaddr, kaddr; + + vaddr = DB_USER_STACK_ADDR; + kaddr = 0; + + /* + * skip nulls at the end + */ + if (db_search_null(task, &vaddr, + DB_NAME_SEARCH_LIMIT, &kaddr, 0) < 0) { + db_printf(DB_NULL_TASK_NAME); + return; + } + /* + * search start of args + */ + if (db_search_null(task, &vaddr, + DB_NAME_SEARCH_LIMIT, &kaddr, 1) < 0) { + db_printf(DB_NULL_TASK_NAME); + return; + } + + n = DB_TASK_NAME_LEN-1; + p = (char *)kaddr + sizeof(unsigned); + for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR && n > 0; + vaddr++, p++, n--) { + if (vaddr % NS532_PGBYTES == 0) { + (void)db_user_to_kernel_address(task, + vaddr, &kaddr, 0); + p = (char*)kaddr; + } + db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p); + } + while (n-- >= 0) /* compare with >= 0 for one more space */ + db_printf(" "); +} diff --git a/sys/arch/pc532/pc532/db_trace.c b/sys/arch/pc532/pc532/db_trace.c new file mode 100644 index 00000000000..3d32b0df2d1 --- /dev/null +++ b/sys/arch/pc532/pc532/db_trace.c @@ -0,0 +1,681 @@ +/* $NetBSD: db_trace.c,v 1.2 1994/10/26 08:24:58 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ns532/db_trace.c + * Author: Tero Kivinen, Tatu Ylonen + * Helsinki University of Technology 1992. + * + * Stack trace and special register support for debugger. + */ + + +#include <mach/boolean.h> +#include <machine/db_machdep.h> +#include <machine/pic.h> + +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <ddb/db_variables.h> + +#include <kern/thread.h> + +int db_spec_regs(); +int db_ns532_reg_value(); +int db_ns532_kreg_value(); + +/* + * Machine register set. + */ +struct db_variable db_regs[] = { + { "r0", (int *)&ddb_regs.r0, db_ns532_reg_value }, + { "r1", (int *)&ddb_regs.r1, db_ns532_reg_value }, + { "r2", (int *)&ddb_regs.r2, db_ns532_reg_value }, + { "r3", (int *)&ddb_regs.r3, db_ns532_reg_value }, + { "r4", (int *)&ddb_regs.r4, db_ns532_reg_value }, + { "r5", (int *)&ddb_regs.r5, db_ns532_reg_value }, + { "r6", (int *)&ddb_regs.r6, db_ns532_reg_value }, + { "r7", (int *)&ddb_regs.r7, db_ns532_reg_value }, + { "sp", (int *)&ddb_regs.usp, db_ns532_reg_value }, + { "fp", (int *)&ddb_regs.fp, db_ns532_reg_value }, + { "sb", (int *)&ddb_regs.sb, db_ns532_reg_value }, + { "pc", (int *)&ddb_regs.pc, db_ns532_reg_value }, + { "psr",(int *)&ddb_regs.psr, db_ns532_reg_value }, + { "tear",(int *)&ddb_regs.tear,db_ns532_reg_value }, + { "msr",(int *)&ddb_regs.msr, db_ns532_reg_value }, + { "ipl",(int *)&db_active_ipl,db_ns532_reg_value }, +#ifdef FLOATS_SAVED + { "f0", (int *)&ddb_regs.l0a, db_ns532_reg_value }, + { "f1", (int *)&ddb_regs.l0b, db_ns532_reg_value }, + { "f2", (int *)&ddb_regs.l1a, db_ns532_reg_value }, + { "f3", (int *)&ddb_regs.l1b, db_ns532_reg_value }, + { "f4", (int *)&ddb_regs.l2a, db_ns532_reg_value }, + { "f5", (int *)&ddb_regs.l2b, db_ns532_reg_value }, + { "f6", (int *)&ddb_regs.l3a, db_ns532_reg_value }, + { "f7", (int *)&ddb_regs.l3b, db_ns532_reg_value }, + { "fsr",(int *)&ddb_regs.fsr, db_ns532_reg_value }, +#endif FLOATS_SAVED + { "ksp", (int *) 0, db_spec_regs }, + { "intbase", (int *) 0, db_spec_regs }, + { "ptb", (int *) 0, db_spec_regs }, + { "ivar", (int *) 0, db_spec_regs }, + { "rtear", (int *) 0, db_spec_regs }, /* current reg value */ + { "mcr", (int *) 0, db_spec_regs }, + { "rmsr", (int *) 0, db_spec_regs }, /* current reg value */ + { "dcr", (int *) 0, db_spec_regs }, + { "dsr", (int *) 0, db_spec_regs }, + { "car", (int *) 0, db_spec_regs }, + { "bpc", (int *) 0, db_spec_regs }, + { "cfg", (int *) 0, db_spec_regs } +}; +struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); + +struct db_regs_bits_s { + char *name; + char *bitfld; +}; + +struct db_regs_bits_s db_regs_bits[] = { + "psr", "0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,i,p,s,u,n,z,f,v,0,l,t,c", + "fsr", "0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,rmb,s5,s4,s3,s2,s1,s0,@roundm,if,ien,uf,uen,@trapt", + "mcr", "0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,ao,ds,ts,tu", + "msr", "0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0 :,0,0,0,0: ,@sst,ust,ddt,@tex", + "rmsr", "0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0 :,0,0,0,0: ,@sst,ust,ddt,@tex", + "dcr", "0,0,0,0: ,0,0,0,0: ,den,sd,ud,pce,tr,bcp,si,0: ,0,0,0,0: ,0,0,0,bf,cae,crd,cwr,vnp,cbe3,cbe2,cbe1,cbe0", + "dsr", "rd,bpc,bex,bca,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0", + "cfg", "0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,0,0: ,0,0,pf,lic,ic,ldc,dc,de,1,1,1,1,c,m,f,i" + }; + +struct db_regs_bits_s *db_eregs_bits = db_regs_bits + + sizeof(db_regs_bits)/sizeof(db_regs_bits[0]); + +struct db_regs_fields_s { + char *name; + int bits; + char *values; +}; + +struct db_regs_fields_s db_regs_fields[] = { + "trapt", 3, "None,Underflow,Overflow,Div by 0,Ill inst,Invalid oper,Inexact res,Reserved", + "roundm", 2, "Nearest,Zero,Pos inf,Neg inf", + "tex", 2, "None,1st PTE inv,2nd PTE inv,Prot", + "sst", 4, "0000,0001,0010,0011,0100,0101,0110,0111,Seq.ins.fetch,Non.seq.ins.fetch,Data transfer,Read-modify-write,Read eff.addr,1101,1110,1111" +}; + +struct db_regs_fields_s *db_eregs_fields = db_regs_fields + + sizeof(db_regs_fields)/sizeof(db_regs_fields[0]); + +/* + * Stack trace. + */ +#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS) + +struct ns532_frame { + struct ns532_frame *f_frame; + int f_retaddr; + int f_arg0; +}; + +#define TRAP 1 +#define INTERRUPT 2 +#define SYSCALL 3 + +struct ns532_kregs { + char *name; + int offset; +} ns532_kregs[] = { + { "r3", (int)(&((struct ns532_kernel_state *)0)->k_r3) }, + { "r4", (int)(&((struct ns532_kernel_state *)0)->k_r4) }, + { "r5", (int)(&((struct ns532_kernel_state *)0)->k_r5) }, + { "r6", (int)(&((struct ns532_kernel_state *)0)->k_r6) }, + { "r7", (int)(&((struct ns532_kernel_state *)0)->k_r7) }, + { "sp", (int)(&((struct ns532_kernel_state *)0)->k_sp) }, + { "fp", (int)(&((struct ns532_kernel_state *)0)->k_fp) }, + { "pc", (int)(&((struct ns532_kernel_state *)0)->k_pc) }, + { 0 }, +}; + +int * +db_lookup_ns532_kreg(name, kregp) + char *name; + int *kregp; +{ + register struct ns532_kregs *kp; + + for (kp = ns532_kregs; kp->name; kp++) { + if (strcmp(name, kp->name) == 0) + return((int *)((int)kregp + kp->offset)); + } + return(0); +} + +int +db_ns532_reg_value(vp, valuep, flag, ap) + struct db_variable *vp; + db_expr_t *valuep; + int flag; + db_var_aux_param_t ap; +{ + int *dp = 0; + db_expr_t null_reg = 0; + register thread_t thread = ap->thread; + + if (db_option(ap->modif, 'u')) { + if (thread == THREAD_NULL) { + if ((thread = current_thread()) == THREAD_NULL) + db_error("no user registers\n"); + } + if (thread == current_thread()) { + if ((ddb_regs.psr & PSR_U) == 0) + dp = vp->valuep; + } + } else { + if (thread == THREAD_NULL || thread == current_thread()) { + dp = vp->valuep; + } else if ((thread->state & TH_SWAPPED) == 0 && + thread->kernel_stack) { + dp = db_lookup_ns532_kreg(vp->name, + (int *)(STACK_IKS(thread->kernel_stack))); + if (dp == 0) + dp = &null_reg; + } else if ((thread->state & TH_SWAPPED) && + thread->swap_func != thread_exception_return) { + /* only pc is valid */ + if (vp->valuep == (int *) &ddb_regs.pc) { + dp = (int *)(&thread->swap_func); + } else { + dp = &null_reg; + } + } + } + if (dp == 0) { + if (thread->pcb == 0) + db_error("no pcb\n"); + dp = (int *)((int)(&thread->pcb->iss) + + ((int)vp->valuep - (int)&ddb_regs)); + } + if (flag == DB_VAR_SET) + *dp = *valuep; + else + *valuep = *dp; + return(0); +} + +db_addr_t db_trap_symbol_value = 0; +db_addr_t db_intr_symbol_value = 0; +boolean_t db_trace_symbols_found = FALSE; + +void +db_find_trace_symbols() +{ + db_expr_t value; + if (db_value_of_name("_trap", &value)) + db_trap_symbol_value = (db_addr_t) value; + if (db_value_of_name("_interrupt", &value)) + db_intr_symbol_value = (db_addr_t) value; + db_trace_symbols_found = TRUE; +} + +/* + * Figure out how many arguments were passed into the frame at "fp". + */ +int db_numargs_default = 5; + +int +db_numargs(fp, task) + struct ns532_frame *fp; + task_t task; +{ + int a; + char *nextaddr; + + nextaddr = (char *) db_get_task_value((int) &fp->f_frame, 4, + FALSE, task); + a = nextaddr-(char *)fp-8; + a /= 4; + if (a < 0 || a > 16) + a = db_numargs_default; + return a; +} + +extern int (*ivect[])(); + +/* + * Figure out the next frame up in the call stack. + * For trap(), we print the address of the faulting instruction and + * proceed with the calling frame. We return the ip that faulted. + * If the trap was caused by jumping through a bogus pointer, then + * the next line in the backtrace will list some random function as + * being called. It should get the argument list correct, though. + * It might be possible to dig out from the next frame up the name + * of the function that faulted, but that could get hairy. + */ +void +db_nextframe(fp, ip, frame_type, thread) + struct ns532_frame **fp; /* in/out */ + db_addr_t *ip; /* out */ + int frame_type; /* in */ + thread_t thread; /* in */ +{ + extern char * trap_type[]; + extern int TRAP_TYPES; + + struct ns532_saved_state *saved_regs; + int vector; + task_t task = (thread != THREAD_NULL)? thread->task: TASK_NULL; + + switch(frame_type) { + case TRAP: + /* + * We know that trap() has 1 argument and we know that + * it is an (int *). + */ + saved_regs = (struct ns532_saved_state *) + db_get_value((int) &((*fp)->f_arg0), 4, FALSE); + if (saved_regs->trapno >= 0 && + saved_regs->trapno < TRAP_TYPES) { + db_printf(">>>>>> %s trap at ", + trap_type[saved_regs->trapno]); + } else { + db_printf(">>>>>> trap (number %d) at ", + saved_regs->trapno & 0xffff); + } + db_task_printsym(saved_regs->pc, DB_STGY_PROC, task); + db_printf(" <<<<<<\n"); + *fp = (struct ns532_frame *)saved_regs->fp; + *ip = (db_addr_t)saved_regs->pc; + break; + case INTERRUPT: + /* + * We know that interrupt() has 3 argument. + */ + + vector = db_get_value((int) &((*fp)->f_arg0), 4, FALSE); + saved_regs = (struct ns532_saved_state *) + db_get_value((int) &((*fp)->f_arg0) + 8, 4, FALSE); + db_printf(">>>>>> "); + if (vector >=0 && vector < NINTR) { + db_task_printsym((int) ivect[vector], + DB_STGY_PROC, task); + db_printf(" interrupt at "); + } else { + db_printf("interrupt vector %d at ", vector); + } + db_task_printsym(saved_regs->pc, DB_STGY_PROC, task); + db_printf(" <<<<<<\n"); + *fp = (struct ns532_frame *)saved_regs->fp; + *ip = (db_addr_t)saved_regs->pc; + break; + default: + *ip = (db_addr_t) + db_get_task_value((int) &(*fp)->f_retaddr, 4, FALSE, task); + *fp = (struct ns532_frame *) + db_get_task_value((int) &(*fp)->f_frame, 4, FALSE, task); + break; + } +} + +void +db_stack_trace_cmd(addr, have_addr, count, modif) + db_expr_t addr; + boolean_t have_addr; + db_expr_t count; + char *modif; +{ + struct ns532_frame *frame, *lastframe; + int *argp; + db_addr_t callpc; + int frame_type; + boolean_t kernel_only = TRUE; + boolean_t trace_thread = FALSE; + char *filename; + int linenum; + task_t task; + thread_t th; + int user_frame = 0; + extern unsigned db_maxoff; + + + if (!db_trace_symbols_found) + db_find_trace_symbols(); + + { + register char *cp = modif; + register char c; + + while ((c = *cp++) != 0) { + if (c == 't') + trace_thread = TRUE; + if (c == 'u') + kernel_only = FALSE; + } + } + + if (count == -1) + count = 65535; + + if (!have_addr && !trace_thread) { + frame = (struct ns532_frame *)ddb_regs.fp; + callpc = (db_addr_t)ddb_regs.pc; + th = current_thread(); + task = (th != THREAD_NULL) ? th->task : TASK_NULL; + } else if (trace_thread) { + if (have_addr) { + th = (thread_t) addr; + if (!db_check_thread_address_valid(th)) + return; + } else { + th = db_default_thread; + if (th = THREAD_NULL) + current_thread(); + if (th == THREAD_NULL) { + db_printf("no active thread\n"); + return; + } + } + task = th->task; + if (th == current_thread()) { + frame = (struct ns532_frame *)ddb_regs.fp; + callpc = (db_addr_t)ddb_regs.pc; + } else { + if (th->pcb == 0) { + db_printf("thread has no pcb\n"); + return; + } + if ((th->state & TH_SWAPPED) || + th->kernel_stack == 0) { + register struct ns532_saved_state *iss = + &th->pcb->iss; + + db_printf("Continuation "); + db_task_printsym(th->swap_func, DB_STGY_PROC, + task); + db_printf("\n"); + + frame = (struct ns532_frame *) (iss->fp); + callpc = (db_addr_t) (iss->pc); + } else { + register struct ns532_kernel_state *iks; + iks = STACK_IKS(th->kernel_stack); + frame = (struct ns532_frame *) (iks->k_fp); + callpc = (db_addr_t) (iks->k_pc); + } + } + } else { + frame = (struct ns532_frame *)addr; + th = (db_default_thread)? db_default_thread: current_thread(); + task = (th != THREAD_NULL)? th->task: TASK_NULL; + callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr, + 4, FALSE, task); + } + + if (!INKERNEL(callpc) && !INKERNEL(frame)) { + db_printf(">>>>>> user space <<<<<<\n"); + user_frame++; + } + + while (count-- && frame != 0) { + register int narg; + char * name; + db_expr_t offset; + + if (INKERNEL(callpc) && user_frame == 0) { + db_addr_t call_func = 0; + + db_symbol_values(db_search_task_symbol(callpc, + DB_STGY_XTRN, + &offset, + TASK_NULL), + &name, &call_func); + if (call_func == db_trap_symbol_value) { + frame_type = TRAP; + narg = 1; + } else if (call_func == db_intr_symbol_value) { + frame_type = INTERRUPT; + narg = 3; +#ifdef SYSCALL_FRAME_IMPLEMENTED + } else if (call_func == db_syscall_symbol_value) { + frame_type = SYSCALL; + goto next_frame; +#endif + } else { + frame_type = 0; + narg = db_numargs(frame, task); + } + } else if ((INKERNEL(callpc) == 0) != (INKERNEL(frame) == 0)) { + frame_type = 0; + narg = -1; + } else { + frame_type = 0; + narg = db_numargs(frame, task); + } + + db_find_task_sym_and_offset(callpc, &name, &offset, task); + if (name == 0 || offset > db_maxoff) { + db_printf("0x%x(", callpc); + offset = 0; + } else + db_printf("%s(", name); + + argp = &frame->f_arg0; + while (narg > 0) { + db_printf("%x", + db_get_task_value((int)argp,4,FALSE,task)); + argp++; + if (--narg != 0) + db_printf(","); + } + if (narg < 0) + db_printf("..."); + db_printf(")"); + if (offset) { + db_printf("+%x", offset); + } + if (db_line_at_pc(0, &filename, &linenum, callpc)) { + db_printf(" [%s", filename); + if (linenum > 0) + db_printf(":%d", linenum); + printf("]"); + } + + db_printf("\n"); + next_frame: + lastframe = frame; + db_nextframe(&frame, &callpc, frame_type, th); + + if (frame == 0) { + /* end of chain */ + break; + } + if (!INKERNEL(lastframe) || + (!INKERNEL(callpc) && !INKERNEL(frame))) + user_frame++; + if (user_frame == 1) { + db_printf(">>>>>> user space <<<<<<\n"); + if (kernel_only) + break; + } + if (frame <= lastframe) { + if (INKERNEL(lastframe) && !INKERNEL(frame)) + continue; + db_printf("Bad frame pointer: 0x%x\n", frame); + break; + } + } +} + +/********************************************** + + Get/Set value of special registers. + + *********************************************/ + +int db_spec_regs(vp, valp, what) + struct db_variable *vp; + db_expr_t *valp; + int what; +{ + if (strcmp(vp->name, "intbase") == 0) + if (what == DB_VAR_GET) + *valp = _get_intbase(); + else + _set_intbase(*valp); + else if (strcmp(vp->name, "ptb") == 0) + if (what == DB_VAR_GET) + *valp = _get_ptb(); + else + _set_ptb(*valp); + else if (strcmp(vp->name, "ivar") == 0) + if (what == DB_VAR_GET) + *valp = 0; + else + _invalidate_page(*valp); + else if (strcmp(vp->name, "rtear") == 0) + if (what == DB_VAR_GET) + *valp = _get_tear(); + else + _set_tear(*valp); + else if (strcmp(vp->name, "mcr") == 0) + if (what == DB_VAR_GET) + *valp = _get_mcr(); + else + _set_mcr(*valp); + else if (strcmp(vp->name, "rmsr") == 0) + if (what == DB_VAR_GET) + *valp = _get_msr(); + else + _set_msr(*valp); + else if (strcmp(vp->name, "dcr") == 0) + if (what == DB_VAR_GET) + *valp = _get_dcr(); + else + _set_dcr(*valp); + else if (strcmp(vp->name, "dsr") == 0) + if (what == DB_VAR_GET) + *valp = _get_dsr(); + else + _set_dsr(*valp); + else if (strcmp(vp->name, "car") == 0) + if (what == DB_VAR_GET) + *valp = _get_car(); + else + _set_car(*valp); + else if (strcmp(vp->name, "bpc") == 0) + if (what == DB_VAR_GET) + *valp = _get_bpc(); + else + _set_bpc(*valp); + else if (strcmp(vp->name, "cfg") == 0) + if (what == DB_VAR_GET) + *valp = _get_cfg(); + else + _set_cfg(*valp); + else if (strcmp(vp->name, "ksp") == 0) + if (what == DB_VAR_GET) + *valp = _get_ksp(); + else + _set_ksp(*valp); + else + db_printf("Internal error, unknown register in db_spec_regs"); +} + +/*************************************************** + + Print special bit mask registers in bitmask format + + **************************************************/ + +int db_print_spec_reg(vp, valuep) + struct db_variable *vp; + db_expr_t valuep; +{ + struct db_regs_bits_s *dbrb; + int i; + char *p, buf[256]; + + for (dbrb = db_regs_bits; dbrb < db_eregs_bits; dbrb++) + if (strcmp(dbrb->name, vp->name) == 0) + break; + if (dbrb == db_eregs_bits) + return 1; + db_printf("\t<"); + p = dbrb->bitfld; + for (i = 31 ; i >= 0 && *p ; i--) { /* All bits */ + if (*p >= '0' && *p <= '9') { /* is number */ + for (; *p != ',' && *p; p++) /* Skip number */ + ; + if (*p == ',') + p++; + } else { /* Is text */ + char *q; + strcpy(buf, p); + for(q = buf; *q != ',' && *q; q++, p++) /* Find end */ + ; + if (*p == ',') + p++; + *q='\0'; + if (buf[0] == '@') { /* Is bitfield */ + struct db_regs_fields_s *df; + q=buf+1; /* Find field */ + for (df = db_regs_fields; + df < db_eregs_fields; df++) + if (strcmp(df->name, q) == 0) + break; + if (df == db_eregs_fields) + db_printf("Internal error in print_spec_regs [%s]\n", buf); + else { + unsigned int ff; + db_printf("%s=", q); /* Print field */ + ff = (~(0xffffffff << df->bits)) & + (valuep>>(i-(df->bits-1))); + i += df->bits; /* Find value */ + for (q = df->values; + ff > 0 && *q; ff--, q++) + for (;*q != ',' && *q; q++) + ; + if (*q != '\0') { + strcpy(buf, q); + for(q = buf; *q != ',' && *q; + q++) + ; + *q='\0'; + db_printf("%s "); /* Print value */ + } else + db_printf(" "); + } + } else { /* Normal bit */ + if ((1<<i) & valuep) { + db_printf("%s ", buf); + } + } + } + } + db_printf(">"); + return 0; +} diff --git a/sys/arch/pc532/pc532/disksubr.c b/sys/arch/pc532/pc532/disksubr.c new file mode 100644 index 00000000000..397a7fc9dd3 --- /dev/null +++ b/sys/arch/pc532/pc532/disksubr.c @@ -0,0 +1,241 @@ +/* $NetBSD: disksubr.c,v 1.7 1995/08/25 07:49:05 phil Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 + */ + +#include "param.h" +#include "systm.h" +#include "buf.h" +#include "disklabel.h" +#include "syslog.h" + +#define b_cylin b_resid + +/* + * 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, osdep) + dev_t dev; + void (*strat)(); + register struct disklabel *lp; + struct cpu_disklabel *osdep; +{ + register struct buf *bp; + struct disklabel *dlp; + char *msg = NULL; + + if (lp->d_secperunit == 0) + lp->d_secperunit = 0x1fffffff; + lp->d_npartitions = 1; + if (lp->d_partitions[0].p_size == 0) + lp->d_partitions[0].p_size = 0x1fffffff; + lp->d_partitions[0].p_offset = 0; + + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + bp->b_blkno = LABELSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylin = LABELSECTOR / lp->d_secpercyl; + (*strat)(bp); + if (biowait(bp)) { + msg = "I/O error"; + } else for (dlp = (struct disklabel *)bp->b_un.b_addr; + dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp)); + dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { + if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { + if (msg == NULL) + msg = "no disk label"; + } else if (dlp->d_npartitions > MAXPARTITIONS || + dkcksum(dlp) != 0) + msg = "disk label corrupted"; + else { + *lp = *dlp; + msg = NULL; + break; + } + } + bp->b_flags = B_INVAL | B_AGE; + brelse(bp); + return (msg); +} + +/* + * Check new disk label for sensibility + * before setting it. + */ +setdisklabel(olp, nlp, openmask, osdep) + register struct disklabel *olp, *nlp; + u_long openmask; + struct cpu_disklabel *osdep; +{ + register i; + register struct partition *opp, *npp; + + 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); +} + +/* encoding of disk minor numbers, should be elsewhere... */ +#define dkunit(dev) (minor(dev) >> 3) +#define dkpart(dev) (minor(dev) & 07) +#define dkminor(unit, part) (((unit) << 3) | (part)) + +/* + * Write disk label back to device after modification. + */ +writedisklabel(dev, strat, lp, osdep) + dev_t dev; + void (*strat)(); + register struct disklabel *lp; + struct cpu_disklabel *osdep; +{ + struct buf *bp; + struct disklabel *dlp; + int labelpart; + int error = 0; + + labelpart = dkpart(dev); + if (lp->d_partitions[labelpart].p_offset != 0) { + if (lp->d_partitions[0].p_offset != 0) + return (EXDEV); /* not quite right */ + labelpart = 0; + } + bp = geteblk((int)lp->d_secsize); + bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart)); + bp->b_blkno = LABELSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_READ; + (*strat)(bp); + if (error = biowait(bp)) + goto done; + for (dlp = (struct disklabel *)bp->b_un.b_addr; + dlp <= (struct disklabel *) + (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp)); + dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { + if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && + dkcksum(dlp) == 0) { + *dlp = *lp; + bp->b_flags = B_WRITE; + (*strat)(bp); + error = biowait(bp); + goto done; + } + } + error = ESRCH; +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(struct buf *bp, struct disklabel *lp, int wlabel) +{ + struct partition *p = lp->d_partitions + dkpart(bp->b_dev); + int maxsz = p->p_size, + sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; + + /* Check to see if it is the label sector and it is write only. */ + if (bp->b_blkno + p->p_offset <= LABELSECTOR && + (bp->b_flags & B_READ) == 0 && wlabel == 0) { + bp->b_error = EROFS; + goto bad; + } + /* beyond partition? */ + if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { + /* if exactly at end of disk, return an EOF */ + if (bp->b_blkno == maxsz) { + bp->b_resid = bp->b_bcount; + return(0); + } + /* or truncate if part of it fits */ + sz = maxsz - bp->b_blkno; + if (sz <= 0) { + bp->b_error = EINVAL; + goto bad; + } + bp->b_bcount = sz << DEV_BSHIFT; + } + + /* calculate cylinder for disksort to order transfers with */ + bp->b_cylin = (bp->b_blkno + p->p_offset) / lp->d_secpercyl; + return(1); + +bad: + bp->b_flags |= B_ERROR; + return(-1); +} + +/* XXX unknown */ +int +dk_establish() +{} diff --git a/sys/arch/pc532/pc532/genassym.c b/sys/arch/pc532/pc532/genassym.c new file mode 100644 index 00000000000..487cd8c72b3 --- /dev/null +++ b/sys/arch/pc532/pc532/genassym.c @@ -0,0 +1,124 @@ +/* $NetBSD: genassym.c,v 1.8 1995/06/09 05:59:58 phil Exp $ */ + +/*- + * Copyright (c) 1982, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + * + * @(#)genassym.c 5.11 (Berkeley) 5/10/91 + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/resourcevar.h> +#include <sys/device.h> +#include <vm/vm.h> +#include <sys/user.h> + +#include <machine/cpu.h> +#include <machine/trap.h> + +#include <stdio.h> + +main() +{ + struct proc *p = (struct proc *)0; + struct user *up = (struct user *)0; + struct rusage *rup = (struct rusage *)0; + struct uprof *uprof = (struct uprof *)0; + struct pcb *pcb = (struct pcb *)0; + struct on_stack *regs = (struct on_stack *)0; + struct iv *iv = (struct iv *)0; + struct vmmeter *vm = 0; + register unsigned i; + + printf("#define\tKERNBASE 0x%x\n", KERNBASE); + printf("#define\tUDOT_SZ %d\n", sizeof(struct user)); + printf("#define\tP_FORW %d\n", &p->p_forw); + printf("#define\tP_BACK %d\n", &p->p_back); + printf("#define\tP_VMSPACE %d\n", &p->p_vmspace); + printf("#define\tP_ADDR %d\n", &p->p_addr); + printf("#define\tP_PRIORITY %d\n", &p->p_priority); + printf("#define\tP_STAT %d\n", &p->p_stat); + printf("#define\tP_WCHAN %d\n", &p->p_wchan); + printf("#define\tP_FLAG %d\n", &p->p_flag); + printf("#define\tP_PID %d\n", &p->p_pid); + + printf("#define\tSSLEEP %d\n", SSLEEP); + printf("#define\tSRUN %d\n", SRUN); + printf("#define\tUPAGES %d\n", UPAGES); + printf("#define\tHIGHPAGES %d\n", HIGHPAGES); + printf("#define\tCLSIZE %d\n", CLSIZE); + printf("#define\tNBPG %d\n", NBPG); + printf("#define\tNPTEPG %d\n", NPTEPG); + printf("#define\tPGSHIFT %d\n", PGSHIFT); + printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE); + printf("#define\tUSRPTSIZE %d\n", USRPTSIZE); + + printf("#define\tKERN_STK_START 0x%x\n", + USRSTACK + UPAGES*NBPG); + printf("#define\tKSTK_SIZE %d\n", UPAGES*NBPG); + printf("#define\tON_STK_SIZE %d\n", sizeof(struct on_stack)); + printf("#define\tREGS_USP %d\n", ®s->pcb_usp); + printf("#define\tREGS_FP %d\n", ®s->pcb_fp); + printf("#define\tREGS_SB %d\n", ®s->pcb_sb); + printf("#define\tREGS_PSR %d\n", ®s->pcb_psr); + + printf("#define\tPCB_ONSTACK %d\n", &pcb->pcb_onstack); + printf("#define\tPCB_FSR %d\n", &pcb->pcb_fsr); + for (i=0; i<8; i++) + printf("#define\tPCB_F%d %d\n", i, &pcb->pcb_freg[i]); + printf("#define\tPCB_KSP %d\n", &pcb->pcb_ksp); + printf("#define\tPCB_KFP %d\n", &pcb->pcb_kfp); + printf("#define\tPCB_PTB %d\n", &pcb->pcb_ptb); + printf("#define\tPCB_PL %d\n", &pcb->pcb_pl); + printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags); + printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault); + + printf("#define\tV_TRAP %d\n", &vm->v_trap); + printf("#define\tV_INTR %d\n", &vm->v_intr); + + printf("#define\tIV_VEC %d\n", &iv->iv_vec); + printf("#define\tIV_ARG %d\n", &iv->iv_arg); + printf("#define\tIV_CNT %d\n", &iv->iv_cnt); + printf("#define\tIV_USE %d\n", &iv->iv_use); + + printf("#define\tUSRSTACK 0x%x\n", USRSTACK); +#ifdef SYSVSHM + printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS); +#endif + printf("#define\tENOENT %d\n", ENOENT); + printf("#define\tEFAULT %d\n", EFAULT); + printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG); + exit(0); +} diff --git a/sys/arch/pc532/pc532/icuinit.c b/sys/arch/pc532/pc532/icuinit.c new file mode 100644 index 00000000000..79ed7d7b718 --- /dev/null +++ b/sys/arch/pc532/pc532/icuinit.c @@ -0,0 +1,86 @@ +/* $NetBSD: icuinit.c,v 1.3 1994/10/26 08:25:03 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. + */ + +/* icuinit.c - C support for 532 icu stuff. */ + +#include <sys/param.h> +#include <machine/cpu.h> +#include <machine/icu.h> + +/* Table for initializing ICU. Written in order to ICU. + * Monitor has already set + * CCTL=0x15 MCTL=0 LCSV=13 IPS=0 PDIR=0xfe PDAT=0xfe + */ +struct icu_init_type { + unsigned char offset; + unsigned char val; +} icu_tab [] = { + {IMSK, 0xff}, /* mask off ints for now */ + {IMSK+1, 0xff}, /* " */ + {CIPTR, IR_CLK << 4}, /* clock int vector (CIPTR) */ + {CICTL, 0x00}, /* clock interrupt enable (CICTL) */ + {IPS, 0x7e}, /* 0=i/o, 1=int_req */ + {PDIR, 0x7e}, /* 1=in, 0=out */ + {OCASN, 0}, /* clock output (n/a) */ + {PDAT, 0xfe}, /* keep ROM at high mem */ + {ISRV, 0}, /* int in service (set by hw) */ + {ISRV+1, 0}, /* int in service */ + {CSRC, 0}, /* cascade source */ + {CSRC+1, 0}, /* cascade source */ + {SVCT, VEC_ICU}, /* isr vector */ + {FPRT, 0}, /* priority */ + {TPL, IPOLARITY & 0xff}, /* polarity */ + {TPL+1, IPOLARITY >> 8}, /* " */ + {ELTG, IEDGE & 0xff}, /* edge trigger (0 = edge) */ + {ELTG+1, IEDGE >> 8}, /* " */ + {MCTL, 0x02}, /* fixed priority */ + {CCTL, 0x1c}, /* prescale, no cat, run clocks */ +}; +#define ICUTAB_SZ (sizeof (icu_tab) / sizeof (struct icu_init_type)) + + +/*===========================================================================* + * icu_init + *===========================================================================*/ + +/* Initialize interrupt control unit. Starts clock interrupts. + */ + +icu_init() +{ + struct icu_init_type *p; + + for (p = icu_tab; p < icu_tab + ICUTAB_SZ; ++p) + WR_ADR (unsigned char, ICU_ADR + p->offset, p->val); +} + diff --git a/sys/arch/pc532/pc532/in_cksum.c b/sys/arch/pc532/pc532/in_cksum.c new file mode 100644 index 00000000000..e45b6ef8d6c --- /dev/null +++ b/sys/arch/pc532/pc532/in_cksum.c @@ -0,0 +1,173 @@ +/* $NetBSD: in_cksum.c,v 1.4 1995/08/29 22:37:44 phil Exp $ */ + +/*- + * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 tahoe: in_cksum.c 1.2 86/01/05 + * @(#)in_cksum.c 1.3 (Berkeley) 1/19/91 + */ + +#include <sys/param.h> +#include <sys/mbuf.h> + +/* + * Checksum routine for Internet Protocol family headers. + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * This implementation is the ns32k version. + */ + +#define REDUCE {sum = (sum & 0xffff) + (sum >> 16);} +#define ADDCARRY {if (sum > 0xffff) sum -= 0xffff;} +#define SWAP {sum <<= 8;} +#define ADVANCE(x) {w += x; mlen -= x;} + +/* + * Thanks to gcc we don't have to guess + * which registers contain sum & w. + */ +#define Asm __asm __volatile +#define ADD(n) Asm("addd " #n "(%2),%0" : "=r" (sum) : "0" (sum), "r" (w)) +#define ADC(n) Asm("addcd " #n "(%2),%0" : "=r" (sum) : "0" (sum), "r" (w)) +#define MOP Asm("addcd 0,%0" : "=r" (sum) : "0" (sum)) +#define UNSWAP Asm("rotd 8,%0" : "=r" (sum) : "0" (sum)) +#define ADDBYTE {sum += *w; SWAP; byte_swapped ^= 1;} +#define ADDWORD {sum += *(u_short *)w;} + +int +in_cksum(m, len) + register struct mbuf *m; + register int len; +{ + register u_char *w; + register unsigned sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + for (; m && len; m = m->m_next) { + mlen = m->m_len; + if (mlen == 0) + continue; + w = mtod(m, u_char *); + if (len < mlen) + mlen = len; + len -= mlen; + if (mlen < 16) + goto short_mbuf; + /* + * Force to long boundary so we do longword aligned + * memory operations + */ + if ((3 & (long)w) != 0) { + REDUCE; + if ((1 & (long)w) != 0) { + ADDBYTE; + ADVANCE(1); + } + if ((2 & (long)w) != 0) { + ADDWORD; + ADVANCE(2); + } + } + /* + * Align 4 bytes past a 16-byte cache line boundary. + */ + if ((4 & (long)w) == 0) { + ADD(0); + MOP; + ADVANCE(4); + } + if ((8 & (long)w) != 0) { + ADD(0); ADC(4); + MOP; + ADVANCE(8); + } + /* + * Do as much of the checksum as possible 32 bits at at time. + * In fact, this loop is unrolled to make overhead from + * branches &c small. + */ + while (mlen >= 32) { + /* + * Add with carry 16 words and fold in the last carry + * by adding a 0 with carry. + * + * Use the burst fill delay for pointer update. + */ + ADD(0); ADC(4); ADC(8); ADC(12); + MOP; + w += 32; + ADD(-16); ADC(-12); ADC(-8); ADC(-4); + MOP; + mlen -= 32; + } + if (mlen >= 16) { + ADD(12); ADC(0); ADC(4); ADC(8); + MOP; + ADVANCE(16); + } + short_mbuf: + if (mlen >= 8) { + ADD(0); ADC(4); + MOP; + ADVANCE(8); + } + if (mlen >= 4) { + ADD(0); + MOP; + ADVANCE(4); + } + if (mlen > 0) { + REDUCE; + if (mlen >= 2) { + ADDWORD; + ADVANCE(2); + } + if (mlen >= 1) { + ADDBYTE; + } + } + } + + if (len) + printf("cksum: out of data\n"); + if (byte_swapped) { + UNSWAP; + } + REDUCE; + ADDCARRY; + return (sum ^ 0xffff); +} + diff --git a/sys/arch/pc532/pc532/intr.c b/sys/arch/pc532/pc532/intr.c new file mode 100644 index 00000000000..4bf7111802d --- /dev/null +++ b/sys/arch/pc532/pc532/intr.c @@ -0,0 +1,229 @@ +/* $NetBSD: intr.c,v 1.5 1995/09/26 20:16:26 phil Exp $ */ + +/* + * Copyright (c) 1994 Matthias Pfaller. + * 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 Matthias Pfaller. + * 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. + * + * $Id: intr.c,v 1.1 1995/10/18 08:51:21 deraadt Exp $ + */ + +#define DEFINE_SPLX +#include <sys/param.h> +#include <sys/vmmeter.h> +#include <sys/systm.h> +#include <net/netisr.h> +#include <machine/psl.h> + +#define INTS 32 +struct iv ivt[INTS]; +static int next_sir = 16; +unsigned int imask[NIPL] = {0xffffffff}; +unsigned int Cur_pl = 0xffffffff, idisabled, sirpending, astpending; + +static void softnet(); +static void badhard(struct intrframe *); +static void badsoft(void *); + +/* + * Initialize the interrupt system. + */ +void +intr_init() +{ + int i; + for (i = 0; i < 16; i++) + ivt[i].iv_vec = badhard; + + for (i = 16; i < 32; i++) { + ivt[i].iv_vec = badsoft; + ivt[i].iv_arg = (void *)i; + } + + intr_establish(SOFTINT, softclock, NULL, "softclock", IPL_CLOCK, 0); + intr_establish(SOFTINT, softnet, NULL, "softnet", IPL_NET, 0); + + for (i = 1; i < NIPL; i++) + imask[i] |= SIR_ALLMASK; +} + +/* + * Handle pending software interrupts. + * This function has to be entered with interrupts disabled and + * it will return with interrupts disabled. + */ +void +check_sir() +{ + register unsigned int cirpending, mask; + register struct iv *iv; + + while (cirpending = sirpending) { + sirpending = 0; + ei(); + for (iv = ivt + 16, mask = 0x10000; + cirpending & -mask; mask <<= 1, iv++) { + if ((cirpending & mask) != 0) { + cnt.v_soft++; + iv->iv_cnt++; + iv->iv_vec(iv->iv_arg); + } + } + di(); + } + return; +} + +/* + * Establish an interrupt. If intr is set to SOFTINT, a software interrupt + * is allocated. + */ +int +intr_establish(int intr, void (*vector)(), void *arg, char *use, + int level, int mode) +{ + if (intr == SOFTINT) { + if (next_sir >= INTS) + panic("No software interrupts left"); + di(); + intr = next_sir++; + } else { + if (ivt[intr].iv_vec != badhard) { + printf("Interrupt %d already allocated\n", intr); + return(-1); + } + di(); + switch (mode) { + case RISING_EDGE: + ICUW(TPL) |= (1 << intr); + ICUW(ELTG) &= ~(1 << intr); + break; + case FALLING_EDGE: + ICUW(TPL) &= ~(1 << intr); + ICUW(ELTG) &= ~(1 << intr); + break; + case HIGH_LEVEL: + ICUW(TPL) |= (1 << intr); + ICUW(ELTG) |= (1 << intr); + break; + case LOW_LEVEL: + ICUW(TPL) &= ~(1 << intr); + ICUW(ELTG) |= (1 << intr); + break; + default: + panic("Unknown interrupt mode"); + } + } + ivt[intr].iv_vec = vector; + ivt[intr].iv_arg = arg; + ivt[intr].iv_cnt = 0; + ivt[intr].iv_use = use; + ei(); + if (level > IPL_ZERO) + imask[level] |= 1 << intr; +#include "sl.h" +#include "ppp.h" +#if NSL > 0 || NPPP > 0 + /* In the presence of SLIP or PPP, splimp > spltty. */ + imask[IPL_IMP] |= imask[IPL_TTY]; +#endif + /* + * There are network and disk drivers that use free() at interrupt + * time, so imp > (net | bio). + */ + imask[IPL_IMP] |= imask[IPL_NET] | imask[IPL_BIO]; + imask[IPL_ZERO] &= ~(1 << intr); + return(intr); +} + +/* + * Network software interrupt routine + */ +static void +softnet() +{ + register int isr; + + di(); isr = netisr; netisr = 0; ei(); + if (isr == 0) return; +#ifdef INET +#include "ether.h" +#if NETHER > 0 + if (isr & (1 << NETISR_ARP)) arpintr(); +#endif + if (isr & (1 << NETISR_IP)) ipintr(); +#endif +#ifdef IMP + if (isr & (1 << NETISR_IMP)) impintr(); +#endif +#ifdef NS + if (isr & (1 << NETISR_NS)) nsintr(); +#endif +#ifdef ISO + if (isr & (1 << NETISR_ISO)) clnlintr(); +#endif +#ifdef CCITT + if (isr & (1 << NETISR_CCITT)) ccittintr(); +#endif +#include "ppp.h" +#if NPPP > 0 + if (isr & (1 << NETISR_PPP)) pppintr(); +#endif +} + +/* + * Default hardware interrupt handler + */ +static void +badhard(struct intrframe *frame) +{ + static int bad_count = 0; + di(); + bad_count++; + if (bad_count < 5) + printf("Unknown hardware interrupt: vec=%d pc=0x%08x psr=0x%04x cpl=0x%08x\n", + frame->if_vec, frame->if_pc, frame->if_psr, frame->if_pl); + + if (bad_count == 5) + printf("Too many unknown hardware interrupts, quitting reporting them.\n"); + ei(); +} + +/* + * Default software interrupt handler + */ +static void +badsoft(void *n) +{ + static int bad_count = 0; + bad_count++; + if (bad_count < 5) + printf("Unknown software interrupt: vec=%d\n", (int)n); + + if (bad_count == 5) + printf("Too many unknown software interrupts, quitting reporting them.\n"); +} diff --git a/sys/arch/pc532/pc532/locore.s b/sys/arch/pc532/pc532/locore.s new file mode 100644 index 00000000000..f468675555d --- /dev/null +++ b/sys/arch/pc532/pc532/locore.s @@ -0,0 +1,1191 @@ +/* $NetBSD: locore.s,v 1.29.2.1 1995/10/17 00:19:05 phil 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. + * + * locore.s + * + * locore.s,v 1.2 1993/09/13 07:26:47 phil Exp + */ + +/* + * locore.s - - assembler routines needed for BSD stuff. (ns32532/pc532) + * + * Phil Nelson, Dec 6, 1992 + * + */ + +/* This is locore.s! */ +#define LOCORE + +/* Get the defines... */ +#include <machine/asm.h> +#include <machine/icu.h> +#include "assym.h" + +/* define some labels */ +#define PSR_U 0x100 +#define PSR_S 0x200 +#define PSR_P 0x400 +#define PSR_I 0x800 + +#define CFG_IVEC 0x1 +#define CFG_FPU 0x2 +#define CFG_MEM 0x4 +#define CFG_DE 0x100 +#define CFG_DATA 0x200 +#define CFG_DLCK 0x400 +#define CFG_INS 0x800 +#define CFG_ILCK 0x1000 + +/* Initial Kernel stack page and the Idle processes' stack. */ +#define KERN_INT_SP 0xFFC00FFC + +/* Global Data */ + +.data +.globl _cold, __save_sp, __save_fp, __old_intbase +_cold: .long 1 +__save_sp: .long 0 +__save_fp: .long 0 +__old_intbase: .long 0 +__have_fpu: .long 0 + +.text +.globl start +start: + br here_we_go + + .align 4 /* So the trap table is double aligned. */ +int_base_tab: /* Here is the fixed jump table for traps! */ + .long __int + .long __trap_nmi + .long __trap_abt + .long __trap_slave + .long __trap_ill + .long __trap_svc + .long __trap_dvz + .long __trap_flg + .long __trap_bpt + .long __trap_trc + .long __trap_und + .long __trap_rbe + .long __trap_nbe + .long __trap_ovf + .long __trap_dbg + .long __trap_reserved + +here_we_go: /* This is the actual start of the locore code! */ + + bicpsrw PSR_I /* make sure interrupts are off. */ + bicpsrw PSR_S /* make sure we are using sp0. */ + lprd sb, 0 /* gcc expects this. */ + sprd sp, __save_sp(pc) /* save monitor's sp. */ + sprd fp, __save_fp(pc) /* save monitor's fp. */ + sprd intbase, __old_intbase(pc) /* save monitor's intbase. */ + +.globl _bootdev +.globl _boothowto + /* Save the registers loaded by the boot program ... if the kernel + was loaded by the boot program. */ + cmpd 0xc1e86394, r3 + bne zero_bss + movd r7, _boothowto(pc) + movd r6, _bootdev(pc) + +zero_bss: + /* Zero the bss segment. */ + addr _end(pc),r0 # setup to zero the bss segment. + addr _edata(pc),r1 + subd r1,r0 # compute _end - _edata + movd r0,tos # push length + addr _edata(pc),tos # push address + bsr _bzero # zero the bss segment + + bsr __low_level_init /* Do the low level setup. */ + + lprd sp, KERN_INT_SP # use the idle/interrupt stack. + lprd fp, KERN_INT_SP # use the idle/interrupt stack. + + /* Load cfg register is bF6 (IC,DC,DE,M,F) or bF4 */ + sprd cfg, r0 + tbitb 1, r0 /* Test the F bit! */ + bfc cfg_no_fpu + movqd 1, __have_fpu(pc) + lprd cfg, 0xbf6 + br jmphi + +cfg_no_fpu: + lprd cfg, 0xbf4 + +/* Now jump to high addresses after starting mapping! */ + +jmphi: + addr here(pc), r0 + ord KERNBASE, r0 + jump 0(r0) + +here: + lprd intbase, int_base_tab /* set up the intbase. */ + + /* stack and frame pointer are pointing at high memory. */ + + bsr _init532 /* Set thing up to call main()! */ + + /* Get the proc0 kernel stack and pcb set up. */ + movd KERN_STK_START, r1 /* Standard sp start! */ + lprd sp, r1 /* Load it! */ + lprd fp, USRSTACK /* fp for the user. */ + lprd usp, USRSTACK /* starting stack for the user. */ + + /* Build the "trap" frame to return to address 0 in user space! */ + movw PSR_I|PSR_S|PSR_U, tos /* psr - user/user stack/interrupts */ + movw 0, tos /* mod - 0! */ + movd 0, tos /* pc - 0 after module table */ + enter [],8 /* Extra space is for USP */ + movqd 0, tos /* Zero the registers in the pcb. */ + movqd 0, tos + movqd 0, tos + movqd 0, tos + movqd 0, tos + movqd 0, tos + movqd 0, tos + movqd 0, tos + movqd 0, REGS_SB(sp) + + /* Now things should be ready to start _main! */ + + addr 0(sp), tos + bsr _main /* Start the kernel! */ + movd tos, r0 /* Pop addr */ + + /* We should only get here in proc 1. */ + movd _curproc(pc), r1 + cmpqd 0, r1 + beq main_panic + movd P_PID(r1),r0 + cmpqd 1, r0 + bne main_panic + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +main_panic: + addr main_panic_str(pc), tos + bsr _panic + +main_panic_str: + .asciz "After main -- no curproc or not proc 1." + +/* Signal support */ +.align 2 +.globl _sigcode +.globl _esigcode +_sigcode: + jsr 0(12(sp)) + movd 103, r0 + svc +.align 2 +_esigcode: + +/* To get the ptb0 register set correctly. */ + +ENTRY(_load_ptb0) + movd S_ARG0, r0 + andd ~KERNBASE, r0 + lmr ptb0, r0 + ret 0 + +ENTRY(_load_ptb1) + movd S_ARG0, r0 + andd ~KERNBASE, r0 + lmr ptb1, r0 + ret 0 + +ENTRY (_get_ptb0) + smr ptb0, r0 + ret 0 + +ENTRY (tlbflush) + smr ptb0, r0 + lmr ptb0, r0 + ret 0 + +ENTRY (_get_sp_adr) /* for use in testing.... */ + addr 4(sp), r0 + ret 0 + +ENTRY (_get_ret_adr) + movd 0(sp), r0 + ret 0 + +ENTRY (_get_fp_ret) + movd 4(fp), r0 + ret 0 + +ENTRY (_get_2fp_ret) + movd 4(0(fp)), r0 + ret 0 + +ENTRY (_get_fp) + addr 0(fp), r0 + ret 0 + +/* reboot the machine :) if possible */ + +ENTRY(low_level_reboot) + + movd -1,tos + bsr _splx + cmpqd 0,tos + ints_off /* Stop things! */ + addr xxxlow(pc), r0 /* jump to low memory */ + andd ~KERNBASE, r0 + movd r0, tos + ret 0 +xxxlow: + lmr mcr, 0 /* Turn off mapping. */ + lprd sp, __save_sp(pc) /* get monitor's sp. */ + jump 0x10000032 /* Jump to the ROM! */ + + +/* To get back to the rom monitor .... */ +ENTRY(bpt_to_monitor) + +/* Switch to monitor's stack. */ + ints_off + bicpsrw PSR_S /* make sure we are using sp0. */ + sprd psr, tos /* Push the current psl. */ + save [r1,r2,r3,r4] + sprd sp, r1 /* save kernel's sp */ + sprd fp, r2 /* save kernel's fp */ + sprd intbase, r3 /* Save current intbase. */ + smr ptb0, r4 /* Save current ptd! */ + +/* Change to low addresses */ + lmr ptb0, _IdlePTD(pc) /* Load the idle ptd */ + addr low(pc), r0 + andd ~KERNBASE, r0 + movd r0, tos + ret 0 + +low: +/* Turn off mapping. */ + smr mcr, r0 + lmr mcr, 0 + lprd sp, __save_sp(pc) /* restore monitors sp */ + lprd fp, __save_fp(pc) /* restore monitors fp */ + lprd intbase, __old_intbase(pc) /* restore monitors intbase */ + bpt + +/* Reload kernel stack AND return. */ + lprd intbase, r3 /* restore kernel's intbase */ + lprd fp, r2 /* restore kernel's fp */ + lprd sp, r1 /* restore kernel's sp */ + lmr mcr, r0 + addr highagain(pc), r0 + ord KERNBASE, r0 + jump 0(r0) +highagain: + lmr ptb0, r4 /* Get the last ptd! */ + restore [r1,r2,r3,r4] + lprd psr, tos /* restore psl */ + ints_on + ret 0 + + +/*===========================================================================* + * ram_size * + *===========================================================================* + + char * + ram_size (start) + char *start; + + Determines RAM size. + + First attempt: write-and-read-back (WRB) each page from start + until WRB fails or get a parity error. This didn't work because + address decoding wraps around. + + New algorithm: + + ret = round-up-page (start); + loop: + if (!WRB or parity or wrap) return ret; + ret += pagesz; (* check end of RAM at powers of two *) + goto loop; + + Several things make this tricky. First, the value read from + an address will be the same value written to the address if + the cache is on -- regardless of whether RAM is located at + the address. Hence the cache must be disabled. Second, + reading an unpopulated RAM address is likely to produce a + parity error. Third, a value written to an unpopulated address + can be held by capacitance on the bus and can be correctly + read back if there is no intervening bus cycle. Hence, + read and write two patterns. + +*/ + +cfg_dc = 0x200 +pagesz = 0x1000 +pattern0 = 0xa5a5a5a5 +pattern1 = 0x5a5a5a5a +nmi_vec = 0x44 +parity_clr = 0x28000050 + +/* + r0 current page, return value + r1 old config register + r2 temp config register + r3 pattern0 + r4 pattern1 + r5 old nmi vector + r6 save word at @0 + r7 save word at @4 +*/ +.globl _ram_size +_ram_size: + enter [r1,r2,r3,r4,r5,r6,r7],0 + # initialize things + movd @0,r6 #save 8 bytes of first page + movd @4,r7 + movd 0,@0 #zero 8 bytes of first page + movd 0,@4 + sprw cfg,r1 #turn off data cache + movw r1,r2 #r1 = old config + andw ~cfg_dc,r2 # was: com cfg_dc,r2 + lprw cfg,r2 + movd @nmi_vec,r5 #save old NMI vector + addr tmp_nmi(pc),@nmi_vec #tmp NMI vector + movd 8(fp),r0 #r0 = start + addr pagesz-1(r0),r0 #round up to page + andd ~(pagesz-1),r0 # was: com (pagesz-1),r0 + movd pattern0,r3 + movd pattern1,r4 +rz_loop: + movd r3,0(r0) #write 8 bytes + movd r4,4(r0) + lprw cfg,r2 #flush write buffer + cmpd r3,0(r0) #read back and compare + bne rz_exit + cmpd r4,4(r0) + bne rz_exit + cmpqd 0,@0 #check for address wrap + bne rz_exit + cmpqd 0,@4 #check for address wrap + bne rz_exit + addr pagesz(r0),r0 #next page + br rz_loop +rz_exit: + movd r6,@0 #restore 8 bytes of first page + movd r7,@4 + lprd cfg,r1 #turn data cache back on + movd r5,@nmi_vec #restore NMI vector + movd parity_clr,r2 + movb 0(r2),r2 #clear parity status + exit [r1,r2,r3,r4,r5,r6,r7] + ret 0 + +tmp_nmi: #come here if parity error + addr rz_exit(pc),0(sp) #modify return addr to exit + rett 0 + +/* Low level kernel support routines. */ + +/* External symbols that are needed. */ +/* .globl EX(cnt) */ +.globl EX(curproc) +.globl EX(curpcb) +.globl EX(qs) +.globl EX(whichqs) +.globl EX(want_resched) +.globl EX(Cur_pl) + +/* + User/Kernel copy routines ... {fu,su}{word,byte} and copyin/coyinstr + + These are "Fetch User" or "Save user" word or byte. They return -1 if + a page fault occurs on access. +*/ + +ENTRY(fuword) +ENTRY(fuiword) + enter [r2],0 + movd _curpcb(pc), r2 + addr fusufault(pc), PCB_ONFAULT(r2) + movd 0(B_ARG0), r0 + br fusu_ret + +ENTRY(fubyte) +ENTRY(fuibyte) + enter [r2],0 + movd _curpcb(pc), r2 + addr fusufault(pc), PCB_ONFAULT(r2) + movzbd 0(B_ARG0), r0 + br fusu_ret + +ENTRY(suword) +ENTRY(suiword) + enter [r2],0 + movqd 4, tos + movd B_ARG0, tos + bsr _check_user_write + adjspd -8 + cmpqd 0, r0 + bne fusufault + movd _curpcb(pc), r2 + addr fusufault(pc), PCB_ONFAULT(r2) + movqd 0, r0 + movd B_ARG1,0(B_ARG0) + br fusu_ret + +ENTRY(subyte) +ENTRY(suibyte) + enter [r2],0 + movqd 1, tos + movd B_ARG0, tos + bsr _check_user_write + adjspd -8 + cmpqd 0, r0 + bne fusufault + movd _curpcb(pc), r2 + addr fusufault(pc), PCB_ONFAULT(r2) + movqd 0, r0 + movb B_ARG1, 0(B_ARG0) + br fusu_ret + +fusufault: + movqd -1, r0 +fusu_ret: + movqd 0, PCB_ONFAULT(r2) + exit [r2] + ret 0 + +/* Two more fu/su routines .... for now ... just return -1. */ +ENTRY(fuswintr) +ENTRY(suswintr) + movqd -1, r0 + ret 0 + +/* C prototype: copyin ( int *usrc, int *kdst, u_int i) + C prototype: copyout ( int *ksrc, int *udst, u_int i) + + i is the number of Bytes! to copy! + + Similar code.... + */ + +ENTRY(copyout) + enter [r2,r3],0 +# Check for copying priviledges! i.e. copy on write! + movd B_ARG2, tos /* Length */ + movd B_ARG1, tos /* adr */ + bsr _check_user_write + adjspd -8 + cmpqd 0, r0 + bne cifault + br docopy + +ENTRY(copyin) + enter [r2,r3],0 +docopy: + movd _curpcb(pc), r3 + addr cifault(pc), PCB_ONFAULT(r3) + movd B_ARG2, r0 /* Length! */ + movd B_ARG0, r1 /* Src adr */ + movd B_ARG1, r2 /* Dst adr */ + movsb /* Move it! */ + movqd 0, r0 + movqd 0, PCB_ONFAULT(r3) + exit [r2,r3] + ret 0 + +cifault: + movd EFAULT, r0 + movd _curpcb(pc), r3 + movqd 0, PCB_ONFAULT(r3) + exit [r2,r3] + ret 0 + + +/*****************************************************************************/ + +/* + * The following primitives manipulate the run queues. + * _whichqs tells which of the 32 queues _qs + * have processes in them. Setrq 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_pri, divided by 4 + * actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ + .globl _whichqs,_qs,_cnt,_panic + +/* + * setrunqueue(struct proc *p); + * Insert a process on the appropriate queue. Should be called at splclock(). + */ +ENTRY(setrunqueue) + movd S_ARG0, r0 + movd r2, tos + + cmpqd 0, P_BACK(r0) /* should not be on q already */ + bne 1f + cmpqd 0, P_WCHAN(r0) + bne 1f + cmpb SRUN, P_STAT(r0) + bne 1f + + movzbd P_PRIORITY(r0),r1 + lshd -2,r1 + sbitd r1,_whichqs(pc) /* set queue full bit */ + addr _qs(pc)[r1:q], r1 /* locate q hdr */ + movd P_BACK(r1),r2 /* locate q tail */ + movd r1, P_FORW(r0) /* set p->p_forw */ + movd r0, P_BACK(r1) /* update q's p_back */ + movd r0, P_FORW(r2) /* update tail's p_forw */ + movd r2, P_BACK(r0) /* set p->p_back */ + movd tos, r2 + ret 0 + +1: addr 2f(pc),tos /* Was on the list! */ + bsr _panic +2: .asciz "setrunqueue problem!" + +/* + * remrq(struct proc *p); + * Remove a process from its queue. Should be called at splclock(). + */ +ENTRY(remrq) + movd S_ARG0, r1 + movd r2, tos + movzbd P_PRIORITY(r1), r0 + + lshd -2, r0 + tbitd r0, _whichqs(pc) + bfc 1f + + movd P_BACK(r1), r2 /* Address of prev. item */ + movqd 0, P_BACK(r1) /* Clear reverse link */ + movd P_FORW(r1), r1 /* Addr of next item. */ + movd r1, P_FORW(r2) /* Unlink item. */ + movd r2, P_BACK(r1) + cmpd r1, r2 /* r1 = r2 => empty queue */ + bne 2f + + cbitd r0, _whichqs(pc) /* mark q as empty */ + +2: movd tos, r2 + ret 0 + +1: addr 2f(pc),tos /* No queue entry! */ + bsr _panic +2: .asciz "remrq problem!" + +/* Switch to another process from kernel code... */ + +ENTRY(cpu_switch) + ints_off /* to make sure cpu_switch runs to completion. */ + enter [r0,r1,r2,r3,r4,r5,r6,r7],0 +/* addqd 1, _cnt+V_SWTCH(pc) */ + + movd _curproc(pc), r0 + cmpqd 0, r0 + beq sw1 + + /* Save "kernel context" - - user context is saved at trap/svc. + Kernel registers are saved at entry to swtch. */ + + movd P_ADDR(r0), r0 + sprd sp, PCB_KSP(r0) + sprd fp, PCB_KFP(r0) + smr ptb0, PCB_PTB(r0) + + /* Save the Cur_pl. */ + movd _Cur_pl(pc), PCB_PL(r0) + + movqd 0, _curproc(pc) /* no current proc! */ + +sw1: /* Get something from a Queue! */ + ints_off /* Just in case we came from Idle. */ + movqd 0, r0 + ffsd _whichqs(pc), r0 + bfs Idle + + /* Get the process and unlink it from the queue. */ + addr _qs(pc)[r0:q], r1 /* address of qs entry! */ + movd 0(r1), r2 /* get process pointer! */ + movd P_FORW(r2), r3 /* get address of next entry. */ + + /* Test code */ + cmpqd 0, r3 + bne notzero + bsr _dump_qs +notzero: + + /* unlink the entry. */ + movd r3, 0(r1) /* New head pointer. */ + movd r1, P_BACK(r3) /* New reverse pointer. */ + cmpd r1, r3 /* Empty? */ + bne restart + + /* queue is empty, turn off whichqs. */ + cbitd r0, _whichqs(pc) + +restart: /* r2 has pointer to new proc.. */ + + /* Reload the new kernel context ... r2 points to proc entry. */ + movqd 0, P_BACK(r2) /* NULL p_forw */ + movqd 0, _want_resched(pc) /* We did a resched! */ + movd P_ADDR(r2), r3 /* get new pcb pointer */ + + + /* Do we need to reload floating point here? */ + + lmr ptb0, PCB_PTB(r3) + lprd sp, PCB_KSP(r3) + lprd fp, PCB_KFP(r3) + movw PCB_FLAGS(r3), r4 /* Get the flags. */ + + movd r2, _curproc(pc) + movd r3, _curpcb(pc) + + /* Restore the previous processor level. */ + movd PCB_PL(r3), tos + bsr _splx + cmpqd 0,tos + /* Return to the caller of swtch! */ + exit [r0,r1,r2,r3,r4,r5,r6,r7] + ret 0 + +/* + * The idle process! + */ +Idle: + lprd sp, KERN_INT_SP /* Set up the "interrupt" stack. */ + movqd 0, r0 + ffsd _whichqs(pc), r0 + bfc sw1 + movd _imask(pc),tos + bsr _splx + cmpqd 0,tos + wait /* Wait for interrupt. */ + br sw1 + +/* As part of the fork operation, we need to prepare a user are for + execution, to be resumed by swtch()... + + C proto is low_level_fork (struct user *up) + + up is a pointer the the "user" struct in the child. + We copy the kernel stack and update the pcb of the child to + return from low_level_fork twice. + + The first return should return a 0. The "second" return should + be because of a swtch() and should return a 1. + +*/ + +ENTRY(low_level_fork) + enter [r0,r1,r2,r3,r4,r5,r6,r7],0 + + /* Save "kernel context" - - user context is saved at trap/svc. + Kernel registers are saved at entry to swtch. */ + + movd B_ARG0, r2 /* Gets the paddr field of child. */ + sprd sp, PCB_KSP(r2) + sprd fp, PCB_KFP(r2) + /* Don't save ptb0 because child has a different ptb0! */ + movd _Cur_pl(pc), PCB_PL(r2) + + /* Copy the kernel stack from this process to new stack. */ + addr 0(sp), r1 /* Source address */ + movd r1, r3 /* Calculate the destination address */ + subd USRSTACK, r3 /* Get the offset */ + addd r3, r2 /* r2 had B_ARG0 in it. now the dest addr */ + movd r2, r5 /* Save the destination address */ + movd KSTK_SIZE, r0 /* Calculate the length of the kernel stack. */ + subd r3, r0 + + movd r0, r4 /* Check for a double alligned stack. */ + andd 3, r4 + cmpqd 0, r4 + beq kcopy + addr m_ll_fork(pc),tos /* panic if not double alligned. */ + bsr _panic + +kcopy: + lshd -2,r0 /* Divide by 4 to get # of doubles. */ + movsd /* Copy the stack! */ + + /* Set parent to return 0. */ + movqd 0,28(sp) + + /* Set child to return 1. */ + movqd 1,28(r5) + + exit [r0,r1,r2,r3,r4,r5,r6,r7] + ret 0 + +m_ll_fork: .asciz "_low_level_fork: kstack not double alligned." + +/* + * savectx(struct pcb *pcb, int altreturn); + * Update pcb, saving current processor state and arranging for alternate + * return in cpu_switch() if altreturn is true. + */ +ENTRY(savectx) + enter [r0,r1,r2,r3,r4,r5,r6,r7],0 + movd B_ARG0, r2 + sprd sp,PCB_KSP(r2) + sprd fp,PCB_KFP(r2) + movd _Cur_pl(pc),PCB_PL(r2) + exit [r0,r1,r2,r3,r4,r5,r6,r7] + ret 0 + +ENTRY(_trap_nmi) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movqd 1, tos + br all_trap + +ENTRY(_trap_abt) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movqd 2, tos + smr tear, tos + smr msr, tos + br abt_trap + +ENTRY(_trap_slave) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movqd 3, tos + br all_trap + +ENTRY(_trap_ill) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movqd 4, tos + br all_trap + +ENTRY(_trap_svc) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + lprd sb, 0 /* for the kernel */ + + /* Have an fpu? */ + cmpqd 0, __have_fpu(pc) + beq svc_no_fpu + + /* Save the FPU registers. */ + movd _curpcb(pc), r3 + sfsr PCB_FSR(r3) + movl f0,PCB_F0(r3) + movl f1,PCB_F1(r3) + movl f2,PCB_F2(r3) + movl f3,PCB_F3(r3) + movl f4,PCB_F4(r3) + movl f5,PCB_F5(r3) + movl f6,PCB_F6(r3) + movl f7,PCB_F7(r3) + + /* Call the system. */ + bsr _syscall + + /* Restore the FPU registers. */ + movd _curpcb(pc), r3 + lfsr PCB_FSR(r3) + movl PCB_F0(r3),f0 + movl PCB_F1(r3),f1 + movl PCB_F2(r3),f2 + movl PCB_F3(r3),f3 + movl PCB_F4(r3),f4 + movl PCB_F5(r3),f5 + movl PCB_F6(r3),f6 + movl PCB_F7(r3),f7 + + /* Restore the usp and sb. */ + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +svc_no_fpu: + /* Call the system. */ + bsr _syscall + + /* Restore the usp and sb. */ + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +ENTRY(_trap_dvz) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movqd 6, tos + br all_trap + +ENTRY(_trap_flg) + cinv ia, r0 + addqd 1, tos /* Increment return address */ + rett 0 + +ENTRY(_trap_bpt) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 8, tos + br all_trap + +ENTRY(_trap_trc) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 9, tos + br all_trap + +ENTRY(_trap_und) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 10, tos + br all_trap + +ENTRY(_trap_rbe) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 11, tos + br all_trap + +ENTRY(_trap_nbe) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 12, tos + br all_trap + +ENTRY(_trap_ovf) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 13, tos + br all_trap + +ENTRY(_trap_dbg) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 14, tos + br all_trap + +ENTRY(_trap_reserved) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp, REGS_USP(sp) + sprd sb, REGS_SB(sp) + movd 15, tos +all_trap: + movqd 0,tos /* Add 2 zeros for msr,tear in frame. */ + movqd 0,tos + +abt_trap: + lprd sb, 0 /* for the kernel */ + + /* Was this a real process? */ + cmpqd 0, _curproc(pc) + beq trap_no_fpu + + /* Have an fpu? */ + cmpqd 0, __have_fpu(pc) + beq trap_no_fpu + + /* Save the FPU registers. */ + movd _curpcb(pc), r3 /* R3 is saved by gcc. */ + sfsr PCB_FSR(r3) + movl f0,PCB_F0(r3) + movl f1,PCB_F1(r3) + movl f2,PCB_F2(r3) + movl f3,PCB_F3(r3) + movl f4,PCB_F4(r3) + movl f5,PCB_F5(r3) + movl f6,PCB_F6(r3) + movl f7,PCB_F7(r3) + + bsr _trap + adjspd -12 /* Pop off software part of trap frame. */ + + /* Restore the FPU registers. */ + lfsr PCB_FSR(r3) + movl PCB_F0(r3),f0 + movl PCB_F1(r3),f1 + movl PCB_F2(r3),f2 + movl PCB_F3(r3),f3 + movl PCB_F4(r3),f4 + movl PCB_F5(r3),f5 + movl PCB_F6(r3),f6 + movl PCB_F7(r3),f7 + + /* Reload the usp and sb just in case anything has changed. */ + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +trap_no_fpu: + bsr _trap + adjspd -12 /* Pop off software part of trap frame. */ + + /* Reload the usp and sb just in case anything has changed. */ + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +/* Interrupt service routines.... */ +ENTRY(_int) + enter [r0,r1,r2,r3,r4,r5,r6,r7],8 + sprd usp,REGS_USP(sp) + sprd sb,REGS_SB(sp) + lprd sb,0 /* for the kernel */ + movd _Cur_pl(pc), tos + movb @ICU_ADR+HVCT,r0 /* fetch vector */ + andd 0x0f,r0 + movd r0,tos + movqd 1,r1 + lshd r0,r1 + orw r1,_Cur_pl(pc) /* or bit to Cur_pl */ + orw r1,@ICU_ADR+IMSK /* and to IMSK */ + /* bits set by idisabled in IMSK */ + /* have to be preserved */ + ints_off /* flush pending writes */ + ints_on /* and now turn ints on */ + addqd 1,_intrcnt(pc)[r0:d] + lshd 4,r0 + addqd 1,_cnt+V_INTR(pc) + addqd 1,_ivt+IV_CNT(r0) /* increment counters */ + movd _ivt+IV_ARG(r0),r1 /* get argument */ + cmpqd 0,r1 + bne 1f + addr 0(sp),r1 /* NULL -> push frame address */ +1: movd r1,tos + movd _ivt+IV_VEC(r0),r0 /* call the handler */ + jsr 0(r0) + + adjspd -8 /* Remove arg and vec from stack */ + bsr _splx_di /* Restore Cur_pl */ + cmpqd 0,tos + + tbitw 8, REGS_PSR(sp) /* In system mode? */ + bfs do_user_intr /* branch if yes! */ + + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +do_user_intr: + /* Do "user" mode interrupt processing, including preemption. */ + ints_off + movd _curproc(pc), r2 + cmpqd 0,r2 + beq intr_panic + + /* Have an fpu? */ + cmpqd 0, __have_fpu(pc) + beq intr_no_fpu + + /* Save the FPU registers. */ + movd _curpcb(pc), r3 /* R3 is saved by gcc. */ + sfsr PCB_FSR(r3) + movl f0,PCB_F0(r3) + movl f1,PCB_F1(r3) + movl f2,PCB_F2(r3) + movl f3,PCB_F3(r3) + movl f4,PCB_F4(r3) + movl f5,PCB_F5(r3) + movl f6,PCB_F6(r3) + movl f7,PCB_F7(r3) + +intr_no_fpu: + /* turn on interrupts! */ + ints_on + + cmpqd 0, _want_resched(pc) + beq do_usr_ret + movd 18, tos + movqd 0,tos + movqd 0,tos + bsr _trap + adjspd -12 /* Pop off software part of trap frame. */ + +do_usr_ret: + + /* Have an fpu? */ + cmpqd 0, __have_fpu(pc) + beq intr_ret_no_fpu + + /* Restore the FPU registers. r3 should be as set before. */ + lfsr PCB_FSR(r3) + movl PCB_F0(r3),f0 + movl PCB_F1(r3),f1 + movl PCB_F2(r3),f2 + movl PCB_F3(r3),f3 + movl PCB_F4(r3),f4 + movl PCB_F5(r3),f5 + movl PCB_F6(r3),f6 + movl PCB_F7(r3),f7 + +intr_ret_no_fpu: + lprd usp, REGS_USP(sp) + lprd sb, REGS_SB(sp) + exit [r0,r1,r2,r3,r4,r5,r6,r7] + rett 0 + +intr_panic: + addr intr_panic_msg(pc),tos /* panic if not double alligned. */ + bsr _panic + +intr_panic_msg: + .asciz "user mode interrupt with no current process!" + +/* Include all other .s files. */ +#include "bcopy.s" +#include "bzero.s" + + +/* pmap support??? ..... */ + +/* + * Note: This version greatly munged to avoid various assembler errors + * that may be fixed in newer versions of gas. Perhaps newer versions + * will have more pleasant appearance. + */ + + .set IDXSHIFT,10 + .set SYSTEM,0xFE000000 # virtual address of system start + /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */ + .set SYSPDROFF,0x3F8 # Page dir index of System Base + +/* + * PTmap is recursive pagemap at top of virtual address space. + * Within PTmap, the page directory can be found (third indirection). + */ +#define PDRPDROFF 0x03F7 /* page dir index of page dir */ + .globl _PTmap, _PTD, _PTDpde, _Sysmap + .set _PTmap,0xFDC00000 + .set _PTD,0xFDFF7000 + .set _Sysmap,0xFDFF8000 + .set _PTDpde,0xFDFF7000+4*PDRPDROFF + +/* + * APTmap, APTD is the alternate recursive pagemap. + * It's used when modifying another process's page tables. + */ +#define APDRPDROFF 0x03FE /* page dir index of page dir */ + .globl _APTmap, _APTD, _APTDpde + .set _APTmap,0xFF800000 + .set _APTD,0xFFBFE000 + .set _APTDpde,0xFDFF7000+4*APDRPDROFF + +/* + * Access to each processes kernel stack is via a region of + * per-process address space (at the beginning), immediatly above + * the user process stack. + */ +#if 0 + .set _kstack, USRSTACK + .globl _kstack +#endif + .set PPDROFF,0x3F6 +/* # .set PPTEOFF,0x400-UPAGES # 0x3FE */ + .set PPTEOFF,0x3FE + +.data +.globl _PDRPDROFF +_PDRPDROFF: + .long PDRPDROFF + +/* vmstat -i uses the following labels and __int even increments the + * counters. This information is also availiable from ivt[n].iv_use + * and ivt[n].iv_cnt in much better form. + */ + .globl _intrnames, _eintrnames, _intrcnt, _eintrcnt +_intrnames: + .asciz "int 0" + .asciz "int 1" + .asciz "int 2" + .asciz "int 3" + .asciz "int 4" + .asciz "int 5" + .asciz "int 6" + .asciz "int 7" + .asciz "int 8" + .asciz "int 9" + .asciz "int 10" + .asciz "int 11" + .asciz "int 12" + .asciz "int 13" + .asciz "int 14" + .asciz "int 15" +_eintrnames: +_intrcnt: + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 + .long 0 +_eintrcnt: diff --git a/sys/arch/pc532/pc532/machdep.c b/sys/arch/pc532/pc532/machdep.c new file mode 100644 index 00000000000..a1b98265e35 --- /dev/null +++ b/sys/arch/pc532/pc532/machdep.c @@ -0,0 +1,1121 @@ +/* $NetBSD: machdep.c,v 1.40.2.1 1995/10/17 00:19:08 phil Exp $ */ + +/*- + * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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 7.4 (Berkeley) 6/3/91 + */ + +/* + * Modified for the pc532 by Phil Nelson. 2/3/93 + */ + +static char rcsid[] = "/b/source/CVS/src/sys/arch/pc532/pc532/machdep.c,v 1.2 1993/09/13 07:26:49 phil Exp"; + +#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/user.h> +#include <sys/exec.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/msgbuf.h> +#include <sys/vnode.h> +#include <sys/device.h> +#include <sys/sysctl.h> +#include <sys/mount.h> +#include <sys/syscallargs.h> + +#include <dev/cons.h> + +#include <net/netisr.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> + +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/cpu.h> +#include <machine/pmap.h> +#include <machine/icu.h> + +extern vm_offset_t avail_end; +extern struct user *proc0paddr; + +vm_map_t buffer_map; + +/* A local function... */ +void reboot_cpu(); +void dumpsys __P((void)); + + +/* the following is used externally (sysctl_hw) */ +char machine[] = "pc532"; +char cpu_model[] = "ns32532"; + +/* + * 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 */ + + +/* Real low level initialization. This is called in unmapped mode and + sets up the inital page directory and page tables for the kernel. + This routine is the first to be called by locore.s to get the + kernel running at the correct place in memory. + */ + +extern char end[], _edata[]; +extern vm_offset_t avail_start; +extern vm_offset_t avail_end; + +int physmem = 0; +int maxmem = 0; + +vm_offset_t KPTphys; + +int IdlePTD; +int start_page; +int _istack; + +int low_mem_map; + +/* Support for VERY low debugging ... in case we get NO output. + (e.g. in case pmap does not work and can't do regular mapped + output. */ +#if VERYLOWDEBUG +#include <pc532/umprintf.c> +#endif + +void +_low_level_init () +{ + int ix, ix1, ix2; + int p0, p1, p2; + extern int _mapped; + +#if VERYLOWDEBUG + umprintf ("starting low level init\n"); +#endif + + mem_size = ram_size(end); + physmem = btoc(mem_size); + start_page = (((int)&end + NS532_PAGE_SIZE) & ~(NS532_PAGE_SIZE-1)) + & 0xffffff; + avail_start = start_page; + avail_end = mem_size - NS532_PAGE_SIZE; + +#if VERYLOWDEBUG + umprintf ("mem_size = 0x%x\nphysmem=%x\nstart_page=0x%x\navail_end=0x%x\n", + mem_size, physmem, start_page, avail_end); +#endif + + + /* Initialize the mmu with a simple memory map. */ + + /* A new interrupt stack, i.e. not the rom monitor's. */ + _istack = avail_start; + avail_start += NS532_PAGE_SIZE; + + /* The page directory that starts the entire mapping. */ + p0 = (int) avail_start; + IdlePTD = p0; + KPTphys = p0; + avail_start += NS532_PAGE_SIZE; + + /* First clear out the page table directory. */ + bzero((char *)p0, NS532_PAGE_SIZE); + + /* Now for the memory mapped I/O, the ICU and the eprom. */ + p1 = (int) avail_start; + avail_start += NS532_PAGE_SIZE; + bzero ((char *)p1, NS532_PAGE_SIZE); + + /* Addresses here start at FFC00000... */ + + /* Map the interrupt stack to FFC00000 - FFC00FFF */ + WR_ADR(int, p1, _istack+3); + + /* All futhur entries are cache inhibited. => 0x4? in low bits. */ + + /* The Duarts and Parity. Addresses FFC80000 */ + WR_ADR(int, p1+4*0x80, 0x28000043); + + /* SCSI Polled (Reduced space.) Addresses FFD00000 - FFDFFFFF */ + for (ix = 0x100; ix < 0x200; ix++) + WR_ADR(int, p1 + ix*4, 0x30000043 + ((ix - 0x100)<<12)); + + /* SCSI "DMA" (Reduced space.) Addresses FFE00000 - FFEEFFFF */ + for (ix = 0x200; ix < 0x2ff; ix++) + WR_ADR(int, p1 + ix*4, 0x38000043 + ((ix - 0x200)<<12)); + + /* SCSI "DMA" With A22 (EOP) Addresses FFEFF000 - FFEFFFFF */ + WR_ADR(int, p1 + 0x2ff*4, 0x38400043); + + /* The e-prom Addresses FFF00000 - FFF3FFFF */ + for (ix = 0x300; ix < 0x340; ix++) + WR_ADR(int, p1 + ix*4, 0x10000043 + ((ix - 0x300)<<12)); + + /* Finally the ICU! Addresses FFFFF000 - FFFFFFFF */ + WR_ADR(int, p1+4*0x3ff, 0xFFFFF043); + + /* Add the memory mapped I/O entry in the directory. */ + WR_ADR(int, p0+4*1023, p1 + 0x43); + + /* Map the kernel pages starting at FE00000 and at 0. + It also maps any pages past the end of the kernel, + up to the value of avail_start at this point. + These pages currently are: + 1 - interrupt stack + 2 - Top level page table + 3 - 2nd level page table for I/O + 4 - 2nd level page table for the kernel & low memory + 5-7 will be allocated as 2nd level page tables by pmap_bootstrap. + */ + + low_mem_map = p2 = (int) avail_start; + avail_start += NS532_PAGE_SIZE; + bzero ((char *)p2, NS532_PAGE_SIZE); + WR_ADR(int,p0+4*pdei(KERNBASE), p2 + 3); + WR_ADR(int,p0, p2+3); + + for (ix = 0; ix < (avail_start)/NS532_PAGE_SIZE; ix++) { + WR_ADR(int, p2 + ix*4, NS532_PAGE_SIZE * ix + 3); + } + + /* Load the ptb0 register and start mapping. */ + + _mapped = 1; + _load_ptb0 (p0); + asm(" lmr mcr, 3"); /* Start the machine mapping, 1 vm space. */ + +} + +extern void icu_init(); + +/* init532 is the first procedure called in mapped mode by locore.s + */ + +init532() +{ + int free_pages; + void (**int_tab)(); + extern int _save_sp; + +/*#include "ddb.h" */ +#if NDDB > 0 + kdb_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif + + /* Initialize the pmap stuff.... */ + pmap_bootstrap (avail_start, 0); + /* now running on new page tables, configured, and u/iom is accessible */ + + /* Set up the proc0paddr struct. */ + proc0paddr->u_pcb.pcb_flags = 0; + proc0paddr->u_pcb.pcb_pl = 0xffffffff; + proc0paddr->u_pcb.pcb_ptb = IdlePTD; + proc0paddr->u_pcb.pcb_onstack = + (struct on_stack *) proc0paddr + UPAGES*NBPG + - sizeof (struct on_stack); + + /* Set up the ICU. */ + icu_init(); + intr_init(); +} + + +/* + * Machine-dependent startup code + */ +int boothowto = 0, Maxmem = 0; +long dumplo; +int physmem, maxmem; + +extern int bootdev; +extern cyloffset; + +/* pmap_enter prototype */ +void pmap_enter __P((register pmap_t, vm_offset_t, register vm_offset_t, + vm_prot_t, boolean_t)); + +void +cpu_startup(void) +{ + register int unixsize; + register unsigned i; + register struct pte *pte; + int mapaddr, j; + register caddr_t v; + int maxbufs, base, residual; + extern long Usrptsize; + vm_offset_t minaddr, maxaddr; + vm_size_t size; + int firstaddr; + + /* + * Initialize error message buffer (at end of core). + */ + + /* avail_end was pre-decremented in pmap_bootstrap to compensate */ + for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) + pmap_enter(pmap_kernel(), (vm_offset_t) msgbufp, + avail_end + i * NBPG, VM_PROT_ALL, TRUE); + msgbufmapped = 1; + +#ifdef KDB + kdb_init(); /* startup kernel debugger */ +#endif + /* + * Good {morning,afternoon,evening,night}. + */ + printf(version); + printf("\nreal mem = 0x%x\n", ctob(physmem)); + + /* + * Allocate space for system data structures. + * The first available kernel virtual address is in "v". + * As pages of kernel virtual memory are allocated, "v" is incremented. + * As pages of memory are allocated and cleared, + * "firstaddr" is incremented. + * An index into the kernel page table corresponding to the + * virtual memory address maintained in "v" is kept in "mapaddr". + */ + + /* + * Make two passes. The first pass calculates how much memory is + * needed and allocates it. The second pass assigns virtual + * addresses to the various data structures. + */ + firstaddr = 0; +again: + v = (caddr_t)firstaddr; + +#define valloc(name, type, num) \ + (name) = (type *)v; v = (caddr_t)((name)+(num)) +#define valloclim(name, type, num, lim) \ + (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) + valloc(callout, struct callout, ncallout); + valloc(swapmap, struct map, nswapmap = maxproc * 2); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif + /* + * Determine how many buffers to allocate. + * Use 10% of memory for the first 2 Meg, 5% of the remaining + * memory. Insure a minimum of 16 buffers. + * We allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + if (physmem < (2 * 1024 * 1024)) + bufpages = physmem / 10 / CLSIZE; + else + bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE; + + bufpages = min(NKMEMCLUSTERS*2/5, bufpages); /* XXX ? - cgd */ + + if (nbuf == 0) { + nbuf = bufpages / 2; + if (nbuf < 16) { + nbuf = 16; + /* XXX (cgd) -- broken vfs_bio currently demands this */ + bufpages = 32; + } + } + + 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); + + /* + * End of first pass, size has been calculated so allocate memory + */ + if (firstaddr == 0) { + size = (vm_size_t)(v - firstaddr); + firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); + if (firstaddr == 0) + panic("startup: no room for tables"); + goto again; + } + + /* + * End of second pass, addresses have been assigned + */ + if ((vm_size_t)(v - firstaddr) != size) + panic("startup: table size inconsistency"); + + /* + * Now allocate buffers proper. They are different than the above + * in that they 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; + if (base >= MAXBSIZE) { + /* don't want to alloc more physical mem than needed */ + base = MAXBSIZE; + residual = 0; + } + 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]; + + printf("avail mem = 0x%x\n", ptoa(cnt.v_free_count)); + printf("using %d buffers containing %d bytes of memory\n", + nbuf, bufpages * CLBYTES); + + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + /* + * Configure the system. + */ + configure(); +} + +#ifdef PGINPROF +/* + * Return the difference (in microseconds) + * between the current time and a previous + * time as represented by the arguments. + * If there is a pending clock interrupt + * which has not been serviced due to high + * ipl, return error code. + */ +/*ARGSUSED*/ +vmtime(otime, olbolt, oicr) + register int otime, olbolt, oicr; +{ + + return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667); +} +#endif + +/* + * Send an interrupt to process. + * + * Stack is set up to allow sigcode stored + * in u. to call routine, followed by kcall + * to sigreturn routine below. After sigreturn + * resets the signal mask, the stack, and the + * frame pointer, it returns to the user + * specified pc, psl. + */ + +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig, mask; + u_long code; +{ + register struct proc *p = curproc; + register int *regs; + register struct sigframe *fp; + struct sigacts *ps = p->p_sigacts; + int oonstack; + extern char sigcode[], esigcode[]; + + regs = p->p_md.md_regs; + oonstack = ps->ps_sigstk.ss_flags & SS_ONSTACK; + + /* + * Allocate space for the signal handler context. + */ + if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && + (ps->ps_sigonstack & sigmask(sig))) { + fp = (struct sigframe *)(ps->ps_sigstk.ss_base + + ps->ps_sigstk.ss_size - sizeof(struct sigframe)); + ps->ps_sigstk.ss_flags |= SS_ONSTACK; + } else { + fp = (struct sigframe *)(regs[REG_SP] + - sizeof(struct sigframe)); + } + + if ((unsigned)fp <= (unsigned)p->p_vmspace->vm_maxsaddr + MAXSSIZ - ctob(p->p_vmspace->vm_ssize)) + (void)grow(p, (unsigned)fp); + + if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) { + /* + * 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. + */ + fp->sf_signum = sig; + fp->sf_code = code; + fp->sf_scp = &fp->sf_sc; + fp->sf_handler = catcher; + + /* save registers */ + bcopy (regs, fp->sf_scp->sc_reg, 8*sizeof(int)); + + /* + * Build the signal context to be used by sigreturn. + */ + fp->sf_sc.sc_onstack = oonstack; + fp->sf_sc.sc_mask = mask; + fp->sf_sc.sc_sp = regs[REG_SP]; + fp->sf_sc.sc_fp = regs[REG_FP]; + fp->sf_sc.sc_pc = regs[REG_PC]; + fp->sf_sc.sc_ps = regs[REG_PSR]; + fp->sf_sc.sc_sb = regs[REG_SB]; + regs[REG_SP] = (int)fp; + regs[REG_PC] = (int)(((char *)PS_STRINGS) - (esigcode - sigcode)); +} + +/* + * 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. + */ +int +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 struct sigframe *fp; + register int *regs = p->p_md.md_regs; + fp = (struct sigframe *) regs[REG_SP] ; + + if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) + return(EINVAL); + + /* restore registers */ + bcopy (fp->sf_scp->sc_reg, regs, 8*sizeof(int)); + + scp = fp->sf_scp; + if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0) + return(EINVAL); +#ifdef notyet + if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) { + return(EINVAL); + } +#endif + if (scp->sc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; + p->p_sigmask = scp->sc_mask &~ + (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP)); + regs[REG_FP] = scp->sc_fp; + regs[REG_SP] = scp->sc_sp; + regs[REG_PC] = scp->sc_pc; + regs[REG_PSR] = scp->sc_ps; + regs[REG_SB] = scp->sc_sb; + return(EJUSTRETURN); +} + +int waittime = -1; +struct pcb dumppcb; + +void +boot(howto) + int howto; +{ + register int devtype; /* r10 == major of root dev */ + extern const char *panicstr; + extern int cold; + int nomsg = 1; + + if(cold) { + printf("cold boot: hit reset please"); + for(;;); + } + boothowto = howto; + if ((howto&RB_NOSYNC) == 0 && waittime < 0) { + waittime = 0; + vfs_shutdown(); + /* + * If we've been adjusting the clock, the todr + * will be out of synch; adjust it now. (non panic!) + */ + if (panicstr == 0) + resettodr(); + + DELAY(10000); /* wait for printf to finish */ + } + splhigh(); + devtype = major(rootdev); + + if (howto&RB_HALT) { + printf ("\nThe operating system has halted.\n\n"); + cpu_reset(); + for(;;) ; + /*NOTREACHED*/ + } else { + if (howto & RB_DUMP) { + savectx(&dumppcb, 0); + dumppcb.pcb_ptb = _get_ptb0(); + dumpsys(); + } + } + + printf("rebooting ..."); + reboot_cpu(); + for(;;) ; + /*NOTREACHED*/ +} + +void +microtime(tvp) + register struct timeval *tvp; +{ + int s = splhigh(); + + *tvp = time; + tvp->tv_usec += tick; + while (tvp->tv_usec > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + splx(s); +} + +/* + * Strange exec values! (Do we want to support a minix a.out header?) + */ +int +cpu_exec_aout_makecmds() +{ + return ENOEXEC; +}; + +/* + * Clear registers on exec + */ +void +setregs(p, entry, stack, retval) + struct proc *p; + struct exec_package *entry; + u_long stack; + register_t *retval; +{ + struct on_stack *r = (struct on_stack *)p->p_md.md_regs; + int i; + +/* printf ("Setregs: entry = %x, stack = %x, (usp = %x)\n", entry, stack, + r->pcb_usp); */ + + /* Start fp at stack also! */ + r->pcb_usp = stack; + r->pcb_fp = stack; + r->pcb_pc = entry->ep_entry; + r->pcb_psr = PSL_USERSET; + r->pcb_reg[0] = (int)PS_STRINGS; + for (i=1; i<8; i++) r->pcb_reg[i] = 0; + + p->p_addr->u_pcb.pcb_flags = 0; +} + + +extern struct pte *CMAP1, *CMAP2; +extern caddr_t CADDR1, CADDR2; +/* + * zero out physical memory + * specified in relocation units (NBPG bytes) + */ +clearseg(n) +{ + /* map page n in to virtual address CADDR2 */ + *(int *)CMAP2 = PG_V | PG_KW | ctob(n); + tlbflush(); + bzero(CADDR2,NBPG); + *(int *) CADDR2 = 0; +} + +/* + * copy a page of physical memory + * specified in relocation units (NBPG bytes) + */ +copyseg(frm, n) +{ + /* map page n in to virtual address CADDR2 */ + *(int *)CMAP2 = PG_V | PG_KW | ctob(n); + tlbflush(); + bcopy((void *)frm, (void *)CADDR2, NBPG); +} + +/* + * copy a page of physical memory + * specified in relocation units (NBPG bytes) + */ +physcopyseg(frm, to) +{ + /* map page frm in to virtual address CADDR1 */ + *(int *)CMAP1 = PG_V | PG_KW | ctob(frm); + /* map page to in to virtual address CADDR2 */ + *(int *)CMAP2 = PG_V | PG_KW | ctob(to); + tlbflush(); + bcopy(CADDR1, CADDR2, NBPG); +} + +/* + * insert an element into a queue + */ +#undef insque +_insque(element, head) + register struct prochd *element, *head; +{ + element->ph_link = head->ph_link; + head->ph_link = (struct proc *)element; + element->ph_rlink = (struct proc *)head; + ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element; +} + +/* + * remove an element from a queue + */ +#undef remque +_remque(element) + register struct prochd *element; +{ + ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink; + ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link; + element->ph_rlink = (struct proc *)0; +} + +vmunaccess() {printf ("vmunaccess!\n");} + +/* + * Below written in C to allow access to debugging code + */ +copyinstr(fromaddr, toaddr, maxlength, lencopied) size_t *lencopied, maxlength; + void *toaddr, *fromaddr; { + int c,tally; + + tally = 0; + while (maxlength--) { + c = fubyte(fromaddr++); + if (c == -1) { + if(lencopied) *lencopied = tally; + return(EFAULT); + } + tally++; + *(char *)toaddr++ = (char) c; + if (c == 0){ + if(lencopied) *lencopied = (u_int)tally; + return(0); + } + } + if(lencopied) *lencopied = (u_int)tally; + return(ENAMETOOLONG); +} + +copyoutstr(fromaddr, toaddr, maxlength, lencopied) size_t *lencopied, maxlength; + void *fromaddr, *toaddr; { + int c; + int tally; + + tally = 0; + while (maxlength--) { + c = subyte(toaddr++, *(char *)fromaddr); + if (c == -1) return(EFAULT); + tally++; + if (*(char *)fromaddr++ == 0){ + if(lencopied) *lencopied = tally; + return(0); + } + } + if(lencopied) *lencopied = tally; + return(ENAMETOOLONG); +} + +copystr(fromaddr, toaddr, maxlength, lencopied) size_t *lencopied, maxlength; + void *fromaddr, *toaddr; { + u_int tally; + + tally = 0; + while (maxlength--) { + *(u_char *)toaddr = *(u_char *)fromaddr++; + tally++; + if (*(u_char *)toaddr++ == 0) { + if(lencopied) *lencopied = tally; + return(0); + } + } + if(lencopied) *lencopied = tally; + return(ENAMETOOLONG); +} + +/* + * These variables are needed by /sbin/savecore + */ +u_long dumpmag = 0x8fca0101; /* magic number */ +int dumpsize = 0; /* pages */ +long dumplo = 0; /* blocks */ + +/* + * This is called by configure to set dumplo and dumpsize. + * Dumps always skip the first CLBYTES of disk space + * in case there might be a disk label stored there. + * If there is extra space, put dump at the end to + * reduce the chance that swapping trashes it. + */ +void +dumpconf() +{ + int nblks; /* size of dump area */ + int maj; + + if (dumpdev == NODEV) + return; + maj = major(dumpdev); + if (maj < 0 || maj >= nblkdev) + panic("dumpconf: bad dumpdev=0x%x", dumpdev); + if (bdevsw[maj].d_psize == NULL) + return; + nblks = (*bdevsw[maj].d_psize)(dumpdev); + if (nblks <= ctod(1)) + return; + + dumpsize = physmem; + + /* Always skip the first CLBYTES, in case there is a label there. */ + if (dumplo < ctod(1)) + dumplo = ctod(1); + + /* Put dump at end of partition, and make it fit. */ + if (dumpsize > dtoc(nblks - dumplo)) + dumpsize = dtoc(nblks - dumplo); + if (dumplo < nblks - ctod(dumpsize)) + dumplo = nblks - ctod(dumpsize); +} + +/* + * Doadump comes here after turning off memory management and + * getting on the dump stack, either when called above, or by + * the auto-restart code. + */ +#define BYTES_PER_DUMP NBPG /* must be a multiple of pagesize XXX small */ +static vm_offset_t dumpspace; + +vm_offset_t +reserve_dumppages(p) + vm_offset_t p; +{ + + dumpspace = p; + return (p + BYTES_PER_DUMP); +} + +void +dumpsys() +{ + unsigned bytes, i, n; + int maddr, psize; + daddr_t blkno; + int (*dump) __P((dev_t, daddr_t, caddr_t, size_t)); + int error = 0; + int c; + + msgbufmapped = 0; /* don't record dump msgs in msgbuf */ + 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); + + psize = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); + printf("dump "); + if (psize == -1) { + printf("area unavailable\n"); + return; + } + +#if 0 /* XXX this doesn't work. grr. */ + /* toss any characters present prior to dump */ + while (sget() != NULL); /*syscons and pccons differ */ +#endif + + bytes = mem_size; + maddr = 0; + blkno = dumplo; + dump = bdevsw[major(dumpdev)].d_dump; + for (i = 0; i < bytes; i += n) { + /* Print out how many MBs we to go. */ + n = bytes - i; + if (n && (n % (1024*1024)) == 0) + printf("%d ", n / (1024 * 1024)); + + /* Limit size for next transfer. */ + if (n > BYTES_PER_DUMP) + n = BYTES_PER_DUMP; + + (void) pmap_map(dumpspace, maddr, maddr + n, VM_PROT_READ); + error = (*dump)(dumpdev, blkno, (caddr_t)dumpspace, n); + if (error) + break; + maddr += n; + blkno += btodb(n); /* XXX? */ + +#if 0 /* XXX this doesn't work. grr. */ + /* operator aborting dump? */ + if (sget() != NULL) { + error = EINTR; + break; + } +#endif + } + + switch (error) { + + case ENXIO: + printf("device bad\n"); + break; + + case EFAULT: + printf("device not ready\n"); + break; + + case EINVAL: + printf("area improper\n"); + break; + + case EIO: + printf("i/o error\n"); + break; + + case EINTR: + printf("aborted from console\n"); + break; + + case 0: + printf("succeeded\n"); + break; + + default: + printf("error %d\n", error); + break; + } + printf("\n\n"); + delay(5000000); /* 5 seconds */ +} + +/* Stub function for reboot_cpu. */ + +void reboot_cpu() +{ + extern void low_level_reboot(); + + /* Point Low MEMORY to Kernel Memory! */ + *((int *)PTD) = low_mem_map+3; /* PTD[pdei(KERNBASE)]; */ + low_level_reboot(); + +} + +int +sys_sysarch(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct sysarch_args /* { + syscallarg(int) op; + syscallarg(char *) parms; + } */ *uap = v; + + return ENOSYS; +} + +/* + * consinit: + * initialize the system console. + * XXX - shouldn't deal with this cons_initted thing, but then, + * it shouldn't be called from init386 either. + */ +static int cons_initted; + +void +consinit() +{ + if (!cons_initted) { + cninit(); + cons_initted = 1; + } +} + +/* DEBUG routine */ + +void dump_qs() +{ int ix; + struct proc *ptr; + + for (ix=0; ix<NQS; ix++) + if (qs[ix].ph_link != qs[ix].ph_rlink) + { + ptr = qs[ix].ph_link; + do { + printf ("qs[%d]: 0x%x 0x%x\n", ix, ptr->p_forw, ptr->p_back); + ptr = ptr->p_forw; + } while (ptr != (struct proc *)0 && ptr != qs[ix].ph_link); + } + panic("nil P_BACK"); +} + +/* + * 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 */ +} diff --git a/sys/arch/pc532/pc532/mem.c b/sys/arch/pc532/pc532/mem.c new file mode 100644 index 00000000000..4d565be9770 --- /dev/null +++ b/sys/arch/pc532/pc532/mem.c @@ -0,0 +1,283 @@ +/* $NetBSD: mem.c,v 1.13 1995/09/26 20:16:30 phil Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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/systm.h> +#include <sys/uio.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> + +#include <vm/vm.h> + +extern char *vmmap; /* poor name! */ +caddr_t zeropage; + +#ifndef NO_RTC +int have_rtc = 1; /* For access to rtc. */ +#else +int have_rtc = 0; /* For no rtc. */ +#endif +#define ROM_ORIGIN 0xFFF00000 /* Mapped origin! */ + +/* Do the actual reading and writing of the rtc. We have to read + and write the entire contents at a time. rw = 0 => read, + rw = 1 => write. */ + +void rw_rtc (unsigned char *buffer, int rw) +{ + static unsigned char magic[8] = + {0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c}; + volatile unsigned char * const rom_p = (unsigned char *)ROM_ORIGIN; + unsigned char *bp; + unsigned char dummy; /* To defeat optimization */ + + /* Read or write to the real time chip. Address line A0 functions as + * data input, A2 is used as the /write signal. Accesses to the RTC + * are always done to one of the addresses (unmapped): + * + * 0x10000000 - write a '0' bit + * 0x10000001 - write a '1' bit + * 0x10000004 - read a bit + * + * Data is output from the RTC using D0. To read or write time + * information, the chip has to be activated first, to distinguish + * clock accesses from normal ROM reads. This is done by writing, + * bit by bit, a magic pattern to the chip. Before that, a dummy read + * assures that the chip's pattern comparison register pointer is + * reset. The RTC register file is always read or written wholly, + * even if we are only interested in a part of it. + */ + + /* Activate the real time chip */ + dummy = rom_p[4]; /* Synchronize the comparison reg. */ + + for (bp=magic; bp<magic+8; bp++) { + int i; + for (i=0; i<8; i++) + dummy = rom_p[ (*bp>>i) & 0x01 ]; + } + + if (rw == 0) { + /* Read the time from the RTC. Do this even this is + a write, since the user might have only given + partial data and the RTC must always be written + completely. + */ + + for (bp=buffer; bp<buffer+8; bp++) { + int i; + for (i=0; i<8; i++) { + *bp >>= 1; + *bp |= ((rom_p[4] & 0x01) ? 0x80 : 0x00); + } + } + } else { + /* Write to the RTC */ + for (bp=buffer; bp<buffer+8; bp++) { + int i; + for (i=0; i<8; i++) + dummy = rom_p[ (*bp>>i) & 0x01 ]; + } + } +} + +/*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; + static int physlock; + /* /dev/rtc support. */ + unsigned char buffer[8]; + + if (minor(dev) == 0) { + /* lock against other uses of shared vmmap */ + while (physlock > 0) { + physlock++; + error = tsleep((caddr_t)&physlock, PZERO | PCATCH, + "mmrw", 0); + if (error) + return (error); + } + physlock = 1; + } + while (uio->uio_resid > 0 && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("mmrw"); + continue; + } + switch (minor(dev)) { + +/* minor device 0 is physical memory */ + case 0: + v = uio->uio_offset; + pmap_enter(pmap_kernel(), (vm_offset_t)vmmap, + trunc_page(v), uio->uio_rw == UIO_READ ? + VM_PROT_READ : VM_PROT_WRITE, TRUE); + o = uio->uio_offset & PGOFSET; + c = min(uio->uio_resid, (int)(NBPG - o)); + error = uiomove((caddr_t)vmmap + o, c, uio); + pmap_remove(pmap_kernel(), (vm_offset_t)vmmap, + (vm_offset_t)vmmap + NBPG); + continue; + +/* minor device 1 is kernel memory */ + case 1: + v = uio->uio_offset; + c = min(iov->iov_len, MAXPHYS); + if (!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); + +#ifdef DEV_RTC +/* minor device 3 is the realtime clock. */ + case 3: + if (!have_rtc) + return (ENXIO); + + /* Calc offsets and lengths. */ + v = uio->uio_offset; + if (v > 8) + return (0); /* EOF */ + c = iov->iov_len; + if (v+c > 8) + c = 8-v; + + rw_rtc(buffer, 0); /* Read the rtc. */ + + error = uiomove((caddr_t)&buffer[v], c, uio); + + if (uio->uio_rw == UIO_READ || error) + return (error); + + rw_rtc(buffer, 1); /* Write the rtc. */ + + return (error); +#endif + +/* 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; + } + if (minor(dev) == 0) { +unlock: + if (physlock > 1) + wakeup((caddr_t)&physlock); + physlock = 0; + } + return (error); +} + +int +mmmmap(dev, off, prot) + dev_t dev; + int off, prot; +{ + + return (EOPNOTSUPP); +} diff --git a/sys/arch/pc532/pc532/ns_cksum.c b/sys/arch/pc532/pc532/ns_cksum.c new file mode 100644 index 00000000000..34660d2ecd2 --- /dev/null +++ b/sys/arch/pc532/pc532/ns_cksum.c @@ -0,0 +1,206 @@ +/* $NetBSD: ns_cksum.c,v 1.2 1994/10/26 08:25:11 cgd Exp $ */ + +/* + * Copyright (c) 1982, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns_cksum.c 7.7 (Berkeley) 4/29/91 + */ + +#include "sys/param.h" +#include "sys/mbuf.h" + +/* + * Checksum routine for Network Systems Protocol Packets (Big-Endian). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + */ + +#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; } +#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);} + +u_short +ns_cksum(m, len) + register struct mbuf *m; + register int len; +{ + register u_short *w; + register int sum = 0; + register int mlen = 0; + register int sum2; + + union { + u_short s[2]; + long l; + } l_util; + + for (;m && len; m = m->m_next) { + if (m->m_len == 0) + continue; + /* + * Each trip around loop adds in + * word from one mbuf segment. + */ + w = mtod(m, u_short *); + if (mlen == -1) { + /* + * There is a byte left from the last segment; + * ones-complement add it into the checksum. + */ +#if BYTE_ORDER == BIG_ENDIAN + sum += *(u_char *)w; +#else + sum += *(u_char *)w << 8; +#endif + sum += sum; + w = (u_short *)(1 + (char *)w); + mlen = m->m_len - 1; + len--; + FOLD(sum); + } else + mlen = m->m_len; + if (len < mlen) + mlen = len; + len -= mlen; + /* + * We can do a 16 bit ones complement sum using + * 32 bit arithmetic registers for adding, + * with carries from the low added + * into the high (by normal carry-chaining) + * so long as we fold back before 16 carries have occured. + */ + if (1 & (int) w) + goto uuuuglyy; +#ifndef TINY +/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += sum; sum += w[1]; sum += sum; + sum += w[2]; sum += sum; sum += w[3]; sum += sum; + sum += w[4]; sum += sum; sum += w[5]; sum += sum; + sum += w[6]; sum += sum; sum += w[7]; sum += sum; + FOLD(sum); + sum += w[8]; sum += sum; sum += w[9]; sum += sum; + sum += w[10]; sum += sum; sum += w[11]; sum += sum; + sum += w[12]; sum += sum; sum += w[13]; sum += sum; + sum += w[14]; sum += sum; sum += w[15]; sum += sum; + FOLD(sum); + w += 16; + } + mlen += 32; +#endif + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += sum; sum += w[1]; sum += sum; + sum += w[2]; sum += sum; sum += w[3]; sum += sum; + FOLD(sum); + w += 4; + } + mlen += 8; + while ((mlen -= 2) >= 0) { + sum += *w++; sum += sum; + } + goto commoncase; +uuuuglyy: +#if BYTE_ORDER == BIG_ENDIAN +#define ww(n) (((u_char *)w)[n + n + 1]) +#define vv(n) (((u_char *)w)[n + n]) +#else +#if BYTE_ORDER == LITTLE_ENDIAN +#define vv(n) (((u_char *)w)[n + n + 1]) +#define ww(n) (((u_char *)w)[n + n]) +#endif +#endif + sum2 = 0; +#ifndef TINY + while ((mlen -= 32) >= 0) { + sum += ww(0); sum += sum; sum += ww(1); sum += sum; + sum += ww(2); sum += sum; sum += ww(3); sum += sum; + sum += ww(4); sum += sum; sum += ww(5); sum += sum; + sum += ww(6); sum += sum; sum += ww(7); sum += sum; + FOLD(sum); + sum += ww(8); sum += sum; sum += ww(9); sum += sum; + sum += ww(10); sum += sum; sum += ww(11); sum += sum; + sum += ww(12); sum += sum; sum += ww(13); sum += sum; + sum += ww(14); sum += sum; sum += ww(15); sum += sum; + FOLD(sum); + sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; + sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; + sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2; + sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2; + FOLD(sum2); + sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2; + sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2; + sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2; + sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2; + FOLD(sum2); + w += 16; + } + mlen += 32; +#endif + while ((mlen -= 8) >= 0) { + sum += ww(0); sum += sum; sum += ww(1); sum += sum; + sum += ww(2); sum += sum; sum += ww(3); sum += sum; + FOLD(sum); + sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2; + sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2; + FOLD(sum2); + w += 4; + } + mlen += 8; + while ((mlen -= 2) >= 0) { + sum += ww(0); sum += sum; + sum2 += vv(0); sum2 += sum2; + w++; + } + sum += (sum2 << 8); +commoncase: + if (mlen == -1) { +#if BYTE_ORDER == BIG_ENDIAN + sum += *(u_char *)w << 8; +#else + sum += *(u_char *)w; +#endif + } + FOLD(sum); + } + if (mlen == -1) { + /* We had an odd number of bytes to sum; assume a garbage + byte of zero and clean up */ + sum += sum; + FOLD(sum); + } + /* + * sum has already been kept to low sixteen bits. + * just examine result and exit. + */ + if(sum==0xffff) sum = 0; + return (sum); +} diff --git a/sys/arch/pc532/pc532/ntoh.s b/sys/arch/pc532/pc532/ntoh.s new file mode 100644 index 00000000000..8801e9a1bbf --- /dev/null +++ b/sys/arch/pc532/pc532/ntoh.s @@ -0,0 +1,47 @@ +/* $NetBSD: ntoh.s,v 1.2 1994/10/26 08:25:12 cgd Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <machine/asm.h> + + .text +ENTRY(ntohl) +ENTRY(htonl) + movd S_ARG0,r0 + rotw 8,r0 + rotd 16,r0 + rotw 8,r0 + ret 0 + + +ENTRY(ntohs) +ENTRY(htons) + movzwd S_ARG0,r0 + rotw 8,r0 + ret 0 diff --git a/sys/arch/pc532/pc532/oc_cksum.s b/sys/arch/pc532/pc532/oc_cksum.s new file mode 100644 index 00000000000..cb42cdb26f3 --- /dev/null +++ b/sys/arch/pc532/pc532/oc_cksum.s @@ -0,0 +1,67 @@ +/* $NetBSD: oc_cksum.s,v 1.2 1994/10/26 08:25:13 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. + * + * + * oc_cksum: ones complement 16 bit checksum for NS32532 + * + * oc_cksum (buffer, count, strtval) + * + * Do a 16 bit one's complement sum of 'count' bytes from 'buffer'. + * 'strtval' is the starting value of the sum (usually zero). + */ + + +#include <machine/asm.h> + + /* This could use some tuning for better speed. */ + + .globl _oc_cksum +_oc_cksum: + movd S_ARG0,r2 /* buffer */ + movd S_ARG1,r1 /* count */ + movd S_ARG2,r0 /* strtval */ + +loop: + cmpqd 1, r1 + ble oneleft + addw 0(r2), r0 + addqd 2,r2 + addqd -2,r1 + br loop + +oneleft: + bls done + movqd 0, r1 + movb 0(r2), r1 + addw r1, r0 +done: + ret 0 diff --git a/sys/arch/pc532/pc532/pmap.c b/sys/arch/pc532/pc532/pmap.c new file mode 100644 index 00000000000..bf6089666fa --- /dev/null +++ b/sys/arch/pc532/pc532/pmap.c @@ -0,0 +1,1945 @@ +/* $NetBSD: pmap.c,v 1.10 1995/08/25 07:49:13 phil Exp $ */ + +/* + * Copyright (c) 1991 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 William Jolitz of UUNET Technologies 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. + * + * @(#)pmap.c 7.7 (Berkeley) 5/12/91 + */ + +/* + * Derived from hp300 version by Mike Hibler, this version by William + * Jolitz uses a recursive map [a pde points to the page directory] to + * map the page tables using the pagetables themselves. This is done to + * reduce the impact on kernel virtual memory for lots of sparse address + * space, and to reduce the cost of memory to each process. + * + * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90 + */ + +/* + * Reno i386 version, from Mike Hibler's hp300 version. + */ + +/* + * Most recently made to be a pc532 pmap! (Phil Nelson, 1/14/93) + */ + +/* + * 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/proc.h> +#include <sys/malloc.h> +#include <sys/user.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> + +/* Prototypes of routines used here. */ + +vm_offset_t pmap_extract(pmap_t, vm_offset_t); +void pmap_activate(register pmap_t, struct pcb *); +extern vm_offset_t reserve_dumppages __P((vm_offset_t)); + +/* + * Allocate various and sundry SYSMAPs used in the days of old VM + * and not yet converted. XXX. + */ + +#define BSDVM_COMPAT 1 + +#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 */ +} enter_stats; +struct { + int calls; + int removes; + int pvfirst; + int pvsearch; + int ptinvalid; + int uflushes; + int sflushes; +} remove_stats; + +int debugmap = 0; +int pmapdebug = 0; /* 0xffff */ +#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_CACHE 0x0040 +#define PDB_BITS 0x0080 +#define PDB_COLLECT 0x0100 +#define PDB_PROTECT 0x0200 +#define PDB_PDRTAB 0x0400 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +int pmapvacflush = 0; +#define PVF_ENTER 0x01 +#define PVF_REMOVE 0x02 +#define PVF_PROTECT 0x04 +#define PVF_TOTAL 0x80 +#endif + +/* + * Get PDEs and PTEs for user/kernel address space + */ +#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023])) + +#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME) + +#define pmap_pde_v(pte) ((pte)->pd_v) +#define pmap_pte_w(pte) ((pte)->pg_w) +/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */ +#define pmap_pte_m(pte) ((pte)->pg_m) +#define pmap_pte_u(pte) ((pte)->pg_u) +#define pmap_pte_v(pte) ((pte)->pg_v) +#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v)) +#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v)) + + +/* for debug output */ +#define pg printf + +/* + * Given a map and a machine independent protection code, + * convert to a ns532 protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +struct user *proc0paddr; +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) */ +vm_offset_t vm_first_phys; /* PA of first managed page */ +vm_offset_t vm_last_phys; /* PA just past last managed page */ +int ns532pagesperpage; /* PAGE_SIZE / NS532_PAGE_SIZE */ +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +short *pmap_attributes; /* reference and modify bits */ + +boolean_t pmap_testbit(); +void pmap_clear_modify(); + +#if BSDVM_COMPAT +#include "msgbuf.h" + +/* + * All those kernel PT submaps that BSD is so fond of + */ +struct pte *CMAP1, *CMAP2, *xxx_mmap; +caddr_t CADDR1, CADDR2, vmmap; +struct pte *msgbufmap; +struct msgbuf *msgbufp; +#endif + +vm_offset_t KPTphys; +extern int PDRPDROFF; + +/* + * 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; +{ + extern boolean_t vm_page_startup_initialized; + vm_offset_t val; + + if (vm_page_startup_initialized) + panic("pmap_bootstrap_alloc: called after startup initialized")\ +; + size = round_page(size); + val = virtual_avail; + + virtual_avail = pmap_map(virtual_avail, avail_start, + avail_start + size, VM_PROT_READ|VM_PROT_WRITE); + avail_start += size; + + blkclr ((caddr_t) val, size); + return ((void *) val); +} + + + +/* static */ +void +v_probe(pmap_t pmap, vm_offset_t va) +{ + int *ptr; + struct pde *pde_entry; + struct pte *pte_entry; + + /* get a pointer to the top level page table entry */ + pde_entry = pmap_pde(pmap, va); + if (!pmap_pde_v(pde_entry)) { + printf("va 0x%x, no top-level entry\n", va); + return; + } + ptr = (int *) pde_entry; + pte_entry = ((struct pte *) ((*ptr & PG_FRAME) | KERNBASE)) + ptei(va); + ptr = (int *) pte_entry; + if (!pmap_pte_v(pte_entry)) { + printf("pte_entry 0x%x *pte_entry 0x%x\n", ptr, *ptr); + printf("va 0x%x, no 2nd-level entry\n", va); + return; + } + /* print the page table entry */ + printf("v_probe: va 0x%x pa 0x%x entry 0x%x\n", + va, (*ptr & PG_FRAME) | (va & ~PG_FRAME), *ptr); +} + +static +void +map_page(pmap_t pmap, vm_offset_t va, vm_offset_t pa) +{ + int *ptr; + struct pde *pde_entry; + struct pte *pte_entry; + + /* get a pointer to the top level page table entry */ + pde_entry = pmap_pde(pmap, va); + if (!pmap_pde_v(pde_entry)) { + printf("map_page(0x%x, 0x%x, 0x%x) failed\n", pmap, va, pa); + panic("missing 2nd level page table"); + } + /* get a pointer to the 2nd level table entry */ + ptr = (int *) pde_entry; + pte_entry = ((struct pte *) (*ptr & PG_FRAME)) + ptei(va); + if (pmap_pte_v(pte_entry)) { + printf("map_page(0x%x, 0x%x, 0x%x) failed\n", pmap, va, pa); + panic("2nd level page table entry already valid"); + } + /* make the page table entry */ + ptr = (int *) pte_entry; + *ptr = pa | PG_V | PG_KW; + /* just to be safe */ + tlbflush(); +} + +/* + * Map in physical page 'pa' to virtual address 'va', and install + * as a 2nd level page table at index 'index' for the given + * pmap. + */ +static +void +map_page_table(pmap_t pmap, int index, vm_offset_t va, vm_offset_t pa) +{ + int *ptr = (int *) &pmap->pm_pdir[index]; + if (*ptr) { + printf("2nd level table present for index %x\n", index); + panic("remapping 2nd level table"); + } + /* map in the 2nd level table */ + map_page(pmap_kernel(), va, pa); + /* init the 2nd level table to all invalid */ + bzero(pa, NBPG); + /* install the 2nd level table */ + *ptr = pa | PG_V | PG_KW; + /* just to be safe */ + tlbflush(); +} + +/* + * Bootstrap the system enough to run with virtual memory. + * Map the kernel's code and data, and allocate the system page table. + * + * On the Ns532 this is called after mapping has already been enabled + * and just syncs the pmap module with what has already been done. + * [We can't call it easily with mapping off since the kernel is not + * mapped with PA == VA, hence we would have to relocate every address + * from the linked base (virtual) address 0xFE000000 to the actual + * (physical) address starting relative to 0] + */ +struct pte *pmap_pte(); + +void +pmap_bootstrap(firstaddr, loadaddr) + vm_offset_t firstaddr; + vm_offset_t loadaddr; +{ + int x, *ptr; +#if BSDVM_COMPAT + vm_offset_t va; + struct pte *pte; +#endif + extern vm_offset_t maxmem, physmem; + + ns532pagesperpage = 1; /* PAGE_SIZE / NS532_PAGE_SIZE; */ + + /* + * Initialize protection array. + */ + ns532_protection_init(); + + /* setup avail_start, avail_end, virtual_avail, virtual_end */ + avail_start = firstaddr; + avail_end = mem_size; + + /* XXX: allow for msgbuf */ + avail_end -= ns532_round_page(sizeof(struct msgbuf)); + + virtual_avail = avail_start + KERNBASE; + virtual_end = VM_MAX_KERNEL_ADDRESS; + + /* + * Create Kernel page directory table and page maps. + */ + pmap_kernel()->pm_pdir = (pd_entry_t *) (KPTphys + KERNBASE); + /* recursively map in ptb0 */ + ptr = ((int *) pmap_kernel()->pm_pdir) + PDRPDROFF; + if (*ptr) { + printf("ptb0 0x%x offset 0x%x should be 0 but is 0x%x\n", + pmap_kernel()->pm_pdir, PDRPDROFF, *ptr); + bpt_to_monitor(); + } + /* don't add KERNBASE as this has to be a physical address */ + *ptr = KPTphys | PG_V | PG_KW; + /* fill in the rest of the top-level kernel VA entries */ + for (x = ns532_btod(VM_MIN_KERNEL_ADDRESS); + x < ns532_btod(VM_MAX_KERNEL_ADDRESS); x++) { + ptr = (int *) &pmap_kernel()->pm_pdir[x]; + /* only fill in the entries not yet made in _low_level_init() */ + if (!*ptr) { + /* map in the page table */ + map_page_table(pmap_kernel(), x, + virtual_avail, avail_start); + avail_start += NBPG; + virtual_avail += NBPG; + } + } + /* map in the kernel stack for process 0 */ + /* install avail_start as a 2nd level table for index 0x3f6 */ + map_page_table(pmap_kernel(), 0x3f6, virtual_avail, avail_start); + avail_start += NBPG; + virtual_avail += NBPG; + /* reserve UPAGES pages */ + proc0paddr = (struct user *) virtual_avail; + curpcb = (struct pcb *) proc0paddr; + va = ns532_dtob(0x3f6) | ns532_ptob(0x3fe); /* USRSTACK ? */ + for (x = 0; x < UPAGES; ++x) { + map_page(pmap_kernel(), va, avail_start); + map_page(pmap_kernel(), virtual_avail, avail_start); + bzero(va, NBPG); + va += NBPG; + avail_start += NBPG; + virtual_avail += NBPG; + } + + simple_lock_init(&pmap_kernel()->pm_lock); + pmap_kernel()->pm_count = 1; + +#ifdef DEBUG + printf("avail_start = 0x%x\n", avail_start); + printf("avail_end = 0x%x\n", avail_end); + printf("virtual_avail = 0x%x\n", virtual_avail); + printf("virtual_end = 0x%x\n", virtual_end); +#endif + +#if BSDVM_COMPAT + /* + * Allocate all the submaps we need + */ +#define SYSMAP(c, p, v, n) \ + v = (c)va; va += ((n)*NS532_PAGE_SIZE); p = pte; pte += (n); + + va = virtual_avail; + pte = pmap_pte(pmap_kernel(), va); + + SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 ) + SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 ) + SYSMAP(caddr_t ,xxx_mmap ,vmmap ,1 ) + SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 ) + virtual_avail = va; +#endif + virtual_avail = reserve_dumppages(va); +#ifdef DEBUG + printf("virtual_avail = 0x%x\n", virtual_avail); +#endif + tlbflush(); + /* XXX why do we do this??? - MM */ + *(int *)PTD = 0; + tlbflush(); +} + +/* + * Initialize the pmap module. + * Called by vm_init, to initialize any structures that the pmap + * system needs to map virtual memory. + */ +void +pmap_init(phys_start, phys_end) + vm_offset_t phys_start, phys_end; +{ + int result; + vm_offset_t addr, addr2; + vm_size_t npg, s; + int rv; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_INIT)) + printf("pmap_init(0x%x, 0x%x)\n", phys_start, phys_end); +#endif + + if (PAGE_SIZE != NBPG) + panic("pmap_init: CLSIZE != 1"); + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in locore. + */ + +#if 0 + /* the following reserves the (virtual) i/o space */ + addr = 0xffc00000; + result = vm_map_find(kernel_map, NULL, (vm_offset_t) 0, + &addr, NBPG, FALSE); + if (result != KERN_SUCCESS) { + printf("vm_map_find for virtual i/o space failed %d\n", result); + } + + /* reserve the used page tables following the kernel */ + /* bumped this to 10 pages just to be paranoid */ + addr = (vm_offset_t) KERNBASE + KPTphys; + vm_object_reference(kernel_object); + result = vm_map_find(kernel_map, kernel_object, addr, + &addr, 10*NBPG, FALSE); + if (result != KERN_SUCCESS) { + printf("vm_map_find for kernel page maps failed %d\n", result); + } +#endif + /* + * Allocate memory for random pmap data structures. Includes the + * pv_head_table and pmap_attributes. + */ + npg = atop(phys_end - phys_start); + s = (vm_size_t) (sizeof(struct pv_entry) * npg + 2*npg); + s = round_page(s); + addr = (vm_offset_t) kmem_alloc(kernel_map, s); + pv_table = (pv_entry_t) addr; + addr += sizeof(struct pv_entry) * npg; + pmap_attributes = (short *) addr; + +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n", + s, npg, pv_table, pmap_attributes); +#endif + + /* + * Now it is safe to enable pv_table recording. + */ + vm_first_phys = phys_start; + vm_last_phys = phys_end; + pmap_initialized = TRUE; +} + +/* + * Used to map a range of physical addresses into kernel + * virtual address space. + * + * For now, VM is already on, we only need to map the + * specified memory. + */ +vm_offset_t +pmap_map(virt, start, end, prot) + vm_offset_t virt; + vm_offset_t start; + vm_offset_t end; + int prot; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot); +#endif + while (start < end) { + pmap_enter(pmap_kernel(), virt, start, prot, FALSE); + virt += PAGE_SIZE; + start += PAGE_SIZE; + } + return(virt); +} + +/* + * 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. + * + * [ just allocate a ptd and mark it uninitialize -- should we track + * with a table which process has which ptd? -wfj ] + */ + +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; +{ +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + pg("pmap_pinit(%x)\n", pmap); +#endif + + /* + * No need to allocate page table space yet but we do need a + * valid page directory table. + */ + pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG); + + /* wire in kernel global address entries */ + bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST, + (KPTDI_LAST-KPTDI_FIRST+1)*4); + + /* install self-referential address mapping entry */ + *(int *)(pmap->pm_pdir+PTDPTDI) = + (int)pmap_extract(pmap_kernel(), (vm_offset_t) pmap->pm_pdir) + | PG_V | PG_KW; + + pmap->pm_count = 1; + simple_lock_init(&pmap->pm_lock); +} + +/* + * 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) + 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 struct pmap *pmap; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + pg("pmap_release(%x)\n", pmap); +#endif +#ifdef notdef /* DIAGNOSTIC */ + /* count would be 0 from pmap_destroy... */ + simple_lock(&pmap->pm_lock); + if (pmap->pm_count != 1) + panic("pmap_release count"); +#endif + kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG); +} + +/* + * 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) + struct pmap *pmap; + register vm_offset_t sva; + register vm_offset_t eva; +{ + register pt_entry_t *ptp,*ptq; + vm_offset_t va; + vm_offset_t pa; + pt_entry_t *pte; + pv_entry_t pv, npv; + int ix; + int s, bits; + +#ifdef DEBUG + pt_entry_t opte; + + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + pg("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); +#endif + + if (pmap == NULL) + return; + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == pmap_kernel()) + ptp=PTmap; + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + ptp=APTmap; + } +#ifdef DEBUG + remove_stats.calls++; +#endif + + /* this is essential since we must check the PDE(sva) for precense */ + while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva))) + sva = (sva & PD_MASK) + (1<<PD_SHIFT); + sva = ns532_btop(sva); + eva = ns532_btop(eva); + + for (; sva < eva; sva++) { + /* + * Weed out invalid mappings. + * Note: we assume that the page directory table is + * always allocated, and in kernel virtual. + */ + ptq=ptp+sva; + while((sva & 0x3ff) && !pmap_pte_pa(ptq)) + { + if(++sva >= eva) + return; + ptq++; + } + + + if(!(sva & 0x3ff)) /* Only check once in a while */ + { + if (!pmap_pde_v(pmap_pde(pmap, ns532_ptob(sva)))) + { + /* We can race ahead here, straight to next pde.. */ + sva = (sva & 0xffc00) + (1<<10) -1 ; + continue; + } + } + if(!pmap_pte_pa(ptp+sva)) + continue; + + pte = ptp + sva; + pa = pmap_pte_pa(pte); + va = ns532_ptob(sva); +#ifdef DEBUG + opte = *pte; + remove_stats.removes++; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTEs. + * XXX: should cluster them up and invalidate as many + * as possible at once. + */ +#ifdef DEBUG + if (pmapdebug & PDB_REMOVE) + printf("remove: inv %x ptes at pte %x pa %x va %x\n", + ns532pagesperpage, pte, pa, va); +#endif + bits = ix = 0; + do { + bits |= *(int *)pte & (PG_U|PG_M); + *(int *)pte++ = 0; + /*TBIS(va + ix * NS532_PAGE_SIZE);*/ + } while (++ix != ns532pagesperpage); + if (curproc && pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pmap, (struct pcb *)curproc->p_addr); +#if 0 +/* commented out in 386 version as well */ + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == pmap_kernel()) { + _load_ptb0(curpcb->pcb_ptb); + } +#endif + tlbflush(); + +#ifdef needednotdone +reduce wiring count on page table pages as references drop +#endif + + /* + * Remove from the PV table (raise IPL since we + * may be called at interrupt time). + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + continue; + 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) { + 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 { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { +#ifdef DEBUG + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) { + printf("vm_first_phys %x pa %x vm_last_phys %x\n", + vm_first_phys, pa, vm_last_phys); + panic("pmap_remove: PA not in pv_tab"); + } +#endif + pv->pv_next = npv->pv_next; + free((caddr_t)npv, M_VMPVENT); + pv = pa_to_pvh(pa); + } + +#ifdef notdef +[tally number of pagetable pages, if sharing of ptpages adjust here] +#endif + /* + * Update saved attributes for managed page + */ + pmap_attributes[pa_index(pa)] |= bits; + splx(s); + } +#ifdef notdef +[cache and tlb flushing, if needed] +#endif +} + +/* + * Routine: pmap_remove_all + * Function: + * Removes this physical page from + * all physical maps in which it resides. + * Reflects back modify bits to the pager. + */ +void +pmap_remove_all(pa) + vm_offset_t pa; +{ + register pv_entry_t pv; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove_all(%x)", pa); + /*pmap_pvdump(pa);*/ +#endif + /* + * Not one of ours + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Do it the easy way for now + */ + while (pv->pv_pmap != NULL) { +#ifdef DEBUG + if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) || + pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa) + panic("pmap_remove_all: bad mapping"); +#endif + pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE); + } + splx(s); +} + +/* + * Routine: pmap_copy_on_write + * Function: + * Remove write privileges from all + * physical maps for this physical page. + */ +void +pmap_copy_on_write(pa) + vm_offset_t pa; +{ +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_copy_on_write(%x)", pa); +#endif + pmap_changebit(pa, /* was PG_RO, TRUE */ PG_RW, FALSE); +} + +/* + * 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 pt_entry_t *pte; + register vm_offset_t va; + register int ix; + int ns532prot; + boolean_t firstpage = TRUE; + register pt_entry_t *ptp; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot); +#endif + if (pmap == NULL) + return; + + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == pmap_kernel()) + ptp=PTmap; + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + ptp=APTmap; + } + for (va = sva; va < eva; va += PAGE_SIZE) { + /* + * Page table page is not allocated. + * Skip it, we don't want to force allocation + * of unnecessary PTE pages just to set the protection. + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + /* XXX: avoid address wrap around */ + if (va >= ns532_trunc_pdr((vm_offset_t)-1)) + break; + va = ns532_round_pdr(va + PAGE_SIZE) - PAGE_SIZE; + continue; + } + + pte = ptp + ns532_btop(va); + + /* + * Page not valid. Again, skip it. + * Should we do this? Or set protection anyway? + */ + if (!pmap_pte_v(pte)) + continue; + + ix = 0; + ns532prot = pte_prot(pmap, prot); + if(va < UPT_MAX_ADDRESS) + ns532prot |= 2 /*PG_u*/; + do { + /* clear VAC here if PG_RO? */ + pmap_pte_set_prot(pte++, ns532prot); + /*TBIS(va + ix * NS532_PAGE_SIZE);*/ + } while (++ix != ns532pagesperpage); + } + if (curproc && pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pmap, (struct pcb *)curproc->p_addr); +} + +/* + * 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 int npte, ix; + vm_offset_t opa; + boolean_t cacheable = TRUE; + boolean_t checkpv = TRUE; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) + printf("pmap_enter(%x, %x, %x, %x, %x)\n", + pmap, va, pa, prot, wired); +#endif + if (pmap == NULL) + return; + + if(va >= VM_MAX_KERNEL_ADDRESS) + panic("pmap_enter: toobig"); + /* also, should not muck with PTD va! */ + +#ifdef DEBUG + if (pmap == pmap_kernel()) + enter_stats.kernel++; + else + enter_stats.user++; +#endif + + /* + * Page Directory table entry not valid, we need a new PT page + */ + pte = pmap_pte(pmap, va); + if (!pte) + panic("ptdi %x", pmap->pm_pdir[PTDPTDI]); + +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pte %x, *pte %x ", pte, *(int *)pte); +#endif + + + if (pmap_pte_v(pte)) { + register vm_offset_t opa; + + opa = pmap_pte_pa(pte); + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { +#ifdef DEBUG + enter_stats.pwchange++; +#endif + /* + * Wiring change, just update stats. + * We don't worry about wiring PT pages as they remain + * resident as long as there are valid mappings in them. + * Hence, if a user page is wired, the PT page will be also. + */ + if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + pg("enter: wiring change -> %x ", wired); +#endif + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; +#ifdef DEBUG + enter_stats.wchange++; +#endif + } + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: removing old mapping %x pa %x ", va, opa); +#endif + pmap_remove(pmap, va, va + NBPG); +#ifdef DEBUG + enter_stats.mchange++; +#endif + } + + /* + * Enter on the PV list if part of our managed memory + * Note that we raise IPL while manipulating pv_table + * since pmap_enter can be called at interrupt time. + */ +/* if (pmap_valid_page(pa)) in the i386 version ... */ + if (pa >= vm_first_phys && pa < vm_last_phys) { + register pv_entry_t pv, npv; + int s; + +#ifdef DEBUG + enter_stats.managed++; +#endif + pv = pa_to_pvh(pa); + s = splimp(); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pv at %x: %x/%x/%x\n", + pv, pv->pv_va, pv->pv_pmap, pv->pv_next); +#endif + /* + * No entries yet, use header as the first entry + */ + if (pv->pv_pmap == NULL) { +#ifdef DEBUG + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { + /*printf("second time: ");*/ +#ifdef DEBUG + for (npv = pv; npv; npv = npv->pv_next) + if (pmap == npv->pv_pmap && va == npv->pv_va) + panic("pmap_enter: already in pv_tab"); +#endif + npv = (pv_entry_t) + malloc(sizeof *npv, M_VMPVENT, M_NOWAIT); + if (npv == NULL) + panic("pmap_enter: malloc returned NULL"); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + pv->pv_next = npv; +#ifdef DEBUG + if (!npv->pv_next) + enter_stats.secondpv++; +#endif + } + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + if (pmap_initialized) { + checkpv = cacheable = FALSE; +#ifdef DEBUG + enter_stats.unmanaged++; +#endif + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: + /* + * Now validate mapping with desired protection/wiring. + * Assume uniform modified and referenced status for all + * Ns532 pages in a MACH page. + */ + npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V; + npte |= (*(int *)pte & (PG_M|PG_U)); + if (wired) + npte |= PG_W; + if (va < VM_MAXUSER_ADDRESS) /* i.e. below USRSTACK */ + npte |= PG_u; + else if (va < UPT_MAX_ADDRESS) + /* pagetables need to be user RW, for some reason, and the + * user area must be writable too. Anything above + * VM_MAXUSER_ADDRESS is protected from user access by + * the user data and code segment descriptors, so this is OK. + * + * andrew@werple.apana.org.au + */ + npte |= PG_u | PG_RW; + +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: new pte value %x\n", npte); +#endif + ix = 0; + do { + *(int *)pte++ = npte; + /*TBIS(va);*/ + npte += NS532_PAGE_SIZE; + va += NS532_PAGE_SIZE; + } while (++ix != ns532pagesperpage); + pte--; +#ifdef DEBUGx +cache, tlb flushes +#endif +#if 0 + pads(pmap); + _load_ptb0(((struct pcb *)curproc->p_addr)->pcb_ptb); +#endif + tlbflush(); +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(phys, prot) + vm_offset_t phys; + vm_prot_t prot; +{ + switch (prot) { + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_copy_on_write(phys); + break; + case VM_PROT_ALL: + break; + default: + pmap_remove_all(phys); + break; + } +} + +/* + * 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; + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_change_wiring(%x, %x, %x)\n", pmap, va, wired); +#endif + if (pmap == NULL) + return; + + pte = pmap_pte(pmap, va); +#ifdef DEBUG + /* + * Page table page is not allocated. + * Should this ever happen? Ignore it for now, + * we don't want to force allocation of unnecessary PTE pages. + */ + if (!pmap_pde_v(pmap_pde(pmap, va))) { + if (pmapdebug & PDB_PARANOIA) + pg("pmap_change_wiring: invalid PDE for %x\n", va); + return; + } + /* + * Page not valid. Should this ever happen? + * Just continue and change wiring anyway. + */ + if (!pmap_pte_v(pte)) { + if (pmapdebug & PDB_PARANOIA) + pg("pmap_change_wiring: invalid PTE for %x\n", va); + } +#endif + if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; + } + /* + * Wiring is not a hardware characteristic so there is no need + * to invalidate TLB. + */ + ix = 0; + do { + pmap_pte_set_w(pte++, wired); + } while (++ix != ns532pagesperpage); +} + +/* + * Routine: pmap_pte + * Function: + * Extract the page table entry associated + * with the given map/virtual_address pair. + * [ what about induced faults -wfj] + */ + +struct pte *pmap_pte(pmap, va) + register pmap_t pmap; + vm_offset_t va; +{ +#ifdef DEBUGx + if (pmapdebug & PDB_FOLLOW) + printf("pmap_pte(%x, %x) ->\n", pmap, va); +#endif + if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { + + /* are we current address space or kernel? */ + if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum + || pmap == pmap_kernel()) + return ((struct pte *) vtopte(va)); + + /* otherwise, we are alternate address space */ + else { + if (pmap->pm_pdir[PTDPTDI].pd_pfnum + != APTDpde.pd_pfnum) { + APTDpde = pmap->pm_pdir[PTDPTDI]; + tlbflush(); + } + return((struct pte *) avtopte(va)); + } + } + return(0); +} + +/* + * 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 DEBUGx + if (pmapdebug & PDB_FOLLOW) + pg("pmap_extract(%x, %x) -> ", pmap, va); +#endif + pa = 0; + if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { + pa = *(int *) pmap_pte(pmap, va); + } + if (pa) + pa = (pa & PG_FRAME) | (va & ~PG_FRAME); +#ifdef DEBUGx + if (pmapdebug & PDB_FOLLOW) + printf("%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; +{ +/* printf ("pmap_copy: dst=0x%x src=0x%x d_addr=0x%x len=0x%x s_addr=0x%x\n", + dst_pmap, src_pmap, dst_addr, len, 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()"); +#endif + tlbflush(); +} + +/* + * 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. + * [ needs to be written -wfj ] + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + register vm_offset_t pa; + register pv_entry_t pv; + register int *pte; + vm_offset_t kpa; + int s; + +#ifdef DEBUG + int *pde; + int opmapdebug; +#endif + if (pmap != pmap_kernel()) + return; +} + +/* [ macro again?, should I force kstack into user map here? -wfj ] */ +void +pmap_activate(pmap, pcbp) + register pmap_t pmap; + struct pcb *pcbp; +{ +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB)) + pg("pmap_activate(%x, %x)\n", pmap, pcbp); +#endif + PMAP_ACTIVATE(pmap, pcbp); +#ifdef DEBUG + { + int x; + printf("pde "); + for(x=0x3f6; x < 0x3fA; x++) + printf("%x ", pmap->pm_pdir[x]); + pads(pmap); + pg(" pcb_ptb %x\n", pcbp->pcb_ptb); + } +#endif +} + +/* + * pmap_zero_page zeros the specified (machine independent) + * page by mapping the page into virtual memory and using + * bzero to clear its contents, one machine dependent page + * at a time. + */ +void +pmap_zero_page(phys) + register vm_offset_t phys; +{ + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)\n", phys); +#endif + phys >>= PG_SHIFT; + ix = 0; + do { + clearseg(phys++); + } while (++ix != ns532pagesperpage); +} + +/* + * pmap_copy_page copies the specified (machine independent) + * page by mapping the page into virtual memory and using + * bcopy to copy the page, one machine dependent page at a + * time. + */ +void +pmap_copy_page(src, dst) + register vm_offset_t src, dst; +{ + register int ix; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)", src, dst); +#endif + src >>= PG_SHIFT; + dst >>= PG_SHIFT; + ix = 0; + do { + physcopyseg(src++, dst++); + } while (++ix != ns532pagesperpage); +} + + +/* + * 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 + /* + * If we are making a PT page pageable then all valid + * mappings must be gone from that page. Hence it should + * be all zeros and there is no need to clean it. + * Assumptions: + * - we are called with only one page at a time + * - PT pages have only one pv_table entry + */ + if (pmap == pmap_kernel() && pageable && sva + PAGE_SIZE == eva) { + register pv_entry_t pv; + register vm_offset_t pa; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE) + printf("pmap_pageable(%x, %x, %x, %x)\n", + pmap, sva, eva, pageable); +#endif + /*if (!pmap_pde_v(pmap_pde(pmap, sva))) + return;*/ + if(pmap_pte(pmap, sva) == 0) + return; + pa = pmap_pte_pa(pmap_pte(pmap, sva)); + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + pv = pa_to_pvh(pa); + /*if (!ispt(pv->pv_va)) + return;*/ +#ifdef DEBUG + if (pv->pv_va != sva || pv->pv_next) { + pg("pmap_pageable: bad PT page va %x next %x\n", + pv->pv_va, pv->pv_next); + return; + } +#endif + /* + * Mark it unmodified to avoid pageout + */ + pmap_clear_modify(pa); +#ifdef needsomethinglikethis + if (pmapdebug & PDB_PTPAGE) + pg("pmap_pageable: PT page %x(%x) unmodified\n", + sva, *(int *)pmap_pte(pmap, sva)); + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("pageable", sva); +#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)", pa); +#endif + pmap_changebit(pa, PG_M, FALSE); +} + +/* + * 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)", pa); +#endif + pmap_changebit(pa, PG_U, FALSE); +} + +/* + * 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 DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_U); + printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_U)); +} + +/* + * 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 DEBUG + if (pmapdebug & PDB_FOLLOW) { + boolean_t rv = pmap_testbit(pa, PG_M); + printf("pmap_is_modified(%x) -> %c\n", pa, "FT"[rv]); + return(rv); + } +#endif + return(pmap_testbit(pa, PG_M)); +} + +vm_offset_t +pmap_phys_address(ppn) + int ppn; +{ + return(ns532_ptob(ppn)); +} + +/* + * Miscellaneous support routines follow + */ + +ns532_protection_init() +{ + register int *kp, prot; + + kp = protection_codes; + for (prot = 0; prot < 8; prot++) { + switch (prot) { + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: + *kp++ = 0; + break; + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: + case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: + *kp++ = PG_RO; + break; + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: + case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: + *kp++ = PG_RW; + break; + } + } +} + +boolean_t +pmap_testbit(pa, bit) + register vm_offset_t pa; + int bit; +{ + register pv_entry_t pv; + register int *pte, ix; + int s; + + if (pa < vm_first_phys || pa >= vm_last_phys) + return(FALSE); + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Check saved info first + */ + if (pmap_attributes[pa_index(pa)] & bit) { + splx(s); + return(TRUE); + } + /* + * Not found, check current mappings returning + * immediately if found. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va); + ix = 0; + do { + if (*pte++ & bit) { + splx(s); + return(TRUE); + } + } while (++ix != ns532pagesperpage); + } + } + splx(s); + return(FALSE); +} + +pmap_changebit(pa, bit, setem) + register vm_offset_t pa; + int bit; + boolean_t setem; +{ + register pv_entry_t pv; + register int *pte, npte, ix; + vm_offset_t va; + int s; + boolean_t firstpage = TRUE; + +#ifdef DEBUG + if (pmapdebug & PDB_BITS) + printf("pmap_changebit(%x, %x, %s)", + pa, bit, setem ? "set" : "clear"); +#endif + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Clear saved attributes (modify, reference) + */ + if (!setem) + pmap_attributes[pa_index(pa)] &= ~bit; + + /* + * Loop over all current mappings setting/clearing as appropos + * If setting RO do we need to clear the VAC? + */ + + if (pv->pv_pmap != NULL) { +#ifdef DEBUG + int toflush = 0; +#endif + for (; pv; pv = pv->pv_next) { +#ifdef DEBUG + toflush |= (pv->pv_pmap == pmap_kernel()) ? 2 : 1; +#endif + va = pv->pv_va; + + /* + * XXX don't write protect pager mappings + */ + if (bit == PG_RO) { + extern vm_offset_t pager_sva, pager_eva; + + if (va >= pager_sva && va < pager_eva) + continue; + } + + pte = (int *) pmap_pte(pv->pv_pmap, va); + ix = 0; + do { + if (setem) + npte = *pte | bit; + else + npte = *pte & ~bit; + if (*pte != npte) { + *pte = npte; + /*TBIS(va);*/ + } + va += NS532_PAGE_SIZE; + pte++; + } while (++ix != ns532pagesperpage); + + if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap) + pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr); + } +#ifdef somethinglikethis + if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) { + if ((pmapvacflush & PVF_TOTAL) || toflush == 3) + DCIA(); + else if (toflush == 2) + DCIS(); + else + DCIU(); + } +#endif + } + splx(s); +} + +#ifdef DEBUG +pmap_pvdump(pa) + vm_offset_t pa; +{ + register pv_entry_t pv; + + printf("pa %x", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) { + printf(" -> pmap %x, va %x, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_flags); + pads(pv->pv_pmap); + } + printf(" "); +} + +#ifdef notyet +pmap_check_wiring(str, va) + char *str; + vm_offset_t va; +{ + vm_map_entry_t entry; + register int count, *pte; + + va = trunc_page(va); + if (!pmap_pde_v(pmap_pde(pmap_kernel(), va)) || + !pmap_pte_v(pmap_pte(pmap_kernel(), va))) + return; + + if (!vm_map_lookup_entry(pt_map, va, &entry)) { + pg("wired_check: entry for %x not found\n", va); + return; + } + count = 0; + for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++) + if (*pte) + count++; + if (entry->wired_count != count) + pg("*%s*: %x: w%d/a%d\n", + str, va, entry->wired_count, count); +} +#endif + +/* print address space of pmap*/ +pads(pm) + pmap_t pm; +{ + unsigned va, i, j; + struct pte *ptep; + int num=0; + +/* if(pm == pmap_kernel()) return; */ + for (i = 0; i < 1024; i++) + if(pm->pm_pdir[i].pd_v) + for (j = 0; j < 1024 ; j++) { + va = (i<<22)+(j<<12); + if (pm == pmap_kernel() && va < 0xfe000000) + continue; + if (pm != pmap_kernel() && va > UPT_MAX_ADDRESS) + continue; + ptep = pmap_pte(pm, va); + if(pmap_pte_v(ptep)) { + if (num % 4 == 0) printf (" "); + printf("%8x:%8x", va, *(int *)ptep); + if (++num %4 == 0) + printf ("\n"); + else + printf (" "); + } + } ; + if (num % 4 != 0) printf ("\n"); +} + +pmap_print (pmap_t pm, unsigned int start, unsigned int stop) +{ + unsigned va, i, j; + struct pte *ptep; + int num; + + printf ("pmap_print: pm_pdir = 0x%x\n", pm->pm_pdir); + printf (" map between 0x%x and 0x%x\n", start, stop); + for (i = 0; i < 1024; i++) + if (pm->pm_pdir != 0) { + if(pm->pm_pdir[i].pd_v && (start>>22) <= i + && (stop>>22) >= i) { + printf ("1st Level Entry 0x%x, 2nd PA = 0x%x000\n", + i, pm->pm_pdir[i].pd_pfnum); + num = 0; + for (j = 0; j < 1024 ; j++) { + va = (i<<22)+(j<<12); + ptep = pmap_pte(pm, va); + if(ptep->pg_v && start <= va && stop >= va) { + if (num % 5 == 0) printf (" "); + printf("%8x:%05x", va, ptep->pg_pfnum); + if (++num %5 == 0) + printf ("\n"); + else + printf (" "); + } + } ; + if (num % 5 != 0) printf ("\n"); + }; + }; + if (num % 5 != 0) printf ("\n"); +} +#endif diff --git a/sys/arch/pc532/pc532/process_machdep.c b/sys/arch/pc532/pc532/process_machdep.c new file mode 100644 index 00000000000..fecbcd2d193 --- /dev/null +++ b/sys/arch/pc532/pc532/process_machdep.c @@ -0,0 +1,179 @@ +/* $NetBSD: process_machdep.c,v 1.8 1995/09/26 20:16:32 phil Exp $ */ + +/* + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1993 Jan-Simon Pendry + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ + +/* Modified by Phil Nelson for the pc532 port. 1/12/94 */ + +/* + * 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> +#include <machine/frame.h> + +static inline struct reg * +process_regs(p) + struct proc *p; +{ + void *ptr; + + if ((p->p_flag & P_INMEM) == 0) + return (NULL); + + ptr = (char *)p->p_addr + ((char *)p->p_md.md_regs - (char *)USRSTACK); + return (ptr); +} + +int +process_read_regs(p, regs) + struct proc *p; + struct reg *regs; +{ + struct reg *pregs; + + pregs = process_regs(p); + if (pregs == NULL) + return (EIO); + + *regs = *pregs; + return (0); +} + +int +process_write_regs(p, regs) + struct proc *p; + struct reg *regs; +{ + struct reg *pregs; + + pregs = process_regs(p); + if (pregs == NULL) + return (EIO); + + if (((regs->r_psr ^ pregs->r_psr) & PSL_USERSTATIC) != 0) + return (EPERM); + + *pregs = *regs; + return (0); +} + +int +process_read_fpregs(p, regs) + struct proc *p; + struct fpreg *regs; +{ + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + + bcopy(&p->p_addr->u_pcb.pcb_fsr, regs, sizeof(*regs)); + return (0); +} + +int +process_write_fpregs(p, regs) + struct proc *p; + struct fpreg *regs; +{ + if ((p->p_flag & P_INMEM) == 0) + return (EIO); + + bcopy(regs, &p->p_addr->u_pcb.pcb_fsr, sizeof(*regs)); + return (0); +} + +int +process_sstep(p, sstep) + struct proc *p; + int sstep; +{ + struct reg *pregs; + + pregs = process_regs(p); + if (pregs == NULL) + return (EIO); + + if (sstep) + pregs->r_psr |= PSL_T; + else + pregs->r_psr &= ~PSL_T; + + return (0); +} + +int +process_set_pc(p, addr) + struct proc *p; + caddr_t addr; +{ + struct reg *pregs; + + pregs = process_regs(p); + if (pregs == NULL) + return (EIO); + + pregs->r_pc = (int)addr; + + return (0); +} diff --git a/sys/arch/pc532/pc532/random.s b/sys/arch/pc532/pc532/random.s new file mode 100644 index 00000000000..174d296cd04 --- /dev/null +++ b/sys/arch/pc532/pc532/random.s @@ -0,0 +1,75 @@ +/* $NetBSD: random.s,v 1.2 1994/10/26 08:25:17 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: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Here is a very good random number generator. This implementation is + * based on ``Two Fast Implementations of the "Minimal Standard" Random + * Number Generator'', David G. Carta, Communications of the ACM, Jan 1990, + * Vol 33 No 1. Do NOT modify this code unless you have a very thorough + * understanding of the algorithm. It's trickier than you think. If + * you do change it, make sure that its 10,000'th invocation returns + * 1043618065. + * + * Here is easier-to-decipher pseudocode: + * + * p = (16807*seed)<30:0> # e.g., the low 31 bits of the product + * q = (16807*seed)<62:31> # e.g., the high 31 bits starting at bit 32 + * if (p + q < 2^31) + * seed = p + q + * else + * seed = ((p + q) & (2^31 - 1)) + 1 + * return (seed); + * + * The result is in (0,2^31), e.g., it's always positive. + * + * written by Phil Nelson for ns32k. + */ + +#include <machine/asm.h> + + .data +randseed: + .long 1 + + .text +ENTRY(random) + enter [r2],0 + movzwd randseed(pc), r2 /* 1st 16 bit multiply */ + muld 16807, r2 /* result is positive */ + movd r2, r1 + bicd 0xffff0000, r2 /* save bottom 16 bits */ + ashd -16, r1 /* move top 16 to bottom */ + movzwd randseed+2(pc), r0 /* 2n 16 bit multiply */ + muld 16807, r0 + addd r0, r1 /* add to top 16 bits of first */ + movd r1, r0 /* save a copy in r0 */ + bicd 0xffff8000, r1 /* move "bottom" 15 to r2 */ + ashd 16, r1 + addd r2, r1 /* this is now p! */ + ashd -15, r0 /* this is now q! */ + addd r1, r0 /* q+r */ + bfc nocarry + subd 0x7fffffff, r0 + +nocarry: + movd r0, randseed(pc) + exit [r2] + ret 0 diff --git a/sys/arch/pc532/pc532/swapgeneric.c b/sys/arch/pc532/pc532/swapgeneric.c new file mode 100644 index 00000000000..33685357263 --- /dev/null +++ b/sys/arch/pc532/pc532/swapgeneric.c @@ -0,0 +1,199 @@ +/* $NetBSD: swapgeneric.c,v 1.1 1995/08/25 07:49:14 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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 5.5 (Berkeley) 5/9/91 + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/buf.h> +#include <sys/systm.h> +#include <sys/reboot.h> +#include <sys/device.h> +#include <sys/disklabel.h> + +#include "sd.h" +#include "cd.h" +#ifdef RAMD_SIZE +#define NRD 1 +#else +#define NRD 0 +#endif + +/* + * Generic configuration; all in one + */ +dev_t rootdev = NODEV; +dev_t argdev = NODEV; +dev_t dumpdev = NODEV; +int nswap; +struct swdevt swdevt[] = { + { NODEV, 1, 0 }, + { NODEV, 0, 0 }, +}; +long dumplo; +int dmmin, dmmax, dmtext; + +#if NSD > 0 +extern struct cfdriver sdcd; +#endif +#if NCD > 0 +extern struct cfdriver cdcd; +#endif +#if NRD > 0 +extern struct cfdriver rdcd; +#endif + +struct genericconf { + struct cfdriver *gc_driver; + char *gc_name; + dev_t gc_major; +} genericconf[] = { +#if NSD > 0 + { &sdcd, "sd", 0 }, +#endif +#if NCD > 0 + { &cdcd, "cd", 4 }, +#endif +#if NRD > 0 + { &rdcd, "rd", 3 }, +#endif + { 0 } +}; + +extern int ffs_mountroot(); +int (*mountroot)() = ffs_mountroot; + +setconf() +{ + register struct genericconf *gc; + int unit, swaponroot = 0; + + if (rootdev != NODEV) + goto doswap; + + if (genericconf[0].gc_driver == 0) + goto verybad; + + if (boothowto & RB_ASKNAME) { + char name[128]; +retry: + printf("root device? "); + gets(name); + for (gc = genericconf; gc->gc_driver; gc++) + if (gc->gc_name[0] == name[0] && + gc->gc_name[1] == name[1]) + goto gotit; + goto bad; +gotit: + if (name[3] == '*') { + name[3] = name[4]; + swaponroot++; + } + if (name[2] >= '0' && name[2] <= '7' && name[3] == 0) { + unit = name[2] - '0'; + goto found; + } + printf("bad/missing unit number\n"); +bad: + printf("use:\n"); + for (gc = genericconf; gc->gc_driver; gc++) + printf("\t%s%%d\n", gc->gc_name); + goto retry; + } + unit = 0; + for (gc = genericconf; gc->gc_driver; gc++) { + if (gc->gc_driver->cd_ndevs > unit && + gc->gc_driver->cd_devs[unit]) { + printf("root on %s0\n", gc->gc_name); + goto found; + } + } +verybad: + printf("no suitable root -- hit any key to reboot\n"); + printf("\n>"); + cngetc(); + cpu_reset(); + for (;;) ; + +found: + rootdev = makedev(gc->gc_major, unit * MAXPARTITIONS); +doswap: + swdevt[0].sw_dev = argdev = dumpdev = + makedev(major(rootdev), minor(rootdev) + 1); + /* swap size and dumplo set during autoconfigure */ + if (swaponroot) + rootdev = dumpdev; +} + +gets(cp) + char *cp; +{ + register char *lp; + register c; + + lp = cp; + for (;;) { + printf("%c", c = cngetc()&0177); + switch (c) { + case '\n': + case '\r': + *lp++ = '\0'; + printf("\r\n"); + return; + case '\b': + case '\177': + if (lp > cp) { + printf(" \b"); + lp--; + } + continue; + case '#': + lp--; + if (lp < cp) + lp = cp; + continue; + case '@': + case 'u'&037: + lp = cp; + printf("%c", '\n'); + continue; + default: + *lp++ = c; + } + } +} diff --git a/sys/arch/pc532/pc532/sys_machdep.c b/sys/arch/pc532/pc532/sys_machdep.c new file mode 100644 index 00000000000..0ae1c03dd9b --- /dev/null +++ b/sys/arch/pc532/pc532/sys_machdep.c @@ -0,0 +1,110 @@ +/* $NetBSD: sys_machdep.c,v 1.5 1995/09/26 20:16:34 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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 5.5 (Berkeley) 1/19/91 + */ + +#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, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + register struct vtrace_args /* { + syscallarg(int) request; + syscallarg(int) value; + } */ *uap = v; + 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 diff --git a/sys/arch/pc532/pc532/trap.c b/sys/arch/pc532/pc532/trap.c new file mode 100644 index 00000000000..d72213d7d48 --- /dev/null +++ b/sys/arch/pc532/pc532/trap.c @@ -0,0 +1,570 @@ +/* $NetBSD: trap.c,v 1.13 1995/06/09 06:00:10 phil Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the University of Utah, and William Jolitz. + * + * 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. + * + * @(#)trap.c 7.4 (Berkeley) 5/13/91 + */ + +/* + * 532 Trap and System call handling + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/acct.h> +#include <sys/kernel.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif +#include <sys/syscall.h> + +#include <vm/vm_param.h> +#include <vm/pmap.h> +#include <vm/vm_map.h> + +#include <machine/cpu.h> +#include <machine/trap.h> +#include <machine/psl.h> + + + +unsigned rcr2(); +extern short cpl; + +/* + * trap(frame): + * Exception, fault, and trap interface to BSD kernel. This + * common code is called from assembly language IDT gate entry + * routines that prepare a suitable stack frame, and restore this + * frame after the exception has been processed. Note that the + * effect is as if the arguments were passed call by reference. + */ +/*ARGSUSED*/ +trap(frame) + struct trapframe frame; +{ + register int i; + register struct proc *p = curproc; + struct timeval sticks; + int ucode, type, tear, msr; + + cnt.v_trap++; + + type = frame.tf_trapno; + tear = frame.tf_tear; + msr = frame.tf_msr; + + if (curpcb->pcb_onfault && frame.tf_trapno != T_ABT) { +copyfault: + frame.tf_pc = (int)curpcb->pcb_onfault; + return; + } + +#ifdef DDB + if (curpcb && curpcb->pcb_onfault) { + if (frame.tf_trapno == T_BPTFLT + || frame.tf_trapno == T_TRCTRAP) + if (kdb_trap (type, 0, &frame)) + return; + } +#endif + + if (curpcb == 0 || curproc == 0) goto we_re_toast; + + if ((frame.tf_psr & PSL_USER) == PSL_USER) { + type |= T_USER; +#ifdef notdef + sticks = p->p_stime; +#endif + p->p_md.md_regs = (int *)&(frame.tf_reg); + } + + ucode = 0; + + switch (type) { + + default: + we_re_toast: +#ifdef KDB + if (kdb_trap(&psl)) + return; +#endif +#ifdef DDB + if (kdb_trap (type, 0, &frame)) + return; +#endif + + printf("bad trap: type=%d, pc=0x%x, tear=0x%x, msr=0x%x\n", + type, frame.tf_pc, frame.tf_tear, frame.tf_msr); + panic("trap"); + /*NOTREACHED*/ + + case T_ABT: /* System level pagefault! */ + if (((msr & MSR_STT) == STT_SEQ_INS) + || ((msr & MSR_STT) == STT_NSQ_INS)) + { + printf ("System pagefault: pc=0x%x, tear=0x%x, msr=0x%x\n", + frame.tf_pc, frame.tf_tear, frame.tf_msr); + goto we_re_toast; + } + + /* fall into */ + case T_ABT | T_USER: /* User level pagefault! */ +/* if (type == (T_ABT | T_USER)) + printf ("pagefault: pc=0x%x, tear=0x%x, msr=0x%x\n", + frame.tf_pc, frame.tf_tear, frame.tf_msr); */ + { + register vm_offset_t va; + register struct vmspace *vm = p->p_vmspace; + register vm_map_t map; + int rv; + vm_prot_t ftype; + extern vm_map_t kernel_map; + unsigned nss,v; + + va = trunc_page((vm_offset_t)tear); + /* + * Avoid even looking at pde_v(va) for high va's. va's + * above VM_MAX_KERNEL_ADDRESS don't correspond to normal + * PDE's (half of them correspond to APDEpde and half to + * an unmapped kernel PDE). va's betweeen 0xFEC00000 and + * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's + * (XXX - why are only 3 initialized when 6 are required to + * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped + * kernel page table would give inconsistent PTD's. + * + * XXX - faulting in unmapped page tables wastes a page if + * va turns out to be invalid. + * + * XXX - should "kernel address space" cover the kernel page + * tables? Might have same problem with PDEpde as with + * APDEpde (or there may be no problem with APDEpde). + */ + if (va > 0xFEBFF000) { + v = KERN_FAILURE; /* becomes SIGBUS */ + goto nogo; + } + /* + * It is only a kernel address space fault iff: + * 1. (type & T_USER) == 0 and + * 2. pcb_onfault not set or + * 3. pcb_onfault set but supervisor space fault + * The last can occur during an exec() copyin where the + * argument space is lazy-allocated. + */ + if (type == T_ABT && va >= KERNBASE) + map = kernel_map; + else + map = &vm->vm_map; + if ((msr & MSR_DDT) == DDT_WRITE + || (msr & MSR_STT) == STT_RMW) + ftype = VM_PROT_READ | VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + +#ifdef DEBUG + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %x\n", va); + goto we_re_toast; + } +#endif + + nss = 0; + if ((caddr_t)va >= vm->vm_maxsaddr + && (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS + && map != kernel_map) { + nss = clrnd(btoc((unsigned)vm->vm_maxsaddr + + MAXSSIZ - (unsigned)va)); + if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { +/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/ + rv = KERN_FAILURE; + goto nogo; + } + } + + /* check if page table is mapped, if not, fault it first */ +#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v) + if (!pde_v(va)) { + v = trunc_page(vtopte(va)); + rv = vm_fault(map, v, ftype, FALSE); + if (rv != KERN_SUCCESS) goto nogo; + /* check if page table fault, increment wiring */ + vm_map_pageable(map, v, round_page(v+1), FALSE); + } else v=0; + rv = vm_fault(map, va, ftype, FALSE); + + if (rv == KERN_SUCCESS) { + /* + * XXX: continuation of rude stack hack + */ + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + va = trunc_page(vtopte(va)); + /* for page table, increment wiring + as long as not a page table fault as well */ + if (!v && map != kernel_map) + vm_map_pageable(map, va, round_page(va+1), FALSE); + if (type == T_ABT) + return; + goto out; + } +nogo: + if (type == T_ABT) { + if (curpcb->pcb_onfault) + goto copyfault; + printf("vm_fault(0x%x, 0x%x, 0x%x, 0) -> 0x%x\n", + map, va, ftype, rv); + printf(" type 0x%x, tear 0x%x msr 0x%x\n", + type, tear, msr); + goto we_re_toast; + } + i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + break; + } + + case T_UND | T_USER: /* undefined instruction */ + case T_ILL | T_USER: /* Illegal instruction! */ + ucode = type &~ T_USER; + i = SIGILL; + break; + + case T_NVI | T_USER: /* Non-vectored interrupt */ + case T_NMI | T_USER: /* non-maskable interrupt */ + case T_FLG | T_USER: /* flag instruction */ + goto we_re_toast; + + case T_NBE | T_USER: /* non-restartable bus error */ + ucode = type &~ T_USER; + i = SIGBUS; + break; + + case T_RBE | T_USER: /* restartable bus error */ + return; + + case T_SLAVE | T_USER: /* coprocessor trap */ + ucode = type &~ T_USER; +/* ucode = FPE_INTDIV_TRAP; */ + i = SIGFPE; + break; + + case T_DVZ | T_USER: /* divide by zero */ + ucode = type &~ T_USER; +/* ucode = FPE_INTDIV_TRAP; */ + i = SIGFPE; + break; + + case T_OVF | T_USER: /* integer overflow trap */ + ucode = type &~ T_USER; +/* ucode = FPE_INTOVF_TRAP; */ + i = SIGFPE; + break; + + + case T_TRC | T_USER: /* trace trap */ + case T_BPT | T_USER: /* breakpoint instruction */ + case T_DBG | T_USER: /* debug trap */ + frame.tf_psr &= ~PSL_P; + i = SIGTRAP; + break; + + case T_INTERRUPT | T_USER: /* Allow Process Switch */ +/* if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) { + addupc(frame.tf_eip, &p->p_stats->p_prof, 1); + p->p_flag &= ~SOWEUPC; + } */ + goto out; + + } /* End of switch */ + + trapsignal(p, i, ucode); + if ((type & T_USER) == 0) + return; +out: + while (i = CURSIG(p)) + postsig(i); + p->p_priority = p->p_usrpri; + if (want_resched) { + /* + * 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 setrunqueue ourselves but + * before we switch()'ed, we might not be on the queue + * indicated by our priority. + */ + (void) splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + (void) splnone(); + while (i = CURSIG(p)) + postsig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; + +#ifdef YO_WHAT + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.tf_eip, &p->p_stats->p_prof, + ticks * profscale); +#else +/* addupc(frame.tf_pc, &p->p_stats->p_prof, ticks); */ +#endif + } +#endif + } + curpriority = p->p_priority; +} + + +/* + * syscall(frame): + * System call request from POSIX system call gate interface to kernel. + * Like trap(), argument is call by reference. + */ +/*ARGSUSED*/ +syscall(frame) + volatile struct syscframe frame; +{ + + register caddr_t params; + register int i; + register struct sysent *callp; + register struct proc *p; + struct timeval sticks; + int error, opc, nsys; + int args[8], rval[2]; + int code; + + cnt.v_syscall++; + + /* is this a user? */ + if ((frame.sf_psr & PSL_USER) != PSL_USER) + panic("syscall - process not in user mode."); + + p = curproc; +#ifdef notdef + sticks = p->p_stime; +#endif + code = frame.sf_reg[REG_R0]; + p->p_md.md_regs = (int *) & (frame.sf_reg); + params = (caddr_t)frame.sf_usp + sizeof (int) ; + + callp = p->p_emul->e_sysent; + nsys = p->p_emul->e_nsysent; + + /* Set new return address and save old one. */ + opc = frame.sf_pc++; + + switch (code) { + case SYS_syscall: + code = fuword(params); + params += sizeof(int); + break; + + case SYS___syscall: + code = fuword(params + _QUAD_LOWWORD * sizeof(int)); + params += sizeof(quad_t); + break; + + default: + /* do nothing by default */ + break; + } + + /* Guard against bad sys call numbers! */ + if (code < 0 || code >= nsys) + callp += p->p_emul->e_nosys; /* indir (illegal) */ + else + callp += code; + + if ((i = callp->sy_argsize) && + (error = copyin(params, (caddr_t)args, (u_int)i))) { + frame.sf_reg[REG_R0] = error; + frame.sf_psr |= PSL_C; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, callp->sy_narg, i, args); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, i, &args); +#endif + goto done; + } +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, callp->sy_narg, i, args); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, i, &args); +#endif + rval[0] = 0; + rval[1] = 0; + error = (*callp->sy_call)(p, args, rval); + if (error == ERESTART) + frame.sf_pc = opc; + else if (error != EJUSTRETURN) { + if (error) { + frame.sf_reg[REG_R0] = error; + frame.sf_psr |= PSL_C; + } else { + frame.sf_reg[REG_R0] = rval[0]; + frame.sf_reg[REG_R1] = rval[1]; + frame.sf_psr &= ~PSL_C; + } + } + /* else if (error == EJUSTRETURN) */ + /* nothing to do */ +done: + /* + * Reinitialize proc pointer `p' as it may be different + * if this is a child returning from fork syscall. + */ + p = curproc; + while (i = CURSIG(p)) + postsig(i); + p->p_priority = p->p_usrpri; + if (want_resched) { + /* + * 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 setrunqeue ourselves but before + * we switch()'ed, we might not be on the queue indicated by + * our priority. + */ + (void) splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + (void) splnone(); + while (i = CURSIG(p)) + postsig(i); + } + if (p->p_stats->p_prof.pr_scale) { + int ticks; +#ifdef YO_WHAT + struct timeval *tv = &p->p_stime; + + ticks = ((tv->tv_sec - syst.tv_sec) * 1000 + + (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000); + if (ticks) { +#ifdef PROFTIMER + extern int profscale; + addupc(frame.sf_pc, &p->p_stats->p_prof, + ticks * profscale); +#else +/* addupc(frame.sf_pc, &p->p_stats->p_prof, ticks); */ +#endif + } +#endif + } + curpriority = p->p_priority; +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, error, rval[0]); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif + +} + +/* For the child, do the stuff after mi_swtch() in syscall so + low_level_fork does not have to rethread the kernel stack. */ +void +ll_fork_sig() +{ + register struct proc *p = curproc; + int i; + + (void) splnone(); + while (i = CURSIG(p)) + postsig(i); +} + + +/* #define dbg_user */ +/* Other stuff.... */ +int +check_user_write ( u_long addr, u_long size) +{ + int rv; + vm_offset_t va; + +#ifdef dbg_user +printf ("ck_ur_wr: addr=0x%x, size=0x%x", addr, size); +#endif + /* check for all possible places! */ + va = trunc_page((vm_offset_t) addr); + if (va > VM_MAXUSER_ADDRESS) return (1); + + while ((u_long)va < (addr + size)) { + /* check for copy on write access. */ +#ifdef dbg_user +printf (" (0x%x:%d)", va, vtopte(va)->pg_prot); +#endif + if (!(vtopte(va)->pg_v) || vtopte(va)->pg_prot != 3 ) { +#ifdef dbg_user +printf (" fault"); +#endif + rv = vm_fault(&curproc->p_vmspace->vm_map, va, + VM_PROT_READ | VM_PROT_WRITE, FALSE); + if (rv != KERN_SUCCESS) +#ifdef dbg_user +{ printf (" bad\n"); +#endif + return(1); +#ifdef dbg_user +} +#endif + } + va += NBPG; + } +#ifdef dbg_user +printf ("\n"); +#endif + + return (0); +} diff --git a/sys/arch/pc532/pc532/umprintf.c b/sys/arch/pc532/pc532/umprintf.c new file mode 100644 index 00000000000..21d4d2cb108 --- /dev/null +++ b/sys/arch/pc532/pc532/umprintf.c @@ -0,0 +1,105 @@ +/* $NetBSD: umprintf.c,v 1.3 1994/10/26 08:25:20 cgd Exp $ */ + +/*- + * Copyright (c) 1986, 1988, 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. + * + * hacked out from .. + * @(#)subr_prf.c 7.30 (Berkeley) 6/29/91 + */ + +#include <stdarg.h> +static char *ksprintn __P((u_long num, int base, int *len)); + +void +umprintf(char *fmt,...) +{ + va_list ap; + char *p; + int tmp; + int base; + unsigned long ul; + char ch; + + va_start (ap,fmt); + + for (;;) { + while ((ch = *fmt++) != '%') { + if (ch == '\0') + return; + scncnputc(0, ch); + } + ch = *fmt++; + switch (ch) { + case 'd': + ul = va_arg(ap, u_long); + base = 10; + goto number; + case 'x': + ul = va_arg(ap, u_long); + base = 16; +number: p = ksprintn(ul, base, &tmp); + while (ch = *p--) + scncnputc(0,ch); + break; + default: + scncnputc(0,ch); + } + } +} + +/* + * Put a number (base <= 16) in a buffer in reverse order; return an + * optional length and a pointer to the NULL terminated (preceded?) + * buffer. + */ +static char * +ksprintn(ul, base, lenp) + register u_long ul; + register int base, *lenp; +{ /* A long in base 8, plus NULL. */ + static char buf[sizeof(long) * NBBY / 3 + 2]; + register char *p; + int d; + + p = buf; + *p='\0'; + do { + d = ul % base; + if (d < 10) + *++p = '0' + d; + else + *++p = 'a' + d - 10; + } while (ul /= base); + if (lenp) + *lenp = p - buf; + return (p); +} diff --git a/sys/arch/pc532/pc532/vm_machdep.c b/sys/arch/pc532/pc532/vm_machdep.c new file mode 100644 index 00000000000..b4a9fc90248 --- /dev/null +++ b/sys/arch/pc532/pc532/vm_machdep.c @@ -0,0 +1,346 @@ +/* $NetBSD: vm_machdep.c,v 1.11 1995/08/29 22:37:54 phil Exp $ */ + +/*- + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * 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 William Jolitz. + * + * 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. + * + * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/buf.h> +#include <sys/user.h> +#include <sys/core.h> +#include <sys/exec.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> + +#include <machine/cpu.h> + +/* + * 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; +{ + struct user *up = p2->p_addr; + int foo, offset, addr, i; + + /* + * Copy pcb from proc p1 to p2. + * _low_level_init will copy the kernel stack as cheeply as + * possible. + */ + p2->p_addr->u_pcb = p1->p_addr->u_pcb; + p2->p_addr->u_pcb.pcb_onstack = + (struct on_stack *) p2->p_addr + USPACE + - sizeof (struct on_stack); + + /* + * Wire top of address space of child to it's kstack. + * First, fault in a page of pte's to map it. + */ + addr = trunc_page((u_int)vtopte(USRSTACK)); + vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+USPACE, FALSE); + for (i=0; i < UPAGES; i++) + pmap_enter(&p2->p_vmspace->vm_pmap, USRSTACK+i*NBPG, + pmap_extract(pmap_kernel(), ((int)p2->p_addr)+i*NBPG), + VM_PROT_READ, TRUE); + + pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb); + + /* + * Low_level_fork returns twice! First with a 0 in the + * parent space and Second with a 1 in the child. + */ + + return (low_level_fork(up)); +} + + +#ifdef notyet + +/* + * cpu_exit is called as the last action during exit. + * + * We change to an inactive address space and a "safe" stack, + * passing thru an argument to the new stack. Now, safely isolated + * from the resources we're shedding, we release the address space + * and any remaining machine-dependent resources, including the + * memory for the user structure and kernel stack. + * + * Next, we assign a dummy context to be written over by swtch, + * calling it to send this process off to oblivion. + * [The nullpcb allows us to minimize cost in swtch() by not having + * a special case]. + */ +struct proc *swtch_to_inactive(); + +void +cpu_exit(p) + register struct proc *p; +{ + static struct pcb nullpcb; /* pcb to overwrite on last swtch */ + + /* free cporcessor (if we have it) */ + if( p == npxproc) npxproc =0; + + /* move to inactive space and stack, passing arg accross */ + p = swtch_to_inactive(p); + + /* drop per-process resources */ + vmspace_free(p->p_vmspace); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); + + p->p_addr = (struct user *) &nullpcb; + splstatclock(); + cpu_switch(); + /* NOTREACHED */ +} +#else +void +cpu_exit(p) + register struct proc *p; +{ + + splstatclock(); + cpu_switch(); + /* Not reached. */ + panic ("cpu_exit! swtch returned!"); +} + +void +cpu_wait(p) + struct proc *p; +{ + + /* drop per-process resources */ + vmspace_free(p->p_vmspace); + kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES)); +} +#endif + + +/* + * Dump the machine specific segment at the start of a core dump. + */ +int +cpu_coredump(p, vp, cred, chdr) + struct proc *p; + struct vnode *vp; + struct ucred *cred; + struct core *chdr; +{ + int error; + struct { + struct reg regs; + struct fpreg fpregs; + } cpustate; + struct coreseg cseg; + + CORE_SETMAGIC(*chdr, COREMAGIC, MID_NS32532, 0); + chdr->c_hdrsize = ALIGN(sizeof(*chdr)); + chdr->c_seghdrsize = ALIGN(sizeof(cseg)); + chdr->c_cpusize = sizeof(cpustate); + cpustate.regs = *((struct reg *)p->p_md.md_regs); + cpustate.fpregs = *((struct fpreg *)&p->p_addr->u_pcb.pcb_fsr); + + CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_NS32532, CORE_CPU); + cseg.c_addr = 0; + cseg.c_size = chdr->c_cpusize; + + error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize, + (off_t)chdr->c_hdrsize, UIO_SYSSPACE, + IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); + if (error) + return error; + + error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cpustate, sizeof(cpustate), + (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE, + IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); + + if (!error) + chdr->c_nseg++; + + return error; +} + + +/* + * Set a red zone in the kernel stack after the u. area. + */ +setredzone(pte, vaddr) + u_short *pte; + caddr_t vaddr; +{ +/* eventually do this by setting up an expand-down stack segment + for ss0: selector, allowing stack access down to top of u. + this means though that protection violations need to be handled + thru a double fault exception that must do an integral task + switch to a known good context, within which a dump can be + taken. a sensible scheme might be to save the initial context + used by sched (that has physical memory mapped 1:1 at bottom) + and take the dump while still in mapped mode */ +} + +/* + * 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. + */ +pagemove(from, to, size) + register caddr_t from, to; + int size; +{ + register struct pte *fpte, *tpte; + + if (size % CLBYTES) + panic("pagemove"); + fpte = kvtopte(from); + tpte = kvtopte(to); + while (size > 0) { + *tpte++ = *fpte; + *(int *)fpte++ = 0; + from += NBPG; + to += NBPG; + size -= NBPG; + } + tlbflush(); +} + +/* + * Convert kernel VA to physical address + */ +kvtop(addr) + register caddr_t addr; +{ + vm_offset_t va; + va = pmap_extract(pmap_kernel(), (vm_offset_t)addr); + if (va == 0) + panic("kvtop: zero page frame"); + return((int)va); +} + +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 useriomap + * (a name with only slightly more meaning than "kernelmap") + */ +vmapbuf(bp) + register struct buf *bp; +{ + register int npf; + register caddr_t addr; + register long flags = bp->b_flags; + struct proc *p; + int off; + vm_offset_t kva; + register vm_offset_t pa; + + if ((flags & B_PHYS) == 0) + panic("vmapbuf"); + addr = bp->b_saveaddr = bp->b_un.b_addr; + off = (int)addr & PGOFSET; + p = bp->b_proc; + npf = btoc(round_page(bp->b_bcount + off)); + kva = kmem_alloc_wait(phys_map, ctob(npf)); + bp->b_un.b_addr = (caddr_t) (kva + off); + while (npf--) { + pa = pmap_extract(&p->p_vmspace->vm_pmap, (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. + */ +vunmapbuf(bp) + register struct buf *bp; +{ + register int npf; + register caddr_t addr = bp->b_un.b_addr; + vm_offset_t kva; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET))); + kva = (vm_offset_t)((int)addr & ~PGOFSET); + kmem_free_wakeup(phys_map, kva, ctob(npf)); + bp->b_un.b_addr = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} + +/* + * (Force reset the processor by invalidating the entire address space!) + * Well, lets just hang! + */ +cpu_reset() +{ + splhigh(); + while (1); +} diff --git a/sys/arch/pc532/stand/Makefile b/sys/arch/pc532/stand/Makefile new file mode 100644 index 00000000000..0dd6ee9ecf3 --- /dev/null +++ b/sys/arch/pc532/stand/Makefile @@ -0,0 +1,98 @@ +# $NetBSD: Makefile,v 1.7.2.1 1995/10/17 00:19:13 phil Exp $ + +# @(#)Makefile 8.1 (Berkeley) 6/10/93 + +#DESTDIR= +STANDDIR=${DESTDIR}/stand +# load at 0x400000 - 18 * 1024 - 0x10000 +# that way the boot code will be at the correct +# address if the floppy image is started from memory +# NOTE: alloc() function takes memory after _end +RELOC= 3EB800 + +CONS= -DSCNCONSOLE +DEFS= -DSTANDALONE ${CONS} +CFLAGS= -O ${INCPATH} ${DEFS} -fwritable-strings + +SRCS= cons.c devopen.c scn.c scsi_low.c scsi_hi.c \ + conf.c prf.c tgets.c machdep.c sd.c rd.c filesystem.c + +S= ${.CURDIR}/../../.. +SAREL= +KERNREL= + +.PATH: ${S}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} +.PATH: ${S}/stand ${S}/lib/libsa + +INCPATH=-I${.CURDIR} -I${.CURDIR}/../.. -I${S} -I${S}/lib/libsa + +### find out what to use for libs +.include "../../../lib/libkern/Makefile.inc" +LIBKERN= ${KERNLIB} + +NO_NET= +.include "../../../lib/libsa/Makefile.inc" +LIBSA= ${SALIB} + +#LIBS= ${LIBSA} ${.OBJDIR}/libdrive.a \ +# ${LIBKERN} ${LIBSA} ${LIBKERN} +LIBS= ${LIBSA} ${.OBJDIR}/libdrive.a \ + ${LIBKERN} ${LIBSA} + +BOOTS= boot zboot.o +ALL= ${BOOTS} + +all: ${ALL} + +${BOOTS}: ${LIBS} + +OBJS= ${SRCS:N*.h:R:S/$/.o/g} +${.OBJDIR}/libdrive.a: ${OBJS} + ar crv $@ $? + ranlib $@ + +# depend on DEFS + +devopen.o machdep.o srt0.o: Makefile +cons.o: Makefile + +# startups + +srt0.o: ${.CURDIR}/srt0.s + cpp ${INCPATH} ${DEFS} ${.CURDIR}/srt0.s | as -o srt0.o + +# new boot +boot: boot.o srt0.o ${LIBS} + ld -z -T ${RELOC} -e begin srt0.o boot.o ${LIBS} -o $@ + @size boot + +zboot.o: inflate.o + ld -r srt0.o inflate.o $(LIBS) -o zboot.o + +# new boot user mode test +TESTBOOT= boot.o test.o $(SC) ${LIBS} +# objects from regular libc; +SC= cerror.o syscall.o malloc.o sbrk.o getpagesize.o +testboot: $(TESTBOOT) + ld -o testboot /usr/lib/crt0.o $(TESTBOOT) ${LIBS} -o $@ + +$(SC): /usr/lib/libc.a + ar x /usr/lib/libc.a $(SC) + +# utilities + +install: ${ALL} + cp ${ALL} ${DESTDIR}/usr/mdec + +.include <bsd.dep.mk> +.include <bsd.obj.mk> +.include <bsd.subdir.mk> + +FRC: + +# clean ... + +clean:: + rm -f ${ALL} ${.OBJDIR}/libdrive.a ${OBJS} boot.o srt0.o inflate.o + +cleandir: clean diff --git a/sys/arch/pc532/stand/README b/sys/arch/pc532/stand/README new file mode 100644 index 00000000000..a835dde57e6 --- /dev/null +++ b/sys/arch/pc532/stand/README @@ -0,0 +1,26 @@ +$NetBSD: README,v 1.2 1994/10/26 08:25:43 cgd Exp $ + +pc532 stand/boot +Phil Budne <phil@ultimate.com> 5/19/1994 + +Based on hp300 stand/pboot.c, uses libso + (lacks the fun "spinner" that the i386 boot program displays) + +May be debugged under usermode (using "testboot" image) + +Passes howto, bootdev, & symbols to booted program; + r3/ magic value 0xc1e86394 (3253232532) + r4/ end of symbols + r5/ physical load address (typ 0x2000) + r6/ bootdev + r7/ howto (flags: RB_{ASKNAME,KDB,SINGLE,HALT}) + +All files have Berzerkley style copyrights, except libso files from +Jordan Hubbard's "libso" (which in turn come from Bruce Culbertson's +ROM monitor); scsi_hi.c scsi_lo.c so.h + +TODO: + +check if kernel will overlap boot program! +pick up initial how and boot dev + diff --git a/sys/arch/pc532/stand/boot.c b/sys/arch/pc532/stand/boot.c new file mode 100644 index 00000000000..6301d6f1cd6 --- /dev/null +++ b/sys/arch/pc532/stand/boot.c @@ -0,0 +1,279 @@ +/* $NetBSD: boot.c,v 1.4.2.1 1995/10/17 00:19:15 phil Exp $ */ + +/*- + * Copyright (c) 1982, 1986, 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. + * + * @(#)boot.c 8.1 (Berkeley) 6/10/93 + */ + +#ifndef lint +static char rcsid[] = "$NetBSD: boot.c,v 1.4.2.1 1995/10/17 00:19:15 phil Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/reboot.h> +#include <a.out.h> +#include "stand.h" +#include "samachdep.h" + +/* + * Boot program... bits in `howto' determine whether boot stops to + * ask for system name. Boot device is derived from ROM provided + * information. + */ + +extern unsigned opendev; +extern int noconsole; +extern int testing; + +char *ssym, *esym; + +char *name; +char *names[] = { + "/netbsd", "/onetbsd", "/netbsd.old", +}; +#define NUMNAMES (sizeof(names)/sizeof(char *)) +#define LOADADDR ((char *)0x2000) + +static int bdev, bctlr, bunit, bpart; + +main() +{ + int currname = 0; + int io; + + cninit(); + scsiinit(); + + printf("\n>> NetBSD BOOT pc532 [$Revision: 1.1 $]\n"); + + bdev = B_TYPE(bootdev); + bctlr = B_CONTROLLER(bootdev); + bunit = B_UNIT(bootdev); + bpart = B_PARTITION(bootdev); + + for (;;) { + name = names[currname++]; + if (currname == NUMNAMES) + currname = 0; + + if (!noconsole) { + howto = 0; + getbootdev(&howto); + } + else + printf(": %s\n", name); + + io = open(name, 0); + + if (io >= 0) { + copyunix(howto, opendev, io); + close(io); + } + else + printf("boot: %s\n", strerror(errno)); + } +} + +/*ARGSUSED*/ +copyunix(howto, devtype, io) + register int howto; /* boot flags */ + register u_int devtype; /* boot device */ + register int io; +{ + struct exec x; + int i; + register char *load; /* load addr for unix */ + register char *addr; + char *file; + int dev, ctlr, unit, part; + + /* XXX use devtype? */ + dev = B_TYPE(opendev); + ctlr = B_CONTROLLER(opendev); + unit = B_UNIT(opendev); + part = B_PARTITION(opendev); + /* get the file name part of name */ + devparse(name, &i, &i, &i, &i, &i, &file); + + i = read(io, (char *)&x, sizeof(x)); + if (i != sizeof(x) || N_BADMAG(x)) { + printf("Bad format\n"); + return; + } + addr = LOADADDR; /* Always load at LOADADDR */ + load = (char *)(x.a_entry & 0x00ffff00); /* XXX make less magical? */ + printf("Booting %s%d%c:%s @ 0x%x\n", + devsw[dev].dv_name, unit + (8*ctlr), 'a' + part, file, load); + + if (testing) { + load = addr = alloc(2*1024*1024); /* XXX stat the file? */ + if (!addr) { + printf("alloc failed\n"); + exit(1); + } + } + + /* Text */ + printf("%d", x.a_text); + if (N_GETMAGIC(x) == ZMAGIC && lseek(io, 0, SEEK_SET) == -1) + goto shread; + if (read(io, addr, x.a_text) != x.a_text) + goto shread; + addr += x.a_text; + if (N_GETMAGIC(x) == NMAGIC) + while ((int)addr & CLOFSET) + *addr++ = 0; + /* Data */ + printf("+%d", x.a_data); + if (read(io, addr, x.a_data) != x.a_data) + goto shread; + addr += x.a_data; + + /* Bss */ + printf("+%d", x.a_bss); + bzero( addr, x.a_bss ); + addr += x.a_bss; + + /* Symbols */ + ssym = load + (addr - LOADADDR); + bcopy(&x.a_syms, addr, sizeof(x.a_syms)); + addr += sizeof(x.a_syms); + printf(" [%d+", x.a_syms); + if (x.a_syms && read(io, addr, x.a_syms) != x.a_syms) + goto shread; + addr += x.a_syms; + + /* read size of string table */ + i = 0; + if (x.a_syms && read(io, &i, sizeof(int)) != sizeof(int)) + goto shread; + + /* read strings */ + printf("%d]", i); + bcopy(&i, addr, sizeof(int)); + if (i) { + i -= sizeof(int); + addr += sizeof(int); + if (read(io, addr, i) != i) + goto shread; + addr += i; + } + + if (load != LOADADDR) { + bcopy(LOADADDR, load, addr - LOADADDR); + addr = load + (addr - LOADADDR); + } +#define round_to_size(x,t) \ + (((int)(x) + sizeof(t) - 1) & ~(sizeof(t) - 1)) + esym = (char *)round_to_size(addr - load,int); +#undef round_to_size + + /* and note the end address of all this */ + printf(" total=0x%x", addr); + + x.a_entry &= 0xffffff; + printf(" start 0x%x\n", x.a_entry); + +#ifdef DEBUG + printf("ssym=0x%x esym=0x%x\n", ssym, esym); + printf("\n\nReturn to boot...\n"); + getchar(); +#endif + + if (!testing) { +#ifdef __GNUC__ + /* do NOT change order!! + * the following are passed as args, and are in registers + * clobbered by the last two movd's!!! + */ + asm(" movd %0,r5" : : "g" (load)); + asm(" movd %0,r6" : : "g" (devtype)); + asm(" movd %0,r7" : : "g" (howto)); + + /* magic value for locore.s to look for (3253232532) */ + asm(" movd %0,r3" : : "i" (0xc1e86394)); + asm(" movd %0,r4" : : "g" (esym)); +#endif /* __GNUC__ */ + (*((int (*)()) x.a_entry))(); + } + return; +shread: + printf("Short read\n"); + return; +} + +char line[100]; + +getbootdev(howto) + int *howto; +{ + char c, *ptr = line; + + printf("Boot: [[[%s%d%c:]%s][-abdrs]] :- ", + devsw[bdev].dv_name, bunit + (8 * bctlr), 'a'+bpart, name); + + if (tgets(line)) { + while (c = *ptr) { + while (c == ' ') + c = *++ptr; + if (!c) + return; + if (c == '-') + while ((c = *++ptr) && c != ' ') + switch (c) { + case 'a': + *howto |= RB_ASKNAME; + continue; + case 'b': + *howto |= RB_HALT; + continue; + case 'd': + *howto |= RB_KDB; + continue; + case 'r': + *howto |= RB_DFLTROOT; + continue; + case 's': + *howto |= RB_SINGLE; + continue; + } + else { + name = ptr; + while ((c = *++ptr) && c != ' '); + if (c) + *ptr++ = 0; + } + } + } else + printf("\n"); +} diff --git a/sys/arch/pc532/stand/conf.c b/sys/arch/pc532/stand/conf.c new file mode 100644 index 00000000000..6f4a50da0a8 --- /dev/null +++ b/sys/arch/pc532/stand/conf.c @@ -0,0 +1,59 @@ +/* $NetBSD: conf.c,v 1.3 1995/08/29 21:55:42 phil Exp $ */ + +/* + * Copyright (c) 1982, 1986, 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. + * + * @(#)conf.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include "stand.h" + +int rdstrategy __P((void *devdata, int rw, + daddr_t blk, u_int size, char *buf, u_int *rsize)); +int rdopen __P((struct open_file *f, ...)); + +int sdstrategy __P((void *devdata, int rw, + daddr_t blk, u_int size, char *buf, u_int *rsize)); +int sdopen __P((struct open_file *f, ...)); + +#define sdioctl noioctl +#define rdioctl noioctl + +struct devsw devsw[] = { + { "sd", sdstrategy, sdopen, nullsys, sdioctl }, /*0*/ + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { "rd", rdstrategy, rdopen, nullsys, rdioctl }, /*3*/ +}; + +int ndevs = (sizeof(devsw)/sizeof(devsw[0])); diff --git a/sys/arch/pc532/stand/cons.c b/sys/arch/pc532/stand/cons.c new file mode 100644 index 00000000000..307a58539c5 --- /dev/null +++ b/sys/arch/pc532/stand/cons.c @@ -0,0 +1,93 @@ +/* $NetBSD: cons.c,v 1.3 1995/08/29 21:55:43 phil Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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: cons.c 1.7 92/02/28 + * + * @(#)cons.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <dev/cons.h> +#include "samachdep.h" + +#ifdef SCNCONSOLE +int scnprobe(), scninit(), scngetchar(), scnputchar(); +#endif + +struct consdev constab[] = { +#ifdef SCNCONSOLE + { scnprobe, scninit, scngetchar, scnputchar }, +#endif + { 0 }, +}; + +struct consdev *cn_tab; +int noconsole; + +cninit() +{ + register struct consdev *cp; + + cn_tab = NULL; + noconsole = 1; + for (cp = constab; cp->cn_probe; cp++) { + (*cp->cn_probe)(cp); + if (cp->cn_pri > CN_DEAD && + (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri)) + cn_tab = cp; + } + if (cn_tab) { + (*cn_tab->cn_init)(cn_tab); + noconsole = 0; + } +} + +cngetc() +{ + if (cn_tab) + return((*cn_tab->cn_getc)(cn_tab->cn_dev)); + return(0); +} + +cnputc(c) + int c; +{ + if (cn_tab) + (*cn_tab->cn_putc)(cn_tab->cn_dev, c); +} diff --git a/sys/arch/pc532/stand/devopen.c b/sys/arch/pc532/stand/devopen.c new file mode 100644 index 00000000000..4ddac7c398a --- /dev/null +++ b/sys/arch/pc532/stand/devopen.c @@ -0,0 +1,203 @@ +/* $NetBSD: devopen.c,v 1.4 1995/08/29 21:55:44 phil Exp $ */ + +/*- + * Copyright (c) 1993 John Brezak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/reboot.h> + +#include "stand.h" +#include "samachdep.h" + +u_int opendev; + +#define ispart(c) ((c) >= 'a' && (c) <= 'h') + +atoi(char *cp) +{ + int val = 0; + while(isdigit(*cp)) + val = val * 10 + (*cp++ - '0'); + return(val); +} + +usage() +{ + printf("\ +Usage: device(adaptor, controller, drive, partition)file\n\ + <device><unit><partitonletter>:file\n\ +"); +} + +devlookup(char *d, int len) +{ + struct devsw *dp = devsw; + int i; + + for (i = 0; i < ndevs; i++, dp++) + if (dp->dv_name && strncmp(dp->dv_name, d, len) == 0) + return(i); + + printf("No such device - Configured devices are:\n"); + for (dp = devsw, i = 0; i < ndevs; i++, dp++) + if (dp->dv_name) + printf(" %s", dp->dv_name); + printf("\n"); + errno = ENODEV; + return(-1); +} + +/* + * Parse a device spec in one of two forms. + * + * dev(adapt, ctlr, unit, part)file + * [A-Za-z]*[0-9]*[A-Za-z]:file + * dev unit part + */ +devparse(char *fname, int *dev, int *adapt, int *ctlr, int *unit, int *part, char **file) +{ + int *argp, i; + char *s, *args[4]; + + /* get device name and make lower case */ + for (s = fname; *s && *s != '/' && *s != ':' && *s != '('; s++) + if (isupper(*s)) *s = tolower(*s); + + /* first form */ + if (*s == '(') { + /* lookup device and get index */ + if ((*dev = devlookup(fname, s - fname)) < 0) + goto baddev; + + /* tokenize device ident */ + args[0] = ++s; + for (i = 1; *s && *s != ')'; s++) { + if (i > 3) + goto baddev; + if (*s == ',') + args[i++] = ++s; + } + switch(i) { + case 4: + *adapt = atoi(args[0]); + *ctlr = atoi(args[1]); + *unit = atoi(args[2]); + *part = atoi(args[3]); + break; + case 3: + *ctlr = atoi(args[0]); + *unit = atoi(args[1]); + *part = atoi(args[2]); + break; + case 2: + *unit = atoi(args[0]); + *part = atoi(args[1]); + break; + case 1: + *part = atoi(args[0]); + break; + case 0: + break; + } + *file = ++s; + } + + /* second form */ + else if (*s == ':') { + /* isolate device */ + for (s = fname; *s != ':' && !isdigit(*s); s++); + + /* lookup device and get index */ + if ((*dev = devlookup(fname, s - fname)) < 0) + goto baddev; + + /* isolate unit */ + if ((*unit = atoi(s)) > ((1 << (sizeof(char) * 8)) - 1)) + goto bad; + for (; isdigit(*s); s++); + + /* translate partition */ + if (!ispart(*s)) + goto bad; + + *part = *s++ - 'a'; + if (*s != ':') + goto bad; + *file = ++s; + } + + /* no device present */ + else + *file = fname; + + /* return the remaining unparsed part as the file to boot */ + return(0); + + bad: + usage(); + + baddev: + return(-1); +} + + +devopen(f, fname, file) + struct open_file *f; + const char *fname; + char **file; +{ + int n, error; + int dev, ctlr, unit, part; + int adapt = 0; /* XXX not used on HP */ + struct devsw *dp = &devsw[0]; + + dev = B_TYPE(bootdev); + ctlr = B_CONTROLLER(bootdev); + unit = B_UNIT(bootdev); + part = B_PARTITION(bootdev); + + if (error = devparse(fname, &dev, &adapt, &ctlr, &unit, &part, file)) + return(error); + + dp = &devsw[dev]; + + if (!dp->dv_open) + return(ENODEV); + + opendev = MAKEBOOTDEV(dev, adapt, ctlr, unit, part); + + f->f_dev = dp; + + if ((error = (*dp->dv_open)(f, ctlr, unit, part)) == 0) + return(0); + + printf("%s(%d,%d,%d,%d): %s\n", devsw[dev].dv_name, + adapt, ctlr, unit, part, strerror(error)); + + return(error); +} diff --git a/sys/arch/pc532/stand/filesystem.c b/sys/arch/pc532/stand/filesystem.c new file mode 100644 index 00000000000..3d0ff77b8d1 --- /dev/null +++ b/sys/arch/pc532/stand/filesystem.c @@ -0,0 +1,40 @@ +/* $NetBSD: filesystem.c,v 1.2 1994/10/26 08:25:48 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. + */ + +#include <stand.h> +#include <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/pc532/stand/inflate.c b/sys/arch/pc532/stand/inflate.c new file mode 100644 index 00000000000..3ebe08c086a --- /dev/null +++ b/sys/arch/pc532/stand/inflate.c @@ -0,0 +1,1433 @@ +/* + * Copyright (c) 1995 Matthias Pfaller. + * + * Most of this code is from the unzip512 distribution and was put + * in the public domain by Mark Adler 1994. + * + * 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 Matthias Pfaller. + * 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. + * + * $Id: inflate.c,v 1.1 1995/10/18 08:51:23 deraadt Exp $ + */ + +#include <sys/param.h> +#include <sys/reboot.h> +#include <a.out.h> +#include "stand.h" +#include "samachdep.h" + +#ifndef EOF +#define EOF -1 +#endif +typedef unsigned char uch; /* code assumes unsigned bytes; these type- */ +typedef unsigned short ush; /* defs replace byte/UWORD/ULONG (which are */ +typedef unsigned long ulg; /* predefined on some systems) & match zip */ + +extern int qflag; +extern uch slide[]; +extern ulg crc_32_tab[]; + +#define NEXTBYTE nextbyte() +#define FLUSH(n) flush(n) +#define WSIZE 0x8000 +#define memzero(dest, len) bzero(dest, len) + +/* Function prototypes */ +#ifndef OF +# ifdef __STDC__ +# define OF(a) a +# else /* !__STDC__ */ +# define OF(a) () +# endif /* ?__STDC__ */ +#endif + +/* From: funzip.c -- put in the public domain by Mark Adler */ + +#define VERSION "3.83 of 28 August 1994" + +/* + + All funzip does is take a zip file from stdin and decompress the + first entry to stdout. The entry has to be either deflated or + stored. If the entry is encrypted, then the decryption password + must be supplied on the command line as the first argument. + + funzip needs to be linked with inflate.o and crypt.o compiled from + the unzip source. If decryption is desired, the full version of + crypt.c (and crypt.h) from zcrypt21.zip or later must be used. + + */ + +/* compression methods */ +#define STORED 0 +#define DEFLATED 8 + +/* PKZIP header definitions */ +#define ZIPMAG 0x4b50 /* two-byte zip lead-in */ +#define LOCREM 0x0403 /* remaining two bytes in zip signature */ +#define LOCSIG 0x04034b50L /* full signature */ +#define LOCFLG 4 /* offset of bit flag */ +#define CRPFLG 1 /* bit for encrypted entry */ +#define EXTFLG 8 /* bit for extended local header */ +#define LOCHOW 6 /* offset of compression method */ +#define LOCTIM 8 /* file mod time (for decryption) */ +#define LOCCRC 12 /* offset of crc */ +#define LOCSIZ 16 /* offset of compressed size */ +#define LOCLEN 20 /* offset of uncompressed length */ +#define LOCFIL 24 /* offset of file name field length */ +#define LOCEXT 26 /* offset of extra field length */ +#define LOCHDR 28 /* size of local header, including LOCREM */ +#define EXTHDR 16 /* size of extended local header, inc sig */ + +/* GZIP header definitions */ +#define GZPMAG 0x8b1f /* two-byte gzip lead-in */ +#define GZPHOW 0 /* offset of method number */ +#define GZPFLG 1 /* offset of gzip flags */ +#define GZPMUL 2 /* bit for multiple-part gzip file */ +#define GZPISX 4 /* bit for extra field present */ +#define GZPISF 8 /* bit for filename present */ +#define GZPISC 16 /* bit for comment present */ +#define GZPISE 32 /* bit for encryption */ +#define GZPTIM 2 /* offset of Unix file modification time */ +#define GZPEXF 6 /* offset of extra flags */ +#define GZPCOS 7 /* offset of operating system compressed on */ +#define GZPHDR 8 /* length of minimal gzip header */ + +/* Macros for getting two-byte and four-byte header values */ +#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) +#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) + +/* Function prototypes */ +ulg updcrc OF((uch *, ulg)); +int inflate OF((void)); +void err OF((int, char *)); + +/* Globals */ +uch *outptr; /* points to next byte in output buffer */ +ulg outcnt; /* bytes in output buffer */ +ulg outsiz; /* total bytes written to out */ +int encrypted; /* flag to turn on decryption */ +int qflag = 1; /* turn off messages in inflate.c */ +uch slide[WSIZE]; +uch *addr, *load, *esym; +extern uch *r3, *r6, *r7; +int bsize; + +/* Masks for inflate.c */ +ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +extern uch input_data[]; +uch *datap = input_data; +struct exec x; + +int nextbyte() +{ + extern int input_len; + + if (!(input_len & 0x1fff)) + twiddle(); + if (input_len-- > 0) + return(*datap++); + else + return(EOF); +} + +int nextblock(p, n) +char *p; +int n; +{ + extern int input_len; + + twiddle(); + if (input_len < n) + return(0); + memcpy(p, datap, n); + input_len -= n; + datap += n; + return(n); +} + +ulg updcrc(s, n) +uch *s; /* pointer to bytes to pump through */ +ulg n; /* number of bytes in s[] */ +/* Run a set of bytes through the crc shift register. If s is a NULL + pointer, then initialize the crc shift register contents instead. + Return the current crc in either case. */ +{ + register ulg c; /* temporary variable */ + + static ulg crc = 0xffffffffL; /* shift register contents */ + + if (s == (uch *)NULL) + c = 0xffffffffL; + else + { + c = crc; + while (n--) + c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); + } + crc = c; + return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ +} + +void nextstate() +{ + static int state = 0; + + switch (state) { + case 0: + if (N_BADMAG(x)) + panic("Bad exec format\n"); + load = addr = (uch *)(x.a_entry & 0x00ffff00); + printf("Uncompressing @ 0x%x\n", addr); + bsize = x.a_text; + if (N_GETMAGIC(x) == ZMAGIC) { + bcopy(&x, addr, sizeof(x)); + addr += sizeof(x); + bsize -= sizeof(x); + } + printf("%d", x.a_text); + state = 1; + break; + + case 1: + if (N_GETMAGIC(x) == NMAGIC) + while ((int)addr & CLOFSET) + *addr++ = 0; + bsize = x.a_data; + printf("+%d", x.a_data); + state = 2; + break; + + case 2: + printf("+%d", x.a_bss); + bzero(addr, x.a_bss ); + addr += x.a_bss; + bcopy(&x.a_syms, addr, sizeof(x.a_syms)); + addr += sizeof(x.a_syms); + printf(" [%d+", x.a_syms); + if (x.a_syms) { + bsize = x.a_syms + sizeof(int); + state = 3; + break; + } + printf("0]"); + + case 4: + printf(" total 0x%x", addr); + x.a_entry &= 0xffffff; + printf(" start 0x%x\n", x.a_entry); +#define round_to_size(x,t) \ + (((int)(x) + sizeof(t) - 1) & ~(sizeof(t) - 1)) + esym = (char *)round_to_size(addr - load, int); +#undef round_to_size + state = -1; + break; + + case 3: + printf("%d]", ((int *)addr)[-1]); + bsize = ((int *)addr)[-1] - sizeof(int); + state = 4; + break; + + case -1: + printf("Already at EOF\n"); + break; + } +} + +int flush(w) /* used by inflate.c (FLUSH macro) */ +ulg w; /* number of bytes to flush */ +{ + uch *p = slide; + + updcrc(slide, w); + outsiz += w; + + while (bsize <= w) { + bcopy(p, addr, bsize); + p += bsize; + addr += bsize; + w -= bsize; + nextstate(); + } + if (w) { + bcopy(p, addr, w); + addr += w; + bsize -= w; + } + return(0); +} + +main() +{ + ush n; + uch h[LOCHDR]; /* first local header (GZPHDR < LOCHDR) */ + int g = 0; /* true if gzip format */ + char *s = ""; + + cninit(); + + addr = (uch *)&x; + bsize = sizeof(x); + + /* read local header, check validity, and skip name and extra fields */ + n = nextbyte(); n |= nextbyte() << 8; + if (n == ZIPMAG) + { + if (nextblock((char *)h, LOCHDR) != LOCHDR || SH(h) != LOCREM) + panic("invalid zip file"); + if (SH(h + LOCHOW) != STORED && SH(h + LOCHOW) != DEFLATED) + panic("first entry not deflated or stored--can't funzip"); + for (n = SH(h + LOCFIL); n--; ) g = nextbyte(); + for (n = SH(h + LOCEXT); n--; ) g = nextbyte(); + g = 0; + encrypted = h[LOCFLG] & CRPFLG; + } + else if (n == GZPMAG) + { + if (nextblock((char *)h, GZPHDR) != GZPHDR) + panic("invalid gzip file"); + if (h[GZPHOW] != DEFLATED) + panic("gzip file not deflated"); + if (h[GZPFLG] & GZPMUL) + panic("cannot handle multi-part gzip files"); + if (h[GZPFLG] & GZPISX) + { + n = nextbyte(); n |= nextbyte() << 8; + while (n--) g = nextbyte(); + } + if (h[GZPFLG] & GZPISF) + while ((g = nextbyte()) != 0 && g != EOF) ; + if (h[GZPFLG] & GZPISC) + while ((g = nextbyte()) != 0 && g != EOF) ; + g = 1; + encrypted = h[GZPFLG] & GZPISE; + } + else + panic("input not a zip or gzip file"); + + /* if entry encrypted, decrypt and validate encryption header */ + if (encrypted) + panic("cannot decrypt entry (need to recompile with full crypt.c)"); + + /* prepare output buffer and crc */ + outptr = slide; + outcnt = 0L; + outsiz = 0L; + updcrc(NULL, 0L); + + /* decompress */ + if (g || h[LOCHOW]) + { /* deflated entry */ + int r; + + if ((r = inflate()) != 0) + if (r == 3) + panic("out of memory"); + else + panic("invalid compressed data--format violated"); + inflate_free(); + } + else + { /* stored entry */ + register ulg n; + + n = LG(h + LOCLEN); + if (n != LG(h + LOCSIZ)) { + printf("len %ld, siz %ld\n", n, LG(h + LOCSIZ)); + panic("invalid compressed data--length mismatch"); + } + while (n--) { + ush c = nextbyte(); + *outptr++ = (uch)c; + if (++outcnt == WSIZE) /* do FlushOutput() */ + { + flush(outcnt); + outptr = slide; + outcnt = 0L; + } + } + if (outcnt) /* flush one last time; no need to reset outptr/outcnt */ + flush(outcnt); + } + + /* if extended header, get it */ + if (g) + { + if (nextblock((char *)h + LOCCRC, 8) != 8) + panic("gzip file ended prematurely"); + } + else + if ((h[LOCFLG] & EXTFLG) && + nextblock((char *)h + LOCCRC - 4, EXTHDR) != EXTHDR) + panic("zip file ended prematurely"); + + /* validate decompression */ + if (LG(h + LOCCRC) != updcrc(slide, 0L)) + panic("invalid compressed data--crc error"); + if (LG(h + (g ? LOCSIZ : LOCLEN)) != outsiz) + panic("invalid compressed data--length error"); + + /* check if there are more entries */ + if (!g && nextblock((char *)h, 4) == 4 && LG(h) == LOCSIG) + printf("funzip warning: zip file has more than one entry--rest ignored\n"); + + asm(" movd %0,r3" : : "g" (r3)); /* magic */ + asm(" movd %0,r4" : : "g" (esym)); + asm(" movd %0,r5" : : "g" (load)); + asm(" movd %0,r6" : : "g" (r6)); /* devtype */ + asm(" movd %0,r7" : : "g" (r7)); /* howto */ + + (*((int (*)()) x.a_entry))(); +} + +/* Table of CRC-32's of all single-byte values (made by makecrc.c) */ +ulg crc_32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/* From: inflate.c -- put in the public domain by Mark Adler + version c14o, 23 August 1994 */ + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor outputs a chunk of data at a time and decides + which method to use on a chunk-by-chunk basis. A chunk might typically + be 32K to 64K, uncompressed. If the chunk is uncompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block ends up smaller that way (usually for quite small + chunks); otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block and so + can code it much better than the pre-determined fixed codes can. + + The Huffman codes themselves are decoded using a mutli-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +#define PKZIP_BUG_WORKAROUND /* PKZIP 1.93a problem--live with it */ + +/* + inflate.h must supply the uch slide[WSIZE] array and the NEXTBYTE, + FLUSH() and memzero macros. If the window size is not 32K, it + should also define WSIZE. If INFMOD is defined, it can include + compiled functions to support the NEXTBYTE and/or FLUSH() macros. + There are defaults for NEXTBYTE and FLUSH() below for use as + examples of what those functions need to do. Normally, you would + also want FLUSH() to compute a crc on the data. inflate.h also + needs to provide these typedefs: + + typedef unsigned char uch; + typedef unsigned short ush; + typedef unsigned long ulg; + + This module uses the external functions malloc() and free() (and + probably memset() or bzero() in the memzero() macro). Their + prototypes are normally found in <string.h> and <stdlib.h>. + */ + +/* Warning: the fwrite above might not work on 16-bit compilers, since + 0x8000 might be interpreted as -32,768 by the library function. */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + +int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *)); +int huft_free OF((struct huft *)); +int inflate_codes OF((struct huft *, struct huft *, int, int)); +int inflate_stored OF((void)); +int inflate_fixed OF((void)); +int inflate_dynamic OF((void)); +int inflate_block OF((int *)); +int inflate OF((void)); +int inflate_free OF((void)); + + +/* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ +unsigned wp; /* current position in slide */ + + +/* Tables for deflate from PKZIP's appnote.txt. */ +static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* And'ing with mask[n] masks the lower n bits */ +ush mask[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the begining of a + routine that uses these macros from a global bit buffer and count. + + In order to not ask for more bits than there are in the compressed + stream, the Huffman tables are constructed to only ask for just + enough bits to make up the end-of-block code (value 256). Then no + bytes need to be "returned" to the buffer at the end of the last + block. See the huft_build() routine. + */ + +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ + +#ifndef CHECK_EOF +# define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}} +#else +# define NEEDBITS(n) {while(k<(n)){int c=NEXTBYTE;if(c==EOF)return 1;\ + b|=((ulg)c)<<k;k+=8;}} +#endif /* Piet Plomp: change "return 1" to "break" */ + +#define DUMPBITS(n) {b>>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +int lbits = 9; /* bits in base literal/length lookup table */ +int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +unsigned hufts; /* track memory usage */ + +void *malloc(n) +int n; +{ + void *p; + p = alloc(n + sizeof(n)); + if (!p) + return(NULL); + *((int *)p) = n; + p += sizeof(n); + return(p); +} + +int huft_build(b, n, s, d, e, t, m) +unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ +unsigned n; /* number of codes (assumed <= N_MAX) */ +unsigned s; /* number of simple-valued codes (0..s-1) */ +ush *d; /* list of base values for non-simple codes */ +ush *e; /* list of extra bits for non-simple codes */ +struct huft **t; /* result: starting table */ +int *m; /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. + The code with value 256 is special, and the tables are constructed + so that no bits beyond that code are fetched when that code is + decoded. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned el; /* length of EOB code (value 256) */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int lx[BMAX+1]; /* memory for l[-1..BMAX-1] */ + int *l = lx+1; /* stack of bits per table */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + static unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + el = n > 256 ? b[256] : BMAX; /* set length of EOB code, if any */ + memzero((char *)c, sizeof(c)); + p = b; i = n; + do { + c[*p]++; p++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)*m < j) + *m = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)*m > i) + *m = i; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = l[-1] = 0; /* no bits decoded yet */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l[h]) + { + w += l[h++]; /* add bits already decoded */ + + /* compute minimum size table less than or equal to *m bits */ + z = (z = g - w) > (unsigned)*m ? *m : z; /* upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + if ((unsigned)w + j > el && (unsigned)w < el) + j = el - w; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + l[h] = j; /* set table size in stack */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == + (struct huft *)NULL) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l[h-1]; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> (w - l[h-1]); + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = *p++; /* simple code is just the value */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + w -= l[--h]; /* don't need to update q */ + } + } + + + /* return actual size of base table */ + *m = l[0]; + + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +int huft_free(t) +struct huft *t; /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free(((void *)p) - sizeof(int), ((int *)p)[-1]); + p = q; + } + return 0; +} + + + +#ifdef ASM_INFLATECODES +# define inflate_codes(tl,td,bl,bd) flate_codes(tl,td,bl,bd,(uch *)slide) + int flate_codes OF((struct huft *, struct huft *, int, int, uch *)); + +#else + +int inflate_codes(tl, td, bl, bd) +struct huft *tl, *td; /* literal/length and distance decoder tables */ +int bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + + /* inflate the coded data */ + ml = mask[bl]; /* precompute masks for speed */ + md = mask[bd]; + while (1) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch)t->v.n; + if (w == WSIZE) + { + FLUSH(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask[e]); + DUMPBITS(e) + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#ifndef NOMEMCPY + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + } while (--e); + if (w == WSIZE) + { + FLUSH(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + + /* done */ + return 0; +} + +#endif /* ASM_INFLATECODES */ + + + +int inflate_stored() +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + + /* go to byte boundary */ + n = k & 7; + DUMPBITS(n); + + + /* get the length and its complement */ + NEEDBITS(16) + n = ((unsigned)b & 0xffff); + DUMPBITS(16) + NEEDBITS(16) + if (n != (unsigned)((~b) & 0xffff)) + return 1; /* error in compressed data */ + DUMPBITS(16) + + + /* read and output the compressed data */ + while (n--) + { + NEEDBITS(8) + slide[w++] = (uch)b; + if (w == WSIZE) + { + FLUSH(w); + w = 0; + } + DUMPBITS(8) + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + return 0; +} + + +/* Globals for literal tables (built once) */ +struct huft *fixed_tl = (struct huft *)NULL; +struct huft *fixed_td; +int fixed_bl, fixed_bd; + +int inflate_fixed() +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + /* if first time, set up tables for fixed blocks */ + if (fixed_tl == (struct huft *)NULL) + { + int i; /* temporary variable */ + static unsigned l[288]; /* length list for huft_build */ + + /* literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + fixed_bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, + &fixed_tl, &fixed_bl)) != 0) + { + fixed_tl = (struct huft *)NULL; + return i; + } + + /* distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + fixed_bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd)) > 1) + { + huft_free(fixed_tl); + fixed_tl = (struct huft *)NULL; + return i; + } + } + + + /* decompress until an end-of-block code */ + return inflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd) != 0; +} + + + +int inflate_dynamic() +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + static unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + static unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in table lengths */ + NEEDBITS(5) + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5) + NEEDBITS(5) + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5) + NEEDBITS(4) + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4) +#ifdef PKZIP_BUG_WORKAROUND + if (nl > 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ + + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + + + /* free decoding table for trees */ + huft_free(tl); + + + /* restore the global bit buffer */ + bb = b; + bk = k; + + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { + return i; /* incomplete code set */ + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { + if (i == 1 && !qflag) { +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +int inflate_block(e) +int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local bit buffer */ + b = bb; + k = bk; + + + /* read in last block bit */ + NEEDBITS(1) + *e = (int)b & 1; + DUMPBITS(1) + + + /* read in block type */ + NEEDBITS(2) + t = (unsigned)b & 3; + DUMPBITS(2) + + + /* restore the global bit buffer */ + bb = b; + bk = k; + + + /* inflate that block type */ + if (t == 2) + return inflate_dynamic(); + if (t == 0) + return inflate_stored(); + if (t == 1) + return inflate_fixed(); + + + /* bad block type */ + return 2; +} + + + +int inflate() +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) + return r; + if (hufts > h) + h = hufts; + } while (!e); + + + /* flush out slide */ + FLUSH(wp); + + + /* return success */ + return 0; +} + + + +int inflate_free() +{ + if (fixed_tl != (struct huft *)NULL) + { + huft_free(fixed_td); + huft_free(fixed_tl); + fixed_td = fixed_tl = (struct huft *)NULL; + } + return 0; +} diff --git a/sys/arch/pc532/stand/machdep.c b/sys/arch/pc532/stand/machdep.c new file mode 100644 index 00000000000..ec044477f0b --- /dev/null +++ b/sys/arch/pc532/stand/machdep.c @@ -0,0 +1,98 @@ +/* $NetBSD: machdep.c,v 1.2 1994/10/26 08:25:49 cgd Exp $ */ + +/* + * Copyright (c) 1994 Philip L. Budne. + * 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 L. Budne. + * 4. The name of Philip L. Budne 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. + */ + +/* + * pc532 standalone machdep code + * Phil Budne, May 10, 1994 + * + */ + +#include <sys/types.h> +#include "samachdep.h" + +int testing = 0; + +void +bzero( char *addr, int len ) +{ + while (len-- > 0) + *addr++ = '\0'; +} + +/* XXX TEMP; would like to use code more like hp300 scsi.c */ + +void +scsiinit(void) +{ +} + +int +scsialive(int ctlr) +{ + return 1; /* controller always alive! */ +} + +/* call functions in scsi_hi.c */ +#include "so.h" + +int +scsi_tt_read(ctlr, slave, buf, len, blk, nblk) + int ctlr, slave; + u_char *buf; + u_int len; + daddr_t blk; + u_int nblk; +{ +#if 0 +printf("scsi_tt_read ctlr %d, slave %d, len %d, blk %d, nblk %d\n", + ctlr, slave, len, blk, nblk ); +#endif + if (sc_rdwt(DISK_READ, blk, buf, nblk, 1<<slave, 0) == 0) + return 0; + return -2; +} + +int +scsi_tt_write(ctlr, slave, buf, len, blk, nblk) + int ctlr, slave; + u_char *buf; + u_int len; + daddr_t blk; + u_int nblk; +{ +#if 0 + if (sc_rdwt(DISK_WRITE, blk, buf, nblk, 1<<slave, 0) == 0) + return 0; +#endif + return -2; +} diff --git a/sys/arch/pc532/stand/prf.c b/sys/arch/pc532/stand/prf.c new file mode 100644 index 00000000000..e9db7e63e57 --- /dev/null +++ b/sys/arch/pc532/stand/prf.c @@ -0,0 +1,79 @@ +/* $NetBSD: prf.c,v 1.2 1994/10/26 08:25:50 cgd Exp $ */ + +/* + * Copyright (c) 1982, 1986, 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. + * + * @(#)prf.c 8.1 (Berkeley) 6/10/93 + */ + +getchar() +{ + register int c; + + while((c = cngetc()) == 0) + ; + if (c == '\r') + c = '\n'; + else if (c == ('c'&037)) { + panic("^C"); + /* NOTREACHED */ + } + if (c != '\b' && c != '\177') + putchar(c); + return(c); +} + +tgetchar() +{ + register int c; + + if ((c = cngetc()) == 0) + return(0); + + if (c == '\r') + c = '\n'; + else if (c == ('c'&037)) { + panic("^C"); + /* NOTREACHED */ + } + if (c != '\b' && c != '\177') + putchar(c); + return(c); +} + +putchar(c) + register int c; +{ + cnputc(c); + if (c == '\n') + cnputc('\r'); +} diff --git a/sys/arch/pc532/stand/rd.c b/sys/arch/pc532/stand/rd.c new file mode 100644 index 00000000000..4f3c3620a68 --- /dev/null +++ b/sys/arch/pc532/stand/rd.c @@ -0,0 +1,29 @@ +#include <sys/param.h> +#include "stand.h" +#include "samachdep.h" + +#ifndef RD_START +#define RD_START 0x288000 +#endif + +rdopen(f, ctlr, unit, part) + struct open_file *f; + int ctlr, unit, part; +{ + f->f_devdata = (void *) RD_START; + return(0); +} + +int +rdstrategy(ss, func, dblk, size, buf, rsize) + void *ss; + int func; + daddr_t dblk; /* block number */ + u_int size; /* request size in bytes */ + void *buf; + u_int *rsize; /* out: bytes transferred */ +{ + memcpy(buf, ss + (dblk << DEV_BSHIFT), size); + *rsize = size; + return(0); +} diff --git a/sys/arch/pc532/stand/samachdep.h b/sys/arch/pc532/stand/samachdep.h new file mode 100644 index 00000000000..a48383f54d5 --- /dev/null +++ b/sys/arch/pc532/stand/samachdep.h @@ -0,0 +1,42 @@ +/* $NetBSD: samachdep.h,v 1.2 1994/10/26 08:25:51 cgd Exp $ */ + +/* + * Copyright (c) 1982, 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. + * + * @(#)samachdep.h 8.1 (Berkeley) 6/10/93 + */ + +#define NSCSI 1 +#define NSD 8 + +extern int howto; +extern unsigned int bootdev; diff --git a/sys/arch/pc532/stand/scn.c b/sys/arch/pc532/stand/scn.c new file mode 100644 index 00000000000..b8637d16c38 --- /dev/null +++ b/sys/arch/pc532/stand/scn.c @@ -0,0 +1,103 @@ +/* $NetBSD: scn.c,v 1.3 1995/08/29 21:55:49 phil Exp $ */ + +/*- + * Copyright (c) 1994 Philip L. Budne. + * 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 L. Budne. + * 4. The name of Philip L. Budne may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY PHILIP BUDNE ``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 BUDNE 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. + */ + +/* + * scn.c -- scn2681/2692/68881 standalone console driver + * Phil Budne, May 10, 1994 + * + */ + +#ifdef SCNCONSOLE +#include <sys/types.h> +#include <dev/cons.h> + +#define DUART 0x28000000 + +/* registers */ +#define SCN_STAT 1 +#define SCN_DATA 3 + +/* status bits */ +#define STAT_RXRDY 0x01 +#define STAT_TXRDY 0x04 + +#ifndef SCNCNUNIT +#define SCNCNUNIT 0 +#endif + +unsigned char * volatile scncnaddr = (unsigned char *) DUART + 8 * SCNCNUNIT; + +scnprobe(cp) + struct consdev *cp; +{ + /* the only game in town */ + cp->cn_pri = CN_NORMAL; /* XXX remote? */ +} + +scninit(cp) + struct consdev *cp; +{ + /* leave things they way the PROM set them */ +} + +scngetchar(cp) + struct consdev *cp; +{ + register unsigned char * volatile scn = scncnaddr; + + if ((scn[SCN_STAT] & STAT_RXRDY) == 0) + return(0); + return scn[SCN_DATA]; +} + +scnputchar(cp, c) + struct consdev *cp; + register int c; +{ + register unsigned char * volatile scn = scncnaddr; + register int timo; + short stat; + + /* wait a reasonable time for the transmitter to come ready */ + timo = 50000; + while (((stat = scn[SCN_STAT]) & STAT_TXRDY) == 0 && --timo) + ; + scn[SCN_DATA] = c; +#if 0 + /* wait for this transmission to complete */ + timo = 1000000; + while (((stat = scn[SCN_STAT]) & STAT_TXRDY) == 0 && --timo) + ; +#endif +} +#endif diff --git a/sys/arch/pc532/stand/scsi_hi.c b/sys/arch/pc532/stand/scsi_hi.c new file mode 100644 index 00000000000..866273596d5 --- /dev/null +++ b/sys/arch/pc532/stand/scsi_hi.c @@ -0,0 +1,303 @@ +/* $NetBSD: scsi_hi.c,v 1.3 1994/10/26 08:25:53 cgd Exp $ */ + +/**************************************************************************** + * NS32K Monitor SCSI high-level driver + * Bruce Culbertson + * 8 March 1990 + * (This source is public domain source) + * + * There are three monitor SCSI commands. "Read" and "write" I think are + * fairly self explanatory once you read the help messages. They, in fact, + * execute the "extended read", "extended write", and "request sense" + * commands from the SCSI standard. + * + * "Raw" lets you execute any SCSI command but you need a SCSI reference to + * know what the commands are and what their formats are. The SCSI + * standard specifies that there are six buffers which, for example, hold a + * SCSI command or are the source or destination for data. You provide + * "raw" with an array of pointers to the six buffers. Using "edit", you + * can enter a SCSI command somewhere in memory and you can create the + * array of pointers. The array must actually be eight entries long; two + * entries are not used. By typing "raw <array address>", the SCSI command + * is executed. + * + * By the way, "read", "write", and "raw" talk only to the DP8490 SCSI + * controller. I have not had time to read the Adaptec data sheet and + * write a driver for it. + ****************************************************************************/ +#include "so.h" + +#define OK 0 +#define NOT_OK OK+1 +#define PRIVATE +#define PUBLIC +#define U8 unsigned char + +long scsiAdr = DEFAULT_SCSI_ADR, /* default SCSI address */ + scsiLun = DEFAULT_SCSI_LUN; + +struct cmd_desc { /* SCSI command description */ + const U8 *cmd; /* command string */ + const U8 *odata; /* data to output, if any */ + const struct cmd_desc *chain; /* next command */ +}; + +struct drive { /* SCSI drive description */ + U8 adr, lun; /* SCSI address and LUN */ + U8 flags; /* drive characteristics */ + U8 stat; /* drive state */ + const struct cmd_desc *init; /* list of initialize commands */ +}; +/* for drive.flags */ +#define EXTENDED_RDWR 1 /* device does extended read, write */ +#define EXTENDED_SENSE 2 /* device does extended sense */ +/* for drive.stat */ +#define INITIALIZED 1 /* device is initialized */ + +#ifdef OMTI +/* These SCSI commands initialize a OMTI 5200 SCSI controller with a 360K + * floppy at LUN=1 and an ST-225 at LUN=0. + */ +const U8 floppy_parms_cmd[] = {0xc2, 0x20, 0, 0, 0, 0}; +const U8 floppy_parms_data[] = {0, 3, 0x27, 0xa, 0, 0, 0, 0x80, 1, 0}; +const U8 floppy_format_cmd[] = {0xc0, 0x20, 0, 0, 9, 0x8b}; +const U8 floppy_recal_cmd[] = {1, 0x20, 0, 0, 0, 0}; +const U8 wini_parms_cmd[] = {0xc2, 0, 0, 0, 0, 0}; +const U8 wini_parms_data[] = {0, 0, 0, 3, 2, 0x63, 0, 1, 0x10, 0}; +const U8 wini_recal_cmd[] = {1, 0, 0, 0, 0, 0}; +const struct cmd_desc floppy_init2 = + {floppy_recal_cmd, 0, 0}; +const struct cmd_desc floppy_init1 = + {floppy_format_cmd, 0, &floppy_init2}; +const struct cmd_desc floppy_init0 = + {floppy_parms_cmd, floppy_parms_data, &floppy_init1}; +const struct cmd_desc wini_init1 = + {wini_recal_cmd, 0, 0}; +const struct cmd_desc wini_init0 = + {wini_parms_cmd, wini_parms_data, &wini_init1}; +#endif + +PRIVATE struct drive drive_tbl[] = { +#ifdef OMTI + {1, 0, 0, 0, &wini_init0}, + {1, 1, 0, 0, &floppy_init0}, +#endif + {0, 0, EXTENDED_RDWR | EXTENDED_SENSE, 1, 0}, +}; +#define DRV_TBL_SZ (sizeof (drive_tbl) / sizeof (struct drive)) + +/* Round up to multiple of four since SCSI transfers are always multiples + * of four bytes. + */ +#define CMD_LEN 12 /* longest SCSI command */ +#define SENSE_LEN 24 /* extended sense length */ +#define MSG_LEN 4 +#define STAT_LEN 4 + +#define MAX_SCSI_RETRIES 6 +#define CMD_IX 2 +#define CMD_SENSE 0x03 +#define CMD_READ 0x08 +#define CMD_WRITE 0x0a +#define CMD_XREAD 0x28 +#define CMD_XWRITE 0x2a +PRIVATE U8 cmd_buf[CMD_LEN]; + +#define SENSE_KEY 2 +#define NO_SENSE 0 +#define RECOVERY_ERR 1 +#define UNIT_ATTN 6 +#define ADD_SENSE_CODE 12 +#define SENSE_RST 0x29 +PRIVATE U8 sense_buf[SENSE_LEN]; + +#define CHECK_CONDITION 2 +#define STAT_IX 3 +#define STAT_MASK 0x1f +PRIVATE U8 stat_buf[STAT_LEN]; +#define IMSG_IX 7 +PRIVATE U8 msg_buf[MSG_LEN]; + +#define ODATA_IX 0 +#define IDATA_IX 1 +PRIVATE struct scsi_args scsi_args; + +/*===========================================================================* + * sc_rdwt * + *===========================================================================*/ +/* Carry out a read or write request for the SCSI disk. */ +PRIVATE int +sc_rdwt(op, block, ram_adr, len, sc_adr, lun) +long block, ram_adr, len, sc_adr, lun; +{ + int retries, ret; + U8 *p; + struct drive *dp; + + /* get drive characteristics */ + for (dp = drive_tbl; dp < drive_tbl + DRV_TBL_SZ - 1; ++dp) + if (dp->adr == sc_adr && dp->lun == lun) break; + if (dp == drive_tbl + DRV_TBL_SZ - 1) { + dp->adr = sc_adr; /* have default, set adr, lun */ + dp->lun = lun; + } + for (retries = 0; retries < MAX_SCSI_RETRIES; ++retries) { + if (dp->init && !(dp->stat & INITIALIZED)) + if (OK != sc_initialize (dp)) { + printf("SCSI cannot initialize device\n"); + return NOT_OK; + } + p = cmd_buf; /* build SCSI command */ + if (dp->flags & EXTENDED_RDWR) { /* use extended commands */ + *p++ = (op == DISK_READ)? CMD_XREAD: CMD_XWRITE; + *p++ = lun << 5; + *p++ = (block >> 24) & 0xff; + *p++ = (block >> 16) & 0xff; + *p++ = (block >> 8) & 0xff; + *p++ = (block >> 0) & 0xff; + *p++ = 0; + *p++ = (len >> 8) & 0xff; + *p++ = (len >> 0) & 0xff; + *p = 0; + } else { /* use short (SASI) commands */ + *p++ = (op == DISK_READ)? CMD_READ: CMD_WRITE; + *p++ = (lun << 5) | ((block >> 16) & 0x1f); + *p++ = (block >> 8) & 0xff; + *p++ = (block >> 0) & 0xff; + *p++ = len; + *p = 0; + } + if (op == DISK_READ) + ret = exec_scsi_hi (cmd_buf, (U8 *)ram_adr, (U8 *)0, dp); + else + ret = exec_scsi_hi (cmd_buf, (U8 *)0, (U8 *)ram_adr, dp); + if (OK == ret) return OK; + dp->stat &= ~INITIALIZED; + } + printf("SCSI %s, block %d failed even after retries\n", + op == DISK_READ? "READ": "WRITE", block); + return NOT_OK; +} + +/*===========================================================================* + * sc_initialize * + *===========================================================================*/ +/* Execute the list of initialization commands for the given drive. + */ +int +sc_initialize (dp) +struct drive *dp; +{ + const struct cmd_desc *cp; + + for (cp = dp->init; cp != 0; cp = cp->chain) + if (OK != exec_scsi_hi (cp->cmd, 0, cp->odata, dp)) { + dp->stat &= ~INITIALIZED; + return NOT_OK; + } + dp->stat |= INITIALIZED; + return OK; +} + +/*===========================================================================* + * exec_scsi_hi * + *===========================================================================*/ +/* Execute a "high-level" SCSI command. This means execute a low level + * command and, if it fails, execute a request sense to find out why. + */ +PRIVATE int +exec_scsi_hi(cmd, data_in, data_out, dp) +U8 *cmd, *data_out, *data_in; +struct drive *dp; +{ + scsi_args.ptr[CMD_IX] = (long)cmd; + scsi_args.ptr[STAT_IX] = (long)stat_buf; + scsi_args.ptr[IMSG_IX] = (long)msg_buf; + scsi_args.ptr[IDATA_IX] = (long)data_in; + scsi_args.ptr[ODATA_IX] = (long)data_out; + if (OK != exec_scsi_low (&scsi_args, dp->adr)) + return NOT_OK; + *stat_buf &= STAT_MASK; /* strip off lun */ + if (*stat_buf == 0) + /* Success -- this should be the usual case */ + return OK; + if (*stat_buf != CHECK_CONDITION) { + /* do not know how to handle this so return error */ + printf("SCSI device returned unknown status: %d\n", *stat_buf); + return NOT_OK; + } + /* Something funny happened, need to execute request-sense command + * to learn more. + */ + if (OK == get_sense(dp)) + /* Something funny happened, but the device recovered from it and + * the command succeeded. + */ + return OK; + return NOT_OK; +} + +/*===========================================================================* + * get_sense * + *===========================================================================*/ +/* Execute a "request sense" SCSI command and check results. When a SCSI + * command returns CHECK_CONDITION, a request-sense command must be executed. + * A request-sense command provides information about the original command. + * The original command might have succeeded, in which case it does not + * need to be retried and OK is returned. Examples: read error corrected + * with error correction code, or error corrected by retries performed by + * the SCSI device. The original command also could have failed, in + * which case NOT_OK is returned. + */ +#define XLOGICAL_ADR \ + (sense_buf[3]<<24 | sense_buf[4]<<16 | sense_buf[5]<<8 | sense_buf[6]) +#define LOGICAL_ADR \ + (sense_buf[1]<<16 | sense_buf[2]<<8 | sense_buf[3]) + +PRIVATE int +get_sense (dp) +struct drive *dp; +{ + U8 *p; + + p = cmd_buf; /* build SCSI command */ + *p++ = CMD_SENSE; + *p++ = dp->lun << 5; + *p++ = 0; + *p++ = 0; + *p++ = (dp->flags & EXTENDED_SENSE)? SENSE_LEN: 0; + *p = 0; + scsi_args.ptr[IDATA_IX] = (long)sense_buf; + scsi_args.ptr[ODATA_IX] = 0; + scsi_args.ptr[CMD_IX] = (long)cmd_buf; + scsi_args.ptr[STAT_IX] = (long)stat_buf; + scsi_args.ptr[IMSG_IX] = (long)msg_buf; + if (OK != exec_scsi_low (&scsi_args, dp->adr)) { + printf("SCSI SENSE command failed\n"); + return NOT_OK; + } + if ((*stat_buf & STAT_MASK) != 0) { + printf("SCSI SENSE returned wrong status %d\n", *stat_buf); + return NOT_OK; + } + if (0 == (dp->flags & EXTENDED_SENSE)) { + printf("SCSI request sense, code 0x%x, log_adr 0x%x\n", + sense_buf[0], LOGICAL_ADR); + return NOT_OK; + } + switch (sense_buf[SENSE_KEY] & 0xf) { + case NO_SENSE: + case UNIT_ATTN: /* reset */ + return NOT_OK; /* must retry command */ + case RECOVERY_ERR: + /* eventually, we probably do not want to hear about these. */ + printf("SCSI ok with recovery, code 0x%x, logical address 0x%x\n", + sense_buf[ADD_SENSE_CODE], XLOGICAL_ADR); + return OK; /* orig command was ok with recovery */ + default: + printf("SCSI failure: key 0x%x code 0x%x log adr 0x%x sense buf 0x%x\n", + sense_buf[SENSE_KEY], sense_buf[ADD_SENSE_CODE], + XLOGICAL_ADR, sense_buf); + return NOT_OK; /* orig command failed */ + } +} diff --git a/sys/arch/pc532/stand/scsi_low.c b/sys/arch/pc532/stand/scsi_low.c new file mode 100644 index 00000000000..6fd2bc643f8 --- /dev/null +++ b/sys/arch/pc532/stand/scsi_low.c @@ -0,0 +1,426 @@ +/* $NetBSD: scsi_low.c,v 1.4 1994/12/09 21:04:42 phil Exp $ */ + +/**************************************************************************** + * NS32K Monitor SCSI low-level driver + * Bruce Culbertson + * 8 March 1990 + * (This source is public domain source.) + * + * Originally written by Bruce Culbertson for a ns32016 port of Minix. + * Adapted from that for the pc532 (ns32632) monitor. + * Adapted from that for NetBSD/pc532 by Philip L. Bunde. + * + * Do not use DMA -- makes 32016 and pc532 versions compatible. + * Do not use interrupts -- makes it harder for the user code to bomb + * this code. + ****************************************************************************/ + +#include "so.h" + +#define OK 0 +#define NOT_OK OK+1 +#define PRIVATE +#define PUBLIC +#define WR_ADR(adr,val) (*((volatile unsigned char *)(adr))=(val)) +#define RD_ADR(adr) (*((volatile unsigned char *)(adr))) +#define AIC6250 0 +#define DP8490 1 +#define MAX_CACHE 0x10000 + +/* SCSI bus phases + */ +#define PH_ODATA 0 +#define PH_IDATA 1 +#define PH_CMD 2 +#define PH_STAT 3 +#define PH_IMSG 7 +#define PH_NONE 8 +#define PH_IN(phase) ((phase) & 1) + +/* NCR5380 SCSI controller registers + */ +#define SC_CTL 0x30000000 /* base for control registers */ +#define SC_DMA 0x38000000 /* base for data registers */ +#define SC_CURDATA SC_CTL+0 +#define SC_OUTDATA SC_CTL+0 +#define SC_ICMD SC_CTL+1 +#define SC_MODE SC_CTL+2 +#define SC_TCMD SC_CTL+3 +#define SC_STAT1 SC_CTL+4 +#define SC_STAT2 SC_CTL+5 +#define SC_START_SEND SC_CTL+5 +#define SC_INDATA SC_CTL+6 +#define SC_RESETIP SC_CTL+7 +#define SC_START_RCV SC_CTL+7 + +/* Bits in NCR5380 registers + */ +#define SC_A_RST 0x80 +#define SC_A_SEL 0x04 +#define SC_S_SEL 0x02 +#define SC_S_REQ 0x20 +#define SC_S_BSY 0x40 +#define SC_S_BSYERR 0x04 +#define SC_S_PHASE 0x08 +#define SC_S_IRQ 0x10 +#define SC_S_DRQ 0x40 +#define SC_M_DMA 0x02 +#define SC_M_BSY 0x04 +#define SC_ENABLE_DB 0x01 + +/* Status of interrupt routine, returned in m1_i1 field of message. + */ +#define ISR_NOTDONE 0 +#define ISR_OK 1 +#define ISR_BSYERR 2 +#define ISR_RSTERR 3 +#define ISR_BADPHASE 4 +#define ISR_TIMEOUT 5 + +#define ICU_ADR 0xfffffe00 +#define ICU_IO (ICU_ADR+20) +#define ICU_DIR (ICU_ADR+21) +#define ICU_DATA (ICU_ADR+19) +#define ICU_SCSI_BIT 0x80 + +/* Miscellaneous + */ +#define MAX_WAIT 2000000 +#define SC_LOG_LEN 32 + +PRIVATE struct scsi_args *sc_ptrs; +PRIVATE char sc_cur_phase, + sc_reset_done = 1, + sc_have_msg, + sc_accept_int, + sc_dma_dir; + +long sc_dma_port = SC_DMA, + sc_dma_adr; + +#ifdef DEBUG +struct sc_log { + unsigned char stat1, stat2; +} sc_log [SC_LOG_LEN], + *sc_log_head = sc_log; +int sc_spurious_int; +#endif +unsigned char + sc_watchdog_error; /* watch dog error */ + +/* error messages */ +char *scsi_errors[] = { + 0, /* ISR_NOTDONE */ + 0, /* ISR_OK */ + "busy error", /* ISR_BSYERR */ + "reset error", /* ISR_RSTERR */ + "NULL pointer for current phase", /* ISR_BADPHASE */ + "timeout", /* ISR_TIMEOUT */ +}; + +/*===========================================================================* + * exec_scsi_low * + *===========================================================================*/ +/* Execute a generic SCSI command. Passed pointers to eight buffers: + * data-out, data-in, command, status, dummy, dummy, message-out, message-in. + */ +PUBLIC +int +exec_scsi_low (args, scsi_adr) +struct scsi_args *args; +long scsi_adr; +{ + int ret; + + sc_ptrs = args; /* make pointers globally accessible */ + scCtlrSelect (DP8490); + if (!sc_reset_done) sc_reset(); + /* TCMD has some undocumented behavior in initiator mode. I think the + * data bus cannot be enabled if i/o is asserted. + */ + WR_ADR (SC_TCMD, 0); + if (OK != sc_wait_bus_free ()) { /* bus-free phase */ + printf("SCSI: bus not free\n"); + return NOT_OK; + } + sc_cur_phase = PH_NONE; + sc_have_msg = 0; + if (OK != sc_select (scsi_adr)) /* select phase */ + return NOT_OK; + sc_watchdog_error = 0; + ret = sc_receive (); /* isr does the rest */ + if (ret == ISR_OK) return OK; + else { + sc_reset(); + printf("SCSI: %s\n", scsi_errors[ret]); + return NOT_OK; + } +} + +/*===========================================================================* + * sc_reset * + *===========================================================================*/ +/* + * Reset SCSI bus. + */ +PRIVATE +sc_reset() +{ + volatile int i; + + WR_ADR (SC_MODE, 0); /* get into harmless state */ + WR_ADR (SC_OUTDATA, 0); + WR_ADR (SC_ICMD, SC_A_RST); /* assert RST on SCSI bus */ + i = 200; /* wait 25 usec */ + while (i--); + WR_ADR (SC_ICMD, 0); /* deassert RST, get off bus */ + sc_reset_done = 1; +} + +/*===========================================================================* + * sc_wait_bus_free * + *===========================================================================*/ +PRIVATE int +sc_wait_bus_free() +{ + int i = MAX_WAIT; + volatile int j; + + while (i--) { + /* Must be clear for 2 usec, so read twice */ + if (RD_ADR (SC_STAT1) & (SC_S_BSY | SC_S_SEL)) continue; + for (j = 0; j < 25; ++j); + if (RD_ADR (SC_STAT1) & (SC_S_BSY | SC_S_SEL)) continue; + return OK; + } + sc_reset_done = 0; + return NOT_OK; +} + +/*===========================================================================* + * sc_select * + *===========================================================================*/ +/* This duplicates much of the work that the interrupt routine would do on a + * phase mismatch and, in fact, the original plan was to just do the select, + * let a phase mismatch occur, and let the interrupt routine do the rest. + * That didn't work because the 5380 did not reliably generate the phase + * mismatch interrupt after selection. + */ +PRIVATE int +sc_select(adr) +long adr; +{ + int i, stat1; + long new_ptr; + + WR_ADR (SC_OUTDATA, adr); /* SCSI bus address */ + WR_ADR (SC_ICMD, SC_A_SEL | SC_ENABLE_DB); + for (i = 0;; ++i) { /* wait for target to assert SEL */ + stat1 = RD_ADR (SC_STAT1); + if (stat1 & SC_S_BSY) break; /* select successful */ + if (i > MAX_WAIT) { /* timeout */ + printf("SCSI: SELECT timeout\n"); + sc_reset(); + return NOT_OK; + } + } + WR_ADR (SC_ICMD, 0); /* clear SEL, disable data out */ + WR_ADR (SC_OUTDATA, 0); + for (i = 0;; ++i) { /* wait for target to assert REQ */ + if (stat1 & SC_S_REQ) break; /* target requesting transfer */ + if (i > MAX_WAIT) { /* timeout */ + printf("SCSI: REQ timeout\n"); + sc_reset(); + return NOT_OK; + } + stat1 = RD_ADR (SC_STAT1); + } + sc_cur_phase = (stat1 >> 2) & 7; /* get new phase from controller */ + if (sc_cur_phase != PH_CMD) { + printf("SCSI: bad phase = %d\n", sc_cur_phase); + sc_reset(); + return NOT_OK; + } + new_ptr = sc_ptrs->ptr[PH_CMD]; + if (new_ptr == 0) { + printf("SCSI: NULL command pointer\n"); + sc_reset(); + return NOT_OK; + } + sc_accept_int = 1; + sc_dma_setup (DISK_WRITE, new_ptr); + WR_ADR (SC_TCMD, PH_CMD); + WR_ADR (SC_ICMD, SC_ENABLE_DB); + WR_ADR (SC_MODE, SC_M_BSY | SC_M_DMA); + WR_ADR (SC_START_SEND, 0); + return OK; +} + +/*===========================================================================* + * scsi_interrupt * + *===========================================================================*/ +/* SCSI interrupt handler. + */ +PUBLIC +int +scsi_interrupt() +{ + unsigned char stat2, dummy; + long new_ptr; + int ret = ISR_NOTDONE; + + stat2 = RD_ADR (SC_STAT2); /* get status before clearing request */ + +# ifdef DEBUG /* debugging log of interrupts */ + sc_log_head->stat1 = RD_ADR (SC_STAT1); + sc_log_head->stat2 = stat2; + if (++sc_log_head >= sc_log + SC_LOG_LEN) sc_log_head = sc_log; + sc_log_head->stat1 = sc_log_head->stat2 = 0xff; +# endif + + for (;;) { + dummy = RD_ADR (SC_RESETIP); /* clear interrupt request */ + if (!sc_accept_int || /* return if spurious interrupt */ + (!sc_watchdog_error && + (stat2 & SC_S_BSYERR) == 0 && (stat2 & SC_S_PHASE) == 1)) + { +# ifdef DEBUG + ++sc_spurious_int; +# endif + return ret; + } + RD_ADR (SC_MODE) &= ~SC_M_DMA; /* clear DMA mode */ + WR_ADR (SC_ICMD, 0); /* disable data bus */ + if (sc_cur_phase != PH_NONE) { /* if did DMA, save the new pointer */ + new_ptr = sc_dma_adr; /* fetch new pointer from DMA cntlr */ + if (sc_cur_phase == PH_IMSG && /* have message? */ + new_ptr != sc_ptrs->ptr[PH_IMSG]) sc_have_msg = 1; + sc_ptrs->ptr[sc_cur_phase] = /* save pointer */ + new_ptr; + } + if (sc_watchdog_error) ret = ISR_TIMEOUT; + else if (stat2 & SC_S_BSYERR) { /* target deasserted BSY? */ + if (sc_have_msg) ret = ISR_OK; + else ret = ISR_BSYERR; + } else if (!(stat2 & SC_S_PHASE)) { /* if phase mismatch, setup new phase */ + sc_cur_phase = /* get new phase from controller */ + (RD_ADR (SC_STAT1) >> 2) & 7; + new_ptr = sc_ptrs->ptr[sc_cur_phase]; + if (new_ptr == 0) ret = ISR_BADPHASE; + else { + WR_ADR (SC_TCMD, sc_cur_phase); /* write new phase into TCMD */ + if (PH_IN (sc_cur_phase)) { /* set DMA controller */ + sc_dma_setup (DISK_READ, new_ptr); + RD_ADR (SC_MODE) |= SC_M_DMA; + WR_ADR (SC_START_RCV, 0); /* tell SCSI to start DMA */ + } else { + sc_dma_setup (DISK_WRITE, new_ptr); + RD_ADR (SC_MODE) |= SC_M_DMA; + WR_ADR (SC_ICMD, SC_ENABLE_DB); + WR_ADR (SC_START_SEND, 0); + } + } + } else ret = ISR_RSTERR; + if (ret != ISR_NOTDONE) { /* if done, send message to task */ + sc_watchdog_error = 0; + sc_accept_int = 0; + WR_ADR (SC_MODE, 0); /* clear monbsy, dma */ + break; /* reti re-enables ints */ + } + if (0 == ((stat2 = /* check for another interrupt */ + RD_ADR (SC_STAT2)) & SC_S_IRQ)) + { + break; + } + } + return ret; +} + +/*===========================================================================* + * sc_dma_setup * + *===========================================================================*/ +/* Fake DMA setup. Just store pointers and direction in global variables. + * + * The pseudo-DMA is subtler than it looks because of the cache. + * + * 1) When accessing I/O devices through a cache, some mechanism is + * necessary to ensure you access the device rather than the cache. + * On the 32532, the IODEC signal is supposed to be asserted for I/O + * addresses to accomplish this. However, a bug makes this much + * slower than necessary and severely hurts pseudo-DMA performance. + * Hence, IODEC is not asserted for the SCSI DMA port. + * + * 2) Because of (1), we must devise our own method of forcing the + * SCSI DMA port to be read. 0x8000000 addresses have been decoded + * to all access this port. By always using new addresses to access + * the DMA port (wrapping only after reading MAX_CACHE bytes), we + * force cache misses and, hence, device reads. Since the cache + * is write-through, we do not need to worry about writes. + * + * 3) It is possible to miss the last few bytes of a transfer if + * bus transfer size is not considered. The loop in sc_receive() + * transfers data until the interrupt signal is asserted. If + * bytes are transferred, the attempt to move the first byte of a + * double word causes the whole word to be read into the cache. + * Then the byte is transferred. If reading the double word + * completed the SCSI transfer, then the loop exits since + * interrupt is asserted. However, the last few bytes have only + * been moved into the cache -- they have not been moved to the + * DMA destination. + * + * 4) It is also possible to miss the first few bytes of a transfer. + * If the address used to access pseudo-dma port is not double word + * aligned, the whole double word is read into the cache, and then + * data is moved from the middle of the word (i.e. something other + * than the first bytes read from the SCSI controller) by the + * pseudo-dma loop in sc_receive(). + */ +sc_dma_setup (dir, adr) +int dir; +long adr; +{ + if (sc_dma_port > SC_DMA + MAX_CACHE) sc_dma_port = SC_DMA; + sc_dma_dir = dir; + sc_dma_adr = adr; +} + +/*===========================================================================* + * sc_receive * + *===========================================================================*/ +/* Replacement for Minix receive(), which waits for a message. This code + * spins, waiting for data to transfer or interrupt requests to handle. + * See sc_dma_setup for details. + */ +int +sc_receive() +{ + int stat2, isr_ret; + + for (;;) { + stat2 = RD_ADR (SC_STAT2); + if (stat2 & SC_S_IRQ) { + if (ISR_NOTDONE != (isr_ret = scsi_interrupt())) break; + } else if (stat2 & SC_S_DRQ) { /* test really not necessary on pc532 */ + if (sc_dma_dir == DISK_READ) + *((long *)sc_dma_adr)++ = *((volatile long *)sc_dma_port)++; + else *((volatile long *)sc_dma_port)++ = *((long *)sc_dma_adr)++; + } + } + return isr_ret; +} + +/*===========================================================================* + * scCtlrSelect + *===========================================================================*/ +/* Select a SCSI device. + */ +scCtlrSelect (ctlr) +int ctlr; +{ + RD_ADR (ICU_IO) &= ~ICU_SCSI_BIT; /* i/o, not port */ + RD_ADR (ICU_DIR) &= ~ICU_SCSI_BIT; /* output */ + if (ctlr == DP8490) + RD_ADR (ICU_DATA) &= ~ICU_SCSI_BIT; /* select = 0 for 8490 */ + else + RD_ADR (ICU_DATA) |= ICU_SCSI_BIT; /* select = 1 for AIC6250 */ +} diff --git a/sys/arch/pc532/stand/sd.c b/sys/arch/pc532/stand/sd.c new file mode 100644 index 00000000000..ff6ea431607 --- /dev/null +++ b/sys/arch/pc532/stand/sd.c @@ -0,0 +1,196 @@ +/* $NetBSD: sd.c,v 1.4 1995/08/29 21:55:50 phil Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990, 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 the Systems + * Programming Group of the University of Utah Computer Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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: sd.c 1.9 92/12/21$ + * + * @(#)sd.c 8.1 (Berkeley) 6/10/93 + */ + +/* + * SCSI CCS disk driver + */ + +#include <sys/param.h> +#include <sys/disklabel.h> +#include "stand.h" +#include "samachdep.h" + +struct sd_softc { + int sc_ctlr; + int sc_unit; + int sc_part; + char sc_retry; + char sc_alive; + struct disklabel sc_label; +} sd_softc[NSCSI][NSD]; + +#ifdef SD_DEBUG +int debug = SD_DEBUG; +#endif + +#define SDRETRY 2 + +sdinit(ctlr, unit) + int ctlr, unit; +{ + register struct sd_softc *ss = &sd_softc[ctlr][unit]; + + /* HP version does test_unit_ready + * followed by read_capacity to get blocksize + */ + ss->sc_alive = 1; + return (1); +} + +sdreset(ctlr, unit) + int ctlr, unit; +{ +} + +char io_buf[MAXBSIZE]; + +sdgetinfo(ss) + register struct sd_softc *ss; +{ + register struct disklabel *lp; + char *msg, *getdisklabel(); + int sdstrategy(), i, err; + + lp = &sd_softc[ss->sc_ctlr][ss->sc_unit].sc_label; + bzero((caddr_t)lp, sizeof *lp); + lp->d_secsize = DEV_BSIZE; + lp->d_secpercyl = 1; + lp->d_npartitions = MAXPARTITIONS; + lp->d_partitions[ss->sc_part].p_offset = 0; + lp->d_partitions[ss->sc_part].p_size = 0x7fffffff; + + if (err = sdstrategy(ss, F_READ, + LABELSECTOR, DEV_BSIZE, io_buf, &i) < 0) { + printf("sdgetinfo: sdstrategy error %d\n", err); + return 0; + } + + msg = getdisklabel(io_buf, lp); + if (msg) { + printf("sd(%d,%d,%d): %s\n", + ss->sc_ctlr, ss->sc_unit, ss->sc_part, msg); + return 0; + } + return(1); +} + +sdopen(f, ctlr, unit, part) + struct open_file *f; + int ctlr, unit, part; +{ + register struct sd_softc *ss; + register struct disklabel *lp; + +#ifdef SD_DEBUG + if (debug) + printf("sdopen: ctlr=%d unit=%d part=%d\n", + ctlr, unit, part); +#endif + + if (ctlr >= NSCSI || !scsialive(ctlr)) + return (EADAPT); + if (unit >= NSD) + return (ECTLR); + ss = &sd_softc[ctlr][unit]; /* XXX alloc()? keep pointers? */ + ss->sc_part = part; + ss->sc_unit = unit; + ss->sc_ctlr = ctlr; + if (!ss->sc_alive) { + if (!sdinit(ctlr, unit)) + return (ENXIO); + if (!sdgetinfo(ss)) + return (ERDLAB); + } + lp = &sd_softc[ctlr][unit].sc_label; + if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) + return (EPART); + + f->f_devdata = (void *)ss; + return (0); +} + +int +sdstrategy(ss, func, dblk, size, buf, rsize) + register struct sd_softc *ss; + int func; + daddr_t dblk; /* block number */ + u_int size; /* request size in bytes */ + char *buf; + u_int *rsize; /* out: bytes transferred */ +{ + register int ctlr = ss->sc_ctlr; + register int unit = ss->sc_unit; + register int part = ss->sc_part; + register struct partition *pp = &ss->sc_label.d_partitions[part]; + u_int nblk = size >> DEV_BSHIFT; + u_int blk = dblk + pp->p_offset; + char stat; + + if (size == 0) + return(0); + + ss->sc_retry = 0; + +#ifdef SD_DEBUG + if (debug) + printf("sdstrategy(%d,%d): size=%d blk=%d nblk=%d\n", + ctlr, unit, size, blk, nblk); +#endif + +retry: + if (func == F_READ) + stat = scsi_tt_read(ctlr, unit, buf, size, blk, nblk); + else + stat = scsi_tt_write(ctlr, unit, buf, size, blk, nblk); + if (stat) { + printf("sd(%d,%d,%d): block=%x, error=0x%x\n", + ctlr, unit, ss->sc_part, blk, stat); + if (++ss->sc_retry > SDRETRY) + return(EIO); + goto retry; + } + *rsize = size; + + return(0); +} diff --git a/sys/arch/pc532/stand/so.h b/sys/arch/pc532/stand/so.h new file mode 100644 index 00000000000..63c85ef9d5a --- /dev/null +++ b/sys/arch/pc532/stand/so.h @@ -0,0 +1,67 @@ +/* $NetBSD: so.h,v 1.2 1994/10/26 08:25:57 cgd Exp $ */ + +#ifndef _SO_H_INCLUDE +#define _SO_H_INCLUDE + +/* Definitions for standalone I/O lib */ + +#define DUART0 0x28000000 +#define DUART1 0x28000020 +#define DUART2 0x28000040 +#define DUART3 0x28000060 +#define PARRDU 0x28000080 +#define PARCLU 0x280000A0 +#define SCSI_POLLED 0x30000000 +#define SCSI_DMA 0x38000000 +#define ICU_ADDR 0xFFFFFE00 + +/* Which UART to use by default */ +#define DEFAULT_UART 0 + +/* Which SCSI device to use by default */ +#define DEFAULT_SCSI_ADR 1 +#define DEFAULT_SCSI_LUN 0 + +/* Low level scsi operation codes */ +#define DISK_READ 3 +#define DISK_WRITE 4 + +/* The size of a disk block */ +#define DBLKSIZE 512 + +/* Some disk address that will never be used */ +#define INSANE_BADDR 0x800000 + +struct scsi_args { + long ptr [8]; +}; + +#ifndef NULL +#define NULL 0L +#endif + +/* + * The next macro defines where the "break" area in memory ends for + * malloc() and friends. The area between edata and this address will + * then be reserved and should not be used for anything else (or you will + * no doubt have big problems). Depending on where your program's end-of-data + * is, you may wish to locate this in such a way as to usurp a minimum + * amount of memory. + */ +#define BREAK_END_ADDR ((char *)0x400000) /* to 4MB */ + +/* Selectivly enable inline functions */ +#ifndef NO_INLINE +#define Inline inline +#else +#define Inline +#endif + +extern void fatal(), warn(); +extern long ulimit(int, long); +extern int brk(char *); +extern char *sbrk(int); + +extern int sc_rdwt(); + +#endif /* _SO_H_INCLUDE */ diff --git a/sys/arch/pc532/stand/srt0.s b/sys/arch/pc532/stand/srt0.s new file mode 100644 index 00000000000..fe7eaa8c127 --- /dev/null +++ b/sys/arch/pc532/stand/srt0.s @@ -0,0 +1,91 @@ +/* $NetBSD: srt0.s,v 1.3 1995/08/29 21:55:51 phil Exp $ */ + +/*- + * Copyright (c) 1994 Philip L. Budne. + * 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 L. Budne. + * 4. The name of Philip L. Budne 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. + */ + +/* + * srt0.s -- standalone C startup + * Phil Budne, May 10, 1994 + * + * from: pc532 kernel locore.s + * Phil Nelson, Dec 6, 1992 + * + */ + +#define PSR_S 0x200 +#define PSR_I 0x800 + +.data +.globl _howto, _bootdev, _r3, _r6, _r7 +__save_sp: .long 0 +__save_fp: .long 0 +_bootdev: .long 0 +_howto: .long 0 +_r3: .long 0 +_r6: .long 0 +_r7: .long 0 + +.text +.globl begin +begin: + bicpsrw PSR_I /* make sure interrupts are off. */ + bicpsrw PSR_S /* make sure we are using sp0. */ + + /* In case we are zboot: */ + movd r3,_r3(pc) /* magic */ + movd r6,_r6(pc) /* devtype */ + movd r7,_r7(pc) /* howto */ + + lprd sb, 0 /* gcc expects this. */ + sprd sp, __save_sp(pc) /* save monitor's sp. */ + sprd fp, __save_fp(pc) /* save monitor's fp. */ +/* sprd intbase, __old_intbase(pc) /* save monitor's intbase. */ + movqd 0, _howto(pc) + +restart: + /* Zero the bss segment. */ + addr _end(pc),r0 # setup to zero the bss segment. + addr _edata(pc),r1 + subd r1,r0 # compute _end - _edata + movd r0,tos # push length + addr _edata(pc),tos # push address + + movqd 0,_bootdev(pc) # XXX trash bootdev + bsr _bzero # zero the bss segment + bsr _main + /* fall */ + +.globl __rtt +__rtt: lprd sp, __save_sp(pc) /* restore monitor's sp. */ + lprd fp, __save_fp(pc) /* restore monitor's fp. */ +/* XXX just return to monitor??? */ + movqd 3, _howto /* RB_SINGLE|RB_ASKNAME */ + br restart diff --git a/sys/arch/pc532/stand/test.c b/sys/arch/pc532/stand/test.c new file mode 100644 index 00000000000..9d41480cb19 --- /dev/null +++ b/sys/arch/pc532/stand/test.c @@ -0,0 +1,191 @@ +/* $NetBSD: test.c,v 1.2 1994/10/26 08:25:59 cgd Exp $ */ + +/*- + * Copyright (c) 1994 Philip L. Budne. + * 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 L. Budne. + * 4. The name of Philip L. Budne may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY PHILIP BUDNE ``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 BUDNE 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. + */ + +/*- + * Allow test of "boot" (and presumably other "stand" utils) + * under user mode. + * + * Phil Budne <phil@ultimate.com> May 10, 1994 + */ + +/* my /sys/sys/syscall.h is out of sync w.r.t. lseek?? */ +#include "/usr/include/sys/syscall.h" +#include <sys/types.h> + +extern int errno; + +int testing = 1; +int bootdev; +int howto; + +_open( char *fname, int mode ) +{ + return syscall( SYS_open, fname, mode ); +} + +_read( int fd, char *buf, int len ) +{ + return syscall( SYS_read, fd, buf, len ); +} + +_write( int fd, char *buf, int len ) +{ + return syscall( SYS_write, fd, buf, len ); +} + +/* + * I'd like to strangle the jerk who thought it + * was a cool idea to change lseek, rather than creating + * a new "qseek" to handle long long offsets + */ +_lseek( int fd, off_t pos, int whence ) +{ + return syscall( SYS_lseek, fd, 0, pos, whence ); +} + +int fd = -1; + +opendisk(int unit) +{ + char fname[32]; + static int _unit = -1; + + if (unit == _unit) + return; + + if (fd >= 0) { + close(fd); + fd = -1; + } + _unit = unit; + +#if 0 + sprintf( fname, "/dev/r%s%dc", "sd", unit ); +#else + strcpy( fname, "/dev/rsd0c" ); +#endif + fd = _open( fname, 0 ); + if (fd < 0) { + printf("open %s failed\n", fname ); + return; + } + printf("opened %s (fd %d)\n", fname, fd ); +} + +void +bzero( char *addr, int len ) +{ + while (len-- > 0) + *addr++ = '\0'; +} + +/* XXX TEMP; would like to use code more like hp300 scsi.c */ + +void +scsiinit(void) +{ +} + +int +scsialive(int ctlr) +{ + return 1; /* controller always alive! */ +} + +#define BPS 512 +scsi_tt_read(ctlr, slave, buf, len, blk, nblk) + char *buf; +{ + int pos; +#if 0 +printf("scsi_tt_read(ctlr %d, slave %d, buf 0x%x, len %d, blk %d, nblk %d)\n", + ctlr, slave, buf, len, blk, nblk); +#endif + + opendisk(slave); + + pos = _lseek( fd, blk * BPS, 0 ); + if (pos != blk * BPS) { + printf("lseek pos %d error %d\n", pos, errno ); + return errno; + } + if (_read( fd, buf, nblk * BPS ) != nblk * BPS) { + printf("read errno %d\n", errno ); + return errno; + } + return 0; +} + +scsi_tt_write() +{ + return -1; +} + +#include <sys/types.h> +#include <dev/cons.h> + +scnprobe(cp) + struct consdev *cp; +{ + /* the only game in town */ + cp->cn_pri = CN_NORMAL; /* XXX remote? */ +} + +scninit(cp) + struct consdev *cp; +{ +} + +scnputchar(c) + int c; +{ + char c2; + c2 = c; + _write(0, &c2, 1); +} + +scngetchar() +{ + char c; + _read(0, &c, 1); + return c; +} + +_rtt() { + syscall( SYS_exit, 1 ); +} + +alloc(int size) +{ + return malloc(size); +} diff --git a/sys/arch/pc532/stand/tgets.c b/sys/arch/pc532/stand/tgets.c new file mode 100644 index 00000000000..232affa930a --- /dev/null +++ b/sys/arch/pc532/stand/tgets.c @@ -0,0 +1,89 @@ +/* $NetBSD: tgets.c,v 1.2 1994/10/26 08:26:00 cgd Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)gets.c 8.1 (Berkeley) 6/11/93 + */ + +tgets(buf) + char *buf; +{ + register int c; + int i; + register char *lp = buf; + + for (i = 2400000; i > 0; i--) { + c = tgetchar() & 0177; + if (c) { + for (;;) { + switch (c) { + case '\n': + case '\r': + *lp = '\0'; + return; + case '\b': + case '\177': + if (lp > buf) { + lp--; + putchar('\b'); + putchar(' '); + putchar('\b'); + } + break; + case '#': + if (lp > buf) + --lp; + break; + case 'r'&037: { + register char *p; + + putchar('\n'); + for (p = buf; p < lp; ++p) + putchar(*p); + break; + } + case '@': + case 'u'&037: + case 'w'&037: + lp = buf; + putchar('\n'); + break; + default: + *lp++ = c; + } + c = getchar() & 0177; + } + } + } + return(0); +} |