From bd04e0b515f202e8f8be165d29c40e3a577a199a Mon Sep 17 00:00:00 2001 From: chuck Date: Tue, 25 Jul 1995 23:11:53 +0000 Subject: [PATCH] mvme68k port -- for the motorola vme147 m68030 card --- sys/arch/mvme68k/Makefile | 5 + sys/arch/mvme68k/README | 152 ++ sys/arch/mvme68k/compile/.keep_me | 1 + sys/arch/mvme68k/conf/Makefile.mvme68k | 164 ++ sys/arch/mvme68k/conf/VME147 | 51 + sys/arch/mvme68k/conf/files.mvme68k | 49 + sys/arch/mvme68k/dev/if_le.c | 965 ++++++++ sys/arch/mvme68k/dev/if_lereg.h | 167 ++ sys/arch/mvme68k/dev/iio.c | 114 + sys/arch/mvme68k/dev/iio.h | 18 + sys/arch/mvme68k/dev/pcc.c | 171 ++ sys/arch/mvme68k/dev/pccreg.h | 130 + sys/arch/mvme68k/dev/scc.h | 64 + sys/arch/mvme68k/dev/zs.c | 996 ++++++++ sys/arch/mvme68k/include/ansi.h | 4 + sys/arch/mvme68k/include/aout_machdep.h | 48 + sys/arch/mvme68k/include/asm.h | 3 + sys/arch/mvme68k/include/cdefs.h | 8 + sys/arch/mvme68k/include/cpu.h | 230 ++ sys/arch/mvme68k/include/db_machdep.h | 4 + sys/arch/mvme68k/include/disklabel.h | 46 + sys/arch/mvme68k/include/endian.h | 4 + sys/arch/mvme68k/include/exec.h | 48 + sys/arch/mvme68k/include/float.h | 8 + sys/arch/mvme68k/include/frame.h | 3 + sys/arch/mvme68k/include/limits.h | 4 + sys/arch/mvme68k/include/param.h | 183 ++ sys/arch/mvme68k/include/pcb.h | 67 + sys/arch/mvme68k/include/pmap.h | 159 ++ sys/arch/mvme68k/include/proc.h | 53 + sys/arch/mvme68k/include/profile.h | 3 + sys/arch/mvme68k/include/psl.h | 3 + sys/arch/mvme68k/include/pte.h | 152 ++ sys/arch/mvme68k/include/ptrace.h | 4 + sys/arch/mvme68k/include/reg.h | 8 + sys/arch/mvme68k/include/setjmp.h | 3 + sys/arch/mvme68k/include/signal.h | 4 + sys/arch/mvme68k/include/stdarg.h | 4 + sys/arch/mvme68k/include/trap.h | 3 + sys/arch/mvme68k/include/types.h | 10 + sys/arch/mvme68k/include/varargs.h | 4 + sys/arch/mvme68k/include/vmparam.h | 246 ++ sys/arch/mvme68k/mvme68k/autoconf.c | 251 ++ sys/arch/mvme68k/mvme68k/clock.c | 367 +++ sys/arch/mvme68k/mvme68k/clockreg.h | 76 + sys/arch/mvme68k/mvme68k/conf.c | 278 +++ sys/arch/mvme68k/mvme68k/disksubr.c | 198 ++ sys/arch/mvme68k/mvme68k/dkbad.c | 66 + sys/arch/mvme68k/mvme68k/genassym.c | 208 ++ sys/arch/mvme68k/mvme68k/isr.h | 47 + sys/arch/mvme68k/mvme68k/locore.s | 1896 +++++++++++++++ sys/arch/mvme68k/mvme68k/machdep.c | 1469 ++++++++++++ sys/arch/mvme68k/mvme68k/mainbus.c | 29 + sys/arch/mvme68k/mvme68k/mem.c | 222 ++ sys/arch/mvme68k/mvme68k/pmap.c | 2659 +++++++++++++++++++++ sys/arch/mvme68k/mvme68k/pmap_bootstrap.c | 505 ++++ sys/arch/mvme68k/mvme68k/swapgeneric.c | 170 ++ sys/arch/mvme68k/mvme68k/sys_machdep.c | 263 ++ sys/arch/mvme68k/mvme68k/trap.c | 1084 +++++++++ sys/arch/mvme68k/mvme68k/vectors.s | 160 ++ sys/arch/mvme68k/mvme68k/vm_machdep.c | 412 ++++ sys/arch/mvme68k/stand/Makefile | 5 + sys/arch/mvme68k/stand/Makefile.inc | 37 + sys/arch/mvme68k/stand/libsa/Makefile | 41 + sys/arch/mvme68k/stand/libsa/SRT0.S | 86 + sys/arch/mvme68k/stand/libsa/SRT1.c | 68 + sys/arch/mvme68k/stand/libsa/clock.c | 128 + sys/arch/mvme68k/stand/libsa/clock.h | 6 + sys/arch/mvme68k/stand/libsa/clockreg.h | 71 + sys/arch/mvme68k/stand/libsa/config.h | 10 + sys/arch/mvme68k/stand/libsa/devopen.c | 24 + sys/arch/mvme68k/stand/libsa/exec.c | 176 ++ sys/arch/mvme68k/stand/libsa/gets.c | 117 + sys/arch/mvme68k/stand/libsa/if_lereg.h | 176 ++ sys/arch/mvme68k/stand/libsa/machdep.c | 154 ++ sys/arch/mvme68k/stand/libsa/netif.c | 530 ++++ sys/arch/mvme68k/stand/libsa/netif.h | 22 + sys/arch/mvme68k/stand/libsa/panic.c | 31 + sys/arch/mvme68k/stand/netboot/Makefile | 15 + sys/arch/mvme68k/stand/netboot/boot.c | 77 + sys/arch/mvme68k/stand/netboot/conf.c | 21 + sys/arch/mvme68k/stand/netboot/dev_net.c | 175 ++ sys/arch/mvme68k/stand/netboot/dev_net.h | 6 + sys/arch/mvme68k/stand/netboot/version.c | 9 + sys/arch/mvme68k/stand/sboot/Makefile | 19 + sys/arch/mvme68k/stand/sboot/clock.c | 117 + sys/arch/mvme68k/stand/sboot/clockreg.h | 69 + sys/arch/mvme68k/stand/sboot/console.c | 139 ++ sys/arch/mvme68k/stand/sboot/etherfun.c | 213 ++ sys/arch/mvme68k/stand/sboot/etherfun.h | 124 + sys/arch/mvme68k/stand/sboot/if_lereg.h | 176 ++ sys/arch/mvme68k/stand/sboot/le_poll.c | 320 +++ sys/arch/mvme68k/stand/sboot/libc_sa.c | 348 +++ sys/arch/mvme68k/stand/sboot/oc_cksum.s | 187 ++ sys/arch/mvme68k/stand/sboot/sboot.c | 150 ++ sys/arch/mvme68k/stand/sboot/sboot.h | 96 + sys/arch/mvme68k/stand/sboot/start.s | 47 + 97 files changed, 18713 insertions(+) create mode 100644 sys/arch/mvme68k/Makefile create mode 100644 sys/arch/mvme68k/README create mode 100644 sys/arch/mvme68k/compile/.keep_me create mode 100644 sys/arch/mvme68k/conf/Makefile.mvme68k create mode 100644 sys/arch/mvme68k/conf/VME147 create mode 100644 sys/arch/mvme68k/conf/files.mvme68k create mode 100644 sys/arch/mvme68k/dev/if_le.c create mode 100644 sys/arch/mvme68k/dev/if_lereg.h create mode 100644 sys/arch/mvme68k/dev/iio.c create mode 100644 sys/arch/mvme68k/dev/iio.h create mode 100644 sys/arch/mvme68k/dev/pcc.c create mode 100644 sys/arch/mvme68k/dev/pccreg.h create mode 100644 sys/arch/mvme68k/dev/scc.h create mode 100644 sys/arch/mvme68k/dev/zs.c create mode 100644 sys/arch/mvme68k/include/ansi.h create mode 100644 sys/arch/mvme68k/include/aout_machdep.h create mode 100644 sys/arch/mvme68k/include/asm.h create mode 100644 sys/arch/mvme68k/include/cdefs.h create mode 100644 sys/arch/mvme68k/include/cpu.h create mode 100644 sys/arch/mvme68k/include/db_machdep.h create mode 100644 sys/arch/mvme68k/include/disklabel.h create mode 100644 sys/arch/mvme68k/include/endian.h create mode 100644 sys/arch/mvme68k/include/exec.h create mode 100644 sys/arch/mvme68k/include/float.h create mode 100644 sys/arch/mvme68k/include/frame.h create mode 100644 sys/arch/mvme68k/include/limits.h create mode 100644 sys/arch/mvme68k/include/param.h create mode 100644 sys/arch/mvme68k/include/pcb.h create mode 100644 sys/arch/mvme68k/include/pmap.h create mode 100644 sys/arch/mvme68k/include/proc.h create mode 100644 sys/arch/mvme68k/include/profile.h create mode 100644 sys/arch/mvme68k/include/psl.h create mode 100644 sys/arch/mvme68k/include/pte.h create mode 100644 sys/arch/mvme68k/include/ptrace.h create mode 100644 sys/arch/mvme68k/include/reg.h create mode 100644 sys/arch/mvme68k/include/setjmp.h create mode 100644 sys/arch/mvme68k/include/signal.h create mode 100644 sys/arch/mvme68k/include/stdarg.h create mode 100644 sys/arch/mvme68k/include/trap.h create mode 100644 sys/arch/mvme68k/include/types.h create mode 100644 sys/arch/mvme68k/include/varargs.h create mode 100644 sys/arch/mvme68k/include/vmparam.h create mode 100644 sys/arch/mvme68k/mvme68k/autoconf.c create mode 100644 sys/arch/mvme68k/mvme68k/clock.c create mode 100644 sys/arch/mvme68k/mvme68k/clockreg.h create mode 100644 sys/arch/mvme68k/mvme68k/conf.c create mode 100644 sys/arch/mvme68k/mvme68k/disksubr.c create mode 100644 sys/arch/mvme68k/mvme68k/dkbad.c create mode 100644 sys/arch/mvme68k/mvme68k/genassym.c create mode 100644 sys/arch/mvme68k/mvme68k/isr.h create mode 100644 sys/arch/mvme68k/mvme68k/locore.s create mode 100644 sys/arch/mvme68k/mvme68k/machdep.c create mode 100644 sys/arch/mvme68k/mvme68k/mainbus.c create mode 100644 sys/arch/mvme68k/mvme68k/mem.c create mode 100644 sys/arch/mvme68k/mvme68k/pmap.c create mode 100644 sys/arch/mvme68k/mvme68k/pmap_bootstrap.c create mode 100644 sys/arch/mvme68k/mvme68k/swapgeneric.c create mode 100644 sys/arch/mvme68k/mvme68k/sys_machdep.c create mode 100644 sys/arch/mvme68k/mvme68k/trap.c create mode 100644 sys/arch/mvme68k/mvme68k/vectors.s create mode 100644 sys/arch/mvme68k/mvme68k/vm_machdep.c create mode 100644 sys/arch/mvme68k/stand/Makefile create mode 100644 sys/arch/mvme68k/stand/Makefile.inc create mode 100644 sys/arch/mvme68k/stand/libsa/Makefile create mode 100644 sys/arch/mvme68k/stand/libsa/SRT0.S create mode 100644 sys/arch/mvme68k/stand/libsa/SRT1.c create mode 100644 sys/arch/mvme68k/stand/libsa/clock.c create mode 100644 sys/arch/mvme68k/stand/libsa/clock.h create mode 100644 sys/arch/mvme68k/stand/libsa/clockreg.h create mode 100644 sys/arch/mvme68k/stand/libsa/config.h create mode 100644 sys/arch/mvme68k/stand/libsa/devopen.c create mode 100644 sys/arch/mvme68k/stand/libsa/exec.c create mode 100644 sys/arch/mvme68k/stand/libsa/gets.c create mode 100644 sys/arch/mvme68k/stand/libsa/if_lereg.h create mode 100644 sys/arch/mvme68k/stand/libsa/machdep.c create mode 100644 sys/arch/mvme68k/stand/libsa/netif.c create mode 100644 sys/arch/mvme68k/stand/libsa/netif.h create mode 100644 sys/arch/mvme68k/stand/libsa/panic.c create mode 100644 sys/arch/mvme68k/stand/netboot/Makefile create mode 100644 sys/arch/mvme68k/stand/netboot/boot.c create mode 100644 sys/arch/mvme68k/stand/netboot/conf.c create mode 100644 sys/arch/mvme68k/stand/netboot/dev_net.c create mode 100644 sys/arch/mvme68k/stand/netboot/dev_net.h create mode 100644 sys/arch/mvme68k/stand/netboot/version.c create mode 100644 sys/arch/mvme68k/stand/sboot/Makefile create mode 100644 sys/arch/mvme68k/stand/sboot/clock.c create mode 100644 sys/arch/mvme68k/stand/sboot/clockreg.h create mode 100644 sys/arch/mvme68k/stand/sboot/console.c create mode 100644 sys/arch/mvme68k/stand/sboot/etherfun.c create mode 100644 sys/arch/mvme68k/stand/sboot/etherfun.h create mode 100644 sys/arch/mvme68k/stand/sboot/if_lereg.h create mode 100644 sys/arch/mvme68k/stand/sboot/le_poll.c create mode 100644 sys/arch/mvme68k/stand/sboot/libc_sa.c create mode 100644 sys/arch/mvme68k/stand/sboot/oc_cksum.s create mode 100644 sys/arch/mvme68k/stand/sboot/sboot.c create mode 100644 sys/arch/mvme68k/stand/sboot/sboot.h create mode 100644 sys/arch/mvme68k/stand/sboot/start.s diff --git a/sys/arch/mvme68k/Makefile b/sys/arch/mvme68k/Makefile new file mode 100644 index 0000000000000..0591b09fa2d8a --- /dev/null +++ b/sys/arch/mvme68k/Makefile @@ -0,0 +1,5 @@ +# $NetBSD: Makefile,v 1.1.1.1 1995/07/25 23:11:53 chuck Exp $ + +SUBDIR= stand + +.include diff --git a/sys/arch/mvme68k/README b/sys/arch/mvme68k/README new file mode 100644 index 0000000000000..fdbb340984e3c --- /dev/null +++ b/sys/arch/mvme68k/README @@ -0,0 +1,152 @@ + $NetBSD: README,v 1.1.1.1 1995/07/25 23:11:53 chuck Exp $ + +NetBSD/mvme68k port + +supported environment: + + Motorola makes a number of m68k VME cards. This port +currently only works on the m68030 based VME147 card (diskless only +for now). + +requirements: + - VME147 card + - a machine to connect the console to + - network connection + - NFS server (to serve root and swap) + +future plans: + - VME147 scsi disk support + - hopefully, support for the VME162 card + + +how to boot: + Booting NetBSD/mvme68k on a VME147 is somewhat painful because +the ROM doesn't know how to talk to the ethernet chip. I have solved +this problem by downloading a bootstrap into RAM via the console line. + + First, you will need a m68k8k NFS mountable /usr and root +directory. NetBSD/sun3 binaries will run fine on the mvme68k system +for the most part (the exception being kvm stuff). These binaries can +be ftp'd from ftp.netbsd.org. You will also need a NetBSD/mvme68k +kernel and related bootstraps. For now these can be obtained from +dworkin.wustl.edu in /dist/netbsd/mvme68k_boot.tar.gz (once I get set +up I will put these plus a snapshot on ftp.netbsd.org). + + Put the mvme68k "netbsd" binary in NFS root directory. Put +boot.vme147 in /tftpboot of your NFS server machine. Make a symbolic +link from the hex encoding of your IP address to that file. For +example: + +lrwxrwxrwx 1 root 11 Apr 13 17:27 80FCA93F.147 -> boot.vme147 + + +[80FCA93F is the IP address (128.252.169.63) of my vme147.] + +Make sure you've got the right info in /etc/ethers and /etc/bootparams +on your server. + + +Now, bring up your 147. You should have the "bug" prompt: + +COLD Start + +Onboard RAM start = $00000000, stop = $007FFFFF + +147-Bug> + + +Make sure the "stop" looks ok (if you've got 8MB you should have the +same value as I). Also make sure the clock is ticking: + +147-Bug>time +Sunday 5/30/27 16:25:14 +147-Bug>time +Sunday 5/30/27 16:25:15 +147-Bug> + + +Looks good. you now need to download "sboot" into RAM. you can +either do that through the console line or through a 2nd serial +connection. I have my 147 connected to a sun4/110 and I access it via +"tip". to load that way do this: + +lo 0 +~Ccat sboot +go 4000 + +which will look like this: +147-Bug> +147-Bug>lo 0 +~CLocal command? cat sboot + +away for 11 seconds +! + +147-Bug>g 4000 +Effective address: 00004000 + +sboot: serial line bootstrap program (&end = 5fd8) + +>>> + + +Now, if you want to do it through serial line 1, then connect serial +line one to a machine. At the "147-Bug> " prompt do this "tm +1"... you should then login to what ever machine it is connected to. +Then hit "^A" to escape to Bug. do "lo 1;x=cat sboot" ... then when +that is done you can reconnect "tm 1" and logout. Then do "go 4000" +and you've got ">>> " prompt of sboot. + + +Once you've got the ">>> " prompt you can do commands such as: +"b" - boot "netbsd" multiuser +"b gennetbsd" - boot "gennetbsd" multiuser +"b -s" - boot "netbsd" single user +"b gennetbsd -s"- boot "gennetbsd" single user + +A typical boot looks like this: + +>>> b +le0: ethernet address: 8:0:3e:20:cb:87 +My ip address is: 128.252.169.63 +Server ip address is: 128.252.169.2 +3800 +Download was a success! +Start @ 0x8000 ... +>> NetBSD netboot [$Revision: 1.1.1.1 $] +boot: client IP address: 128.252.169.63 +boot: client name: vme147 +root addr=128.252.169.2 path=/export/root/vme147 +449744+20348+64444+[29268+29051]=0x90f0b +Start @ 0x88aa ... +Copyright (c) 1982, 1986, 1989, 1991, 1993 + The Regents of the University of California. All rights reserved. + +NetBSD 1.0A (VME147) #17: Sat Jul 1 00:07:04 CDT 1995 + chuck@vme147.ccrc.wustl.edu:/um/netbsd/src/sys/arch/mvme68k/compile/VME147 +Motorola MVME147 MC68030 CPU+MMU, ???MHz MC68882 FPU) +real mem = 8388608 +avail mem = 6832128 +using 102 buffers containing 417792 bytes of memory +mainbus0 (root) +iio0 at mainbus0 addr 0xfffe0000 +pcc0 at iio0 offset 0x1000 rev 0 intbvr 0x40 +clock0 at iio0 offset 0x7f8 ipl 5 +zs0 at iio0 offset 0x3000 ipl 4 +le0 at iio0 offset 0x1800 ipl 2 ler2 0x94000 address 08:00:3e:20:cb:87 +nfs_boot: using network interface 'le0' +nfs_boot: client_addr=0x80fca93f +nfs_boot: server_addr=0x80fca902 +nfs_boot: hostname=vme147 +root on dworkin:/export/root/vme147 +root time: 0x2ffc6859 +WARNING: clock gained 18 days -- CHECK AND RESET THE DATE! +swap on dworkin:/export/swap/vme147 +swap size: 0x4000 (blocks) +init: copying out path `/sbin/init' 11 +Automatic boot in progress: starting file system checks. +[etc...] + + +good luck! + diff --git a/sys/arch/mvme68k/compile/.keep_me b/sys/arch/mvme68k/compile/.keep_me new file mode 100644 index 0000000000000..aedb72a50a73c --- /dev/null +++ b/sys/arch/mvme68k/compile/.keep_me @@ -0,0 +1 @@ +This normally empty directory needs to be kept in the distribution. diff --git a/sys/arch/mvme68k/conf/Makefile.mvme68k b/sys/arch/mvme68k/conf/Makefile.mvme68k new file mode 100644 index 0000000000000..416148b2fbcb3 --- /dev/null +++ b/sys/arch/mvme68k/conf/Makefile.mvme68k @@ -0,0 +1,164 @@ +# $NetBSD: Makefile.mvme68k,v 1.1.1.1 1995/07/25 23:12:05 chuck Exp $ + +# @(#)Makefile.hp300 8.2 (Berkeley) 1/23/94 +# +# Makefile for NetBSD +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/arch/mvme68k/conf/``machineid'' +# after which you should do +# config.new machineid +# Machine generic makefile changes should be made in +# /sys/arch/mvme68k/conf/Makefile.mvme68k +# after which config should be rerun for all machines of that type. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE +# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING +# +# -DTRACE compile in kernel tracing hooks +# -DQUOTA compile in file system quotas + + +# DEBUG is set to -g by config if debugging is requested (config -g). +# PROF is set to -pg by config if profiling is requested (config -p). +AS= as ${DEBUG} +CC= cc ${DEBUG} +CPP= cpp +LD= ld +TOUCH= touch -f -c +AWK= awk + +# source tree is located via $S relative to the compilation directory +S= ../../../.. +MVME68K= ../.. + +INCLUDES= -I. -I$S/arch -I$S -I$S/sys +COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -Dmc68020 -Dmvme68k -DFPCOPROC +CFLAGS= -O ${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 + +### for the Motorola 68040 Floating Point Software Product +.include "$S/arch/m68k/fpsp/Makefile.inc" + +# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP} +# where TYPE is NORMAL, DRIVER, or PROFILE}; SUFFIX is the file suffix, +# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file +# is marked as config-dependent. + +NORMAL_C= ${CC} -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} $< + +PROFILE_C= ${CC} -S -c ${COPTS} $<; \ + sed -e s/_mcount/mcount/ -e s/subrmcount/subr_mcount/ <$*.s | \ + ${AS} -o $@; \ + rm -f $*.s + +NORMAL_S= ${CPP} ${COPTS} $< | ${AS} -o $@ +NORMAL_S_C= ${CPP} ${COPTS} ${PARAM} $< | ${AS} -o $@ + +%OBJS + +%CFILES + +# load lines for config "xxx" will be emitted as: +# xxx: ${SYSTEM_DEP} swapxxx.o +# ${SYSTEM_LD_HEAD} +# ${SYSTEM_LD} swapxxx.o +# ${SYSTEM_LD_TAIL} +DEBUG?= +.if ${DEBUG} == "-g" +LDX=-X +.else +LDX=-x +.endif +SYSTEM_OBJ= locore.o ${FPSP} vnode_if.o ${OBJS} param.o ioconf.o \ + ${LIBKERN} ${LIBCOMPAT} +SYSTEM_DEP= Makefile ${SYSTEM_OBJ} +SYSTEM_LD_HEAD= @echo loading $@; rm -f $@ +SYSTEM_LD= @${LD} ${LDX} -Ttext 0x8000 -n -o $@ -e start \ + ${SYSTEM_OBJ} vers.o +SYSTEM_LD_TAIL= @echo rearranging symbols; size $@; chmod 755 $@ + +%LOAD + +newvers: vers.o + +vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP} + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} -c vers.c + +clean:: + rm -f eddep *netbsd netbsd.gdb tags vnode_if.[ch] *.o locore.i \ + [a-z]*.s [Ee]rrs linterrs makelinks genassym + +lint: /tmp param.c + @lint -hbxn -DGENERIC -Dvolatile= ${COPTS} ${PARAM} -UKGDB \ + ${MVME68K}/mvme68k/Locore.c ${CFILES} ${MVME68K}/mvme68k/swapgeneric.c \ + ioconf.c param.c | \ + grep -v 'struct/union .* never defined' | \ + grep -v 'possible pointer alignment problem' + +locore.o: assym.s ${MVME68K}/mvme68k/vectors.s ${MVME68K}/mvme68k/locore.s +locore.o: ${MVME68K}/include/trap.h ${MVME68K}/include/psl.h ${MVME68K}/include/pte.h +locore.o: ${MVME68K}/include/cpu.h + ${CPP} -DLOCORE ${COPTS} ${MVME68K}/mvme68k/locore.s | ${AS} -o locore.o + +# depend on maxusers +assym.s: Makefile + +assym.s: genassym + ./genassym > assym.s + +genassym: ${MVME68K}/mvme68k/genassym.c Makefile + cc ${INCLUDES} ${IDENT} ${PARAM} -Dmc68020 -Dmvme68k -o genassym \ + ${MVME68K}/mvme68k/genassym.c + +depend: assym.s param.c vnode_if.h + mkdep ${COPTS} ${CFILES} ioconf.c param.c + mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${MVME68K}/mvme68k/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 + ${CC} -c ${CFLAGS} ioconf.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 + +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/mvme68k/conf/VME147 b/sys/arch/mvme68k/conf/VME147 new file mode 100644 index 0000000000000..97498fff5baef --- /dev/null +++ b/sys/arch/mvme68k/conf/VME147 @@ -0,0 +1,51 @@ +# $NetBSD: VME147,v 1.1.1.1 1995/07/25 23:12:05 chuck Exp $ + +machine mvme68k m68k + +options "M68040" # support for 040 +options FPSP # MC68040 floating point support +options "M68030" # support for 030 +options FPCOPROC # Support for MC6888[12] (Required) + +maxusers 2 + +# obsolete timezone spec +options TIMEZONE=0, DST=0 + +options DIAGNOSTIC, DEBUG +#options FFS +options NFSCLIENT +#options NFSSERVER +#options SYSVSHM +options KTRACE +options COMPAT_43 +options FIFO +#options MFS +options DEVPAGER, SWAPPAGER, VNODEPAGER +#options MSDOSFS + +# Networking options +options INET +options TCP_COMPAT_42 # compatibility with 4.2BSD TCP/IP +#options GATEWAY # IP packet forwarding +#options ISO # OSI networking +#options TPIP +#options EON +options COMPAT_09, COMPAT_10 +options COMPAT_SUNOS + +config netbsd root on nfs swap on nfs + +pseudo-device sl +pseudo-device ppp 2 +pseudo-device loop +pseudo-device bpfilter +pseudo-device pty + +mainbus0 at root +iio0 at mainbus0 + +pcc0 at iio0 offset 0x1000 +zs0 at iio0 offset 0x3000 ipl 4 +clock0 at iio0 offset 0x07f8 ipl 5 +le0 at iio0 offset 0x1800 ipl 2 diff --git a/sys/arch/mvme68k/conf/files.mvme68k b/sys/arch/mvme68k/conf/files.mvme68k new file mode 100644 index 0000000000000..9c6e6ce97bddc --- /dev/null +++ b/sys/arch/mvme68k/conf/files.mvme68k @@ -0,0 +1,49 @@ +# $NetBSD: files.mvme68k,v 1.1.1.1 1995/07/25 23:12:05 chuck Exp $ + +# config file for mvme68k + +# maxpartitions must be first item in files.${ARCH}.newconf +maxpartitions 8 + +device mainbus at root { } + +device iio at mainbus { offset = -1, [ ipl = 0 ] } +file arch/mvme68k/dev/iio.c iio + +device clock at iio +file arch/mvme68k/mvme68k/clock.c clock + +device zs at iio: tty +file arch/mvme68k/dev/zs.c zs needs-count + +device pcc at iio +file arch/mvme68k/dev/pcc.c pcc + +device le at iio: ifnet, ether +file arch/mvme68k/dev/if_le.c le + +include "../../../scsi/files.scsi" + +major { sd = 7 } +major { cd = 18 } +major { vnd = 6 } + +file arch/mvme68k/mvme68k/autoconf.c +file arch/mvme68k/mvme68k/conf.c +file arch/mvme68k/mvme68k/disksubr.c +file arch/mvme68k/mvme68k/dkbad.c +file arch/mvme68k/mvme68k/machdep.c config-dependent +file arch/mvme68k/mvme68k/mem.c +file arch/mvme68k/mvme68k/pmap.c +file arch/mvme68k/mvme68k/pmap_bootstrap.c +file arch/mvme68k/mvme68k/sys_machdep.c +file arch/mvme68k/mvme68k/trap.c +file arch/mvme68k/mvme68k/vm_machdep.c +file arch/m68k/m68k/copy.s +file dev/cons.c +file dev/cninit.c + +# SunOS Binary Compatibility (COMPAT_SUNOS) +include "../../../compat/sunos/files.sunos" +file arch/m68k/m68k/sunos_machdep.c compat_sunos + diff --git a/sys/arch/mvme68k/dev/if_le.c b/sys/arch/mvme68k/dev/if_le.c new file mode 100644 index 0000000000000..cd7fe4403043b --- /dev/null +++ b/sys/arch/mvme68k/dev/if_le.c @@ -0,0 +1,965 @@ +/* $NetBSD: if_le.c,v 1.1.1.1 1995/07/25 23:12:09 chuck Exp $ */ + +/*- + * Copyright (c) 1982, 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. + * + * @(#)if_le.c 8.2 (Berkeley) 10/30/93 + */ + +#include "bpfilter.h" + +/* + * AMD 7990 LANCE + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#if NBPFILTER > 0 +#include +#include +#include +#endif + +#ifdef INET +#include +#include +#include +#include +#include +#endif + +#ifdef NS +#include +#include +#endif + +#ifdef APPLETALK +#include +#endif + +#include +#include + +#include +#include +#include + +/* DVMA address to LANCE address -- the Sbus/MMU will resupply the 0xff */ +#define LANCE_ADDR(x) ((int)x) + +int ledebug = 0; /* console error messages */ + +#ifdef PACKETSTATS +long lexpacketsizes[LEMTU+1]; +long lerpacketsizes[LEMTU+1]; +#endif + +/* Per interface statistics */ +/* XXX this should go in something like if_levar.h */ +struct lestats { + long lexints; /* transmitter interrupts */ + long lerints; /* receiver interrupts */ + long lerbufs; /* total buffers received during interrupts */ + long lerhits; /* times current rbuf was full */ + long lerscans; /* rbufs scanned before finding first full */ +}; + +/* + * Ethernet software status per interface. + * + * Each interface is referenced by a network interface structure, + * le_if, which the routing code uses to locate the interface. + * This structure contains the output queue for the interface, its address, ... + */ +struct le_softc { + struct device sc_dev; /* base device */ + struct evcnt sc_intrcnt; /* # of interrupts, per le */ + struct evcnt sc_errcnt; /* # of errors, per le */ + + struct arpcom sc_ac; /* common Ethernet structures */ +#define sc_if sc_ac.ac_if /* network-visible interface */ +#define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ + struct lereg1 *sc_r1; /* LANCE registers */ + struct lereg2 *sc_r2; /* dual-port RAM */ + int sc_rmd; /* predicted next rmd to process */ + int sc_runt; + int sc_jab; + int sc_merr; + int sc_babl; + int sc_cerr; + int sc_miss; + int sc_xint; + int sc_xown; + int sc_uflo; + int sc_rxlen; + int sc_rxoff; + int sc_txoff; + int sc_busy; + short sc_iflags; + struct lestats sc_lestats; /* per interface statistics */ +}; + + +/* autoconfiguration driver */ +void leattach(struct device *, struct device *, void *); +int lematch(struct device *, void *, void *); +struct cfdriver lecd = + { NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc) }; + +/* Forwards */ +void leattach(struct device *, struct device *, void *); +void lesetladrf(struct le_softc *); +void lereset(struct device *); +int leinit(int); +void lestart(struct ifnet *); +int leintr(void *); +void lexint(struct le_softc *); +void lerint(struct le_softc *); +void leread(struct le_softc *, char *, int); +int leput(char *, struct mbuf *); +struct mbuf *leget(char *, int, int, struct ifnet *); +int leioctl(struct ifnet *, u_long, caddr_t); +void leerror(struct le_softc *, int); +void lererror(struct le_softc *, char *); +void lexerror(struct le_softc *); + +void *ledatabuf; /* XXXCDC hack from pmap bootstrap */ + +int +lematch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct iioargs *ia = args; + + return !badbaddr((caddr_t) IIO_CFLOC_ADDR(cf)); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +void +leattach(parent, self, args) + struct device *parent; + struct device *self; + void *args; +{ + register struct le_softc *sc = (struct le_softc *)self; + register struct lereg2 *ler2; + struct ifnet *ifp = &sc->sc_if; + register int a; + int pri = IIO_CFLOC_LEVEL(self->dv_cfdata); + + /* XXX the following declarations should be elsewhere */ + extern void myetheraddr(u_char *); + + iio_print(self->dv_cfdata); + + /* connect the interrupt */ + pccintr_establish(PCCV_LE, leintr, pri, sc); + + sc->sc_r1 = (struct lereg1 *) IIO_CFLOC_ADDR(self->dv_cfdata); + + + ler2 = sc->sc_r2 = (struct lereg2 *) ledatabuf; + + myetheraddr(sc->sc_addr); + printf(" ler2 0x%x address %s\n", ler2, ether_sprintf(sc->sc_addr)); + + /* + * Setup for transmit/receive + * + * According to Van, some versions of the Lance only use this + * address to receive packets; it doesn't put them in + * output packets. We'll want to make sure that lestart() + * installs the address. + */ + ler2->ler2_padr[0] = sc->sc_addr[1]; + ler2->ler2_padr[1] = sc->sc_addr[0]; + ler2->ler2_padr[2] = sc->sc_addr[3]; + ler2->ler2_padr[3] = sc->sc_addr[2]; + ler2->ler2_padr[4] = sc->sc_addr[5]; + ler2->ler2_padr[5] = sc->sc_addr[4]; + a = LANCE_ADDR(&ler2->ler2_rmd); + ler2->ler2_rlen = LE_RLEN | (a >> 16); + ler2->ler2_rdra = a; + a = LANCE_ADDR(&ler2->ler2_tmd); + ler2->ler2_tlen = LE_TLEN | (a >> 16); + ler2->ler2_tdra = a; + + /* + * Set up event counters. + */ + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); + evcnt_attach(&sc->sc_dev, "errs", &sc->sc_errcnt); + + ifp->if_unit = sc->sc_dev.dv_unit; + ifp->if_name = "le"; + ifp->if_ioctl = leioctl; + ifp->if_start = lestart; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; +#ifdef IFF_NOTRAILERS + /* XXX still compile when the blasted things are gone... */ + ifp->if_flags |= IFF_NOTRAILERS; +#endif +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + if_attach(ifp); + ether_ifattach(ifp); + sys_pcc->le_int = pri | PCC_IENABLE; + +} + +/* + * Setup the logical address filter + */ +void +lesetladrf(sc) + register struct le_softc *sc; +{ + register struct lereg2 *ler2 = sc->sc_r2; + register struct ifnet *ifp = &sc->sc_if; + register struct ether_multi *enm; + register u_char *cp, c; + register u_long crc; + register int i, len; + struct ether_multistep step; + + /* + * Set up multicast address filter by passing all multicast + * addresses through a crc generator, and then using the high + * order 6 bits as a index into the 64 bit logical address + * filter. The high order two bits select the word, while the + * rest of the bits select the bit within the word. + */ + + ler2->ler2_ladrf[0] = 0; + ler2->ler2_ladrf[1] = 0; + ler2->ler2_ladrf[2] = 0; + ler2->ler2_ladrf[3] = 0; + ifp->if_flags &= ~IFF_ALLMULTI; + ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); + while (enm != NULL) { + if (bcmp((caddr_t)&enm->enm_addrlo, + (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) != 0) { + /* + * We must listen to a range of multicast + * addresses. For now, just accept all + * multicasts, rather than trying to set only + * those filter bits needed to match the range. + * (At this time, the only use of address + * ranges is for IP multicast routing, for + * which the range is big enough to require all + * bits set.) + */ + ler2->ler2_ladrf[0] = 0xffff; + ler2->ler2_ladrf[1] = 0xffff; + ler2->ler2_ladrf[2] = 0xffff; + ler2->ler2_ladrf[3] = 0xffff; + ifp->if_flags |= IFF_ALLMULTI; + return; + } + + /* + * One would think, given the AM7990 document's polynomial + * of 0x04c11db6, that this should be 0x6db88320 (the bit + * reversal of the AMD value), but that is not right. See + * the BASIC listing: bit 0 (our bit 31) must then be set. + */ + cp = (unsigned char *)&enm->enm_addrlo; + crc = 0xffffffff; + for (len = 6; --len >= 0;) { + c = *cp++; + for (i = 0; i < 8; i++) { + if ((c & 0x01) ^ (crc & 0x01)) { + crc >>= 1; + crc = crc ^ 0xedb88320; + } else + crc >>= 1; + c >>= 1; + } + } + /* Just want the 6 most significant bits. */ + crc = crc >> 26; + + /* Turn on the corresponding bit in the filter. */ + ler2->ler2_ladrf[crc >> 4] |= 1 << (crc & 0xf); + + ETHER_NEXT_MULTI(step, enm); + } +} + +void +lereset(dev) + struct device *dev; +{ + register struct le_softc *sc = (struct le_softc *)dev; + register struct lereg1 *ler1 = sc->sc_r1; + register struct lereg2 *ler2 = sc->sc_r2; + register int i, a, timo, stat; + +#if NBPFILTER > 0 + if (sc->sc_if.if_flags & IFF_PROMISC) + ler2->ler2_mode = LE_MODE_NORMAL | LE_MODE_PROM; + else +#endif + ler2->ler2_mode = LE_MODE_NORMAL; + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STOP; + + /* Setup the logical address filter */ + lesetladrf(sc); + + /* init receive and transmit rings */ + for (i = 0; i < LERBUF; i++) { + a = LANCE_ADDR(&ler2->ler2_rbuf[i][0]); + ler2->ler2_rmd[i].rmd0 = a; + ler2->ler2_rmd[i].rmd1_hadr = a >> 16; + ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; + ler2->ler2_rmd[i].rmd2 = -LEMTU | LE_XMD2_ONES; + ler2->ler2_rmd[i].rmd3 = 0; + } + for (i = 0; i < LETBUF; i++) { + a = LANCE_ADDR(&ler2->ler2_tbuf[i][0]); + ler2->ler2_tmd[i].tmd0 = a; + ler2->ler2_tmd[i].tmd1_hadr = a >> 16; + ler2->ler2_tmd[i].tmd1_bits = 0; + ler2->ler2_tmd[i].tmd2 = LE_XMD2_ONES; + ler2->ler2_tmd[i].tmd3 = 0; + } + +bzero((void *)&ler2->ler2_rbuf[0][0], (LERBUF + LETBUF) * LEMTU); + /* lance will stuff packet into receive buffer 0 next */ + sc->sc_rmd = 0; + + /* tell the chip where to find the initialization block */ + a = LANCE_ADDR(&ler2->ler2_mode); + ler1->ler1_rap = LE_CSR1; + ler1->ler1_rdp = a; + ler1->ler1_rap = LE_CSR2; + ler1->ler1_rdp = a >> 16; + ler1->ler1_rap = LE_CSR3; + ler1->ler1_rdp = LE_C3_BSWP /*| LE_C3_ACON | LE_C3_BCON*/; + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_INIT; + timo = 100000; + while (((stat = ler1->ler1_rdp) & (LE_C0_ERR | LE_C0_IDON)) == 0) { + if (--timo == 0) { + printf("%s: init timeout, stat=%b\n", + sc->sc_dev.dv_xname, stat, LE_C0_BITS); + break; + } + } + if (stat & LE_C0_ERR) + printf("%s: init failed, ler1=0x%x, stat=%b\n", + sc->sc_dev.dv_xname, ler1, stat, LE_C0_BITS); + else + ler1->ler1_rdp = LE_C0_IDON; /* clear IDON */ + ler1->ler1_rdp = LE_C0_STRT | LE_C0_INEA; + sc->sc_if.if_flags &= ~IFF_OACTIVE; +} + +/* + * Initialization of interface + */ +int +leinit(unit) + int unit; +{ + register struct le_softc *sc = lecd.cd_devs[unit]; + register struct ifnet *ifp = &sc->sc_if; + register int s; + + if ((ifp->if_flags & IFF_RUNNING) == 0) { + s = splimp(); + ifp->if_flags |= IFF_RUNNING; + lereset(&sc->sc_dev); + lestart(ifp); + splx(s); + } + return (0); +} + +/* + * Start output on interface. Get another datagram to send + * off of the interface queue, and copy it to the interface + * before starting the output. + */ +void +lestart(ifp) + register struct ifnet *ifp; +{ + register struct le_softc *sc = lecd.cd_devs[ifp->if_unit]; + register struct letmd *tmd; + register struct mbuf *m; + register int len; + if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) + return; + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if (m == 0) + return; + + len = leput((char *)sc->sc_r2->ler2_tbuf[0], m); + +#if NBPFILTER > 0 + /* + * If bpf is listening on this interface, let it + * see the packet before we commit it to the wire. + */ + if (sc->sc_if.if_bpf) + bpf_tap(sc->sc_if.if_bpf, (char *)sc->sc_r2->ler2_tbuf[0], len); +#endif + +#ifdef PACKETSTATS + if (len <= LEMTU) + lexpacketsizes[len]++; +#endif + tmd = sc->sc_r2->ler2_tmd; + tmd->tmd3 = 0; + tmd->tmd2 = -len | LE_XMD2_ONES; + tmd->tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; + sc->sc_if.if_flags |= IFF_OACTIVE; + return; +} + +int +leintr(dev) + register void *dev; +{ + register struct le_softc *sc = dev; + register struct lereg1 *ler1 = sc->sc_r1; + register int csr0; + + csr0 = ler1->ler1_rdp; + if ((csr0 & LE_C0_INTR) == 0) + return (0); + sc->sc_intrcnt.ev_count++; + + if (csr0 & LE_C0_ERR) { + sc->sc_errcnt.ev_count++; + leerror(sc, csr0); + if (csr0 & LE_C0_MERR) { + sc->sc_merr++; + lereset(&sc->sc_dev); + return (1); + } + if (csr0 & LE_C0_BABL) + sc->sc_babl++; + if (csr0 & LE_C0_CERR) + sc->sc_cerr++; + if (csr0 & LE_C0_MISS) + sc->sc_miss++; + ler1->ler1_rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_INEA; + } + if ((csr0 & LE_C0_RXON) == 0) { + sc->sc_rxoff++; + lereset(&sc->sc_dev); + return (1); + } + if ((csr0 & LE_C0_TXON) == 0) { + sc->sc_txoff++; + lereset(&sc->sc_dev); + return (1); + } + if (csr0 & LE_C0_RINT) { + /* interrupt is cleared in lerint */ + lerint(sc); + } + if (csr0 & LE_C0_TINT) { + ler1->ler1_rdp = LE_C0_TINT|LE_C0_INEA; + lexint(sc); + } + return (1); +} + +/* + * Ethernet interface transmitter interrupt. + * Start another output if more data to send. + */ +void +lexint(sc) + register struct le_softc *sc; +{ + register struct letmd *tmd = sc->sc_r2->ler2_tmd; + + sc->sc_lestats.lexints++; + if ((sc->sc_if.if_flags & IFF_OACTIVE) == 0) { + sc->sc_xint++; + return; + } + if (tmd->tmd1_bits & LE_T1_OWN) { + sc->sc_xown++; + return; + } + if (tmd->tmd1_bits & LE_T1_ERR) { +err: + lexerror(sc); + sc->sc_if.if_oerrors++; + if (tmd->tmd3 & (LE_T3_BUFF|LE_T3_UFLO)) { + sc->sc_uflo++; + lereset(&sc->sc_dev); + } else if (tmd->tmd3 & LE_T3_LCOL) + sc->sc_if.if_collisions++; + else if (tmd->tmd3 & LE_T3_RTRY) + sc->sc_if.if_collisions += 16; + } + else if (tmd->tmd3 & LE_T3_BUFF) + /* XXX documentation says BUFF not included in ERR */ + goto err; + else if (tmd->tmd1_bits & LE_T1_ONE) + sc->sc_if.if_collisions++; + else if (tmd->tmd1_bits & LE_T1_MORE) + /* what is the real number? */ + sc->sc_if.if_collisions += 2; + else + sc->sc_if.if_opackets++; + sc->sc_if.if_flags &= ~IFF_OACTIVE; + lestart(&sc->sc_if); +} + +#define LENEXTRMP \ + if (++bix == LERBUF) bix = 0, rmd = sc->sc_r2->ler2_rmd; else ++rmd + +/* + * Ethernet interface receiver interrupt. + * If input error just drop packet. + * Decapsulate packet based on type and pass to type specific + * higher-level input routine. + */ +void +lerint(sc) + register struct le_softc *sc; +{ + register int bix = sc->sc_rmd; + register struct lermd *rmd = &sc->sc_r2->ler2_rmd[bix]; + + sc->sc_lestats.lerints++; + /* + * Out of sync with hardware, should never happen? + */ + if (rmd->rmd1_bits & LE_R1_OWN) { + do { + sc->sc_lestats.lerscans++; + LENEXTRMP; + } while ((rmd->rmd1_bits & LE_R1_OWN) && bix != sc->sc_rmd); + if (bix == sc->sc_rmd) + printf("%s: RINT with no buffer\n", + sc->sc_dev.dv_xname); + } else + sc->sc_lestats.lerhits++; + + /* + * Process all buffers with valid data + */ + while ((rmd->rmd1_bits & LE_R1_OWN) == 0) { + int len = rmd->rmd3; + + /* Clear interrupt to avoid race condition */ + sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA; + + if (rmd->rmd1_bits & LE_R1_ERR) { + sc->sc_rmd = bix; + lererror(sc, "bad packet"); + sc->sc_if.if_ierrors++; + } else if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != + (LE_R1_STP|LE_R1_ENP)) { + /* XXX make a define for LE_R1_STP|LE_R1_ENP? */ + /* + * Find the end of the packet so we can see how long + * it was. We still throw it away. + */ + do { + sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA; + rmd->rmd3 = 0; + rmd->rmd1_bits = LE_R1_OWN; + LENEXTRMP; + } while (!(rmd->rmd1_bits & + (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP))); + sc->sc_rmd = bix; + lererror(sc, "chained buffer"); + sc->sc_rxlen++; + /* + * If search terminated without successful completion + * we reset the hardware (conservative). + */ + if ((rmd->rmd1_bits & + (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP)) != + LE_R1_ENP) { + lereset(&sc->sc_dev); + return; + } + } else { + leread(sc, (char *)sc->sc_r2->ler2_rbuf[bix], len); +#ifdef PACKETSTATS + lerpacketsizes[len]++; +#endif + sc->sc_lestats.lerbufs++; + } + rmd->rmd3 = 0; + rmd->rmd1_bits = LE_R1_OWN; + LENEXTRMP; + } + sc->sc_rmd = bix; +} + +void +leread(sc, pkt, len) + register struct le_softc *sc; + char *pkt; + int len; +{ + register struct ether_header *et; + register struct ifnet *ifp = &sc->sc_if; + struct mbuf *m; + struct ifqueue *inq; + int flags; + + ifp->if_ipackets++; + et = (struct ether_header *)pkt; + et->ether_type = ntohs((u_short)et->ether_type); + /* adjust input length to account for header and CRC */ + len -= sizeof(struct ether_header) + 4; + + if (len <= 0) { + if (ledebug) + log(LOG_WARNING, + "%s: ierror(runt packet): from %s: len=%d\n", + sc->sc_dev.dv_xname, + ether_sprintf(et->ether_shost), len); + sc->sc_runt++; + ifp->if_ierrors++; + return; + } + + /* Setup mbuf flags we'll need later */ + flags = 0; + if (bcmp((caddr_t)etherbroadcastaddr, + (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0) + flags |= M_BCAST; + if (et->ether_dhost[0] & 1) + flags |= M_MCAST; + +#if NBPFILTER > 0 + /* + * Check if there's a bpf filter listening on this interface. + * If so, hand off the raw packet to enet, then discard things + * not destined for us (but be sure to keep broadcast/multicast). + */ + if (sc->sc_if.if_bpf) { + bpf_tap(sc->sc_if.if_bpf, pkt, + len + sizeof(struct ether_header)); + if ((flags & (M_BCAST | M_MCAST)) == 0 && + bcmp(et->ether_dhost, sc->sc_addr, + sizeof(et->ether_dhost)) != 0) + return; + } +#endif + m = leget(pkt, len, 0, ifp); + if (m == 0) + return; + ether_input(ifp, et, m); +} + +/* + * Routine to copy from mbuf chain to transmit + * buffer in board local memory. + * + * ### this can be done by remapping in some cases + */ +int +leput(lebuf, m) + register char *lebuf; + register struct mbuf *m; +{ + register struct mbuf *mp; + register int len, tlen = 0; + + for (mp = m; mp; mp = mp->m_next) { + len = mp->m_len; + if (len == 0) + continue; + tlen += len; + bcopy(mtod(mp, char *), lebuf, len); + lebuf += len; + } + m_freem(m); + if (tlen < LEMINSIZE) { + bzero(lebuf, LEMINSIZE - tlen); + tlen = LEMINSIZE; + } + return (tlen); +} + +/* + * Routine to copy from board local memory into mbufs. + */ +struct mbuf * +leget(lebuf, totlen, off0, ifp) + char *lebuf; + int totlen, off0; + struct ifnet *ifp; +{ + register struct mbuf *m; + struct mbuf *top = 0, **mp = ⊤ + register int off = off0, len; + register char *cp; + char *epkt; + + lebuf += sizeof(struct ether_header); + cp = lebuf; + epkt = cp + totlen; + if (off) { + cp += off + 2 * sizeof(u_short); + totlen -= 2 * sizeof(u_short); + } + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = totlen; + m->m_len = MHLEN; + + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + m->m_len = MLEN; + } + len = min(totlen, epkt - cp); + if (len >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = len = min(len, MCLBYTES); + else + len = m->m_len; + } else { + /* + * Place initial small packet/header at end of mbuf. + */ + if (len < m->m_len) { + if (top == 0 && len + max_linkhdr <= m->m_len) + m->m_data += max_linkhdr; + m->m_len = len; + } else + len = m->m_len; + } + bcopy(cp, mtod(m, caddr_t), (unsigned)len); + cp += len; + *mp = m; + mp = &m->m_next; + totlen -= len; + if (cp == epkt) + cp = lebuf; + } + return (top); +} + +/* + * Process an ioctl request. + */ +int +leioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + register struct ifaddr *ifa; + register struct le_softc *sc = lecd.cd_devs[ifp->if_unit]; + register struct lereg1 *ler1; + int s = splimp(), error = 0; + + switch (cmd) { + + case SIOCSIFADDR: + ifa = (struct ifaddr *)data; + ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + (void)leinit(ifp->if_unit); + arp_ifinit(&sc->sc_ac, ifa); + break; +#endif +#ifdef NS + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + + if (ns_nullhost(*ina)) + ina->x_host = *(union ns_host *)(sc->sc_addr); + else { + /* + * The manual says we can't change the address + * while the receiver is armed, + * so reset everything + */ + ifp->if_flags &= ~IFF_RUNNING; + bcopy((caddr_t)ina->x_host.c_host, + (caddr_t)sc->sc_addr, sizeof(sc->sc_addr)); + } + (void)leinit(ifp->if_unit); /* does le_setaddr() */ + break; + } +#endif + default: + (void)leinit(ifp->if_unit); + break; + } + break; + + case SIOCSIFFLAGS: + ler1 = sc->sc_r1; + if ((ifp->if_flags & IFF_UP) == 0 && + ifp->if_flags & IFF_RUNNING) { + ler1->ler1_rdp = LE_C0_STOP; + ifp->if_flags &= ~IFF_RUNNING; + } else if (ifp->if_flags & IFF_UP && + (ifp->if_flags & IFF_RUNNING) == 0) + (void)leinit(ifp->if_unit); + /* + * If the state of the promiscuous bit changes, the interface + * must be reset to effect the change. + */ + if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) && + (ifp->if_flags & IFF_RUNNING)) { + sc->sc_iflags = ifp->if_flags; + lereset(&sc->sc_dev); + lestart(ifp); + } + break; + + case SIOCADDMULTI: + error = ether_addmulti((struct ifreq *)data, &sc->sc_ac); + goto update_multicast; + + case SIOCDELMULTI: + error = ether_delmulti((struct ifreq *)data, &sc->sc_ac); + update_multicast: + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware + * filter accordingly. + */ + lereset(&sc->sc_dev); + error = 0; + } + break; + + default: + error = EINVAL; + } + splx(s); + return (error); +} + +void +leerror(sc, stat) + register struct le_softc *sc; + int stat; +{ + if (!ledebug) + return; + + /* + * Not all transceivers implement heartbeat + * so we only log CERR once. + */ + if ((stat & LE_C0_CERR) && sc->sc_cerr) + return; + log(LOG_WARNING, "%s: error: stat=%b\n", + sc->sc_dev.dv_xname, stat, LE_C0_BITS); +} + +void +lererror(sc, msg) + register struct le_softc *sc; + char *msg; +{ + register struct lermd *rmd; + int len; + + if (!ledebug) + return; + + rmd = &sc->sc_r2->ler2_rmd[sc->sc_rmd]; + len = rmd->rmd3; + log(LOG_WARNING, "%s: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", + sc->sc_dev.dv_xname, msg, len > 11 ? + ether_sprintf((u_char *)&sc->sc_r2->ler2_rbuf[sc->sc_rmd][6]) : + "unknown", + sc->sc_rmd, len, rmd->rmd1_bits, LE_R1_BITS); +} + +void +lexerror(sc) + register struct le_softc *sc; +{ + register struct letmd *tmd; + register int len, tmd3, tdr; + + if (!ledebug) + return; + + tmd = sc->sc_r2->ler2_tmd; + tmd3 = tmd->tmd3; + tdr = tmd3 & LE_T3_TDR_MASK; + len = -(tmd->tmd2 & ~LE_XMD2_ONES); + log(LOG_WARNING, + "%s: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b, tdr=%d (%d nsecs)\n", + sc->sc_dev.dv_xname, len > 5 ? + ether_sprintf((u_char *)&sc->sc_r2->ler2_tbuf[0][0]) : "unknown", + 0, len, + tmd->tmd1_bits, LE_T1_BITS, + tmd3, LE_T3_BITS, tdr, tdr * 100); +} diff --git a/sys/arch/mvme68k/dev/if_lereg.h b/sys/arch/mvme68k/dev/if_lereg.h new file mode 100644 index 0000000000000..6e80247096652 --- /dev/null +++ b/sys/arch/mvme68k/dev/if_lereg.h @@ -0,0 +1,167 @@ +/* $NetBSD: if_lereg.h,v 1.1.1.1 1995/07/25 23:12:10 chuck Exp $ */ + +/*- + * Copyright (c) 1982, 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. + * + * @(#)if_lereg.h 8.2 (Berkeley) 10/30/93 + */ + +#define LEMTU 1518 +#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */ +#define LERBUF 8 +#define LERBUFLOG2 3 +#define LE_RLEN (LERBUFLOG2 << 13) +#define LETBUF 1 +#define LETBUFLOG2 0 +#define LE_TLEN (LETBUFLOG2 << 13) + +/* Local Area Network Controller for Ethernet (LANCE) registers */ +struct lereg1 { + volatile u_short ler1_rdp; /* register data port */ + volatile u_short ler1_rap; /* register address port */ +}; + +/* register addresses */ +#define LE_CSR0 0 /* Control and status register */ +#define LE_CSR1 1 /* low address of init block */ +#define LE_CSR2 2 /* high address of init block */ +#define LE_CSR3 3 /* Bus master and control */ + +/* Control and status register 0 (csr0) */ +#define LE_C0_ERR 0x8000 /* error summary */ +#define LE_C0_BABL 0x4000 /* transmitter timeout error */ +#define LE_C0_CERR 0x2000 /* collision */ +#define LE_C0_MISS 0x1000 /* missed a packet */ +#define LE_C0_MERR 0x0800 /* memory error */ +#define LE_C0_RINT 0x0400 /* receiver interrupt */ +#define LE_C0_TINT 0x0200 /* transmitter interrupt */ +#define LE_C0_IDON 0x0100 /* initalization done */ +#define LE_C0_INTR 0x0080 /* interrupt condition */ +#define LE_C0_INEA 0x0040 /* interrupt enable */ +#define LE_C0_RXON 0x0020 /* receiver on */ +#define LE_C0_TXON 0x0010 /* transmitter on */ +#define LE_C0_TDMD 0x0008 /* transmit demand */ +#define LE_C0_STOP 0x0004 /* disable all external activity */ +#define LE_C0_STRT 0x0002 /* enable external activity */ +#define LE_C0_INIT 0x0001 /* begin initalization */ + +#define LE_C0_BITS \ + "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\ +\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT" + +/* Control and status register 3 (csr3) */ +#define LE_C3_BSWP 0x4 /* byte swap */ +#define LE_C3_ACON 0x2 /* ALE control, eh? */ +#define LE_C3_BCON 0x1 /* byte control */ +/* + * Current size is 13,758 bytes with 8 x 1518 receive buffers and + * 1 x 1518 transmit buffer. + */ +struct lereg2 { + /* initialization block */ + volatile u_short ler2_mode; /* mode */ + volatile u_char ler2_padr[6]; /* physical address */ + volatile u_short ler2_ladrf[4]; /* logical address filter */ + volatile u_short ler2_rdra; /* receive descriptor addr */ + volatile u_short ler2_rlen; /* rda high and ring size */ + volatile u_short ler2_tdra; /* transmit descriptor addr */ + volatile u_short ler2_tlen; /* tda high and ring size */ + /* receive message descriptors. bits/hadr are byte order dependent. */ + struct lermd { + volatile u_short rmd0; /* low address of packet */ + volatile u_char rmd1_bits; /* descriptor bits */ + volatile u_char rmd1_hadr; /* high address of packet */ + volatile short rmd2; /* buffer byte count */ + volatile u_short rmd3; /* message byte count */ + } ler2_rmd[LERBUF]; + /* transmit message descriptors */ + struct letmd { + volatile u_short tmd0; /* low address of packet */ + volatile u_char tmd1_bits; /* descriptor bits */ + volatile u_char tmd1_hadr; /* high address of packet */ + volatile short tmd2; /* buffer byte count */ + volatile u_short tmd3; /* transmit error bits */ + } ler2_tmd[LETBUF]; + volatile char ler2_rbuf[LERBUF][LEMTU]; + volatile char ler2_tbuf[LETBUF][LEMTU]; +}; + +/* Initialzation block (mode) */ +#define LE_MODE_PROM 0x8000 /* promiscuous mode */ +/* 0x7f80 reserved, must be zero */ +#define LE_MODE_INTL 0x0040 /* internal loopback */ +#define LE_MODE_DRTY 0x0020 /* disable retry */ +#define LE_MODE_COLL 0x0010 /* force a collision */ +#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */ +#define LE_MODE_LOOP 0x0004 /* loopback mode */ +#define LE_MODE_DTX 0x0002 /* disable transmitter */ +#define LE_MODE_DRX 0x0001 /* disable receiver */ +#define LE_MODE_NORMAL 0 /* none of the above */ + + +/* Receive message descriptor 1 (rmd1_bits) */ +#define LE_R1_OWN 0x80 /* LANCE owns the packet */ +#define LE_R1_ERR 0x40 /* error summary */ +#define LE_R1_FRAM 0x20 /* framing error */ +#define LE_R1_OFLO 0x10 /* overflow error */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUFF 0x04 /* buffer error */ +#define LE_R1_STP 0x02 /* start of packet */ +#define LE_R1_ENP 0x01 /* end of packet */ + +#define LE_R1_BITS \ + "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP" + +/* Transmit message descriptor 1 (tmd1_bits) */ +#define LE_T1_OWN 0x80 /* LANCE owns the packet */ +#define LE_T1_ERR 0x40 /* error summary */ +#define LE_T1_MORE 0x10 /* multiple collisions */ +#define LE_T1_ONE 0x08 /* single collision */ +#define LE_T1_DEF 0x04 /* defferred transmit */ +#define LE_T1_STP 0x02 /* start of packet */ +#define LE_T1_ENP 0x01 /* end of packet */ + +#define LE_T1_BITS \ + "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP" + +/* Transmit message descriptor 3 (tmd3) */ +#define LE_T3_BUFF 0x8000 /* buffer error */ +#define LE_T3_UFLO 0x4000 /* underflow error */ +#define LE_T3_LCOL 0x1000 /* late collision */ +#define LE_T3_LCAR 0x0800 /* loss of carrier */ +#define LE_T3_RTRY 0x0400 /* retry error */ +#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */ + +#define LE_XMD2_ONES 0xf000 + +#define LE_T3_BITS \ + "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY" diff --git a/sys/arch/mvme68k/dev/iio.c b/sys/arch/mvme68k/dev/iio.c new file mode 100644 index 0000000000000..d02c96b3e6c18 --- /dev/null +++ b/sys/arch/mvme68k/dev/iio.c @@ -0,0 +1,114 @@ +/* $Id: iio.c,v 1.1.1.1 1995/07/25 23:12:10 chuck Exp $ */ + +/* + * + * Copyright (c) 1995 Charles D. Cranor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor. + * 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. + */ + +/* + * peripheral channel controller + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Configuration routines for the internal I/O bus + */ +void iioattach __P((struct device *, struct device *, void *)); +int iiomatch __P((struct device *, void *, void *)); + +struct iiosoftc { + struct device sc_dev; +}; + +struct cfdriver iiocd = { + NULL, "iio", iiomatch, iioattach, + DV_DULL, sizeof(struct iiosoftc), 0 +}; + +int +iiomatch(parent, cf, args) + struct device *parent; + void *cf; + void *args; +{ + return (1); +} + +void +iioattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + extern struct cfdata cfdata[]; + extern struct cfdriver pcccd; + struct cfdata *cf, *pcccf = NULL; + + printf(" addr 0x%x\n", INTIOBASE); + + /* + * attach the pcc first! + */ + for (cf = cfdata; pcccf==NULL && cf->cf_driver; cf++) { + if (cf->cf_driver != &pcccd) + continue; + pcccf = cf; + } + if (!pcccf) + panic("no pcc device configured"); + config_attach(self, pcccf, NULL, NULL); + + while (config_found(self, NULL, NULL)) + ; +} + +void +iio_print(cf) + struct cfdata *cf; +{ + printf(" offset 0x%x", cf->cf_loc[0]); + if (cf->cf_loc[1] > 0) + printf(" ipl %d", cf->cf_loc[1]); +} diff --git a/sys/arch/mvme68k/dev/iio.h b/sys/arch/mvme68k/dev/iio.h new file mode 100644 index 0000000000000..cbc722dfacd27 --- /dev/null +++ b/sys/arch/mvme68k/dev/iio.h @@ -0,0 +1,18 @@ +/* $NetBSD: iio.h,v 1.1.1.1 1995/07/25 23:12:11 chuck Exp $ */ +/* $Id: iio.h,v 1.1.1.1 1995/07/25 23:12:11 chuck Exp $ */ + +struct iioargs { + int ic_addr; + int ic_lev; +}; + +#define IIO_CFLOC_ADDR(cf) (IIOV(INTIOBASE + (cf)->cf_loc[0])) +#define IIO_CFLOC_LEVEL(cf) ((cf)->cf_loc[1]) + +/* + * for the console we need zs phys addr + */ + +#define ZS0_PHYS (INTIOBASE + 0x3000) +#define ZS1_PHYS (INTIOBASE + 0x3800) + diff --git a/sys/arch/mvme68k/dev/pcc.c b/sys/arch/mvme68k/dev/pcc.c new file mode 100644 index 0000000000000..5008481bd4885 --- /dev/null +++ b/sys/arch/mvme68k/dev/pcc.c @@ -0,0 +1,171 @@ +/* $Id: pcc.c,v 1.1.1.1 1995/07/25 23:12:08 chuck Exp $ */ + +/* + * + * Copyright (c) 1995 Charles D. Cranor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor. + * 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. + */ + +/* + * peripheral channel controller + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Autoconfiguration stuff. + */ + +struct pccsoftc { + struct device sc_dev; + struct pcc *sc_pcc; +}; + + +void pccattach __P((struct device *, struct device *, void *)); +int pccmatch __P((struct device *, void *, void *)); + +struct cfdriver pcccd = { + NULL, "pcc", pccmatch, pccattach, + DV_DULL, sizeof(struct pccsoftc), 0 +}; + +/* + * globals + */ + +struct pcc *sys_pcc = NULL; + +struct { + int (*pcc_fn)(); + void *arg; + int lvl; +} pcc_vecs[PCC_NVEC]; + +int +pccmatch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + + return !badbaddr((caddr_t) IIO_CFLOC_ADDR(cf)); +} + +void +pccattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct pccsoftc *pccsc; + + if (sys_pcc) + panic("pcc already attached!"); + + iio_print(self->dv_cfdata); + + /* + * link into softc and set up interrupt vector base + */ + pccsc = (struct pccsoftc *) self; + sys_pcc = pccsc->sc_pcc = (struct pcc *)IIO_CFLOC_ADDR(self->dv_cfdata); + pccsc->sc_pcc->int_vectr = PCC_VECBASE; + bzero(pcc_vecs, sizeof(pcc_vecs)); + + printf(" rev %d intbvr 0x%x\n", pccsc->sc_pcc->pcc_rev, + pccsc->sc_pcc->int_vectr); +} + + +/* + * pccintr: called from locore with the PC and evec from the trap frame. + */ +int +pccintr(pc, evec, frame) + int pc; + int evec; + void *frame; +{ + int vec = (evec & 0xfff) >> 2; /* XXX should be m68k macro? */ + extern u_long intrcnt[]; /* XXX from locore */ + + vec = vec & 0xf; /* XXX mask out */ + if (vec >= PCC_NVEC || pcc_vecs[vec].pcc_fn == NULL) + return(straytrap(pc, evec)); + + cnt.v_intr++; + intrcnt[pcc_vecs[vec].lvl]++; + + /* arg override? only timer1 gets access to frame */ + if (vec != PCCV_TIMER1) + frame = pcc_vecs[vec].arg; + return((*pcc_vecs[vec].pcc_fn)(frame)); +} + + +/* + * pccintr_establish: establish pcc interrupt + */ +int +pccintr_establish(vec, hand, lvl, arg) + u_long vec; + int (*hand)(), lvl; + void *arg; +{ + if (vec >= PCC_NVEC) { + printf("pcc: illegal vector: 0x%x\n", vec); + panic("pccintr_establish"); + } + + if (pcc_vecs[vec].pcc_fn) { + printf("pcc: vector 0x%x in use: (0x%x,0x%x) (0x%x,0x%x)\n", + hand, arg, pcc_vecs[vec].pcc_fn, pcc_vecs[vec].arg); + panic("pccintr_establish"); + } + + pcc_vecs[vec].pcc_fn = hand; + pcc_vecs[vec].lvl = lvl; + pcc_vecs[vec].arg = arg; +} diff --git a/sys/arch/mvme68k/dev/pccreg.h b/sys/arch/mvme68k/dev/pccreg.h new file mode 100644 index 0000000000000..78134965ee9d4 --- /dev/null +++ b/sys/arch/mvme68k/dev/pccreg.h @@ -0,0 +1,130 @@ +/* $Id: pccreg.h,v 1.1.1.1 1995/07/25 23:12:08 chuck Exp $ */ + +/* + * + * Copyright (c) 1995 Charles D. Cranor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor. + * 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. + */ + +/* + * peripheral channel controller (at pa fffe1000) + */ + +struct pcc { + volatile u_long dma_taddr; /* dma table address */ + volatile u_long dma_daddr; /* dma data address */ + volatile u_long dma_bcnt; /* dma byte count */ + volatile u_long dma_hold; /* dma data hold register */ + volatile u_short t1_pload; /* timer1 preload */ + volatile u_short t1_count; /* timer1 count */ + volatile u_short t2_pload; /* timer2 preload */ + volatile u_short t2_count; /* timer2 count */ + volatile u_char t1_int; /* timer1 interrupt ctrl */ + volatile u_char t1_cr; /* timer1 ctrl reg */ + volatile u_char t2_int; /* timer2 interrupt ctrl */ + volatile u_char t2_cr; /* timer2 ctrl reg */ + volatile u_char acf_int; /* acfail intr reg */ + volatile u_char dog_int; /* watchdog intr reg */ + volatile u_char pr_int; /* printer intr reg */ + volatile u_char pr_cr; /* printer ctrl */ + volatile u_char dma_int; /* dma interrupt control */ + volatile u_char dma_csr; /* dma csr */ + volatile u_char bus_int; /* bus error interrupt */ + volatile u_char dma_sr; /* dma status register */ + volatile u_char abrt_int; /* abort interrupt control reg */ + volatile u_char ta_fcr; /* table address function code reg */ + volatile u_char zs_int; /* serial interrupt reg */ + volatile u_char gen_cr; /* general control register */ + volatile u_char le_int; /* ethernet interrupt */ + volatile u_char gen_sr; /* general status */ + volatile u_char scsi_int; /* scsi interrupt reg */ + volatile u_char slave_ba; /* slave base addr reg */ + volatile u_char sw1_int; /* software interrupt #1 cr */ + volatile u_char int_vectr; /* interrupt base vector register */ + volatile u_char sw2_int; /* software interrupt #2 cr */ + volatile u_char pcc_rev; /* revision level */ +}; + + +/* + * points to system's PCC + */ + +extern struct pcc *sys_pcc; + +/* + * we lock off our interrupt vector at 0x40. if this is changed + * we'll need to change vector.s + */ + +#define PCC_VECBASE 0x40 +#define PCC_NVEC 12 + +/* + * vectors we use + */ + +#define PCCV_ACFAIL 0 +#define PCCV_BERR 1 +#define PCCV_ABORT 2 +#define PCCV_ZS 3 +#define PCCV_LE 4 +#define PCCV_SCSIP 5 +#define PCCV_SCSID 6 +#define PCCV_PRINTER 7 +#define PCCV_TIMER1 8 +#define PCCV_TIMER2 9 +#define PCCV_SOFT1 10 +#define PCCV_SOFT2 11 + +/* + * enable interrupt + */ + +#define PCC_IENABLE 0x08 + +/* + * interrupt mask + */ + +#define PCC_IMASK 0x7 + +/* + * clock/timer + */ + +#define PCC_TIMERACK 0x80 /* ack intr */ +#define PCC_TIMER100HZ 63936 /* load value for 100Hz */ +#define PCC_TIMERCLEAR 0x0 /* reset and clear timer */ +#define PCC_TIMERSTART 0x3 /* start timer */ + +/* + * serial control + */ + +#define PCC_ZSEXTERN 0x10 /* let PCC supply vector */ diff --git a/sys/arch/mvme68k/dev/scc.h b/sys/arch/mvme68k/dev/scc.h new file mode 100644 index 0000000000000..4d94f6c3fde95 --- /dev/null +++ b/sys/arch/mvme68k/dev/scc.h @@ -0,0 +1,64 @@ +/* $NetBSD: scc.h,v 1.1.1.1 1995/07/25 23:12:07 chuck Exp $ */ + +/* + * Copyright (c) 1993 Paul Mackerras. + * 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 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. + */ +/* + * SCC I/O register definitions + */ + +#define PCLK_FREQ 8333333 /* XXX */ + +struct scc { + unsigned char cr; + unsigned char dr; +}; + +struct sccregs { + volatile struct scc *s_adr; + unsigned char s_val[16]; +}; + +#define ZREAD0(scc) ((scc)->s_adr->cr) +#define ZREAD(scc, n) ((scc)->s_adr->cr = n, (scc)->s_adr->cr) +#define ZREADD(scc) ((scc)->s_adr->dr) + +#define ZWRITE0(scc, v) ((scc)->s_adr->cr = v) +#define ZWRITE(scc, n, v) (ZWRITE0(scc, n), ZWRITE0(scc, (scc)->s_val[n] = v)) +#define ZWRITED(scc, v) ((scc)->s_adr->dr = v) + +#define ZBIS(scc, n, v) (ZWRITE(scc, n, (scc)->s_val[n] | (v))) +#define ZBIC(scc, n, v) (ZWRITE(scc, n, (scc)->s_val[n] & ~(v))) + +#define SCC_RXFULL 1 /* bits in rr0 */ +#define SCC_TXRDY 4 +#define SCC_DCD 8 +#define SCC_CTS 0x20 + +#define SCC_RCVEN 1 /* bits in wr3 */ + +#define SCC_RTS 2 /* bits in wr5 */ +#define SCC_DTR 0x80 diff --git a/sys/arch/mvme68k/dev/zs.c b/sys/arch/mvme68k/dev/zs.c new file mode 100644 index 0000000000000..9a52dbd8f9c2e --- /dev/null +++ b/sys/arch/mvme68k/dev/zs.c @@ -0,0 +1,996 @@ +/* $NetBSD: zs.c,v 1.1.1.1 1995/07/25 23:12:07 chuck Exp $ */ + +/* + * Copyright (c) 1993 Paul Mackerras. + * 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 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. + */ +/* + * Serial I/O via an SCC, + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zs.h" +#if NZS > 0 + +/*#define PCLK_FREQ 8333333*/ +#undef PCLK_FREQ /* XXXCDC */ +#define PCLK_FREQ 5000000 +#define NZSLINE (NZS*2) + +#define RECV_BUF 512 +#define ERROR_DET 0xed + +#define TS_DRAIN TS_FLUSH/* waiting for output to drain */ + +#define splzs() spl4() + +struct zs { + short flags; /* see below */ + char rr0; /* holds previous CTS, DCD state */ + unsigned char imask; /* mask for input chars */ + int nzs_open; /* # opens as /dev/zsn */ + int nkbd_open; /* # opens as a keyboard */ + int gsp_unit; /* unit to send kbd chars to */ + struct tty *tty; /* link to tty structure */ + struct sccregs scc; /* SCC shadow registers */ + u_char *rcv_get; + u_char *rcv_put; + u_char *rcv_end; + volatile int rcv_count; + int rcv_len; + char *send_ptr; + int send_count; + int sent_count; + volatile char modem_state; + volatile char modem_change; + volatile short hflags; + char rcv_buf[RECV_BUF]; +}; + +/* Bits in flags */ +#define ZS_SIDEA 1 +#define ZS_INITED 2 +#define ZS_INTEN 4 +#define ZS_RESET 8 +#define ZS_CONSOLE 0x20 + +/* Bits in hflags */ +#define ZH_OBLOCK 1 /* output blocked by CTS */ +#define ZH_SIRQ 2 /* soft interrupt request */ +#define ZH_TXING 4 /* transmitter active */ +#define ZH_RXOVF 8 /* receiver buffer overflow */ + +struct zssoftc { + struct device dev; + struct zs zs[2]; +}; + +struct tty *zs_tty[NZSLINE]; + +struct termios zs_cons_termios; +int zs_cons_unit = 0; +int zs_is_console = 0; +struct sccregs *zs_cons_scc; + +int zsopen __P((dev_t, int, int, struct proc *)); +void zsstart __P((struct tty *)); +int zsparam __P((struct tty *, struct termios *)); +int zsirq __P((int unit)); +void zs_softint __P((void)); + +unsigned long sir_zs; +void zs_softint(); + +#define zsunit(dev) (minor(dev) >> 1) +#define zsside(dev) (minor(dev) & 1) + +/* + * Autoconfiguration stuff. + */ +void zsattach __P((struct device *, struct device *, void *)); +int zsmatch __P((struct device *, void *, void *)); + +struct cfdriver zscd = { + NULL, "zs", zsmatch, zsattach, DV_TTY, sizeof(struct zssoftc), 0 +}; + +int +zsmatch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + + return !badbaddr((caddr_t) IIO_CFLOC_ADDR(cf)); +} + +void +zsattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct zssoftc *dv; + struct zs *zp, *zc; + u_char ir; + volatile struct scc *scc; + int zs_level = IIO_CFLOC_LEVEL(self->dv_cfdata); + + iio_print(self->dv_cfdata); + + /* connect the interrupt */ + dv = (struct zssoftc *) self; + pccintr_establish(PCCV_ZS, zsirq, zs_level, self->dv_unit); + /* XXXCDC: needs some work to handle zs1 */ + + zp = &dv->zs[0]; + scc = (volatile struct scc *) IIO_CFLOC_ADDR(self->dv_cfdata); + + if (zs_is_console && self->dv_unit == zsunit(zs_cons_unit)) { + /* SCC is the console - it's already reset */ + zc = zp + zsside(zs_cons_unit); + zc->scc = *zs_cons_scc; + zs_cons_scc = &zc->scc; + zc->flags |= ZS_CONSOLE; + } else { + /* reset the SCC */ + scc->cr = 0; + scc->cr = 9; + scc->cr = 0xC0; /* hardware reset of SCC, both sides */ + } + + /* side A */ + zp->scc.s_adr = scc + 1; + zp->flags |= ZS_SIDEA | ZS_RESET; + + /* side B */ + ++zp; + zp->scc.s_adr = scc; + zp->flags |= ZS_RESET; + + if (sir_zs == 0) + sir_zs = allocate_sir(zs_softint, 0); + printf("\n"); + + ir = sys_pcc->zs_int; + if ((ir & PCC_IMASK) != 0 && (ir & PCC_IMASK) != zs_level) + panic("zs configured at different IPLs"); + sys_pcc->zs_int = zs_level | PCC_IENABLE | PCC_ZSEXTERN; +} + +zs_ttydef(struct zs *zp) +{ + struct tty *tp = zp->tty; + + if ((zp->flags & ZS_CONSOLE) == 0) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + } else + tp->t_termios = zs_cons_termios; + ttychars(tp); + ttsetwater(tp); + tp->t_oproc = zsstart; + tp->t_param = zsparam; + + zp->rcv_get = zp->rcv_buf; + zp->rcv_put = zp->rcv_buf; + zp->rcv_end = zp->rcv_buf + sizeof(zp->rcv_buf); + zp->rcv_len = sizeof(zp->rcv_buf) / 2; +} + +struct tty * +zstty(dev) + dev_t dev; +{ + + if (minor(dev) < NZSLINE) + return (zs_tty[minor(dev)]); + + return (NULL); +} + +/* ARGSUSED */ +zsopen(dev_t dev, int flag, int mode, struct proc * p) +{ + register struct tty *tp; + int error; + struct zs *zp; + struct zssoftc *dv; + + if (zsunit(dev) > zscd.cd_ndevs + || (dv = (struct zssoftc *) zscd.cd_devs[zsunit(dev)]) == NULL) + return ENODEV; + + zp = &dv->zs[zsside(dev)]; + if (zp->tty == NULL) { + zp->tty = ttymalloc(); + zs_ttydef(zp); + if (minor(dev) < NZSLINE) + zs_tty[minor(dev)] = zp->tty; + } + tp = zp->tty; + tp->t_dev = dev; + + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_WOPEN; + zs_init(zp); + if ((zp->modem_state & SCC_DCD) != 0) + tp->t_state |= TS_CARR_ON; + } else + if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) + return (EBUSY); + + error = ((*linesw[tp->t_line].l_open) (dev, tp)); + + if (error == 0) + ++zp->nzs_open; + return error; +} + +int +zsclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct zs *zp; + struct tty *tp; + struct zssoftc *dv; + int s; + + if (zsunit(dev) > zscd.cd_ndevs + || (dv = (struct zssoftc *) zscd.cd_devs[zsunit(dev)]) == NULL) + return ENODEV; + zp = &dv->zs[zsside(dev)]; + tp = zp->tty; + + if (zp->nkbd_open == 0) { + (*linesw[tp->t_line].l_close) (tp, flag); + s = splzs(); + if ((zp->flags & ZS_CONSOLE) == 0 && (tp->t_cflag & HUPCL) != 0) + ZBIC(&zp->scc, 5, 0x82); /* drop DTR, RTS */ + ZBIC(&zp->scc, 3, 1); /* disable receiver */ + splx(s); + ttyclose(tp); + } + zp->nzs_open = 0; + return (0); +} + +/*ARGSUSED*/ +zsread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(dev)]; + struct zs *zp = &dv->zs[zsside(dev)]; + struct tty *tp = zp->tty; + + return ((*linesw[tp->t_line].l_read) (tp, uio, flag)); +} + +/*ARGSUSED*/ +zswrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(dev)]; + struct zs *zp = &dv->zs[zsside(dev)]; + struct tty *tp = zp->tty; + + return ((*linesw[tp->t_line].l_write) (tp, uio, flag)); +} + +zsioctl(dev, cmd, data, flag, p) + dev_t dev; + caddr_t data; + int cmd, flag; + struct proc *p; +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(dev)]; + struct zs *zp = &dv->zs[zsside(dev)]; + struct tty *tp = zp->tty; + register struct sccregs *scc = &zp->scc; + register int error, s; + + 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); + error = 0; + s = splzs(); + switch (cmd) { + case TIOCSDTR: + ZBIS(scc, 5, 0x80); + break; + case TIOCCDTR: + ZBIC(scc, 5, 0x80); + break; + case TIOCSBRK: + splx(s); + zs_drain(zp); + s = splzs(); + ZBIS(scc, 5, 0x10); + spltty(); + zs_unblock(tp); + break; + case TIOCCBRK: + ZBIC(scc, 5, 0x10); + break; + case TIOCMGET: + *(int *) data = zscc_mget(scc); + break; + case TIOCMSET: + zscc_mset(scc, *(int *) data); + zscc_mclr(scc, ~*(int *) data); + break; + case TIOCMBIS: + zscc_mset(scc, *(int *) data); + break; + case TIOCMBIC: + zscc_mclr(scc, *(int *) data); + break; + default: + error = ENOTTY; + } + splx(s); + return error; +} + +zsparam(tp, t) + struct tty *tp; + struct termios *t; +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(tp->t_dev)]; + struct zs *zp = &dv->zs[zsside(tp->t_dev)]; + register int s; + + zs_drain(zp); + s = splzs(); + zp->imask = zscc_params(&zp->scc, t); + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + if ((tp->t_cflag & CCTS_OFLOW) == 0) + zp->hflags &= ~ZH_OBLOCK; + else + if ((zp->modem_state & 0x20) == 0) + zp->hflags |= ZH_OBLOCK; + spltty(); + zs_unblock(tp); + splx(s); + return 0; +} + +void +zsstart(tp) + struct tty *tp; +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(tp->t_dev)]; + struct zs *zp = &dv->zs[zsside(tp->t_dev)]; + register int s, n; + + s = spltty(); + if ((tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP | TS_DRAIN)) == 0) { + n = ndqb(&tp->t_outq, 0); + if (n > 0) { + tp->t_state |= TS_BUSY; + splzs(); + zp->hflags |= ZH_TXING; + zp->send_ptr = tp->t_outq.c_cf; + zp->send_count = n; + zp->sent_count = 0; + zs_txint(zp); + spltty(); + } + } + splx(s); +} + +zsstop(struct tty * tp, int flag) +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(tp->t_dev)]; + struct zs *zp = &dv->zs[zsside(tp->t_dev)]; + int s, n; + + s = splzs(); + zp->send_count = 0; + n = zp->sent_count; + zp->sent_count = 0; + if ((tp->t_state & TS_BUSY) != 0 && (flag & FWRITE) == 0) { + tp->t_state &= ~TS_BUSY; + spltty(); + ndflush(&tp->t_outq, n); + 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); + } + } + splx(s); +} + +zs_init(zp) + struct zs *zp; +{ + register int s; + + s = splzs(); + zscc_init(zp, &zp->tty->t_termios); + zp->rr0 = zp->modem_state = ZREAD0(&zp->scc); + ZBIS(&zp->scc, 1, 0x13);/* ints on tx, rx and ext/status */ + ZBIS(&zp->scc, 9, 8); /* enable ints */ + zp->flags |= ZS_INTEN; + splx(s); +} + +zscc_init(zp, par) + struct zs *zp; + struct termios *par; +{ + struct sccregs *scc; + + scc = &zp->scc; + ZWRITE(scc, 2, 0); + ZWRITE(scc, 10, 0); + ZWRITE(scc, 11, 0x50); /* rx & tx clock = brgen */ + ZWRITE(scc, 14, 3); /* brgen enabled, from pclk */ + zp->imask = zscc_params(scc, par); + ZBIS(scc, 5, 0x82); /* set DTR and RTS */ + zp->flags |= ZS_INITED; +} + +int +zscc_params(scc, par) + struct sccregs *scc; + struct termios *par; +{ + unsigned divisor, speed; + int spd, imask, ints; + + speed = par->c_ospeed; + if (speed == 0) { + /* disconnect - drop DTR & RTS, disable receiver */ + ZBIC(scc, 5, 0x82); + ZBIC(scc, 3, 1); + return 0xFF; + } + if ((par->c_cflag & CREAD) == 0) + ZBIC(scc, 3, 1);/* disable receiver */ + divisor = (PCLK_FREQ / 32 + (speed >> 1)) / speed - 2; + ZWRITE(scc, 12, divisor); + ZWRITE(scc, 13, divisor >> 8); + switch (par->c_cflag & CSIZE) { + case CS5: + spd = 0; + imask = 0x1F; + break; + case CS6: + spd = 0x40; + imask = 0x3F; + break; + case CS7: + spd = 0x20; + imask = 0x7F; + break; + default: + spd = 0x60; + imask = 0xFF; + } + ZWRITE(scc, 5, (scc->s_val[5] & ~0x60) | spd); + ZWRITE(scc, 3, (scc->s_val[3] & ~0xC0) | (spd << 1)); + spd = par->c_cflag & CSTOPB ? 8 : 0; + spd |= par->c_cflag & PARENB ? par->c_cflag & PARODD ? 1 : 3 : 0; + ZWRITE(scc, 4, 0x44 | spd); + ZBIS(scc, 5, 8); /* enable transmitter */ + if ((par->c_cflag & CREAD) != 0) + ZBIS(scc, 3, 1);/* enable receiver */ + ints = 0; + if ((par->c_cflag & CLOCAL) == 0) + ints |= SCC_DCD; + if ((par->c_cflag & CCTS_OFLOW) != 0) + ints |= SCC_CTS; + ZWRITE(scc, 15, ints); + return imask; +} + +zscc_mget(register struct sccregs * scc) +{ + int bits = 0, rr0; + + if ((scc->s_val[3] & SCC_RCVEN) != 0) + bits |= TIOCM_LE; + if ((scc->s_val[5] & SCC_DTR) != 0) + bits |= TIOCM_DTR; + if ((scc->s_val[5] & SCC_RTS) != 0) + bits |= TIOCM_RTS; + rr0 = ZREAD0(scc); + if ((rr0 & SCC_CTS) != 0) + bits |= TIOCM_CTS; + if ((rr0 & SCC_DCD) != 0) + bits |= TIOCM_CAR; + return bits; +} + +zscc_mset(register struct sccregs * scc, int bits) +{ + if ((bits & TIOCM_LE) != 0) + ZBIS(scc, 3, SCC_RCVEN); + if ((bits & TIOCM_DTR) != 0) + ZBIS(scc, 5, SCC_DTR); + if ((bits & TIOCM_RTS) != 0) + ZBIS(scc, 5, SCC_RTS); +} + +zscc_mclr(register struct sccregs * scc, int bits) +{ + if ((bits & TIOCM_LE) != 0) + ZBIC(scc, 3, SCC_RCVEN); + if ((bits & TIOCM_DTR) != 0) + ZBIC(scc, 5, TIOCM_DTR); + if ((bits & TIOCM_RTS) != 0) + ZBIC(scc, 5, SCC_RTS); +} + +zs_drain(register struct zs * zp) +{ + register int s; + + zp->tty->t_state |= TS_DRAIN; + /* wait for Tx buffer empty and All sent bits to be set */ + s = splzs(); + while ((ZREAD0(&zp->scc) & SCC_TXRDY) == 0 + || (ZREAD(&zp->scc, 1) & 1) == 0) { + splx(s); + DELAY(100); + s = splzs(); + } + splx(s); +} + +zs_unblock(register struct tty * tp) +{ + tp->t_state &= ~TS_DRAIN; + if (tp->t_outq.c_cc != 0) + zsstart(tp); +} + +/* + * Hardware interrupt from an SCC. + */ +int +zsirq(int unit) +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[unit]; + register struct zs *zp = &dv->zs[0]; + register int ipend, x; + register volatile struct scc *scc; + + x = splzs(); + scc = zp->scc.s_adr; + scc->cr = 3; /* read int pending from A side */ + DELAY(5); + ipend = scc->cr; + if ((ipend & 0x20) != 0) + zs_rxint(zp); + if ((ipend & 0x10) != 0) + zs_txint(zp); + if ((ipend & 0x8) != 0) + zs_extint(zp); + ++zp; /* now look for B side ints */ + if ((ipend & 0x4) != 0) + zs_rxint(zp); + if ((ipend & 0x2) != 0) + zs_txint(zp); + if ((ipend & 0x1) != 0) + zs_extint(zp); + splx(x); + return ipend != 0; +} + +zs_txint(register struct zs * zp) +{ + struct tty *tp = zp->tty; + struct sccregs *scc; + int c; + u_char *get; + + scc = &zp->scc; + ZWRITE0(scc, 0x28); /* reset Tx interrupt */ + if ((zp->hflags & ZH_OBLOCK) == 0) { + get = zp->send_ptr; + while ((ZREAD0(scc) & SCC_TXRDY) != 0 && zp->send_count > 0) { + c = *get++; + ZWRITED(scc, c); + --zp->send_count; + ++zp->sent_count; + } + zp->send_ptr = get; + if (zp->send_count == 0 && (zp->hflags & ZH_TXING) != 0) { + zp->hflags &= ~ZH_TXING; + zp->hflags |= ZH_SIRQ; + setsoftint(sir_zs); + } + } +} + +zs_rxint(register struct zs * zp) +{ + register int stat, c, n, extra; + u_char *put; + + put = zp->rcv_put; + n = zp->rcv_count; + for (;;) { + if ((ZREAD0(&zp->scc) & SCC_RXFULL) == 0) /* check Rx full */ + break; + stat = ZREAD(&zp->scc, 1) & 0x70; + c = ZREADD(&zp->scc) & zp->imask; + /* stat encodes parity, overrun, framing errors */ + if (stat != 0) + ZWRITE0(&zp->scc, 0x30); /* reset error */ + if ((zp->hflags & ZH_RXOVF) != 0) { + zp->hflags &= ~ZH_RXOVF; + stat |= 0x20; + } + extra = (stat != 0 || c == ERROR_DET) ? 2 : 0; + if (n + extra + 1 < zp->rcv_len) { + if (extra != 0) { + *put++ = ERROR_DET; + if (put >= zp->rcv_end) + put = zp->rcv_buf; + *put++ = stat; + if (put >= zp->rcv_end) + put = zp->rcv_buf; + n += 2; + } + *put++ = c; + if (put >= zp->rcv_end) + put = zp->rcv_buf; + ++n; + } else + zp->hflags |= ZH_RXOVF; + } + if (n > zp->rcv_count) { + zp->rcv_put = put; + zp->rcv_count = n; + zp->hflags |= ZH_SIRQ; + setsoftint(sir_zs); + } +} + +/* Ext/status interrupt */ +zs_extint(register struct zs * zp) +{ + int rr0; + struct tty *tp = zp->tty; + + rr0 = ZREAD0(&zp->scc); + ZWRITE0(&zp->scc, 0x10);/* reset ext/status int */ + if ((tp->t_cflag & CCTS_OFLOW) != 0) { + if ((rr0 & 0x20) == 0) + zp->hflags |= ZH_OBLOCK; + else { + zp->hflags &= ~ZH_OBLOCK; + if ((rr0 & SCC_TXRDY) != 0) + zs_txint(zp); + } + } + zp->modem_change |= rr0 ^ zp->modem_state; + zp->modem_state = rr0; + zp->hflags |= ZH_SIRQ; + setsoftint(sir_zs); +} + +void +zs_softint() +{ + int s, n, n0, c, stat, rr0; + struct zs *zp; + struct tty *tp; + u_char *get; + int unit, side; + + s = splzs(); + for (unit = 0; unit < zscd.cd_ndevs; ++unit) { + if (zscd.cd_devs[unit] == NULL) + continue; + zp = &((struct zssoftc *) zscd.cd_devs[unit])->zs[0]; + for (side = 0; side < 2; ++side, ++zp) { + if ((zp->hflags & ZH_SIRQ) == 0) + continue; + zp->hflags &= ~ZH_SIRQ; + tp = zp->tty; + + /* check for tx done */ + spltty(); + if (tp != NULL && zp->send_count == 0 + && (tp->t_state & TS_BUSY) != 0) { + tp->t_state &= ~(TS_BUSY | TS_FLUSH); + ndflush(&tp->t_outq, zp->sent_count); + 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_line != 0) + (*linesw[tp->t_line].l_start) (tp); + else + zsstart(tp); + } + splzs(); + + /* check for received characters */ + get = zp->rcv_get; + while (zp->rcv_count > 0) { + c = *get++; + if (get >= zp->rcv_end) + get = zp->rcv_buf; + if (c == ERROR_DET) { + stat = *get++; + if (get >= zp->rcv_end) + get = zp->rcv_buf; + c = *get++; + if (get >= zp->rcv_end) + get = zp->rcv_buf; + zp->rcv_count -= 3; + } else { + stat = 0; + --zp->rcv_count; + } + spltty(); + if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) + continue; + if (zp->nzs_open == 0) { +#ifdef notdef + if (stat == 0) + kbd_newchar(zp->gsp_unit, c); +#endif + } else { + if ((stat & 0x10) != 0) + c |= TTY_PE; + if ((stat & 0x20) != 0) { + log(LOG_WARNING, "zs: fifo overflow\n"); + c |= TTY_FE; /* need some error for + * slip stuff */ + } + if ((stat & 0x40) != 0) + c |= TTY_FE; + (*linesw[tp->t_line].l_rint) (c, tp); + } + splzs(); + } + zp->rcv_get = get; + + /* check for modem lines changing */ + while (zp->modem_change != 0 || zp->modem_state != zp->rr0) { + rr0 = zp->rr0 ^ zp->modem_change; + zp->modem_change = rr0 ^ zp->modem_state; + + /* Check if DCD (carrier detect) has changed */ + if (tp != NULL && (rr0 & 8) != (zp->rr0 & 8)) { + spltty(); + ttymodem(tp, rr0 & 8); + /* XXX possibly should disable line if + * return value is 0 */ + splzs(); + } + zp->rr0 = rr0; + } + } + } + splx(s); +} + +/* + * Routines to divert an SCC channel to the input side of /dev/gsp + * for the keyboard. + */ +int +zs_kbdopen(int unit, int gsp_unit, struct termios * tiop, struct proc * p) +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(unit)]; + struct zs *zp = &dv->zs[zsside(unit)]; + int error; + + error = zsopen(unit, 0, 0, p); + if (error != 0) + return error; + ++zp->nkbd_open; + --zp->nzs_open; + zsparam(zp->tty, tiop); + zp->gsp_unit = gsp_unit; + return 0; +} + +void +zs_kbdclose(int unit) +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(unit)]; + struct zs *zp = &dv->zs[zsside(unit)]; + + zp->nkbd_open = 0; + if (zp->nzs_open == 0) + zsclose(unit, 0, 0, 0); +} + +void +zs_kbdput(int unit, int c) +{ + struct zssoftc *dv = (struct zssoftc *) zscd.cd_devs[zsunit(unit)]; + struct zs *zp = &dv->zs[zsside(unit)]; + struct tty *tp = zp->tty; + + putc(c, &tp->t_outq); + zsstart(tp); +} + +/* + * Routines for using side A of the first SCC as a console. + */ + +/* probe for the SCC; should check hardware */ +zscnprobe(cp) + struct consdev *cp; +{ + int maj; + char *prom_cons; + extern char *prom_getvar(); + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == zsopen) + break; + + /* initialize required fields */ + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_NORMAL; + + return 1; +} + +/* initialize the keyboard for use as the console */ +struct termios zscn_termios = { + TTYDEF_IFLAG, + TTYDEF_OFLAG, + TTYDEF_CFLAG, + TTYDEF_LFLAG, + {0}, + TTYDEF_SPEED, + TTYDEF_SPEED +}; + +struct sccregs zs_cons_sccregs; +int zs_cons_imask; + +unsigned zs_cons_addrs[] = {ZS0_PHYS, ZS1_PHYS}; + + +zscninit() +{ + zs_cnsetup(0, &zscn_termios); +} + +/* Polling routine for console input from a serial port. */ +int +zscngetc(dev_t dev) +{ + register struct sccregs *scc = zs_cons_scc; + int c, s, stat; + + s = splzs(); + for (;;) { + while ((ZREAD0(scc) & SCC_RXFULL) == 0) /* wait for Rx full */ + ; + stat = ZREAD(scc, 1) & 0x70; + c = ZREADD(scc) & zs_cons_imask; + /* stat encodes parity, overrun, framing errors */ + if (stat == 0) + break; + ZWRITE0(scc, 0x30); /* reset error */ + } + splx(s); + return c; +} + +zscnputc(dev_t dev, int c) +{ + register struct sccregs *scc = zs_cons_scc; + int s; + + s = splzs(); + while ((ZREAD0(scc) & SCC_TXRDY) == 0); + ZWRITED(scc, c); + splx(s); +} + +zs_cnsetup(int unit, struct termios * tiop) +{ + register volatile struct scc *scc_adr; + register struct sccregs *scc; + + zs_cons_unit = unit; + zs_is_console = 1; + zs_cons_scc = scc = &zs_cons_sccregs; + + scc_adr = (volatile struct scc *) IIOV(zs_cons_addrs[zsunit(unit)]); + + scc_adr[1].cr = 0; + scc_adr[1].cr = 9; + scc_adr[1].cr = 0xC0; /* hardware reset of SCC, both sides */ + if (!zsside(unit)) + ++scc_adr; + + scc->s_adr = scc_adr; + ZWRITE(scc, 2, 0); + ZWRITE(scc, 10, 0); + ZWRITE(scc, 11, 0x50); /* rx & tx clock = brgen */ + ZWRITE(scc, 14, 3); /* brgen enabled, from pclk */ + zs_cons_imask = zscc_params(scc, tiop); + ZBIS(scc, 5, 0x82); /* set DTR and RTS */ + + zs_cons_termios = *tiop;/* save for later */ +} + +/* + * Routines for using the keyboard SCC as the input side of + * the 'gsp' console device. + */ + +/* probe for the keyboard; should check hardware */ +zs_kbdcnprobe(cp, unit) + struct consdev *cp; + int unit; +{ + return (unsigned) unit < NZSLINE; +} +#endif /* NZS */ diff --git a/sys/arch/mvme68k/include/ansi.h b/sys/arch/mvme68k/include/ansi.h new file mode 100644 index 0000000000000..745f1b30ca2e5 --- /dev/null +++ b/sys/arch/mvme68k/include/ansi.h @@ -0,0 +1,4 @@ +/* $NetBSD: ansi.h,v 1.1.1.1 1995/07/25 23:12:12 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/aout_machdep.h b/sys/arch/mvme68k/include/aout_machdep.h new file mode 100644 index 0000000000000..21b755d12e12d --- /dev/null +++ b/sys/arch/mvme68k/include/aout_machdep.h @@ -0,0 +1,48 @@ +/* $NetBSD: aout_machdep.h,v 1.1.1.1 1995/07/25 23:12:15 chuck 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. 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_EXEC_H_ +#define _MACHINE_EXEC_H_ + +#define __LDPGSZ 8192 + +/* Relocation format. */ +struct relocation_info_m68k { + int r_address; /* offset in text or data segment */ + unsigned int r_symbolnum : 24, /* ordinal number of add symbol */ + 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_baserel : 1, /* linkage table relative */ + r_jmptable : 1, /* relocate to jump table */ + r_relative : 1, /* load address relative */ + r_copy : 1; /* run time copy */ +}; +#define relocation_info relocation_info_m68k + +#endif /* _MACHINE_EXEC_H_ */ diff --git a/sys/arch/mvme68k/include/asm.h b/sys/arch/mvme68k/include/asm.h new file mode 100644 index 0000000000000..e4f75e3949f26 --- /dev/null +++ b/sys/arch/mvme68k/include/asm.h @@ -0,0 +1,3 @@ +/* $NetBSD: asm.h,v 1.1.1.1 1995/07/25 23:12:13 chuck Exp $ */ + +#include diff --git a/sys/arch/mvme68k/include/cdefs.h b/sys/arch/mvme68k/include/cdefs.h new file mode 100644 index 0000000000000..641030e3e3000 --- /dev/null +++ b/sys/arch/mvme68k/include/cdefs.h @@ -0,0 +1,8 @@ +/* $NetBSD: cdefs.h,v 1.1.1.1 1995/07/25 23:12:19 chuck Exp $ */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#include + +#endif diff --git a/sys/arch/mvme68k/include/cpu.h b/sys/arch/mvme68k/include/cpu.h new file mode 100644 index 0000000000000..aec3e71fbe6a5 --- /dev/null +++ b/sys/arch/mvme68k/include/cpu.h @@ -0,0 +1,230 @@ +/* $NetBSD: cpu.h,v 1.1.1.1 1995/07/25 23:12:13 chuck Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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: cpu.h 1.16 91/03/25$ + * + * @(#)cpu.h 8.4 (Berkeley) 1/5/94 + */ + +/* + * Exported definitions unique to mvme68k/68k cpu support. + */ + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define cpu_swapin(p) /* nothing */ +#define cpu_wait(p) /* nothing */ +#define cpu_setstack(p, ap) (p)->p_md.md_regs[SP] = ap +#define cpu_swapout(p) /* nothing */ + +/* + * Arguments to hardclock and gatherstats encapsulate the previous + * machine state in an opaque clockframe. One the mvme68k, we use + * what the hardware pushes on an interrupt (frame format 0). + */ +struct clockframe { + u_short sr; /* sr at time of interrupt */ + u_long pc; /* pc at time of interrupt */ + u_short vo; /* vector offset (4-word frame) */ +}; + +#define CLKF_USERMODE(framep) (((framep)->sr & PSL_S) == 0) +#define CLKF_BASEPRI(framep) (((framep)->sr & PSL_IPL) == 0) +#define CLKF_PC(framep) ((framep)->pc) +#if 0 +/* We would like to do it this way... */ +#define CLKF_INTR(framep) (((framep)->sr & PSL_M) == 0) +#else +/* but until we start using PSL_M, we have to do this instead */ +#define CLKF_INTR(framep) (0) /* XXX */ +#endif + + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +#define need_resched() { want_resched++; aston(); } + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the hp300, request an ast to send us + * through trap, marking the proc as needing a profiling tick. + */ +#define need_proftick(p) { (p)->p_flag |= P_OWEUPC; aston(); } + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) aston() + +#define aston() (astpending++) + +int astpending; /* need to trap before returning to user mode */ +int want_resched; /* resched() was called */ + + +/* + * simulated software interrupt register + */ +extern unsigned char ssir; + +#define SIR_NET 0x1 +#define SIR_CLOCK 0x2 + +#define setsoftint(x) ssir |= (x) +#define siroff(x) ssir &= ~(x) +#define setsoftnet() ssir |= SIR_NET +#define setsoftclock() ssir |= SIR_CLOCK + +extern unsigned long allocate_sir(); + +/* + * 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 }, \ +} + +/* values for mmutype (assigned for quick testing) */ +#define MMU_68040 -2 /* 68040 on-chip MMU */ +#define MMU_68030 -1 /* 68030 on-chip subset of 68851 */ +#define MMU_68851 1 /* Motorola 68851 */ + +/* values for ectype */ +#define EC_PHYS -1 /* external physical address cache */ +#define EC_NONE 0 /* no external cache */ +#define EC_VIRT 1 /* external virtual address cache */ + +#define MHZ_16 2 /* XXX kill */ + + +#ifdef _KERNEL +extern int mmutype, ectype; +extern int cpuspeed; /* XXX kill */ +extern char *intiobase, *intiolimit; +#endif + +/* physical memory sections for mvme147 */ +#define INTIOBASE (0xfffe0000) +#define INTIOTOP (0xfffe5000) + +/* + * Internal IO space: + * + * Ranges from 0x800000 to 0x1000000 (IIOMAPSIZE). + * + * Internal IO space is mapped in the kernel from ``intiobase'' to + * ``intiolimit'' (defined in locore.s). Since it is always mapped, + * conversion between physical and kernel virtual addresses is easy. + */ +#define ISIIOVA(va) \ + ((char *)(va) >= intiobase && (char *)(va) < intiolimit) +#define IIOV(pa) ((int)(pa)-INTIOBASE+(int)intiobase) +#define IIOP(va) ((int)(va)-(int)intiobase+INTIOBASE) +#define IIOPOFF(pa) ((int)(pa)-INTIOBASE) +#define IIOMAPSIZE btoc(INTIOTOP-INTIOBASE) /* 1mb */ + +/* + * 68851 and 68030 MMU + */ +#define PMMU_LVLMASK 0x0007 +#define PMMU_INV 0x0400 +#define PMMU_WP 0x0800 +#define PMMU_ALV 0x1000 +#define PMMU_SO 0x2000 +#define PMMU_LV 0x4000 +#define PMMU_BE 0x8000 +#define PMMU_FAULT (PMMU_WP|PMMU_INV) + +/* + * 68040 MMU + */ +#define MMU4_RES 0x001 +#define MMU4_TTR 0x002 +#define MMU4_WP 0x004 +#define MMU4_MOD 0x010 +#define MMU4_CMMASK 0x060 +#define MMU4_SUP 0x080 +#define MMU4_U0 0x100 +#define MMU4_U1 0x200 +#define MMU4_GLB 0x400 +#define MMU4_BE 0x800 + +/* 680X0 function codes */ +#define FC_USERD 1 /* user data space */ +#define FC_USERP 2 /* user program space */ +#define FC_SUPERD 5 /* supervisor data space */ +#define FC_SUPERP 6 /* supervisor program space */ +#define FC_CPU 7 /* CPU space */ + +/* fields in the 68020 cache control register */ +#define IC_ENABLE 0x0001 /* enable instruction cache */ +#define IC_FREEZE 0x0002 /* freeze instruction cache */ +#define IC_CE 0x0004 /* clear instruction cache entry */ +#define IC_CLR 0x0008 /* clear entire instruction cache */ + +/* additional fields in the 68030 cache control register */ +#define IC_BE 0x0010 /* instruction burst enable */ +#define DC_ENABLE 0x0100 /* data cache enable */ +#define DC_FREEZE 0x0200 /* data cache freeze */ +#define DC_CE 0x0400 /* clear data cache entry */ +#define DC_CLR 0x0800 /* clear entire data cache */ +#define DC_BE 0x1000 /* data burst enable */ +#define DC_WA 0x2000 /* write allocate */ + +#define CACHE_ON (DC_WA|DC_BE|DC_CLR|DC_ENABLE|IC_BE|IC_CLR|IC_ENABLE) +#define CACHE_OFF (DC_CLR|IC_CLR) +#define CACHE_CLR (CACHE_ON) +#define IC_CLEAR (DC_WA|DC_BE|DC_ENABLE|IC_BE|IC_CLR|IC_ENABLE) +#define DC_CLEAR (DC_WA|DC_BE|DC_CLR|DC_ENABLE|IC_BE|IC_ENABLE) + +/* 68040 cache control register */ +#define IC4_ENABLE 0x8000 /* instruction cache enable bit */ +#define DC4_ENABLE 0x80000000 /* data cache enable bit */ + +#define CACHE4_ON (IC4_ENABLE|DC4_ENABLE) +#define CACHE4_OFF (0) diff --git a/sys/arch/mvme68k/include/db_machdep.h b/sys/arch/mvme68k/include/db_machdep.h new file mode 100644 index 0000000000000..a736e228618e6 --- /dev/null +++ b/sys/arch/mvme68k/include/db_machdep.h @@ -0,0 +1,4 @@ +/* $NetBSD: db_machdep.h,v 1.1.1.1 1995/07/25 23:12:14 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/disklabel.h b/sys/arch/mvme68k/include/disklabel.h new file mode 100644 index 0000000000000..9a0722ee82952 --- /dev/null +++ b/sys/arch/mvme68k/include/disklabel.h @@ -0,0 +1,46 @@ +/* $NetBSD: disklabel.h,v 1.1.1.1 1995/07/25 23:12:14 chuck 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/mvme68k/include/endian.h b/sys/arch/mvme68k/include/endian.h new file mode 100644 index 0000000000000..3876563a9f356 --- /dev/null +++ b/sys/arch/mvme68k/include/endian.h @@ -0,0 +1,4 @@ +/* $NetBSD: endian.h,v 1.1.1.1 1995/07/25 23:12:15 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/exec.h b/sys/arch/mvme68k/include/exec.h new file mode 100644 index 0000000000000..eea9bf11738ed --- /dev/null +++ b/sys/arch/mvme68k/include/exec.h @@ -0,0 +1,48 @@ +/* $NetBSD: exec.h,v 1.1.1.1 1995/07/25 23:12:15 chuck 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. 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_EXEC_H_ +#define _MACHINE_EXEC_H_ + +#define __LDPGSZ 8192 + +/* Relocation format. */ +struct relocation_info_m68k { + int r_address; /* offset in text or data segment */ + unsigned int r_symbolnum : 24, /* ordinal number of add symbol */ + 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_baserel : 1, /* linkage table relative */ + r_jmptable : 1, /* relocate to jump table */ + r_relative : 1, /* load address relative */ + r_copy : 1; /* run time copy */ +}; +#define relocation_info relocation_info_m68k + +#endif /* _MACHINE_EXEC_H_ */ diff --git a/sys/arch/mvme68k/include/float.h b/sys/arch/mvme68k/include/float.h new file mode 100644 index 0000000000000..5eeebfa7f4b83 --- /dev/null +++ b/sys/arch/mvme68k/include/float.h @@ -0,0 +1,8 @@ +/* $NetBSD: float.h,v 1.1.1.1 1995/07/25 23:12:15 chuck Exp $ */ + +#ifndef _MACHINE_FLOAT_H_ +#define _MACHINE_FLOAT_H_ + +#include + +#endif diff --git a/sys/arch/mvme68k/include/frame.h b/sys/arch/mvme68k/include/frame.h new file mode 100644 index 0000000000000..a6b1f3c584b66 --- /dev/null +++ b/sys/arch/mvme68k/include/frame.h @@ -0,0 +1,3 @@ +/* $NetBSD: frame.h,v 1.1.1.1 1995/07/25 23:12:15 chuck Exp $ */ + +#include diff --git a/sys/arch/mvme68k/include/limits.h b/sys/arch/mvme68k/include/limits.h new file mode 100644 index 0000000000000..ab36a0f1dc712 --- /dev/null +++ b/sys/arch/mvme68k/include/limits.h @@ -0,0 +1,4 @@ +/* $NetBSD: limits.h,v 1.1.1.1 1995/07/25 23:12:16 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/param.h b/sys/arch/mvme68k/include/param.h new file mode 100644 index 0000000000000..68866525b758e --- /dev/null +++ b/sys/arch/mvme68k/include/param.h @@ -0,0 +1,183 @@ +/* $NetBSD: param.h,v 1.1.1.1 1995/07/25 23:12:16 chuck 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. + * + * from: Utah $Hdr: machparam.h 1.16 92/12/20$ + * + * @(#)param.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine dependent constants for mvme68k, based on HP9000 series 300. + */ +#define MACHINE "mvme68k" +#define MACHINE_ARCH "m68k" +#define MID_MACHINE MID_M68K + +/* + * 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 PGSHIFT 12 /* LOG2(NBPG) */ +#define NBPG (1 << PGSHIFT) /* bytes/page */ +#define PGOFSET (NBPG-1) /* byte offset into page */ +#define NPTEPG (NBPG/(sizeof (pt_entry_t))) + +#define SEGSHIFT 22 /* LOG2(NBSEG) */ +#define NBSEG (1 << SEGSHIFT) /* bytes/segment */ +#define SEGOFSET (NBSEG-1) /* byte offset into segment */ + +#define KERNBASE 0x00000000 /* start of kernel virtual */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define DEV_BSIZE (1 << DEV_BSHIFT) +#define BLKDEV_IOSIZE 2048 +#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */ + +#define CLSIZELOG2 0 +#define CLSIZE (1 << CLSIZELOG2) + +/* 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 3 /* pages of u-area */ +#define USPACE (UPAGES * NBPG) /* total size of u-area */ + +/* + * Constants related to network buffer management. + * MCLBYTES must be no larger than CLBYTES (the software page size), and, + * on machines that exchange pages of input or output buffers with mbuf + * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple + * of the hardware page size. + */ +#define MSIZE 128 /* size of an mbuf */ +#define MCLSHIFT 11 +#define MCLBYTES (1 << MCLSHIFT) /* large enough for ether MTU */ +#define MCLOFSET (MCLBYTES - 1) + +#ifndef NMBCLUSTERS +#ifdef GATEWAY +#define NMBCLUSTERS 512 /* map size, max cluster allocation */ +#else +#define NMBCLUSTERS 256 /* map size, max cluster allocation */ +#endif +#endif + +/* + * Size of kernel malloc arena in CLBYTES-sized logical pages + */ +#ifndef NKMEMCLUSTERS +#define NKMEMCLUSTERS (2048 * 1024 / CLBYTES) +#endif + +/* pages ("clicks") to disk blocks */ +#define ctod(x) ((x) << (PGSHIFT - DEV_BSHIFT)) +#define dtoc(x) ((x) >> (PGSHIFT - DEV_BSHIFT)) + +/* pages to bytes */ +#define ctob(x) ((x) << PGSHIFT) +#define btoc(x) (((x) + PGOFSET) >> PGSHIFT) + +/* bytes to disk blocks */ +#define dbtob(x) ((x) << DEV_BSHIFT) +#define btodb(x) ((x) >> DEV_BSHIFT) + +/* + * Map a ``block device block'' to a file system block. + * This should be device dependent, and should use the bsize + * field from the disk label. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE / DEV_BSIZE)) + +/* + * Mach derived conversion macros + */ +#define m68k_round_page(x) ((((unsigned)(x)) + PGOFSET) & ~PGOFSET) +#define m68k_trunc_page(x) ((unsigned)(x) & ~PGOFSET) +#define m68k_btop(x) ((unsigned)(x) >> PGSHIFT) +#define m68k_ptob(x) ((unsigned)(x) << PGSHIFT) + +/* + * spl functions; all but spl0 are done in-line + */ +#include + +#define _spl(s) \ +({ \ + register int _spl_r; \ +\ + __asm __volatile ("clrl %0; movew sr,%0; movew %1,sr" : \ + "&=d" (_spl_r) : "di" (s)); \ + _spl_r; \ +}) + +/* spl0 requires checking for software interrupts */ +#define spl1() _spl(PSL_S|PSL_IPL1) +#define spl2() _spl(PSL_S|PSL_IPL2) +#define spl3() _spl(PSL_S|PSL_IPL3) +#define spl4() _spl(PSL_S|PSL_IPL4) +#define spl5() _spl(PSL_S|PSL_IPL5) +#define spl6() _spl(PSL_S|PSL_IPL6) +#define spl7() _spl(PSL_S|PSL_IPL7) + +#define splsoftclock() spl1() +#define splnet() spl1() +#define splbio() spl2() +#define splimp() spl3() +#define spltty() spl3() +#define splclock() spl5() +#define splstatclock() spl5() +#define splvm() spl5() +#define splhigh() spl7() +#define splsched() spl7() + +/* watch out for side effects */ +#define splx(s) (s & PSL_IPL ? _spl(s) : spl0()) + +#ifdef _KERNEL +#ifndef LOCORE +int cpuspeed; +#define DELAY(n) { register int N = cpuspeed * (n); while (--N > 0); } +#endif +#endif diff --git a/sys/arch/mvme68k/include/pcb.h b/sys/arch/mvme68k/include/pcb.h new file mode 100644 index 0000000000000..001543c03c47b --- /dev/null +++ b/sys/arch/mvme68k/include/pcb.h @@ -0,0 +1,67 @@ +/* $NetBSD: pcb.h,v 1.1.1.1 1995/07/25 23:12:16 chuck 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. + * + * from: Utah $Hdr: pcb.h 1.14 91/03/25$ + * + * @(#)pcb.h 8.1 (Berkeley) 6/10/93 + */ + +#include + +/* + * mvme68k process control block + */ +struct pcb { + short pcb_flags; /* misc. process flags */ + short pcb_ps; /* processor status word */ + int pcb_ustp; /* user segment table pointer */ + int pcb_usp; /* user stack pointer */ + int pcb_regs[12]; /* D2-D7, A2-A7 */ + caddr_t pcb_onfault; /* for copyin/out faults */ + struct fpframe pcb_fpregs; /* 68881/2 context save area */ +}; + +/* + * The pcb is augmented with machine-dependent additional data for + * core dumps. For the hp300, this includes an HP-UX exec header + * which is dumped for HP-UX processes. + */ +struct md_coredump { + int md_exec[16]; /* exec structure for HP-UX core dumps */ +}; diff --git a/sys/arch/mvme68k/include/pmap.h b/sys/arch/mvme68k/include/pmap.h new file mode 100644 index 0000000000000..323861224dd98 --- /dev/null +++ b/sys/arch/mvme68k/include/pmap.h @@ -0,0 +1,159 @@ +/* $NetBSD: pmap.h,v 1.1.1.1 1995/07/25 23:12:16 chuck Exp $ */ + +/* + * Copyright (c) 1987 Carnegie-Mellon University + * Copyright (c) 1991, 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. + * + * @(#)pmap.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _MACHINE_PMAP_H_ +#define _MACHINE_PMAP_H_ + +#include + +#if defined(M68040) +#define HP_SEG_SIZE (mmutype == MMU_68040 ? 0x40000 : NBSEG) +#else +#define HP_SEG_SIZE NBSEG +#endif + +#define m68k_trunc_seg(x) (((unsigned)(x)) & ~(HP_SEG_SIZE-1)) +#define m68k_round_seg(x) m68k_trunc_seg((unsigned)(x) + HP_SEG_SIZE-1) + +/* + * Pmap stuff + */ +struct pmap { + pt_entry_t *pm_ptab; /* KVA of page table */ + st_entry_t *pm_stab; /* KVA of segment table */ + int pm_stchanged; /* ST changed */ + int pm_stfree; /* 040: free lev2 blocks */ + st_entry_t *pm_stpa; /* 040: ST phys addr */ + short pm_sref; /* segment table 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; + +/* + * On the 040 we keep track of which level 2 blocks are already in use + * with the pm_stfree mask. Bits are arranged from LSB (block 0) to MSB + * (block 31). For convenience, the level 1 table is considered to be + * block 0. + * + * MAX[KU]L2SIZE control how many pages of level 2 descriptors are allowed. + * for the kernel and users. 8 implies only the initial "segment table" + * page is used. WARNING: don't change MAXUL2SIZE unless you can allocate + * physically contiguous pages for the ST in pmap.c! + */ +#define MAXKL2SIZE 32 +#define MAXUL2SIZE 8 +#define l2tobm(n) (1 << (n)) +#define bmtol2(n) (ffs(n) - 1) + +/* + * Macros for speed + */ +#define PMAP_ACTIVATE(pmapp, pcbp, iscurproc) \ + if ((pmapp)->pm_stchanged) { \ + (pcbp)->pcb_ustp = m68k_btop((vm_offset_t)(pmapp)->pm_stpa); \ + if (iscurproc) \ + loadustp((pcbp)->pcb_ustp); \ + (pmapp)->pm_stchanged = 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, the list is pv_table. + */ +struct pv_entry { + struct pv_entry *pv_next; /* next pv_entry */ + struct pmap *pv_pmap; /* pmap where mapping lies */ + vm_offset_t pv_va; /* virtual address for mapping */ + st_entry_t *pv_ptste; /* non-zero if VA maps a PT page */ + struct pmap *pv_ptpmap; /* if pv_ptste, pmap for PT page */ + int pv_flags; /* flags */ +}; + +#define PV_CI 0x01 /* header: all entries are cache inhibited */ +#define PV_PTPAGE 0x02 /* header: entry maps a page table page */ + +struct pv_page; + +struct pv_page_info { + TAILQ_ENTRY(pv_page) pgi_list; + struct pv_entry *pgi_freelist; + int pgi_nfree; +}; + +/* + * This is basically: + * ((NBPG - sizeof(struct pv_page_info)) / sizeof(struct pv_entry)) + */ +#define NPVPPG 170 + +struct pv_page { + struct pv_page_info pvp_pgi; + struct pv_entry pvp_pv[NPVPPG]; +}; + +#ifdef _KERNEL + +extern struct pmap kernel_pmap_store; +extern vm_offset_t vm_first_phys, vm_num_phys; + +#define pmap_kernel() (&kernel_pmap_store) +#define active_pmap(pm) \ + ((pm) == pmap_kernel() || (pm) == curproc->p_vmspace->vm_map.pmap) + +extern struct pv_entry *pv_table; /* array of entries, one per page */ + +#define pmap_page_index(pa) atop(pa - vm_first_phys) +#define pa_to_pvh(pa) (&pv_table[pmap_page_index(pa)]) + +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) + +extern pt_entry_t *Sysmap; +extern char *vmmap; /* map for mem, dumps, etc. */ +#endif /* _KERNEL */ + +#endif /* !_MACHINE_PMAP_H_ */ diff --git a/sys/arch/mvme68k/include/proc.h b/sys/arch/mvme68k/include/proc.h new file mode 100644 index 0000000000000..e50f573dea8e7 --- /dev/null +++ b/sys/arch/mvme68k/include/proc.h @@ -0,0 +1,53 @@ +/* $NetBSD: proc.h,v 1.1.1.1 1995/07/25 23:12:16 chuck 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. + * + * @(#)proc.h 8.1 (Berkeley) 6/10/93 + */ + +/* + * Machine-dependent part of the proc structure for mvme68k. + */ +struct mdproc { + int *md_regs; /* registers on current frame */ + int md_flags; /* machine-dependent flags */ +}; + +/* md_flags */ +#define MDP_STACKADJ 0x0002 /* frame SP adjusted, might have to + undo when system call returns + ERESTART. */ +#define MDP_HPUXTRACE 0x0004 /* being traced by HP-UX process */ +#define MDP_HPUXMMAP 0x0008 /* VA space is multiply mapped */ +#define MDP_CCBDATA 0x0010 /* copyback caching of data (68040) */ +#define MDP_CCBSTACK 0x0020 /* copyback caching of stack (68040) */ diff --git a/sys/arch/mvme68k/include/profile.h b/sys/arch/mvme68k/include/profile.h new file mode 100644 index 0000000000000..135774c7a25e8 --- /dev/null +++ b/sys/arch/mvme68k/include/profile.h @@ -0,0 +1,3 @@ +/* $NetBSD: profile.h,v 1.1.1.1 1995/07/25 23:12:17 chuck Exp $ */ + +#include diff --git a/sys/arch/mvme68k/include/psl.h b/sys/arch/mvme68k/include/psl.h new file mode 100644 index 0000000000000..e374e95e9bb83 --- /dev/null +++ b/sys/arch/mvme68k/include/psl.h @@ -0,0 +1,3 @@ +/* $NetBSD: psl.h,v 1.1.1.1 1995/07/25 23:12:17 chuck Exp $ */ + +#include diff --git a/sys/arch/mvme68k/include/pte.h b/sys/arch/mvme68k/include/pte.h new file mode 100644 index 0000000000000..e7c55296f1eac --- /dev/null +++ b/sys/arch/mvme68k/include/pte.h @@ -0,0 +1,152 @@ +/* $NetBSD: pte.h,v 1.1.1.1 1995/07/25 23:12:17 chuck 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. + * + * from: Utah $Hdr: pte.h 1.13 92/01/20$ + * + * @(#)pte.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _MACHINE_PTE_H_ +#define _MACHINE_PTE_H_ + +/* + * m68k hardware segment/page table entries + */ + +#if 0 +struct ste { + unsigned int sg_pfnum:20; /* page table frame number */ + unsigned int :8; /* reserved at 0 */ + unsigned int :1; /* reserved at 1 */ + unsigned int sg_prot:1; /* write protect bit */ + unsigned int sg_v:2; /* valid bits */ +}; + +struct ste40 { + unsigned int sg_ptaddr:24; /* page table page addr */ + unsigned int :4; /* reserved at 0 */ + unsigned int sg_u; /* hardware modified (dirty) bit */ + unsigned int sg_prot:1; /* write protect bit */ + unsigned int sg_v:2; /* valid bits */ +}; + +struct pte { + unsigned int pg_pfnum:20; /* page frame number or 0 */ + unsigned int :3; + unsigned int pg_w:1; /* is wired */ + unsigned int :1; /* reserved at zero */ + unsigned int pg_ci:1; /* cache inhibit bit */ + unsigned int :1; /* reserved at zero */ + unsigned int pg_m:1; /* hardware modified (dirty) bit */ + unsigned int pg_u:1; /* hardware used (reference) bit */ + unsigned int pg_prot:1; /* write protect bit */ + unsigned int pg_v:2; /* valid bit */ +}; +#endif + +typedef int st_entry_t; /* segment table entry */ +typedef int pt_entry_t; /* Mach page table entry */ + +#define PT_ENTRY_NULL ((pt_entry_t *) 0) +#define ST_ENTRY_NULL ((st_entry_t *) 0) + +#define SG_V 0x00000002 /* segment is valid */ +#define SG_NV 0x00000000 +#define SG_PROT 0x00000004 /* access protection mask */ +#define SG_RO 0x00000004 +#define SG_RW 0x00000000 +#define SG_U 0x00000008 /* modified bit (68040) */ +#define SG_FRAME 0xfffff000 +#define SG_IMASK 0xffc00000 +#define SG_ISHIFT 22 +#define SG_PMASK 0x003ff000 +#define SG_PSHIFT 12 + +/* 68040 additions */ +#define SG4_MASK1 0xfe000000 +#define SG4_SHIFT1 25 +#define SG4_MASK2 0x01fc0000 +#define SG4_SHIFT2 18 +#define SG4_MASK3 0x0003f000 +#define SG4_SHIFT3 12 +#define SG4_ADDR1 0xfffffe00 +#define SG4_ADDR2 0xffffff00 +#define SG4_LEV1SIZE 128 +#define SG4_LEV2SIZE 128 +#define SG4_LEV3SIZE 64 + +#define PG_V 0x00000001 +#define PG_NV 0x00000000 +#define PG_PROT 0x00000004 +#define PG_U 0x00000008 +#define PG_M 0x00000010 +#define PG_W 0x00000100 +#define PG_RO 0x00000004 +#define PG_RW 0x00000000 +#define PG_FRAME 0xfffff000 +#define PG_CI 0x00000040 +#define PG_SHIFT 12 +#define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) + +/* 68040 additions */ +#define PG_CMASK 0x00000060 /* cache mode mask */ +#define PG_CWT 0x00000000 /* writethrough caching */ +#define PG_CCB 0x00000020 /* copyback caching */ +#define PG_CIS 0x00000040 /* cache inhibited serialized */ +#define PG_CIN 0x00000060 /* cache inhibited nonserialized */ +#define PG_SO 0x00000080 /* supervisor only */ + +#define HP_STSIZE (MAXUL2SIZE*SG4_LEV2SIZE*sizeof(st_entry_t)) + /* user process segment table size */ +#define HP_MAX_PTSIZE 0x400000 /* max size of UPT */ +#define HP_MAX_KPTSIZE 0x100000 /* max memory to allocate to KPT */ +#define HP_PTBASE 0x10000000 /* UPT map base address */ +#define HP_PTMAXSIZE 0x70000000 /* UPT map maximum size */ + +/* + * Kernel virtual address to page table entry and to physical address. + */ +#define kvtopte(va) \ + (&Sysmap[((unsigned)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT]) +#define ptetokv(pt) \ + ((((pt_entry_t *)(pt) - Sysmap) << PGSHIFT) + VM_MIN_KERNEL_ADDRESS) +#define kvtophys(va) \ + ((kvtopte(va)->pg_pfnum << PGSHIFT) | ((int)(va) & PGOFSET)) + +#endif /* !_MACHINE_PTE_H_ */ diff --git a/sys/arch/mvme68k/include/ptrace.h b/sys/arch/mvme68k/include/ptrace.h new file mode 100644 index 0000000000000..5a92bbbe41015 --- /dev/null +++ b/sys/arch/mvme68k/include/ptrace.h @@ -0,0 +1,4 @@ +/* $NetBSD: ptrace.h,v 1.1.1.1 1995/07/25 23:12:17 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/reg.h b/sys/arch/mvme68k/include/reg.h new file mode 100644 index 0000000000000..a78c3a7c91050 --- /dev/null +++ b/sys/arch/mvme68k/include/reg.h @@ -0,0 +1,8 @@ +/* $NetBSD: reg.h,v 1.1.1.1 1995/07/25 23:12:18 chuck Exp $ */ + +#ifndef _MACHINE_REG_H_ +#define _MACHINE_REG_H_ + +#include + +#endif /* _MACHINE_REG_H_ */ diff --git a/sys/arch/mvme68k/include/setjmp.h b/sys/arch/mvme68k/include/setjmp.h new file mode 100644 index 0000000000000..bccffd9143bb4 --- /dev/null +++ b/sys/arch/mvme68k/include/setjmp.h @@ -0,0 +1,3 @@ +/* $NetBSD: setjmp.h,v 1.1.1.1 1995/07/25 23:12:18 chuck Exp $ */ + +#include diff --git a/sys/arch/mvme68k/include/signal.h b/sys/arch/mvme68k/include/signal.h new file mode 100644 index 0000000000000..a00ca454c0621 --- /dev/null +++ b/sys/arch/mvme68k/include/signal.h @@ -0,0 +1,4 @@ +/* $NetBSD: signal.h,v 1.1.1.1 1995/07/25 23:12:18 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/stdarg.h b/sys/arch/mvme68k/include/stdarg.h new file mode 100644 index 0000000000000..5018e7e3993a2 --- /dev/null +++ b/sys/arch/mvme68k/include/stdarg.h @@ -0,0 +1,4 @@ +/* $NetBSD: stdarg.h,v 1.1.1.1 1995/07/25 23:12:18 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/trap.h b/sys/arch/mvme68k/include/trap.h new file mode 100644 index 0000000000000..881b0ad8e3a76 --- /dev/null +++ b/sys/arch/mvme68k/include/trap.h @@ -0,0 +1,3 @@ +/* $NetBSD: trap.h,v 1.1.1.1 1995/07/25 23:12:19 chuck Exp $ */ + +#include diff --git a/sys/arch/mvme68k/include/types.h b/sys/arch/mvme68k/include/types.h new file mode 100644 index 0000000000000..0a0c7885eecc8 --- /dev/null +++ b/sys/arch/mvme68k/include/types.h @@ -0,0 +1,10 @@ +/* $NetBSD: types.h,v 1.1.1.1 1995/07/25 23:12:19 chuck Exp $ */ + +#ifndef _MACHINE_TYPES_H_ +#define _MACHINE_TYPES_H_ + +#include + +#define __BDEVSW_DUMP_OLD_TYPE + +#endif diff --git a/sys/arch/mvme68k/include/varargs.h b/sys/arch/mvme68k/include/varargs.h new file mode 100644 index 0000000000000..797ad3e7e0cbe --- /dev/null +++ b/sys/arch/mvme68k/include/varargs.h @@ -0,0 +1,4 @@ +/* $NetBSD: varargs.h,v 1.1.1.1 1995/07/25 23:12:19 chuck Exp $ */ + +/* Just use the common m68k definition */ +#include diff --git a/sys/arch/mvme68k/include/vmparam.h b/sys/arch/mvme68k/include/vmparam.h new file mode 100644 index 0000000000000..7e274b713dc92 --- /dev/null +++ b/sys/arch/mvme68k/include/vmparam.h @@ -0,0 +1,246 @@ +/* $NetBSD: vmparam.h,v 1.1.1.1 1995/07/25 23:12:19 chuck 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. + * + * from: Utah $Hdr: vmparam.h 1.16 91/01/18$ + * + * @(#)vmparam.h 8.2 (Berkeley) 4/19/94 + */ + +/* + * Machine dependent constants for MVME68K + */ +/* + * USRTEXT is the start of the user text/data space, while USRSTACK + * is the top (end) of the user stack. LOWPAGES and HIGHPAGES are + * the number of pages from the beginning of the P0 region to the + * beginning of the text and from the beginning of the P1 region to the + * beginning of the stack respectively. + * + * NOTE: the ONLY reason that HIGHPAGES is 0x100 instead of UPAGES (3) + * is for HPUX compatibility. Why?? Because HPUX's debuggers + * have the user's stack hard-wired at FFF00000 for post-mortems, + * and we must be compatible... + */ +#define USRTEXT 8192 /* Must equal __LDPGSZ */ +#define USRSTACK (-HIGHPAGES*NBPG) /* Start of user stack */ +#define BTOPUSRSTACK (0x100000-HIGHPAGES) /* btop(USRSTACK) */ +#define P1PAGES 0x100000 +#define LOWPAGES 0 +#define HIGHPAGES (0x100000/NBPG) + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ (8*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ (16*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (64*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (512*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ MAXDSIZ /* max stack size */ +#endif + +/* + * Default sizes of swap allocation chunks (see dmap.h). + * The actual values may be changed in vminit() based on MAXDSIZ. + * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024. + * DMMIN should be at least ctod(1) so that vtod() works. + * vminit() insures this. + */ +#define DMMIN 32 /* smallest swap allocation */ +#define DMMAX 4096 /* largest potential swap allocation */ + +/* + * Sizes of the system and user portions of the system page table. + */ +/* SYSPTSIZE IS SILLY; IT SHOULD BE COMPUTED AT BOOT TIME */ +#define SYSPTSIZE (2 * NPTEPG) /* 8mb */ +#define USRPTSIZE (1 * NPTEPG) /* 4mb */ + +/* + * PTEs for mapping user space into the kernel for phyio operations. + * One page is enough to handle 4Mb of simultaneous raw IO operations. + */ +#ifndef USRIOSIZE +#define USRIOSIZE (1 * NPTEPG) /* 4mb */ +#endif + +/* + * PTEs for system V style shared memory. + * This is basically slop for kmempt which we actually allocate (malloc) from. + */ +#ifndef SHMMAXPGS +#define SHMMAXPGS 1024 /* 4mb */ +#endif + +/* + * External IO space map size. + */ +#ifndef EIOMAPSIZE +#define EIOMAPSIZE 0 /* nothing */ +#endif + +/* + * Boundary at which to place first MAPMEM segment if not explicitly + * specified. Should be a power of two. This allows some slop for + * the data segment to grow underneath the first mapped segment. + */ +#define MMSEG 0x200000 + +/* + * The size of the clock loop. + */ +#define LOOPPAGES (maxfree - firstfree) + +/* + * The time for a process to be blocked before being very swappable. + * This is a number of seconds which the system takes as being a non-trivial + * amount of real time. You probably shouldn't change this; + * it is used in subtle ways (fractions and multiples of it are, that is, like + * half of a ``long time'', almost a long time, etc.) + * It is related to human patience and other factors which don't really + * change over time. + */ +#define MAXSLP 20 + +/* + * A swapped in process is given a small amount of core without being bothered + * by the page replacement algorithm. Basically this says that if you are + * swapped in you deserve some resources. We protect the last SAFERSS + * pages against paging and will just swap you out rather than paging you. + * Note that each process has at least UPAGES+CLSIZE pages which are not + * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this + * number just means a swapped in process is given around 25k bytes. + * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81), + * so we loan each swapped in process memory worth 100$, or just admit + * that we don't consider it worthwhile and swap it out to disk which costs + * $30/mb or about $0.75. + */ +#define SAFERSS 4 /* nominal ``small'' resident set size + protected against replacement */ + +/* + * DISKRPM is used to estimate the number of paging i/o operations + * which one can expect from a single disk controller. + */ +#define DISKRPM 60 + +/* + * Klustering constants. Klustering is the gathering + * of pages together for pagein/pageout, while clustering + * is the treatment of hardware page size as though it were + * larger than it really is. + * + * KLMAX gives maximum cluster size in CLSIZE page (cluster-page) + * units. Note that ctod(KLMAX*CLSIZE) must be <= DMMIN in dmap.h. + * ctob(KLMAX) should also be less than MAXPHYS (in vm_swp.c) + * unless you like "big push" panics. + */ + +#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 */ + +/* + * Paging thresholds (see vm_sched.c). + * Strategy of 1/19/85: + * lotsfree is 512k bytes, but at most 1/4 of memory + * desfree is 200k bytes, but at most 1/8 of memory + */ +#define LOTSFREE (512 * 1024) +#define LOTSFREEFRACT 4 +#define DESFREE (200 * 1024) +#define DESFREEFRACT 8 + +/* + * There are two clock hands, initially separated by HANDSPREAD bytes + * (but at most all of user memory). The amount of time to reclaim + * a page once the pageout process examines it increases with this + * distance and decreases as the scan rate rises. + */ +#define HANDSPREAD (2 * 1024 * 1024) + +/* + * The number of times per second to recompute the desired paging rate + * and poke the pagedaemon. + */ +#define RATETOSCHEDPAGING 4 + +/* + * Believed threshold (in megabytes) for which interleaved + * swapping area is desirable. + */ +#define LOTSOFMEM 2 + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS ((vm_offset_t)0) +#define VM_MAXUSER_ADDRESS ((vm_offset_t)0xFFF00000) +#define VM_MAX_ADDRESS ((vm_offset_t)0xFFF00000) +#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0) +#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFFFFF000) + +/* 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) diff --git a/sys/arch/mvme68k/mvme68k/autoconf.c b/sys/arch/mvme68k/mvme68k/autoconf.c new file mode 100644 index 0000000000000..02c0758dbc677 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/autoconf.c @@ -0,0 +1,251 @@ +/* $NetBSD: autoconf.c,v 1.1.1.1 1995/07/25 23:11:55 chuck 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. + * + * from: Utah $Hdr: autoconf.c 1.36 92/12/20$ + * + * @(#)autoconf.c 8.2 (Berkeley) 1/12/94 + */ + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * The following several variables are related to + * the configuration process, and are used in initializing + * the machine. + */ +int cold; /* if 1, still working on cold-start */ +int dkn; /* number of iostat dk numbers assigned so far */ +int cpuspeed = MHZ_16; /* relative cpu speed */ +struct isr isrqueue[NISR]; + +void mainbus_attach __P((struct device *, struct device *, void *)); +int mainbus_match __P((struct device *, void *, void *)); + +struct mainbus_softc { + struct device sc_dev; +}; + +struct cfdriver mainbuscd = { + NULL, "mainbus", mainbus_match, mainbus_attach, + DV_DULL, sizeof(struct mainbus_softc), 0 +}; + +int +mainbus_match(parent, cf, args) + struct device *parent; + void *cf; + void *args; +{ + return (1); +} + +void +mainbus_attach(parent, self, args) + struct device *parent, *self; + void *args; +{ + printf("\n"); + + while (config_found(self, NULL, NULL)) + ; +} +/* + * Determine mass storage and memory configuration for a machine. + */ +configure() +{ + init_sir(); + isrinit(); + + if (!config_rootfound("mainbus", NULL)) + panic("autoconfig failed, no root"); + +#if GENERIC + if ((boothowto & RB_ASKNAME) == 0) + setroot(); + setconf(); +#else + setroot(); +#endif + swapconf(); + cold = 0; +} + +isrinit() +{ + register int i; + + for (i = 0; i < NISR; i++) + isrqueue[i].isr_forw = isrqueue[i].isr_back = &isrqueue[i]; +} + +void +isrlink(isr) + register struct isr *isr; +{ + int i = ISRIPL(isr->isr_ipl); + + if (i < 0 || i >= NISR) { + printf("bad IPL %d\n", i); + panic("configure"); + } + insque(isr, isrqueue[i].isr_back); +} + +/* + * Configure swap space and related parameters. + */ +swapconf() +{ + register struct swdevt *swp; + register int nblks; + + for (swp = swdevt; swp->sw_dev != NODEV; swp++) + if (bdevsw[major(swp->sw_dev)].d_psize) { + nblks = + (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); + if (nblks != -1 && + (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) + swp->sw_nblks = nblks; + } + dumpconf(); +} + +#define DOSWAP /* Change swdevt and dumpdev too */ +u_long bootdev; /* should be dev_t, but not until 32 bits */ + +static char devname[][2] = { + 0,0, /* 0 = xx */ + 's','d', /* 1 = sd */ + 'w','d', /* 2 = wd */ + 0,0, /* 3 = sw */ + 'i','d', /* 4 = id */ +}; + +#define PARTITIONMASK 0x7 +#define PARTITIONSHIFT 3 + +/* + * 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() +{ + register struct hp_ctlr *hc; + register struct hp_device *hd; + int majdev, mindev, unit, part, controller, 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; + /* + * First, find the controller type which supports this device. + * Next, find the controller of that type corresponding to + * the adaptor number. + * Finally, find the device in question attached to that controller. + */ + /* + * Form a new rootdev + */ + mindev = (unit << PARTITIONSHIFT) + 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], + mindev >> PARTITIONSHIFT, part + 'a'); + +#ifdef DOSWAP + mindev &= ~PARTITIONMASK; + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (majdev == major(swp->sw_dev) && + mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev == NODEV) + return; + + /* + * If dumpdev was the same as the old primary swap + * device, move it to the new primary swap device. + */ + if (temp == dumpdev) + dumpdev = swdevt[0].sw_dev; +#endif +} diff --git a/sys/arch/mvme68k/mvme68k/clock.c b/sys/arch/mvme68k/mvme68k/clock.c new file mode 100644 index 0000000000000..2279e6a066a0b --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/clock.c @@ -0,0 +1,367 @@ +/* $NetBSD: clock.c,v 1.1.1.1 1995/07/25 23:11:56 chuck Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 8.1 (Berkeley) 6/11/93 + */ + + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(GPROF) +#include +#endif + +struct clocksc { + struct device sc_dev; + struct clockreg *sc_creg; +}; + +struct clockreg *RTCbase = NULL; +u_char clock_lvl; + +/* + * autoconf + */ + +void clockattach __P((struct device *, struct device *, void *)); +int clockmatch __P((struct device *, void *, void *)); + +struct cfdriver clockcd = { + NULL, "clock", clockmatch, clockattach, + DV_DULL, sizeof(struct clocksc), 0 +}; + +void clockintr __P((void *)); + +int +clockmatch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + + return RTCbase == NULL && !badbaddr((caddr_t) IIO_CFLOC_ADDR(cf)); +} + +void +clockattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + iio_print(self->dv_cfdata); + + if (RTCbase) + panic("too many clocks configured"); + + RTCbase = (struct clockreg *) IIO_CFLOC_ADDR(self->dv_cfdata); + clock_lvl = IIO_CFLOC_LEVEL(self->dv_cfdata); + if (clock_lvl != CLOCK_LEVEL) + panic("wrong interrupt level for clock"); + pccintr_establish(PCCV_TIMER1, clockintr, clock_lvl, NULL); + clock_lvl = clock_lvl | PCC_IENABLE | PCC_TIMERACK; + + printf("\n"); +} + +/* + * clockintr: ack intr and call hardclock + */ +void +clockintr(arg) + void *arg; +{ + sys_pcc->t1_int = clock_lvl; + hardclock(arg); +} + +/* + * Set up real-time clock; we don't have a statistics clock at + * present. + */ +cpu_initclocks() +{ + register struct clockreg *rtc = RTCbase; + + if (rtc == NULL) + panic("clock not configured"); + if (hz != 100) { + printf("%d Hz clock not available; using 100 Hz\n", hz); + hz = 100; + } + sys_pcc->t1_pload = PCC_TIMER100HZ; + sys_pcc->t1_cr = PCC_TIMERCLEAR; + sys_pcc->t1_cr = PCC_TIMERSTART; + sys_pcc->t1_int = clock_lvl; + + stathz = 0; +} + +void +setstatclockrate(newhz) + int newhz; +{ +} + +void +statintr(fp) + struct clockframe *fp; +{ +} + +/* + * Return the best possible estimate of the time in the timeval + * to which tvp points. We do this by returning the current time + * plus the amount of time since the last clock interrupt (clock.c:clkread). + * + * Check that this time is no less than any previously-reported time, + * which could happen around the time of a clock adjustment. Just for fun, + * we guarantee that the time will be greater than the value obtained by a + * previous call. + */ + +void microtime(tvp) + register struct timeval *tvp; +{ + int s = splhigh(); + static struct timeval lasttime; + + *tvp = time; + tvp->tv_usec; + while (tvp->tv_usec > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + if (tvp->tv_sec == lasttime.tv_sec && + tvp->tv_usec <= lasttime.tv_usec && + (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + lasttime = *tvp; + splx(s); +} + +/* + * BCD to decimal and decimal to BCD. + */ +#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) +#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10)) + +#define SECDAY (24 * 60 * 60) +#define SECYR (SECDAY * 365) +#define LEAPYEAR(y) (((y) & 3) == 0) + +/* + * This code is defunct after 2068. + * Will Unix still be here then?? + */ +const short dayyr[12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + +static u_long chiptotime(sec, min, hour, day, mon, year) + register int sec, min, hour, day, mon, year; +{ + register int days, yr; + + sec = FROMBCD(sec); + min = FROMBCD(min); + hour = FROMBCD(hour); + day = FROMBCD(day); + mon = FROMBCD(mon); + year = FROMBCD(year) + YEAR0; + + /* simple sanity checks */ + if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31) + return (0); + days = 0; + for (yr = 70; yr < year; yr++) + days += LEAPYEAR(yr) ? 366 : 365; + days += dayyr[mon - 1] + day - 1; + if (LEAPYEAR(yr) && mon > 2) + days++; + /* now have days since Jan 1, 1970; the rest is easy... */ + return (days * SECDAY + hour * 3600 + min * 60 + sec); +} + +struct chiptime { + int sec; + int min; + int hour; + int wday; + int day; + int mon; + int year; +}; + +timetochip(c) + register struct chiptime *c; +{ + register int t, t2, t3, now = time.tv_sec; + + /* compute the year */ + t2 = now / SECDAY; + t3 = (t2 + 2) % 7; /* day of week */ + c->wday = TOBCD(t3 + 1); + + t = 69; + while (t2 >= 0) { /* whittle off years */ + t3 = t2; + t++; + t2 -= LEAPYEAR(t) ? 366 : 365; + } + c->year = t; + + /* t3 = month + day; separate */ + t = LEAPYEAR(t); + for (t2 = 1; t2 < 12; t2++) + if (t3 < dayyr[t2] + (t && t2 > 1)) + break; + + /* t2 is month */ + c->mon = t2; + c->day = t3 - dayyr[t2 - 1] + 1; + if (t && t2 > 2) + c->day--; + + /* the rest is easy */ + t = now % SECDAY; + c->hour = t / 3600; + t %= 3600; + c->min = t / 60; + c->sec = t % 60; + + c->sec = TOBCD(c->sec); + c->min = TOBCD(c->min); + c->hour = TOBCD(c->hour); + c->day = TOBCD(c->day); + c->mon = TOBCD(c->mon); + c->year = TOBCD(c->year - YEAR0); +} + + +/* + * Set up the system's time, given a `reasonable' time value. + */ +inittodr(base) + time_t base; +{ + register struct clockreg *cl = RTCbase; + int sec, min, hour, day, mon, year; + int badbase = 0, waszero = base == 0; + + if (base < 5 * SECYR) { + /* + * If base is 0, assume filesystem time is just unknown + * in stead of preposterous. Don't bark. + */ + if (base != 0) + printf("WARNING: preposterous time in file system\n"); + /* not going to use it anyway, if the chip is readable */ + base = 21*SECYR + 186*SECDAY + SECDAY/2; + badbase = 1; + } + cl->cl_csr |= CLK_READ; /* enable read (stop time) */ + sec = cl->cl_sec; + min = cl->cl_min; + hour = cl->cl_hour; + day = cl->cl_mday; + mon = cl->cl_month; + year = cl->cl_year; + cl->cl_csr &= ~CLK_READ; /* time wears on */ + if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) { + printf("WARNING: bad date in battery clock"); + /* + * Believe the time in the file system for lack of + * anything better, resetting the clock. + */ + time.tv_sec = base; + if (!badbase) + resettodr(); + } else { + int deltat = time.tv_sec - base; + + if (deltat < 0) + deltat = -deltat; + if (waszero || deltat < 2 * SECDAY) + return; + printf("WARNING: clock %s %d days", + time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); + } + printf(" -- CHECK AND RESET THE DATE!\n"); +} + + +/* + * Reset the clock based on the current time. + * Used when the current clock is preposterous, when the time is changed, + * and when rebooting. Do nothing if the time is not yet known, e.g., + * when crashing during autoconfig. + */ +resettodr() +{ + register struct clockreg *cl; + struct chiptime c; + + if (!time.tv_sec || (cl = RTCbase) == NULL) + return; + timetochip(&c); + cl->cl_csr |= CLK_WRITE; /* enable write */ + cl->cl_sec = c.sec; + cl->cl_min = c.min; + cl->cl_hour = c.hour; + cl->cl_wday = c.wday; + cl->cl_mday = c.day; + cl->cl_month = c.mon; + cl->cl_year = c.year; + cl->cl_csr &= ~CLK_WRITE; /* load them up */ +} + diff --git a/sys/arch/mvme68k/mvme68k/clockreg.h b/sys/arch/mvme68k/mvme68k/clockreg.h new file mode 100644 index 0000000000000..19998f8265c4d --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/clockreg.h @@ -0,0 +1,76 @@ +/* $NetBSD: clockreg.h,v 1.1.1.1 1995/07/25 23:11:56 chuck Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + * + * @(#)clockreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Mostek MK48T02 clock. + */ +struct clockreg { + volatile u_char cl_csr; /* control register */ + volatile u_char cl_sec; /* seconds (0..59; BCD) */ + volatile u_char cl_min; /* minutes (0..59; BCD) */ + volatile u_char cl_hour; /* hour (0..23; BCD) */ + volatile u_char cl_wday; /* weekday (1..7) */ + volatile u_char cl_mday; /* day in month (1..31; BCD) */ + volatile u_char cl_month; /* month (1..12; BCD) */ + volatile u_char cl_year; /* year (0..99; BCD) */ +}; + +/* bits in cl_csr */ +#define CLK_WRITE 0x80 /* want to write */ +#define CLK_READ 0x40 /* want to read (freeze clock) */ + +/* + * Sun chose the year `68' as their base count, so that + * cl_year==0 means 1968. + */ +#define YEAR0 68 + + +/* + * interrupt level for clock + */ + +#define CLOCK_LEVEL 5 diff --git a/sys/arch/mvme68k/mvme68k/conf.c b/sys/arch/mvme68k/mvme68k/conf.c new file mode 100644 index 0000000000000..71daa131f9999 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/conf.c @@ -0,0 +1,278 @@ +/* $NetBSD: conf.c,v 1.1.1.1 1995/07/25 23:11:56 chuck 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 +#include +#include +#include +#include +#include +#include + +int ttselect __P((dev_t, int, struct proc *)); + +#ifdef LKM +int lkmenodev(); +#else +#define lkmenodev enodev +#endif + +#include "vnd.h" +bdev_decl(vnd); +bdev_decl(sw); +#include "sd.h" +bdev_decl(sd); +#include "cd.h" +bdev_decl(cd); +#include "st.h" +bdev_decl(st); + +struct bdevsw bdevsw[] = +{ + bdev_notdef(), /* 0 */ + bdev_notdef(), /* 1 */ + bdev_notdef(), /* 2 */ + bdev_swap_init(1,sw), /* 3: swap pseudo-device */ + bdev_disk_init(NSD,sd), /* 4: SCSI disk */ + bdev_tape_init(NST,st), /* 5: SCSI tape */ + bdev_disk_init(NVND,vnd), /* 6: vnode disk driver */ + bdev_disk_init(NCD,cd), /* 7: SCSI CD-ROM */ + bdev_notdef(), /* 8 */ + bdev_lkm_dummy(), /* 9 */ + bdev_lkm_dummy(), /* 10 */ + bdev_lkm_dummy(), /* 11 */ + bdev_lkm_dummy(), /* 12 */ + bdev_lkm_dummy(), /* 13 */ + bdev_lkm_dummy(), /* 14 */ +}; + +int nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]); + +cdev_decl(cn); +cdev_decl(ctty); +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); +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); +cdev_decl(fd); + +#include "zs.h" +cdev_decl(zs); + +cdev_decl(sd); +cdev_decl(cd); +cdev_decl(st); +cdev_decl(vnd); + +#include "bpfilter.h" +cdev_decl(bpf); + +#include "tun.h" +cdev_decl(tun); +#ifdef LKM +#define NLKM 1 +#else +#define NLKM 0 +#endif +cdev_decl(lkm); + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_ctty_init(1,ctty), /* 1: controlling terminal */ + cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */ + cdev_swap_init(1,sw), /* 3: /dev/drum (swap pseudo-device) */ + cdev_tty_init(NPTY,pts), /* 4: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 5: pseudo-tty master */ + cdev_log_init(1,log), /* 6: /dev/klog */ + cdev_notdef(), /* 7 */ + cdev_disk_init(NSD,sd), /* 8: SCSI disk */ + cdev_disk_init(NCD,cd), /* 9: SCSI CD-ROM */ + cdev_notdef(), /* 10 */ + cdev_notdef(), /* 11: parallel interface */ + cdev_tty_init(NZS,zs), /* 12: SCC serial ports */ + cdev_notdef(), /* 13 */ + cdev_notdef(), /* 14 */ + cdev_notdef(), /* 15 */ + cdev_notdef(), /* 16 */ + cdev_notdef(), /* 17: concatenated disk */ + cdev_notdef(), /* 18 */ + cdev_disk_init(NVND,vnd), /* 19: vnode disk */ + cdev_tape_init(NST,st), /* 20: SCSI tape */ + cdev_fd_init(1,fd), /* 21: file descriptor pseudo-dev */ + cdev_bpftun_init(NBPFILTER,bpf),/* 22: berkeley packet filter */ + cdev_bpftun_init(NTUN,tun), /* 23: network tunnel */ + cdev_lkm_init(NLKM,lkm), /* 24: loadable module driver */ + cdev_lkm_dummy(), /* 25 */ + cdev_lkm_dummy(), /* 26 */ + cdev_lkm_dummy(), /* 27 */ + cdev_lkm_dummy(), /* 28 */ + cdev_lkm_dummy(), /* 29 */ + cdev_lkm_dummy(), /* 30 */ +}; + +int nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]); + +int mem_no = 2; /* major device number of memory special file */ + +/* + * Swapdev is a fake device implemented + * in sw.c used only internally to get to swstrategy. + * It cannot be provided to the users, because the + * swstrategy routine munches the b_dev and b_blkno entries + * before calling the appropriate driver. This would horribly + * confuse, e.g. the hashing routines. Instead, /dev/drum is + * provided as a character (raw) device. + */ +dev_t swapdev = makedev(3, 0); + +/* + * Returns true if dev is /dev/mem or /dev/kmem. + */ +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); +} + +/* + * Returns true if dev is a disk device. + */ +isdisk(dev, type) + dev_t dev; + int type; +{ + + /* XXXX This needs to be dynamic for LKMs. */ + switch (major(dev)) { + case 1: + case 2: + case 4: + case 6: + return (type == VBLK); + case 8: + case 9: + case 10: + case 19: + return (type == VCHR); + default: + return (0); + } +} + +static int chrtoblktbl[] = { + /* XXXX This needs to be dynamic for LKMs. */ + /*VCHR*/ /*VBLK*/ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ NODEV, + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ 4, + /* 9 */ 7, + /* 10 */ NODEV, + /* 11 */ NODEV, + /* 12 */ NODEV, + /* 13 */ NODEV, + /* 14 */ NODEV, + /* 15 */ NODEV, + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ NODEV, + /* 19 */ 6, + /* 20 */ NODEV, + /* 21 */ NODEV, + /* 22 */ NODEV, +}; + +/* + * 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 + +#define zscnpollc nullcnpollc +cons_decl(zs); + +struct consdev constab[] = { +#if NZS > 0 + cons_init(zs), +#endif + { 0 }, +}; diff --git a/sys/arch/mvme68k/mvme68k/disksubr.c b/sys/arch/mvme68k/mvme68k/disksubr.c new file mode 100644 index 0000000000000..c4cbce6fdfb52 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/disksubr.c @@ -0,0 +1,198 @@ +/* $NetBSD: disksubr.c,v 1.1.1.1 1995/07/25 23:11:57 chuck Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1988, 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. + * + * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 + */ + +#include +#include +#include +#include +#include + +#define b_cylinder 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_cylinder = LABELSECTOR / lp->d_secpercyl; + (*strat)(bp); + if (biowait(bp)) + msg = "I/O error"; + else for (dlp = (struct disklabel *)bp->b_data; + dlp <= (struct disklabel *)((char *)bp->b_data + + 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. + */ +int +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. + */ +int +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_data; + dlp <= (struct disklabel *) + ((char *)bp->b_data + 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); +} diff --git a/sys/arch/mvme68k/mvme68k/dkbad.c b/sys/arch/mvme68k/mvme68k/dkbad.c new file mode 100644 index 0000000000000..686bc109912c6 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/dkbad.c @@ -0,0 +1,66 @@ +/* $NetBSD: dkbad.c,v 1.1.1.1 1995/07/25 23:11:57 chuck 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. + * + * @(#)dkbad.c 8.2 (Berkeley) 1/12/94 + */ + +#ifndef NOBADSECT +#include +#include +#include + +/* + * Search the bad sector table looking for + * the specified sector. Return index if found. + * Return -1 if not found. + */ + +isbad(bt, cyl, trk, sec) + register struct dkbad *bt; + int cyl, trk, sec; +{ + register int i; + register long blk, bblk; + + blk = ((long)cyl << 16) + (trk << 8) + sec; + for (i = 0; i < 126; i++) { + bblk = ((long)bt->bt_bad[i].bt_cyl << 16) + bt->bt_bad[i].bt_trksec; + if (blk == bblk) + return (i); + if (blk < bblk || bblk < 0) + break; + } + return (-1); +} +#endif diff --git a/sys/arch/mvme68k/mvme68k/genassym.c b/sys/arch/mvme68k/mvme68k/genassym.c new file mode 100644 index 0000000000000..ab87485ae4b5f --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/genassym.c @@ -0,0 +1,208 @@ +/* $NetBSD: genassym.c,v 1.1.1.1 1995/07/25 23:11:57 chuck 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. + * + * @(#)genassym.c 8.3 (Berkeley) 1/4/94 + */ + +/* XXXX */ +#define _VA_LIST_ _BSD_VA_LIST_ +#define _PTRDIFF_T_ _BSD_PTRDIFF_T_ + +#define _KERNEL + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern int errno; + +void +def(what, val) + char *what; + int val; +{ + + if (printf("#define\t%s\t%d\n", what, val) < 0) { + (void)fprintf(stderr, "genassym: printf: %s\n", + strerror(errno)); + exit(1); + } +} + +void +flush() +{ + + if (fflush(stdout) || fsync(fileno(stdout)) < 0) { + (void)fprintf(stderr, "genassym: flush stdout: %s\n", + strerror(errno)); + exit(1); + } +} + +#define off(what, s, m) def(what, (int)offsetof(s, m)) + +main() +{ + /* general constants */ + def("UPAGES", UPAGES); + def("USPACE", USPACE); + def("NBPG", NBPG); + def("PGSHIFT", PGSHIFT); + def("USRSTACK", USRSTACK); + + /* proc fields and values */ + off("P_FORW", struct proc, p_forw); + off("P_BACK", struct proc, p_back); + off("P_VMSPACE", struct proc, p_vmspace); + off("P_ADDR", struct proc, p_addr); + off("P_PRIORITY", struct proc, p_priority); + off("P_STAT", struct proc, p_stat); + off("P_WCHAN", struct proc, p_wchan); + off("P_FLAG", struct proc, p_flag); + off("P_MD_FLAGS", struct proc, p_md.md_flags); + off("P_MD_REGS", struct proc, p_md.md_regs); + + def("SSLEEP", SSLEEP); + def("SRUN", SRUN); + + /* VM structure fields */ + off("VM_PMAP", struct vmspace, vm_pmap); + off("PM_STCHG", struct pmap, pm_stchanged); + + /* interrupt/fault metering */ + off("V_SWTCH", struct vmmeter, v_swtch); + off("V_INTR", struct vmmeter, v_intr); + + /* trap types (should just include trap.h?) */ + def("T_BUSERR", T_BUSERR); + def("T_ADDRERR", T_ADDRERR); + def("T_ILLINST", T_ILLINST); + def("T_ZERODIV", T_ZERODIV); + def("T_CHKINST", T_CHKINST); + def("T_TRAPVINST", T_TRAPVINST); + def("T_PRIVINST", T_PRIVINST); + def("T_TRACE", T_TRACE); + def("T_MMUFLT", T_MMUFLT); + def("T_SSIR", T_SSIR); + def("T_FMTERR", T_FMTERR); + def("T_COPERR", T_COPERR); + def("T_FPERR", T_FPERR); + def("T_ASTFLT", T_ASTFLT); + def("T_TRAP15", T_TRAP15); + def("T_FPEMULI", T_FPEMULI); + def("T_FPEMULD", T_FPEMULD); + + /* PSL values (should just include psl.h?) */ + def("PSL_S", PSL_S); + def("PSL_IPL7", PSL_IPL7); + def("PSL_LOWIPL", PSL_LOWIPL); + def("PSL_HIGHIPL", PSL_HIGHIPL); + def("PSL_USER", PSL_USER); + def("SPL1", PSL_S | PSL_IPL1); + def("SPL2", PSL_S | PSL_IPL2); + def("SPL3", PSL_S | PSL_IPL3); + def("SPL4", PSL_S | PSL_IPL4); + def("SPL5", PSL_S | PSL_IPL5); + def("SPL6", PSL_S | PSL_IPL6); + + /* magic */ + def("FC_USERD", FC_USERD); + def("INTIOBASE", INTIOBASE); + def("IIOMAPSIZE", IIOMAPSIZE); + def("EIOMAPSIZE", EIOMAPSIZE); + def("CACHE_ON", CACHE_ON); + def("CACHE_OFF", CACHE_OFF); + def("CACHE_CLR", CACHE_CLR); + def("IC_CLEAR", IC_CLEAR); + def("DC_CLEAR", DC_CLEAR); + + /* pte/ste bits */ + def("PG_V", PG_V); + def("PG_NV", PG_NV); + def("PG_RO", PG_RO); + def("PG_RW", PG_RW); + def("PG_CI", PG_CI); + def("PG_PROT", PG_PROT); + def("PG_FRAME", PG_FRAME); + def("SG_V", SG_V); + def("SG_NV", SG_NV); + def("SG_RW", SG_RW); + def("SG_FRAME", SG_FRAME); + def("SG_ISHIFT", SG_ISHIFT); + + /* pcb fields */ + off("PCB_PS", struct pcb, pcb_ps); + off("PCB_USTP", struct pcb, pcb_ustp); + off("PCB_USP", struct pcb, pcb_usp); + off("PCB_REGS", struct pcb, pcb_regs); + off("PCB_ONFAULT", struct pcb, pcb_onfault); + off("PCB_FPCTX", struct pcb, pcb_fpregs); + def("SIZEOF_PCB", sizeof(struct pcb)); + + /* exception frame offset/sizes */ + off("FR_SP", struct frame, f_regs[15]); + off("FR_HW", struct frame, f_sr); + off("FR_ADJ", struct frame, f_stackadj); + + /* system calls */ + def("SYS_exit", SYS_exit); + def("SYS_execve", SYS_execve); + def("SYS_sigreturn", SYS_sigreturn); + + /* errno */ + def("EFAULT", EFAULT); + def("ENAMETOOLONG", ENAMETOOLONG); + + exit(0); +} diff --git a/sys/arch/mvme68k/mvme68k/isr.h b/sys/arch/mvme68k/mvme68k/isr.h new file mode 100644 index 0000000000000..01caf41b0fb2e --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/isr.h @@ -0,0 +1,47 @@ +/* $NetBSD: isr.h,v 1.1.1.1 1995/07/25 23:11:58 chuck Exp $ */ + +/* + * Copyright (c) 1982, 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. + * + * @(#)isr.h 7.1 (Berkeley) 5/8/90 + */ + +struct isr { + struct isr *isr_forw; + struct isr *isr_back; + int (*isr_intr)(); + int isr_arg; + int isr_ipl; +}; + +#define NISR 6 +#define ISRIPL(x) ((x) - 1) diff --git a/sys/arch/mvme68k/mvme68k/locore.s b/sys/arch/mvme68k/mvme68k/locore.s new file mode 100644 index 0000000000000..6e84797fa04d6 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/locore.s @@ -0,0 +1,1896 @@ +/* $NetBSD: locore.s,v 1.1.1.1 1995/07/25 23:11:58 chuck Exp $ */ + +#undef STACKCHECK /* doesn't work any more */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1980, 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: locore.s 1.66 92/12/22$ + * + * @(#)locore.s 8.6 (Berkeley) 5/27/94 + */ + +/* + * STACKCHECK enables two types of kernel stack checking: + * 1. stack "overflow". On every clock interrupt we ensure that + * the current kernel stack has not grown into the user struct + * page, i.e. size exceeded UPAGES-1 pages. + * 2. stack "underflow". Before every rte to user mode we ensure + * that we will be exactly at the base of the stack after the + * exception frame has been popped. + * Both checks are performed at splclock since they operate on the + * global temporary stack. + */ +/* #define STACKCHECK */ + +#include "assym.s" +#include + +/* + * Temporary stack for a variety of purposes. + * Try and make this the first thing is the data segment so it + * is page aligned. Note that if we overflow here, we run into + * our text segment. + */ + .data + .space NBPG +tmpstk: + + .text +/* + * This is where we wind up if the kernel jumps to location 0. + * (i.e. a bogus PC) This is known to immediately follow the vector + * table and is hence at 0x400 (see reset vector in vectors.s). + */ + .globl _panic + pea Ljmp0panic + jbsr _panic + /* NOTREACHED */ +Ljmp0panic: + .asciz "kernel jump to zero" + .even + +/* + * Do a dump. + * Called by auto-restart. + */ + .globl _dumpsys + .globl _doadump +_doadump: + jbsr _dumpsys + jbsr _doboot + /*NOTREACHED*/ + +/* + * Trap/interrupt vector routines + */ + + .globl _trap, _nofault, _longjmp +_buserr: + tstl _nofault | device probe? + jeq Lberr | no, handle as usual + movl _nofault,sp@- | yes, + jbsr _longjmp | longjmp(nofault) +Lberr: +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne _addrerr | no, skip + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- | save user registers + movl usp,a0 | save the user SP + movl a0,sp@(FR_SP) | in the savearea + lea sp@(FR_HW),a1 | grab base of HW berr frame + moveq #0,d0 + movw a1@(12),d0 | grab SSW + movl a1@(20),d1 | and fault VA + btst #11,d0 | check for mis-aligned access + jeq Lberr2 | no, skip + addl #3,d1 | yes, get into next page + andl #PG_FRAME,d1 | and truncate +Lberr2: + movl d1,sp@- | push fault VA + movl d0,sp@- | and padded SSW + btst #10,d0 | ATC bit set? + jeq Lisberr | no, must be a real bus error + movc dfc,d1 | yes, get MMU fault + movc d0,dfc | store faulting function code + movl sp@(4),a0 | get faulting address + .word 0xf568 | ptestr a0@ + movc d1,dfc + .long 0x4e7a0805 | movc mmusr,d0 + movw d0,sp@ | save (ONLY LOW 16 BITS!) + jra Lismerr +#endif +_addrerr: + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- | save user registers + movl usp,a0 | save the user SP + movl a0,sp@(FR_SP) | in the savearea + lea sp@(FR_HW),a1 | grab base of HW berr frame +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lbenot040 | no, skip + movl a1@(8),sp@- | yes, push fault address + clrl sp@- | no SSW for address fault + jra Lisaerr | go deal with it +Lbenot040: +#endif + moveq #0,d0 + movw a1@(10),d0 | grab SSW for fault processing + btst #12,d0 | RB set? + jeq LbeX0 | no, test RC + bset #14,d0 | yes, must set FB + movw d0,a1@(10) | for hardware too +LbeX0: + btst #13,d0 | RC set? + jeq LbeX1 | no, skip + bset #15,d0 | yes, must set FC + movw d0,a1@(10) | for hardware too +LbeX1: + btst #8,d0 | data fault? + jeq Lbe0 | no, check for hard cases + movl a1@(16),d1 | fault address is as given in frame + jra Lbe10 | thats it +Lbe0: + btst #4,a1@(6) | long (type B) stack frame? + jne Lbe4 | yes, go handle + movl a1@(2),d1 | no, can use save PC + btst #14,d0 | FB set? + jeq Lbe3 | no, try FC + addql #4,d1 | yes, adjust address + jra Lbe10 | done +Lbe3: + btst #15,d0 | FC set? + jeq Lbe10 | no, done + addql #2,d1 | yes, adjust address + jra Lbe10 | done +Lbe4: + movl a1@(36),d1 | long format, use stage B address + btst #15,d0 | FC set? + jeq Lbe10 | no, all done + subql #2,d1 | yes, adjust address +Lbe10: + movl d1,sp@- | push fault VA + movl d0,sp@- | and padded SSW + movw a1@(6),d0 | get frame format/vector offset + andw #0x0FFF,d0 | clear out frame format + cmpw #12,d0 | address error vector? + jeq Lisaerr | yes, go to it + movl d1,a0 | fault address + ptestr #1,a0@,#7 | do a table search + pmove psr,sp@ | save result + btst #7,sp@ | bus error bit set? + jeq Lismerr | no, must be MMU fault + clrw sp@ | yes, re-clear pad word + jra Lisberr | and process as normal bus error +Lismerr: + movl #T_MMUFLT,sp@- | show that we are an MMU fault + jra Ltrapnstkadj | and deal with it +Lisaerr: + movl #T_ADDRERR,sp@- | mark address error + jra Ltrapnstkadj | and deal with it +Lisberr: + movl #T_BUSERR,sp@- | mark bus error +Ltrapnstkadj: + jbsr _trap | handle the error + lea sp@(12),sp | pop value args + movl sp@(FR_SP),a0 | restore user SP + movl a0,usp | from save area + movw sp@(FR_ADJ),d0 | need to adjust stack? + jne Lstkadj | yes, go to it + moveml sp@+,#0x7FFF | no, restore most user regs + addql #8,sp | toss SSP and stkadj + jra rei | all done +Lstkadj: + lea sp@(FR_HW),a1 | pointer to HW frame + addql #8,a1 | source pointer + movl a1,a0 | source + addw d0,a0 | + hole size = dest pointer + movl a1@-,a0@- | copy + movl a1@-,a0@- | 8 bytes + movl a0,sp@(FR_SP) | new SSP + moveml sp@+,#0x7FFF | restore user registers + movl sp@,sp | and our SP + jra rei | all done + +/* + * FP exceptions. + */ +_fpfline: +#if defined(M68040) + cmpw #0x202c,sp@(6) | format type 2? + jne _illinst | no, not an FP emulation +#ifdef FPSP + .globl fpsp_unimp + jmp fpsp_unimp | yes, go handle it +#else + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- | save registers + moveq #T_FPEMULI,d0 | denote as FP emulation trap + jra fault | do it +#endif +#else + jra _illinst +#endif + +_fpunsupp: +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne _illinst | no, treat as illinst +#ifdef FPSP + .globl fpsp_unsupp + jmp fpsp_unsupp | yes, go handle it +#else + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- | save registers + moveq #T_FPEMULD,d0 | denote as FP emulation trap + jra fault | do it +#endif +#else + jra _illinst +#endif + +/* + * Handles all other FP coprocessor exceptions. + * Note that since some FP exceptions generate mid-instruction frames + * and may cause signal delivery, we need to test for stack adjustment + * after the trap call. + */ + .globl _fpfault +_fpfault: +#ifdef FPCOPROC + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- | save user registers + movl usp,a0 | and save + movl a0,sp@(FR_SP) | the user stack pointer + clrl sp@- | no VA arg + movl _curpcb,a0 | current pcb + lea a0@(PCB_FPCTX),a0 | address of FP savearea + fsave a0@ | save state + tstb a0@ | null state frame? + jeq Lfptnull | yes, safe + clrw d0 | no, need to tweak BIU + movb a0@(1),d0 | get frame size + bset #3,a0@(0,d0:w) | set exc_pend bit of BIU +Lfptnull: + fmovem fpsr,sp@- | push fpsr as code argument + frestore a0@ | restore state + movl #T_FPERR,sp@- | push type arg + jra Ltrapnstkadj | call trap and deal with stack cleanup +#else + jra _badtrap | treat as an unexpected trap +#endif + +/* + * Coprocessor and format errors can generate mid-instruction stack + * frames and cause signal delivery hence we need to check for potential + * stack adjustment. + */ +_coperr: + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- + movl usp,a0 | get and save + movl a0,sp@(FR_SP) | the user stack pointer + clrl sp@- | no VA arg + clrl sp@- | or code arg + movl #T_COPERR,sp@- | push trap type + jra Ltrapnstkadj | call trap and deal with stack adjustments + +_fmterr: + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- + movl usp,a0 | get and save + movl a0,sp@(FR_SP) | the user stack pointer + clrl sp@- | no VA arg + clrl sp@- | or code arg + movl #T_FMTERR,sp@- | push trap type + jra Ltrapnstkadj | call trap and deal with stack adjustments + +/* + * Other exceptions only cause four and six word stack frame and require + * no post-trap stack adjustment. + */ +_illinst: + clrl sp@- + moveml #0xFFFF,sp@- + moveq #T_ILLINST,d0 + jra fault + +_zerodiv: + clrl sp@- + moveml #0xFFFF,sp@- + moveq #T_ZERODIV,d0 + jra fault + +_chkinst: + clrl sp@- + moveml #0xFFFF,sp@- + moveq #T_CHKINST,d0 + jra fault + +_trapvinst: + clrl sp@- + moveml #0xFFFF,sp@- + moveq #T_TRAPVINST,d0 + jra fault + +_privinst: + clrl sp@- + moveml #0xFFFF,sp@- + moveq #T_PRIVINST,d0 + jra fault + + .globl fault +fault: + movl usp,a0 | get and save + movl a0,sp@(FR_SP) | the user stack pointer + clrl sp@- | no VA arg + clrl sp@- | or code arg + movl d0,sp@- | push trap type + jbsr _trap | handle trap + lea sp@(12),sp | pop value args + movl sp@(FR_SP),a0 | restore + movl a0,usp | user SP + moveml sp@+,#0x7FFF | restore most user regs + addql #8,sp | pop SP and stack adjust + jra rei | all done + + .globl _pcctrap +_pcctrap: + moveml #0xC0C0,sp@- | save scratch regs + lea sp@(16),a1 | get pointer to frame + movl a1,sp@- + movw sp@(26),d0 + movl d0,sp@- | push exception vector info + movl sp@(26),sp@- | and PC + jbsr _pccintr | doit + lea sp@(12),sp | pop value args + moveml sp@+,#0x0303 | restore regs + jra rei | all done + + .globl _straytrap +_badtrap: + moveml #0xC0C0,sp@- | save scratch regs + movw sp@(22),sp@- | push exception vector info + clrw sp@- + movl sp@(22),sp@- | and PC + jbsr _straytrap | report + addql #8,sp | pop args + moveml sp@+,#0x0303 | restore regs + jra rei | all done + + .globl _syscall +_trap0: + clrl sp@- | stack adjust count + moveml #0xFFFF,sp@- | save user registers + movl usp,a0 | save the user SP + movl a0,sp@(FR_SP) | in the savearea + movl d0,sp@- | push syscall number + jbsr _syscall | handle it + addql #4,sp | pop syscall arg + tstl _astpending + jne Lrei2 + tstb _ssir + jeq Ltrap1 + movw #SPL1,sr + tstb _ssir + jne Lsir1 +Ltrap1: + movl sp@(FR_SP),a0 | grab and restore + movl a0,usp | user SP + moveml sp@+,#0x7FFF | restore most registers + addql #8,sp | pop SP and stack adjust +#ifdef STACKCHECK + jra Ldorte +#else + rte +#endif + +/* + * Routines for traps 1 and 2. The meaning of the two traps depends + * on whether we are an HPUX compatible process or a native 4.3 process. + * Our native 4.3 implementation uses trap 1 as sigreturn() and trap 2 + * as a breakpoint trap. HPUX uses trap 1 for a breakpoint, so we have + * to make adjustments so that trap 2 is used for sigreturn. + */ +_trap1: +#ifdef COMPAT_HPUX + btst #MDP_TRCB,mdpflag | being traced by an HPUX process? + jeq sigreturn | no, trap1 is sigreturn + jra _trace | yes, trap1 is breakpoint +#else + jra sigreturn | no, trap1 is sigreturn +#endif + +_trap2: +#ifdef COMPAT_HPUX + btst #MDP_TRCB,mdpflag | being traced by an HPUX process? + jeq _trace | no, trap2 is breakpoint + jra sigreturn | yes, trap2 is sigreturn +#else + jra _trace | no, trap2 is breakpoint +#endif + +/* + * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD) + * cachectl(command, addr, length) + * command in d0, addr in a1, length in d1 + */ + .globl _cachectl +_trap12: + movl d1,sp@- | push length + movl a1,sp@- | push addr + movl d0,sp@- | push command + jbsr _cachectl | do it + lea sp@(12),sp | pop args + jra rei | all done + +/* + * Trap 15 is used for: + * - KGDB traps + * - trace traps for SUN binaries (not fully supported yet) + * We just pass it on and let trap() sort it all out + */ +_trap15: + clrl sp@- + moveml #0xFFFF,sp@- +#ifdef KGDB + moveq #T_TRAP15,d0 + movw sp@(FR_HW),d1 | get PSW + andw #PSL_S,d1 | from user mode? + jeq fault | yes, just a regular fault + movl d0,sp@- + .globl _kgdb_trap_glue + jbsr _kgdb_trap_glue | returns if no debugger + addl #4,sp +#endif + moveq #T_TRAP15,d0 + jra fault + +/* + * Hit a breakpoint (trap 1 or 2) instruction. + * Push the code and treat as a normal fault. + */ +_trace: + clrl sp@- + moveml #0xFFFF,sp@- +#ifdef KGDB + moveq #T_TRACE,d0 + movw sp@(FR_HW),d1 | get SSW + andw #PSL_S,d1 | from user mode? + jeq fault | no, regular fault + movl d0,sp@- + jbsr _kgdb_trap_glue | returns if no debugger + addl #4,sp +#endif + moveq #T_TRACE,d0 + jra fault + +/* + * The sigreturn() syscall comes here. It requires special handling + * because we must open a hole in the stack to fill in the (possibly much + * larger) original stack frame. + */ +sigreturn: + lea sp@(-84),sp | leave enough space for largest frame + movl sp@(84),sp@ | move up current 8 byte frame + movl sp@(88),sp@(4) + movl #84,sp@- | default: adjust by 84 bytes + moveml #0xFFFF,sp@- | save user registers + movl usp,a0 | save the user SP + movl a0,sp@(FR_SP) | in the savearea + movl #SYS_sigreturn,sp@- | push syscall number + jbsr _syscall | handle it + addql #4,sp | pop syscall# + movl sp@(FR_SP),a0 | grab and restore + movl a0,usp | user SP + lea sp@(FR_HW),a1 | pointer to HW frame + movw sp@(FR_ADJ),d0 | do we need to adjust the stack? + jeq Lsigr1 | no, just continue + moveq #92,d1 | total size + subw d0,d1 | - hole size = frame size + lea a1@(92),a0 | destination + addw d1,a1 | source + lsrw #1,d1 | convert to word count + subqw #1,d1 | minus 1 for dbf +Lsigrlp: + movw a1@-,a0@- | copy a word + dbf d1,Lsigrlp | continue + movl a0,a1 | new HW frame base +Lsigr1: + movl a1,sp@(FR_SP) | new SP value + moveml sp@+,#0x7FFF | restore user registers + movl sp@,sp | and our SP + jra rei | all done + +/* + * Interrupt handlers. + * All device interrupts are auto-vectored. Most + * interrupt in the range IPL1 to IPL6. Here are our assignments: + * + * Level 0: Spurious: ignored. + * Level 1: networking devices (ethernet) + * Level 2: bio devices (scsi) + * Level 3: + * Level 4: Serial (SCC) + * Level 5: Clock + * Level 6: + * Level 7: Non-maskable (none) + */ + .globl _intrhand, _hardclock, _nmihand + +_spurintr: + addql #1,_intrcnt+0 + addql #1,_cnt+V_INTR + jra rei + +_lev1intr: +_lev2intr: +_lev3intr: +_lev4intr: +_lev5intr: +_lev6intr: + moveml #0xC0C0,sp@- + lea _intrcnt,a0 + movw sp@(22),d0 | use vector offset + andw #0xfff,d0 | sans frame type + addql #1,a0@(-0x60,d0:w) | to increment apropos counter + movw sr,sp@- | push current SR value + clrw sp@- | padded to longword + jbsr _intrhand | handle interrupt + addql #4,sp | pop SR + moveml sp@+,#0x0303 + addql #1,_cnt+V_INTR + jra rei + +_lev7intr: + addql #1,_intrcnt+32 + clrl sp@- + moveml #0xFFFF,sp@- | save registers + movl usp,a0 | and save + movl a0,sp@(FR_SP) | the user stack pointer + jbsr _nmihand | call handler + movl sp@(FR_SP),a0 | restore + movl a0,usp | user SP + moveml sp@+,#0x7FFF | and remaining registers + addql #8,sp | pop SP and stack adjust + jra rei | all done + +/* + * Emulation of VAX REI instruction. + * + * This code deals with checking for and servicing ASTs + * (profiling, scheduling) and software interrupts (network, softclock). + * We check for ASTs first, just like the VAX. To avoid excess overhead + * the T_ASTFLT handling code will also check for software interrupts so we + * do not have to do it here. After identifing that we need an AST we + * drop the IPL to allow device interrupts. + * + * This code is complicated by the fact that sendsig may have been called + * necessitating a stack cleanup. + */ + .comm _ssir,1 + .globl _astpending + .globl rei +rei: +#ifdef STACKCHECK + tstl _panicstr | have we paniced? + jne Ldorte1 | yes, do not make matters worse +#endif + tstl _astpending | AST pending? + jeq Lchksir | no, go check for SIR +Lrei1: + btst #5,sp@ | yes, are we returning to user mode? + jne Lchksir | no, go check for SIR + movw #PSL_LOWIPL,sr | lower SPL + clrl sp@- | stack adjust + moveml #0xFFFF,sp@- | save all registers + movl usp,a1 | including + movl a1,sp@(FR_SP) | the users SP +Lrei2: + clrl sp@- | VA == none + clrl sp@- | code == none + movl #T_ASTFLT,sp@- | type == async system trap + jbsr _trap | go handle it + lea sp@(12),sp | pop value args + movl sp@(FR_SP),a0 | restore user SP + movl a0,usp | from save area + movw sp@(FR_ADJ),d0 | need to adjust stack? + jne Laststkadj | yes, go to it + moveml sp@+,#0x7FFF | no, restore most user regs + addql #8,sp | toss SP and stack adjust +#ifdef STACKCHECK + jra Ldorte +#else + rte | and do real RTE +#endif +Laststkadj: + lea sp@(FR_HW),a1 | pointer to HW frame + addql #8,a1 | source pointer + movl a1,a0 | source + addw d0,a0 | + hole size = dest pointer + movl a1@-,a0@- | copy + movl a1@-,a0@- | 8 bytes + movl a0,sp@(FR_SP) | new SSP + moveml sp@+,#0x7FFF | restore user registers + movl sp@,sp | and our SP +#ifdef STACKCHECK + jra Ldorte +#else + rte | and do real RTE +#endif +Lchksir: + tstb _ssir | SIR pending? + jeq Ldorte | no, all done + movl d0,sp@- | need a scratch register + movw sp@(4),d0 | get SR + andw #PSL_IPL7,d0 | mask all but IPL + jne Lnosir | came from interrupt, no can do + movl sp@+,d0 | restore scratch register +Lgotsir: + movw #SPL1,sr | prevent others from servicing int + tstb _ssir | too late? + jeq Ldorte | yes, oh well... + clrl sp@- | stack adjust + moveml #0xFFFF,sp@- | save all registers + movl usp,a1 | including + movl a1,sp@(FR_SP) | the users SP +Lsir1: + clrl sp@- | VA == none + clrl sp@- | code == none + movl #T_SSIR,sp@- | type == software interrupt + jbsr _trap | go handle it + lea sp@(12),sp | pop value args + movl sp@(FR_SP),a0 | restore + movl a0,usp | user SP + moveml sp@+,#0x7FFF | and all remaining registers + addql #8,sp | pop SP and stack adjust +#ifdef STACKCHECK + jra Ldorte +#else + rte +#endif +Lnosir: + movl sp@+,d0 | restore scratch register +Ldorte: +#ifdef STACKCHECK + movw #SPL6,sr | avoid trouble + btst #5,sp@ | are we returning to user mode? + jne Ldorte1 | no, skip it + movl a6,tmpstk-20 + movl d0,tmpstk-76 + moveq #0,d0 + movb sp@(6),d0 | get format/vector + lsrl #3,d0 | convert to index + lea _exframesize,a6 | into exframesize + addl d0,a6 | to get pointer to correct entry + movw a6@,d0 | get size for this frame + addql #8,d0 | adjust for unaccounted for bytes + lea _kstackatbase,a6 | desired stack base + subl d0,a6 | - frame size == our stack + cmpl a6,sp | are we where we think? + jeq Ldorte2 | yes, skip it + lea tmpstk,a6 | will be using tmpstk + movl sp@(4),a6@- | copy common + movl sp@,a6@- | frame info + clrl a6@- + movl sp,a6@- | save sp + subql #4,a6 | skip over already saved a6 + moveml #0x7FFC,a6@- | push remaining regs (d0/a6/a7 done) + lea a6@(-4),sp | switch to tmpstk (skip saved d0) + clrl sp@- | is an underflow + jbsr _badkstack | badkstack(0, frame) + addql #4,sp + moveml sp@+,#0x7FFF | restore most registers + movl sp@,sp | and SP + rte +Ldorte2: + movl tmpstk-76,d0 + movl tmpstk-20,a6 +Ldorte1: +#endif + rte | real return + +#ifdef STACKCHECK +/* + * Kernel access to the current processes kernel stack is via a fixed + * virtual address. It is at the same address as in the users VA space. + */ + .data + .set _kstack,USRSTACK + .set _kstackatbase,USRSTACK+USPACE-4 + .globl _kstackatbase + .globl _kstack +#endif + +#define RELOC(var, ar) \ + lea var,ar + +/* + * Initialization + * + * The bootstrap loader loads us in starting at 0, and VBR is non-zero. + * On entry, args on stack are boot device, boot filename, console unit, + * boot flags (howto), boot device name, filesystem type name. + */ + .comm _lowram,4 + .comm _esym,4 + + .text + .globl _edata + .globl _etext,_end + .globl start +start: + movw #PSL_HIGHIPL,sr | no interrupts + movl #0,d6 | get bootdev + movl sp@(4),d7 | get boothowto + RELOC(tmpstk, a0) + movl a0,sp | give ourselves a temporary stack + + lea _edata,a0 | clear out BSS + movl #_end-4,d0 | (must be <= 256 kB) + subl #_edata,d0 + lsrl #2,d0 +1: clrl a0@+ + dbra d0,1b + + RELOC(_esym, a0) +#if 1 + movl a4,a0@ | store end of symbol table +#else + clrl a0@ | no symbol table, yet +#endif + movl #0,a5 | RAM starts at 0 + RELOC(_lowram, a0) + movl a5,a0@ | store start of physical memory + movl #CACHE_OFF,d0 + movc d0,cacr | clear and disable on-chip cache(s) + +/* determine our CPU/MMU combo - check for all regardless of kernel config */ + movl #0x200,d0 | data freeze bit + movc d0,cacr | only exists on 68030 + movc cacr,d0 | read it back + tstl d0 | zero? + jeq Lnot68030 | yes, we have 68020/68040 + RELOC(_mmutype, a0) | no, we have 68030 + movl #-1,a0@ | set to reflect 68030 PMMU + jra Lstart1 +Lnot68030: + bset #31,d0 | data cache enable bit + movc d0,cacr | only exists on 68040 + movc cacr,d0 | read it back + tstl d0 | zero? + beq Lis68020 | yes, we have 68020 + moveq #0,d0 | now turn it back off + movec d0,cacr | before we access any data + RELOC(_mmutype, a0) + movl #-2,a0@ | with a 68040 MMU + jra Lstart1 +Lis68020: + RELOC(_mmutype, a0) + movl #1,a0@ | no, we have PMMU + +Lstart1: + /* XXXCDC SHUTUP 147 CALL */ + movb #0, 0xfffe1026 | serial interrupt off + movb #0, 0xfffe1018 | timer 1 off + movb #0, 0xfffe1028 | ethernet off + /* XXXCDC SHUTUP 147 CALL */ +/* initialize source/destination control registers for movs */ + moveq #FC_USERD,d0 | user space + movc d0,sfc | as source + movc d0,dfc | and destination of transfers +/* initialize memory sizes (for pmap_bootstrap) */ + movl 0xfffe0774,d1 | XXXCDC -- hardwired HEX + movl 0xfffe0778,_myea | XXXCDC -- ethernet addr + moveq #PGSHIFT,d2 + lsrl d2,d1 | convert to page (click) number + RELOC(_maxmem, a0) + movl d1,a0@ | save as maxmem + movl a5,d0 | lowram value from ROM via boot + lsrl d2,d0 | convert to page number + subl d0,d1 | compute amount of RAM present + RELOC(_physmem, a0) + movl d1,a0@ | and physmem +/* configure kernel and proc0 VA space so we can get going */ + .globl _Sysseg, _pmap_bootstrap, _avail_start +#ifdef DDB + RELOC(_esym,a0) | end of static kernel test/data/syms + movl a0@,d5 + jne Lstart2 +#endif + movl #_end,d5 | end of static kernel text/data +Lstart2: + addl #NBPG-1,d5 + andl #PG_FRAME,d5 | round to a page + movl d5,a4 + addl a5,a4 | convert to PA + movl #0, sp@- | firstpa + pea a4@ | nextpa + RELOC(_pmap_bootstrap,a0) + jbsr a0@ | pmap_bootstrap(firstpa, nextpa) + addql #8,sp + +/* + * Enable the MMU. + * Since the kernel is mapped logical == physical, we just turn it on. + */ + RELOC(_Sysseg, a0) | system segment table addr + movl a0@,d1 | read value (a KVA) + addl a5,d1 | convert to PA + RELOC(_mmutype, a0) + cmpl #-2,a0@ | 68040? + jne Lmotommu1 | no, skip + .long 0x4e7b1807 | movc d1,srp + jra Lstploaddone +Lmotommu1: + RELOC(_protorp, a0) + movl #0x80000202,a0@ | nolimit + share global + 4 byte PTEs + movl d1,a0@(4) | + segtable address + pmove a0@,srp | load the supervisor root pointer + movl #0x80000002,a0@ | reinit upper half for CRP loads +Lstploaddone: + RELOC(_mmutype, a0) + cmpl #-2,a0@ | 68040? + jne Lmotommu2 | no, skip + moveq #0,d0 | ensure TT regs are disabled + .long 0x4e7b0004 | movc d0,itt0 + .long 0x4e7b0005 | movc d0,itt1 + .long 0x4e7b0006 | movc d0,dtt0 + .long 0x4e7b0007 | movc d0,dtt1 + .word 0xf4d8 | cinva bc + .word 0xf518 | pflusha + movl #0x8000,d0 + .long 0x4e7b0003 | movc d0,tc + movl #0x80008000,d0 + movc d0,cacr | turn on both caches + jmp Lenab1 +Lmotommu2: + movl #0x82c0aa00,a2@ | value to load TC with + pmove a2@,tc | load it +Lenab1: + +/* + * Should be running mapped from this point on + */ +/* select the software page size now */ + lea tmpstk,sp | temporary stack + jbsr _vm_set_page_size | select software page size +/* set kernel stack, user SP, and initial pcb */ + movl _proc0paddr,a1 | get proc0 pcb addr + lea a1@(USPACE-4),sp | set kernel stack to end of area + movl #USRSTACK-4,a2 + movl a2,usp | init user SP + movl a1,_curpcb | proc0 is running +#ifdef FPCOPROC + clrl a1@(PCB_FPCTX) | ensure null FP context + movl a1,sp@- + jbsr _m68881_restore | restore it (does not kill a1) + addql #4,sp +#endif +/* flush TLB and turn on caches */ + jbsr _TBIA | invalidate TLB + cmpl #-2,_mmutype | 68040? + jeq Lnocache0 | yes, cache already on + movl #CACHE_ON,d0 + movc d0,cacr | clear cache(s) +Lnocache0: +/* final setup for C code */ + movl #0x8000,d0 | set VBR XXXCDC + movc d0,vbr + jbsr _isrinit | be ready for stray ints + movw #PSL_LOWIPL,sr | lower SPL + movl d7,_boothowto | save reboot flags + movl d6,_bootdev | and boot device + +/* + * Create a fake exception frame so that cpu_fork() can copy it. + * main() nevers returns; we exit to user mode from a forked process + * later on. + */ + clrw sp@- | vector offset/frame type + clrl sp@- | PC - filled in by "execve" + movw #PSL_USER,sp@- | in user mode + clrl sp@- | stack adjust count and padding + lea sp@(-64),sp | construct space for D0-D7/A0-A7 + lea _proc0,a0 | save pointer to frame + movl sp,a0@(P_MD_REGS) | in proc0.p_md.md_regs + + jra _main | main() + + .globl _proc_trampoline +_proc_trampoline: + movl a3@(P_MD_REGS),sp | process' frame pointer in sp + movl a3,sp@- + jbsr a2@ + addql #4,sp + movl sp@(FR_SP),a0 | grab and load + movl a0,usp | user SP + moveml sp@+,#0x7FFF | restore most user regs + addql #8,sp | toss SP and stack adjust + jra rei | and return + +/* + * Signal "trampoline" code (18 bytes). Invoked from RTE setup by sendsig(). + * + * Stack looks like: + * + * sp+0 -> signal number + * sp+4 signal specific code + * sp+8 pointer to signal context frame (scp) + * sp+12 address of handler + * sp+16 saved hardware state + * . + * . + * scp+0-> beginning of signal context frame + */ + .globl _sigcode, _esigcode, _sigcodetrap + .data +_sigcode: + movl sp@(12),a0 | signal handler addr (4 bytes) + jsr a0@ | call signal handler (2 bytes) + addql #4,sp | pop signo (2 bytes) +_sigcodetrap: + trap #1 | special syscall entry (2 bytes) + movl d0,sp@(4) | save errno (4 bytes) + moveq #1,d0 | syscall == exit (2 bytes) + trap #0 | exit(errno) (2 bytes) + .align 2 +_esigcode: + +/* + * Primitives + */ + +#ifdef __STDC__ +#define EXPORT(name) .globl _ ## name; _ ## name: +#else +#define EXPORT(name) .globl _/**/name; _/**/name: +#endif +#ifdef GPROF +#if __GNUC__ >= 2 +#define ENTRY(name) EXPORT(name) link a6,\#0; jbsr mcount; unlk a6 +#else +#define ENTRY(name) EXPORT(name) link a6,#0; jbsr mcount; unlk a6 +#endif +#define ALTENTRY(name, rname) ENTRY(name); jra rname+12 +#else +#define ENTRY(name) EXPORT(name) +#define ALTENTRY(name, rname) ENTRY(name) +#endif + +/* + * copypage(fromaddr, toaddr) + * + * Optimized version of bcopy for a single page-aligned NBPG byte copy. + */ +ENTRY(copypage) + movl sp@(4),a0 | source address + movl sp@(8),a1 | destination address + movl #NBPG/32,d0 | number of 32 byte chunks +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lmlloop | no, use movl +Lm16loop: + .long 0xf6209000 | move16 a0@+,a1@+ + .long 0xf6209000 | move16 a0@+,a1@+ + subql #1,d0 + jne Lm16loop + rts +#endif +Lmlloop: + movl a0@+,a1@+ + movl a0@+,a1@+ + movl a0@+,a1@+ + movl a0@+,a1@+ + movl a0@+,a1@+ + movl a0@+,a1@+ + movl a0@+,a1@+ + movl a0@+,a1@+ + subql #1,d0 + jne Lmlloop + rts + +/* + * non-local gotos + */ +ENTRY(setjmp) + movl sp@(4),a0 | savearea pointer + moveml #0xFCFC,a0@ | save d2-d7/a2-a7 + movl sp@,a0@(48) | and return address + moveq #0,d0 | return 0 + rts + +ENTRY(longjmp) + movl sp@(4),a0 + moveml a0@+,#0xFCFC + movl a0@,sp@ + moveq #1,d0 + rts + +/* + * The following primitives manipulate the run queues. _whichqs tells which + * of the 32 queues _qs have processes in them. Setrunqueue puts processes + * into queues, Remrq removes them from queues. The running process is on + * no queue, other processes are on a queue related to p->p_priority, divided + * by 4 actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ + + .globl _whichqs,_qs,_cnt,_panic + .globl _curproc,_want_resched + +/* + * Setrunqueue(p) + * + * Call should be made at spl6(), and p->p_stat should be SRUN + */ +ENTRY(setrunqueue) + movl sp@(4),a0 +#ifdef DIAGNOSTIC + tstl a0@(P_BACK) + jne Lset1 + tstl a0@(P_WCHAN) + jne Lset1 + cmpb #SRUN,a0@(P_STAT) + jne Lset1 +#endif + clrl d0 + movb a0@(P_PRIORITY),d0 + lsrb #2,d0 + movl _whichqs,d1 + bset d0,d1 + movl d1,_whichqs + lslb #3,d0 + addl #_qs,d0 + movl d0,a0@(P_FORW) + movl d0,a1 + movl a1@(P_BACK),a0@(P_BACK) + movl a0,a1@(P_BACK) + movl a0@(P_BACK),a1 + movl a0,a1@(P_FORW) + rts +#ifdef DIAGNOSTIC +Lset1: + movl #Lset2,sp@- + jbsr _panic +Lset2: + .asciz "setrunqueue" + .even +#endif + +/* + * Remrq(p) + * + * Call should be made at spl6(). + */ +ENTRY(remrq) + movl sp@(4),a0 + movb a0@(P_PRIORITY),d0 +#ifdef DIAGNOSTIC + lsrb #2,d0 + movl _whichqs,d1 + btst d0,d1 + jeq Lrem2 +#endif + movl a0@(P_BACK),a1 + clrl a0@(P_BACK) + movl a0@(P_FORW),a0 + movl a0,a1@(P_FORW) + movl a1,a0@(P_BACK) + cmpal a0,a1 + jne Lrem1 +#ifndef DIAGNOSTIC + lsrb #2,d0 + movl _whichqs,d1 +#endif + bclr d0,d1 + movl d1,_whichqs +Lrem1: + rts +#ifdef DIAGNOSTIC +Lrem2: + movl #Lrem3,sp@- + jbsr _panic +Lrem3: + .asciz "remrq" + .even +#endif + +Lsw0: + .asciz "switch" + .even + + .globl _curpcb + .globl _masterpaddr | XXX compatibility (debuggers) + .data +_masterpaddr: | XXX compatibility (debuggers) +_curpcb: + .long 0 +mdpflag: + .byte 0 | copy of proc md_flags low byte + .align 2 + .comm nullpcb,SIZEOF_PCB + .text + +/* + * At exit of a process, do a switch for the last time. + * Switch to a safe stack and PCB, and deallocate the process's resources. + */ +ENTRY(switch_exit) + movl sp@(4),a0 + movl #nullpcb,_curpcb | save state into garbage pcb + lea tmpstk,sp | goto a tmp stack + + /* Free old process's resources. */ + movl #USPACE,sp@- | size of u-area + movl a0@(P_ADDR),sp@- | address of process's u-area + movl _kernel_map,sp@- | map it was allocated in + jbsr _kmem_free | deallocate it + lea sp@(12),sp | pop args + + jra _cpu_switch + +/* + * When no processes are on the runq, Swtch branches to Idle + * to wait for something to come ready. + */ + .globl Idle +Idle: + stop #PSL_LOWIPL + movw #PSL_HIGHIPL,sr + movl _whichqs,d0 + jeq Idle + jra Lsw1 + +Lbadsw: + movl #Lsw0,sp@- + jbsr _panic + /*NOTREACHED*/ + +/* + * cpu_switch() + * + * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the + * entire ATC. The effort involved in selective flushing may not be + * worth it, maybe we should just flush the whole thing? + * + * NOTE 2: With the new VM layout we now no longer know if an inactive + * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag + * bit). For now, we just always flush the full ATC. + */ +ENTRY(cpu_switch) + movl _curpcb,a0 | current pcb + movw sr,a0@(PCB_PS) | save sr before changing ipl +#ifdef notyet + movl _curproc,sp@- | remember last proc running +#endif + clrl _curproc + + /* + * Find the highest-priority queue that isn't empty, + * then take the first proc from that queue. + */ + movw #PSL_HIGHIPL,sr | lock out interrupts + movl _whichqs,d0 + jeq Idle +Lsw1: + movl d0,d1 + negl d0 + andl d1,d0 + bfffo d0{#0:#32},d1 + eorib #31,d1 + + movl d1,d0 + lslb #3,d1 | convert queue number to index + addl #_qs,d1 | locate queue (q) + movl d1,a1 + movl a1@(P_FORW),a0 | p = q->p_forw + cmpal d1,a0 | anyone on queue? + jeq Lbadsw | no, panic + movl a0@(P_FORW),a1@(P_FORW) | q->p_forw = p->p_forw + movl a0@(P_FORW),a1 | n = p->p_forw + movl d1,a1@(P_BACK) | n->p_back = q + cmpal d1,a1 | anyone left on queue? + jne Lsw2 | yes, skip + movl _whichqs,d1 + bclr d0,d1 | no, clear bit + movl d1,_whichqs +Lsw2: + movl a0,_curproc + clrl _want_resched +#ifdef notyet + movl sp@+,a1 + cmpl a0,a1 | switching to same proc? + jeq Lswdone | yes, skip save and restore +#endif + /* + * Save state of previous process in its pcb. + */ + movl _curpcb,a1 + moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers + movl usp,a2 | grab USP (a2 has been saved) + movl a2,a1@(PCB_USP) | and save it +#ifdef FPCOPROC + lea a1@(PCB_FPCTX),a2 | pointer to FP save area + fsave a2@ | save FP state + tstb a2@ | null state frame? + jeq Lswnofpsave | yes, all done + fmovem fp0-fp7,a2@(216) | save FP general registers + fmovem fpcr/fpsr/fpi,a2@(312) | save FP control registers +Lswnofpsave: +#endif + +#ifdef DIAGNOSTIC + tstl a0@(P_WCHAN) + jne Lbadsw + cmpb #SRUN,a0@(P_STAT) + jne Lbadsw +#endif + clrl a0@(P_BACK) | clear back link + movb a0@(P_MD_FLAGS+3),mdpflag | low byte of p_md.md_flags + movl a0@(P_ADDR),a1 | get p_addr + movl a1,_curpcb + + /* see if pmap_activate needs to be called; should remove this */ + movl a0@(P_VMSPACE),a0 | vmspace = p->p_vmspace +#ifdef DIAGNOSTIC + tstl a0 | map == VM_MAP_NULL? + jeq Lbadsw | panic +#endif + lea a0@(VM_PMAP),a0 | pmap = &vmspace.vm_pmap + tstl a0@(PM_STCHG) | pmap->st_changed? + jeq Lswnochg | no, skip + pea a1@ | push pcb (at p_addr) + pea a0@ | push pmap + jbsr _pmap_activate | pmap_activate(pmap, pcb) + addql #8,sp + movl _curpcb,a1 | restore p_addr +Lswnochg: + + lea tmpstk,sp | now goto a tmp stack for NMI +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lres1a | no, skip + .word 0xf518 | yes, pflusha + movl a1@(PCB_USTP),d0 | get USTP + moveq #PGSHIFT,d1 + lsll d1,d0 | convert to addr + .long 0x4e7b0806 | movc d0,urp + jra Lcxswdone +Lres1a: +#endif + movl #CACHE_CLR,d0 + movc d0,cacr | invalidate cache(s) + pflusha | flush entire TLB + movl a1@(PCB_USTP),d0 | get USTP + moveq #PGSHIFT,d1 + lsll d1,d0 | convert to addr + lea _protorp,a0 | CRP prototype + movl d0,a0@(4) | stash USTP + pmove a0@,crp | load new user root pointer +Lcxswdone: + moveml a1@(PCB_REGS),#0xFCFC | and registers + movl a1@(PCB_USP),a0 + movl a0,usp | and USP +#ifdef FPCOPROC + lea a1@(PCB_FPCTX),a0 | pointer to FP save area + tstb a0@ | null state frame? + jeq Lresfprest | yes, easy +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lresnot040 | no, skip + clrl sp@- | yes... + frestore sp@+ | ...magic! +Lresnot040: +#endif + fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers + fmovem a0@(216),fp0-fp7 | restore FP general registers +Lresfprest: + frestore a0@ | restore state +#endif + movw a1@(PCB_PS),sr | no, restore PS + moveq #1,d0 | return 1 (for alternate returns) + rts + +/* + * savectx(pcb) + * Update pcb, saving current processor state. + */ +ENTRY(savectx) + movl sp@(4),a1 + movw sr,a1@(PCB_PS) + movl usp,a0 | grab USP + movl a0,a1@(PCB_USP) | and save it + moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers +#ifdef FPCOPROC + lea a1@(PCB_FPCTX),a0 | pointer to FP save area + fsave a0@ | save FP state + tstb a0@ | null state frame? + jeq Lsvnofpsave | yes, all done + fmovem fp0-fp7,a0@(216) | save FP general registers + fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers +Lsvnofpsave: +#endif + moveq #0,d0 | return 0 + rts + +#if defined(M68040) +ENTRY(suline) + movl sp@(4),a0 | address to write + movl _curpcb,a1 | current pcb + movl #Lslerr,a1@(PCB_ONFAULT) | where to return to on a fault + movl sp@(8),a1 | address of line + movl a1@+,d0 | get lword + movsl d0,a0@+ | put lword + nop | sync + movl a1@+,d0 | get lword + movsl d0,a0@+ | put lword + nop | sync + movl a1@+,d0 | get lword + movsl d0,a0@+ | put lword + nop | sync + movl a1@+,d0 | get lword + movsl d0,a0@+ | put lword + nop | sync + moveq #0,d0 | indicate no fault + jra Lsldone +Lslerr: + moveq #-1,d0 +Lsldone: + movl _curpcb,a1 | current pcb + clrl a1@(PCB_ONFAULT) | clear fault address + rts +#endif + +/* + * Invalidate entire TLB. + */ +ENTRY(TBIA) +__TBIA: +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lmotommu3 | no, skip + .word 0xf518 | yes, pflusha + rts +Lmotommu3: +#endif + tstl _mmutype | what mmu? + jpl Lmc68851a | 68851 implies no d-cache + movl #DC_CLEAR,d0 + movc d0,cacr | invalidate on-chip d-cache +Lmc68851a: + rts + +/* + * Invalidate any TLB entry for given VA (TB Invalidate Single) + */ +ENTRY(TBIS) +#ifdef DEBUG + tstl fulltflush | being conservative? + jne __TBIA | yes, flush entire TLB +#endif +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lmotommu4 | no, skip + movl sp@(4),a0 + movc dfc,d1 + moveq #1,d0 | user space + movc d0,dfc + .word 0xf508 | pflush a0@ + moveq #5,d0 | super space + movc d0,dfc + .word 0xf508 | pflush a0@ + movc d1,dfc + rts +Lmotommu4: +#endif + tstl _mmutype | is 68851? + jpl Lmc68851b | + movl sp@(4),a0 | get addr to flush + pflush #0,#0,a0@ | flush address from both sides + movl #DC_CLEAR,d0 + movc d0,cacr | invalidate on-chip data cache + rts +Lmc68851b: + pflushs #0,#0,a0@ | flush address from both sides + rts + +/* + * Invalidate supervisor side of TLB + */ +ENTRY(TBIAS) +#ifdef DEBUG + tstl fulltflush | being conservative? + jne __TBIA | yes, flush everything +#endif +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lmotommu5 | no, skip + .word 0xf518 | yes, pflusha (for now) XXX + rts +Lmotommu5: +#endif + pflush #4,#4 | flush supervisor TLB entries + movl #DC_CLEAR,d0 + movc d0,cacr | invalidate on-chip d-cache + rts + +/* + * Invalidate user side of TLB + */ +ENTRY(TBIAU) +#ifdef DEBUG + tstl fulltflush | being conservative? + jne __TBIA | yes, flush everything +#endif +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne Lmotommu6 | no, skip + .word 0xf518 | yes, pflusha (for now) XXX + rts +Lmotommu6: +#endif + pflush #0,#4 | flush user TLB entries + movl #DC_CLEAR,d0 + movc d0,cacr | invalidate on-chip d-cache + rts + +/* + * Invalidate instruction cache + */ +ENTRY(ICIA) +#if defined(M68040) +ENTRY(ICPA) + cmpl #-2,_mmutype | 68040 + jne Lmotommu7 | no, skip + .word 0xf498 | cinva ic + rts +Lmotommu7: +#endif + movl #IC_CLEAR,d0 + movc d0,cacr | invalidate i-cache + rts + +/* + * Invalidate data cache. + * NOTE: we do not flush 68030 on-chip cache as there are no aliasing + * problems with DC_WA. The only cases we have to worry about are context + * switch and TLB changes, both of which are handled "in-line" in resume + * and TBI*. + */ +ENTRY(DCIA) +__DCIA: +#if defined(M68040) + cmpl #-2,_mmutype | 68040 + jne Lmotommu8 | no, skip + /* XXX implement */ + rts +Lmotommu8: +#endif + rts + +ENTRY(DCIS) +__DCIS: +#if defined(M68040) + cmpl #-2,_mmutype | 68040 + jne Lmotommu9 | no, skip + /* XXX implement */ + rts +Lmotommu9: +#endif + rts + +ENTRY(DCIU) +__DCIU: +#if defined(M68040) + cmpl #-2,_mmutype | 68040 + jne LmotommuA | no, skip + /* XXX implement */ + rts +LmotommuA: +#endif + rts + +#if defined(M68040) +ENTRY(ICPL) + movl sp@(4),a0 | address + .word 0xf488 | cinvl ic,a0@ + rts +ENTRY(ICPP) + movl sp@(4),a0 | address + .word 0xf490 | cinvp ic,a0@ + rts +ENTRY(DCPL) + movl sp@(4),a0 | address + .word 0xf448 | cinvl dc,a0@ + rts +ENTRY(DCPP) + movl sp@(4),a0 | address + .word 0xf450 | cinvp dc,a0@ + rts +ENTRY(DCPA) + .word 0xf458 | cinva dc + rts +ENTRY(DCFL) + movl sp@(4),a0 | address + .word 0xf468 | cpushl dc,a0@ + rts +ENTRY(DCFP) + movl sp@(4),a0 | address + .word 0xf470 | cpushp dc,a0@ + rts +#endif + +ENTRY(PCIA) +#if defined(M68040) +ENTRY(DCFA) + cmpl #-2,_mmutype | 68040 + jne LmotommuB | no, skip + .word 0xf478 | cpusha dc + rts +LmotommuB: +#endif + movl #DC_CLEAR,d0 + movc d0,cacr | invalidate on-chip d-cache + rts + +ENTRY(ecacheon) + rts + +ENTRY(ecacheoff) + rts + +/* + * Get callers current SP value. + * Note that simply taking the address of a local variable in a C function + * doesn't work because callee saved registers may be outside the stack frame + * defined by A6 (e.g. GCC generated code). + */ + .globl _getsp +_getsp: + movl sp,d0 | get current SP + addql #4,d0 | compensate for return address + rts + + .globl _getsfc, _getdfc +_getsfc: + movc sfc,d0 + rts +_getdfc: + movc dfc,d0 + rts + +/* + * Load a new user segment table pointer. + */ +ENTRY(loadustp) + movl sp@(4),d0 | new USTP + moveq #PGSHIFT, d1 + lsll d1,d0 | convert to addr +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jne LmotommuC | no, skip + .long 0x4e7b0806 | movc d0,urp + rts +LmotommuC: +#endif + lea _protorp,a0 | CRP prototype + movl d0,a0@(4) | stash USTP + pmove a0@,crp | load root pointer + movl #DC_CLEAR,d0 + movc d0,cacr | invalidate on-chip d-cache + rts | since pmove flushes TLB + +ENTRY(ploadw) + movl sp@(4),a0 | address to load + ploadw #1,a0@ | pre-load translation + rts + +/* + * Set processor priority level calls. Most are implemented with + * inline asm expansions. However, spl0 requires special handling + * as we need to check for our emulated software interrupts. + */ + +ENTRY(spl0) + moveq #0,d0 + movw sr,d0 | get old SR for return + movw #PSL_LOWIPL,sr | restore new SR + tstb _ssir | software interrupt pending? + jeq Lspldone | no, all done + subql #4,sp | make room for RTE frame + movl sp@(4),sp@(2) | position return address + clrw sp@(6) | set frame type 0 + movw #PSL_LOWIPL,sp@ | and new SR + jra Lgotsir | go handle it +Lspldone: + rts + +ENTRY(_insque) + movw sr,d0 + movw #PSL_HIGHIPL,sr | atomic + movl sp@(8),a0 | where to insert (after) + movl sp@(4),a1 | element to insert (e) + movl a0@,a1@ | e->next = after->next + movl a0,a1@(4) | e->prev = after + movl a1,a0@ | after->next = e + movl a1@,a0 + movl a1,a0@(4) | e->next->prev = e + movw d0,sr + rts + +ENTRY(_remque) + movw sr,d0 + movw #PSL_HIGHIPL,sr | atomic + movl sp@(4),a0 | element to remove (e) + movl a0@,a1 + movl a0@(4),a0 + movl a0,a1@(4) | e->next->prev = e->prev + movl a1,a0@ | e->prev->next = e->next + movw d0,sr + rts + +/* + * bzero(addr, count) + */ +ALTENTRY(blkclr, _bzero) +ENTRY(bzero) + movl sp@(4),a0 | address + movl sp@(8),d0 | count + jeq Lbzdone | if zero, nothing to do + movl a0,d1 + btst #0,d1 | address odd? + jeq Lbzeven | no, can copy words + clrb a0@+ | yes, zero byte to get to even boundary + subql #1,d0 | decrement count + jeq Lbzdone | none left, all done +Lbzeven: + movl d0,d1 + andl #31,d0 + lsrl #5,d1 | convert count to 8*longword count + jeq Lbzbyte | no such blocks, zero byte at a time +Lbzloop: + clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; + clrl a0@+; clrl a0@+; clrl a0@+; clrl a0@+; + subql #1,d1 | one more block zeroed + jne Lbzloop | more to go, do it + tstl d0 | partial block left? + jeq Lbzdone | no, all done +Lbzbyte: + clrb a0@+ + subql #1,d0 | one more byte cleared + jne Lbzbyte | more to go, do it +Lbzdone: + rts + +/* + * strlen(str) + */ +ENTRY(strlen) + moveq #-1,d0 + movl sp@(4),a0 | string +Lslloop: + addql #1,d0 | increment count + tstb a0@+ | null? + jne Lslloop | no, keep going + rts + +/* + * bcmp(s1, s2, len) + * + * WARNING! This guy only works with counts up to 64K + */ +ENTRY(bcmp) + movl sp@(4),a0 | string 1 + movl sp@(8),a1 | string 2 + moveq #0,d0 + movw sp@(14),d0 | length + jeq Lcmpdone | if zero, nothing to do + subqw #1,d0 | set up for DBcc loop +Lcmploop: + cmpmb a0@+,a1@+ | equal? + dbne d0,Lcmploop | yes, keep going + addqw #1,d0 | +1 gives zero on match +Lcmpdone: + rts + +/* + * {ov}bcopy(from, to, len) + * + * Works for counts up to 128K. + */ +ALTENTRY(ovbcopy, _bcopy) +ENTRY(bcopy) + movl sp@(12),d0 | get count + jeq Lcpyexit | if zero, return + movl sp@(4),a0 | src address + movl sp@(8),a1 | dest address + cmpl a1,a0 | src before dest? + jlt Lcpyback | yes, copy backwards (avoids overlap) + movl a0,d1 + btst #0,d1 | src address odd? + jeq Lcfeven | no, go check dest + movb a0@+,a1@+ | yes, copy a byte + subql #1,d0 | update count + jeq Lcpyexit | exit if done +Lcfeven: + movl a1,d1 + btst #0,d1 | dest address odd? + jne Lcfbyte | yes, must copy by bytes + movl d0,d1 | no, get count + lsrl #2,d1 | convert to longwords + jeq Lcfbyte | no longwords, copy bytes + subql #1,d1 | set up for dbf +Lcflloop: + movl a0@+,a1@+ | copy longwords + dbf d1,Lcflloop | til done + andl #3,d0 | get remaining count + jeq Lcpyexit | done if none +Lcfbyte: + subql #1,d0 | set up for dbf +Lcfbloop: + movb a0@+,a1@+ | copy bytes + dbf d0,Lcfbloop | til done +Lcpyexit: + rts +Lcpyback: + addl d0,a0 | add count to src + addl d0,a1 | add count to dest + movl a0,d1 + btst #0,d1 | src address odd? + jeq Lcbeven | no, go check dest + movb a0@-,a1@- | yes, copy a byte + subql #1,d0 | update count + jeq Lcpyexit | exit if done +Lcbeven: + movl a1,d1 + btst #0,d1 | dest address odd? + jne Lcbbyte | yes, must copy by bytes + movl d0,d1 | no, get count + lsrl #2,d1 | convert to longwords + jeq Lcbbyte | no longwords, copy bytes + subql #1,d1 | set up for dbf +Lcblloop: + movl a0@-,a1@- | copy longwords + dbf d1,Lcblloop | til done + andl #3,d0 | get remaining count + jeq Lcpyexit | done if none +Lcbbyte: + subql #1,d0 | set up for dbf +Lcbbloop: + movb a0@-,a1@- | copy bytes + dbf d0,Lcbbloop | til done + rts + +#ifdef FPCOPROC +/* + * Save and restore 68881 state. + */ +ENTRY(m68881_save) + movl sp@(4),a0 | save area pointer + fsave a0@ | save state + tstb a0@ | null state frame? + jeq Lm68881sdone | yes, all done + fmovem fp0-fp7,a0@(216) | save FP general registers + fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers +Lm68881sdone: + rts + +ENTRY(m68881_restore) + movl sp@(4),a0 | save area pointer + tstb a0@ | null state frame? + jeq Lm68881rdone | yes, easy + fmovem a0@(312),fpcr/fpsr/fpi | restore FP control registers + fmovem a0@(216),fp0-fp7 | restore FP general registers +Lm68881rdone: + frestore a0@ | restore state + rts +#endif + +/* + * Handle the nitty-gritty of rebooting the machine. + * Basically we just turn off the MMU and jump to the appropriate ROM routine. + */ + .globl _doboot +_doboot: +#if defined(M68040) + cmpl #-2,_mmutype | 68040? + jeq Lnocache5 | yes, skip +#endif + movl #CACHE_OFF,d0 + movc d0,cacr | disable on-chip cache(s) +Lnocache5: + movl _boothowto,d1 | load howto + movl _bootdev,d0 | and devtype + movl sp@(4),d1 | arg + lea tmpstk,sp | physical SP in case of NMI + movl #0,a7@- | value for pmove to TC (turn off MMU) + pmove a7@,tc | disable MMU + movl #0, d0 + movc d0,vbr | ROM VBR + cmpl #0, d1 | autoboot? + jeq Lauto | yes + jmp 0x4000 | back to sboot +Lauto: jmp 0x400a | tell sboot to reboot us + + .data + .globl _mmutype,_protorp +_mmutype: + .long -1 | default to MMU_68030 +_protorp: + .long 0,0 | prototype root pointer + .globl _cold +_cold: + .long 1 | cold start flag + .globl _want_resched +_want_resched: + .long 0 + .globl _intiobase, _intiolimit, _extiobase, _RTCbase + .globl _proc0paddr +_proc0paddr: + .long 0 | KVA of proc0 u-area +_intiobase: + .long 0 | KVA of base of internal IO space +_intiolimit: + .long 0 | KVA of end of internal IO space +_extiobase: + .long 0 | KVA of base of external IO space +#ifdef DEBUG + .globl fulltflush, fullcflush +fulltflush: + .long 0 +fullcflush: + .long 0 +#endif +/* interrupt counters */ + .globl _intrcnt,_eintrcnt,_intrnames,_eintrnames +_intrnames: + .asciz "spur" + .asciz "lev1" + .asciz "lev2" + .asciz "lev3" + .asciz "lev4" + .asciz "clock" + .asciz "lev6" + .asciz "nmi" + .asciz "statclock" +_eintrnames: + .even +_intrcnt: + .long 0,0,0,0,0,0,0,0,0,0 +_eintrcnt: diff --git a/sys/arch/mvme68k/mvme68k/machdep.c b/sys/arch/mvme68k/mvme68k/machdep.c new file mode 100644 index 0000000000000..042264ceab0fc --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/machdep.c @@ -0,0 +1,1469 @@ +/* $NetBSD: machdep.c,v 1.1.1.1 1995/07/25 23:11:58 chuck 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. + * + * from: Utah $Hdr: machdep.c 1.74 92/12/20$ + * + * @(#)machdep.c 8.10 (Berkeley) 4/20/94 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SYSVMSG +#include +#endif +#ifdef SYSVSEM +#include +#endif +#ifdef SYSVSHM +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */ +#include + +/* the following is used externally (sysctl_hw) */ +char machine[] = "mvme68k"; /* cpu "architecture" */ + +vm_map_t buffer_map; +extern vm_offset_t avail_end; + +/* + * 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; /* set when safe to use msgbuf */ +int maxmem; /* max memory per process */ +int physmem = MAXMEM; /* max supported memory, changes to actual */ +/* + * safepri is a safe priority for sleep to set for a spin-wait + * during autoconfiguration or after a panic. + */ +int safepri = PSL_LOWIPL; + +u_long myea; /* from ROM XXXCDC */ + +extern u_int lowram; +extern short exframesize[]; + +#ifdef COMPAT_HPUX +extern struct emul emul_hpux; +#endif +#ifdef COMPAT_SUNOS +extern struct emul emul_sunos; +#endif +#ifdef COMPAT_SVR4 +extern struct emul emul_svr4; +#endif + +/* + * Console initialization: called early on from main, + * before vm init or startup. Do enough configuration + * to choose and initialize a console. + */ +consinit() +{ + + /* + * Set cpuspeed immediately since cninit() called routines + * might use delay. Note that we only set it if a custom value + * has not already been specified. + */ + if (cpuspeed == 0) { + cpuspeed = MHZ_16; + if (mmutype == MMU_68040) + cpuspeed *= 2; /* XXX */ + } + + /* + * Initialize the console before we print anything out. + */ + cninit(); + +#ifdef DDB + ddb_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif +} + +/* + * cpu_startup: allocate memory for variable-sized tables, + * initialize cpu, and do autoconfiguration. + */ +void +cpu_startup() +{ + register unsigned i; + register caddr_t v, firstaddr; + int base, residual; + vm_offset_t minaddr, maxaddr; + vm_size_t size; +#ifdef BUFFERS_UNMANAGED + vm_offset_t bufmemp; + caddr_t buffermem; + int ix; +#endif +#ifdef DEBUG + extern int pmapdebug; + int opmapdebug = pmapdebug; + + pmapdebug = 0; +#endif + + /* + * 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; + + /* + * Good {morning,afternoon,evening,night}. + */ + printf(version); + identifycpu(); + printf("real mem = %d\n", ctob(physmem)); + + /* + * Allocate space for system data structures. + * The first available real memory address is in "firstaddr". + * 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))) +#ifdef REAL_CLISTS + valloc(cfree, struct cblock, nclist); +#endif + valloc(callout, struct callout, ncallout); + valloc(swapmap, struct map, nswapmap = maxproc * 2); +#ifdef SYSVSHM + valloc(shmsegs, struct shmid_ds, shminfo.shmmni); +#endif +#ifdef SYSVSEM + valloc(sema, struct semid_ds, seminfo.semmni); + valloc(sem, struct sem, seminfo.semmns); + /* This is pretty disgusting! */ + valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); +#endif +#ifdef SYSVMSG + valloc(msgpool, char, msginfo.msgmax); + valloc(msgmaps, struct msgmap, msginfo.msgseg); + valloc(msghdrs, struct msg, msginfo.msgtql); + valloc(msqids, struct msqid_ds, msginfo.msgmni); +#endif + + /* + * Determine how many buffers to allocate. + * We just allocate a flat 5%. Insure a minimum of 16 buffers. + * We allocate 1/2 as many swap buffer headers as file i/o buffers. + */ + if (bufpages == 0) + bufpages = physmem / 20 / CLSIZE; + if (nbuf == 0) { + nbuf = bufpages; + if (nbuf < 16) + nbuf = 16; + } + if (nswbuf == 0) { + nswbuf = (nbuf / 2) &~ 1; /* force even */ + if (nswbuf > 256) + nswbuf = 256; /* sanity */ + } + valloc(swbuf, struct buf, nswbuf); + valloc(buf, struct buf, nbuf); + /* + * End of first pass, size has been calculated so allocate memory + */ + if (firstaddr == 0) { + size = (vm_size_t)(v - firstaddr); + firstaddr = (caddr_t) kmem_alloc(kernel_map, round_page(size)); + if (firstaddr == 0) + panic("startup: no room for tables"); +#ifdef BUFFERS_UNMANAGED + buffermem = (caddr_t) kmem_alloc(kernel_map, bufpages*CLBYTES); + if (buffermem == 0) + panic("startup: no room for buffers"); +#endif + 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; +#ifdef BUFFERS_UNMANAGED + bufmemp = (vm_offset_t) buffermem; +#endif + for (i = 0; i < nbuf; i++) { + vm_size_t curbufsize; + vm_offset_t curbuf; + + /* + * First 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); +#ifdef BUFFERS_UNMANAGED + /* + * Move the physical pages over from buffermem. + */ + for (ix = 0; ix < curbufsize/CLBYTES; ix++) { + vm_offset_t pa; + + pa = pmap_extract(pmap_kernel(), bufmemp); + if (pa == 0) + panic("startup: unmapped buffer"); + pmap_remove(pmap_kernel(), bufmemp, bufmemp+CLBYTES); + pmap_enter(pmap_kernel(), + (vm_offset_t)(curbuf + ix * CLBYTES), + pa, VM_PROT_READ|VM_PROT_WRITE, TRUE); + bufmemp += CLBYTES; + } +#else + vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); + vm_map_simplify(buffer_map, curbuf); +#endif + } +#ifdef BUFFERS_UNMANAGED +#if 0 + /* + * We would like to free the (now empty) original address range + * but too many bad things will happen if we try. + */ + kmem_free(kernel_map, (vm_offset_t)buffermem, bufpages*CLBYTES); +#endif +#endif + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + 16*NCARGS, TRUE); + /* + * Allocate a submap for physio + */ + phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + VM_PHYS_SIZE, TRUE); + + /* + * Finally, allocate mbuf pool. Since mclrefcnt is an off-size + * we use the more space efficient malloc in place of kmem_alloc. + */ + mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, + M_MBUF, M_NOWAIT); + bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); + mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr, + VM_MBUF_SIZE, FALSE); + /* + * Initialize callouts + */ + callfree = callout; + for (i = 1; i < ncallout; i++) + callout[i-1].c_next = &callout[i]; + callout[i-1].c_next = NULL; + +#ifdef DEBUG + pmapdebug = opmapdebug; +#endif + printf("avail mem = %d\n", ptoa(cnt.v_free_count)); + printf("using %d buffers containing %d bytes of memory\n", + nbuf, bufpages * CLBYTES); + /* + * Set up CPU-specific registers, cache, etc. + */ + initcpu(); + + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + /* + * Configure the system. + */ + configure(); +} + +/* + * Set registers on exec. + * XXX Should clear registers except sp, pc, + * but would break init; should be fixed soon. + */ +void +setregs(p, pack, stack, retval) + register struct proc *p; + struct exec_package *pack; + u_long stack; + register_t *retval; +{ + struct frame *frame = (struct frame *)p->p_md.md_regs; + + frame->f_pc = pack->ep_entry & ~1; + frame->f_regs[SP] = stack; + frame->f_regs[A2] = (int)PS_STRINGS; +#ifdef FPCOPROC + /* restore a null state frame */ + p->p_addr->u_pcb.pcb_fpregs.fpf_null = 0; + m68881_restore(&p->p_addr->u_pcb.pcb_fpregs); +#endif +#ifdef COMPAT_HPUX + p->p_md.md_flags &= ~MDP_HPUXMMAP; + if (p->p_emul == &emul_hpux) { + frame->f_regs[A0] = 0; /* not 68010 (bit 31), no FPA (30) */ + retval[0] = 0; /* no float card */ +#ifdef FPCOPROC + retval[1] = 1; /* yes 68881 */ +#else + retval[1] = 0; /* no 68881 */ +#endif + } + /* + * XXX This doesn't have much to do with setting registers but + * I didn't want to muck up kern_exec.c with this code, so I + * stuck it here. + * + * Ensure we perform the right action on traps type 1 and 2: + * If our parent is an HPUX process and we are being traced, turn + * on HPUX style interpretation. Else if we were using the HPUX + * style interpretation, revert to the BSD interpretation. + * + * Note that we do this by changing the trap instruction in the + * global "sigcode" array which then gets copied out to the user's + * sigcode in the stack. Since we are changing it in the global + * array we must always reset it, even for non-HPUX processes. + * + * Note also that implementing it in this way creates a potential + * race where we could have tweaked it for process A which then + * blocks in the copyout to the stack and process B comes along + * and untweaks it causing A to wind up with the wrong setting + * when the copyout continues. However, since we have already + * copied something out to this user stack page (thereby faulting + * it in), this scenerio is extremely unlikely. + */ + { + extern short sigcodetrap[]; + + if ((p->p_pptr->p_emul == &emul_hpux) && + (p->p_flag & P_TRACED)) { + p->p_md.md_flags |= MDP_HPUXTRACE; + *sigcodetrap = 0x4E42; + } else { + p->p_md.md_flags &= ~MDP_HPUXTRACE; + *sigcodetrap = 0x4E41; + } + } +#endif +} + +/* + * Info for CTL_HW + */ +char cpu_model[120]; +extern char version[]; + +identifycpu() +{ + char *t, *mc; + int len; + + switch (mmutype) { + case MMU_68851: + t = "?"; + break; + case MMU_68030: + t = "147"; + break; + case MMU_68040: + t = "16[27]"; + break; + default: + t = "unknown"; + break; + } + mc = (mmutype == MMU_68040 ? "40" : + (mmutype == MMU_68030 ? "30" : "20")); + sprintf(cpu_model, "Motorola MVME%s MC680%s CPU", t, mc); + switch (mmutype) { + case MMU_68040: + case MMU_68030: + strcat(cpu_model, "+MMU"); + break; + case MMU_68851: + strcat(cpu_model, ", MC68851 MMU"); + break; + default: + printf("%s\nunknown MMU type %d\n", cpu_model, mmutype); + panic("startup"); + } + len = strlen(cpu_model); + if (mmutype == MMU_68040) + len += sprintf(cpu_model + len, + "+FPU, 4k on-chip physical I/D caches"); + else if (mmutype == MMU_68030) + len += sprintf(cpu_model + len, ", %sMHz MC68882 FPU", + "???"); + else + len += sprintf(cpu_model + len, ", %sMHz MC68881 FPU", + "???"); + strcat(cpu_model, ")"); + printf("%s\n", cpu_model); +} + +/* + * 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 */ +} + +#ifdef USELEDS +#include + +int inledcontrol = 0; /* 1 if we are in ledcontrol already, cheap mutex */ +char *ledaddr; + +/* + * Map the LED page and setup the KVA to access it. + */ +ledinit() +{ + extern caddr_t ledbase; + + pmap_enter(pmap_kernel(), (vm_offset_t)ledbase, (vm_offset_t)LED_ADDR, + VM_PROT_READ|VM_PROT_WRITE, TRUE); + ledaddr = (char *) ((int)ledbase | (LED_ADDR & PGOFSET)); +} + +/* + * Do lights: + * `ons' is a mask of LEDs to turn on, + * `offs' is a mask of LEDs to turn off, + * `togs' is a mask of LEDs to toggle. + * Note we don't use splclock/splx for mutual exclusion. + * They are expensive and we really don't need to be that precise. + * Besides we would like to be able to profile this routine. + */ +ledcontrol(ons, offs, togs) + register int ons, offs, togs; +{ + static char currentleds; + register char leds; + + inledcontrol = 1; + leds = currentleds; + if (ons) + leds |= ons; + if (offs) + leds &= ~offs; + if (togs) + leds ^= togs; + currentleds = leds; + *ledaddr = ~leds; + inledcontrol = 0; +} +#endif + +#define SS_RTEFRAME 1 +#define SS_FPSTATE 2 +#define SS_USERREGS 4 + +struct sigstate { + int ss_flags; /* which of the following are valid */ + struct frame ss_frame; /* original exception frame */ + struct fpframe ss_fpstate; /* 68881/68882 state info */ +}; + +/* + * WARNING: code in locore.s assumes the layout shown for sf_signum + * thru sf_handler so... don't screw with them! + */ +struct sigframe { + int sf_signum; /* signo for handler */ + int sf_code; /* additional info for handler */ + struct sigcontext *sf_scp; /* context ptr for handler */ + sig_t sf_handler; /* handler addr for u_sigc */ + struct sigstate sf_state; /* state of the hardware */ + struct sigcontext sf_sc; /* actual context */ +}; + +#ifdef COMPAT_HPUX +struct hpuxsigcontext { + int hsc_syscall; + char hsc_action; + char hsc_pad1; + char hsc_pad2; + char hsc_onstack; + int hsc_mask; + int hsc_sp; + short hsc_ps; + int hsc_pc; +/* the rest aren't part of the context but are included for our convenience */ + short hsc_pad; + u_int hsc_magic; /* XXX sigreturn: cookie */ + struct sigcontext *hsc_realsc; /* XXX sigreturn: ptr to BSD context */ +}; + +/* + * For an HP-UX process, a partial hpuxsigframe follows the normal sigframe. + * Tremendous waste of space, but some HP-UX applications (e.g. LCL) need it. + */ +struct hpuxsigframe { + int hsf_signum; + int hsf_code; + struct sigcontext *hsf_scp; + struct hpuxsigcontext hsf_sc; + int hsf_regs[15]; +}; +#endif + +#ifdef DEBUG +int sigdebug = 0; +int sigpid = 0; +#define SDB_FOLLOW 0x01 +#define SDB_KSTACK 0x02 +#define SDB_FPSTATE 0x04 +#endif + +/* + * Send an interrupt to process. + */ +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig, mask; + u_long code; +{ + register struct proc *p = curproc; + register struct sigframe *fp, *kfp; + register struct frame *frame; + register struct sigacts *psp = p->p_sigacts; + register short ft; + int oonstack, fsize; + extern char sigcode[], esigcode[]; + + frame = (struct frame *)p->p_md.md_regs; + ft = frame->f_format; + oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; + /* + * Allocate and validate space for the signal handler + * context. Note that if the stack is in P0 space, the + * call to grow() is a nop, and the useracc() check + * will fail if the process has not already allocated + * the space with a `brk'. + */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) + fsize = sizeof(struct sigframe) + sizeof(struct hpuxsigframe); + else +#endif + fsize = sizeof(struct sigframe); + if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && + (psp->ps_sigonstack & sigmask(sig))) { + fp = (struct sigframe *)(psp->ps_sigstk.ss_base + + psp->ps_sigstk.ss_size - fsize); + psp->ps_sigstk.ss_flags |= SA_ONSTACK; + } else + fp = (struct sigframe *)(frame->f_regs[SP] - fsize); + if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) + (void)grow(p, (unsigned)fp); +#ifdef DEBUG + if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d ssp %x usp %x scp %x ft %d\n", + p->p_pid, sig, &oonstack, fp, &fp->sf_sc, ft); +#endif + if (useracc((caddr_t)fp, fsize, B_WRITE) == 0) { +#ifdef DEBUG + if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): useracc failed on sig %d\n", + p->p_pid, sig); +#endif + /* + * 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; + } + kfp = (struct sigframe *)malloc((u_long)fsize, M_TEMP, M_WAITOK); + /* + * Build the argument list for the signal handler. + */ + kfp->sf_signum = sig; + kfp->sf_code = code; + kfp->sf_scp = &fp->sf_sc; + kfp->sf_handler = catcher; + /* + * Save necessary hardware state. Currently this includes: + * - general registers + * - original exception frame (if not a "normal" frame) + * - FP coprocessor state + */ + kfp->sf_state.ss_flags = SS_USERREGS; + bcopy((caddr_t)frame->f_regs, + (caddr_t)kfp->sf_state.ss_frame.f_regs, sizeof frame->f_regs); + if (ft >= FMT7) { +#ifdef DEBUG + if (ft > 15 || exframesize[ft] < 0) + panic("sendsig: bogus frame type"); +#endif + kfp->sf_state.ss_flags |= SS_RTEFRAME; + kfp->sf_state.ss_frame.f_format = frame->f_format; + kfp->sf_state.ss_frame.f_vector = frame->f_vector; + bcopy((caddr_t)&frame->F_u, + (caddr_t)&kfp->sf_state.ss_frame.F_u, exframesize[ft]); + /* + * Leave an indicator that we need to clean up the kernel + * stack. We do this by setting the "pad word" above the + * hardware stack frame to the amount the stack must be + * adjusted by. + * + * N.B. we increment rather than just set f_stackadj in + * case we are called from syscall when processing a + * sigreturn. In that case, f_stackadj may be non-zero. + */ + frame->f_stackadj += exframesize[ft]; + frame->f_format = frame->f_vector = 0; +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sendsig(%d): copy out %d of frame %d\n", + p->p_pid, exframesize[ft], ft); +#endif + } +#ifdef FPCOPROC + kfp->sf_state.ss_flags |= SS_FPSTATE; + m68881_save(&kfp->sf_state.ss_fpstate); +#ifdef DEBUG + if ((sigdebug & SDB_FPSTATE) && *(char *)&kfp->sf_state.ss_fpstate) + printf("sendsig(%d): copy out FP state (%x) to %x\n", + p->p_pid, *(u_int *)&kfp->sf_state.ss_fpstate, + &kfp->sf_state.ss_fpstate); +#endif +#endif + /* + * Build the signal context to be used by sigreturn. + */ + kfp->sf_sc.sc_onstack = oonstack; + kfp->sf_sc.sc_mask = mask; + kfp->sf_sc.sc_sp = frame->f_regs[SP]; + kfp->sf_sc.sc_fp = frame->f_regs[A6]; + kfp->sf_sc.sc_ap = (int)&fp->sf_state; + kfp->sf_sc.sc_pc = frame->f_pc; + kfp->sf_sc.sc_ps = frame->f_sr; +#ifdef COMPAT_HPUX + /* + * Create an HP-UX style sigcontext structure and associated goo + */ + if (p->p_emul == &emul_hpux) { + register struct hpuxsigframe *hkfp; + + hkfp = (struct hpuxsigframe *)&kfp[1]; + hkfp->hsf_signum = bsdtohpuxsig(kfp->sf_signum); + hkfp->hsf_code = kfp->sf_code; + hkfp->hsf_scp = (struct sigcontext *) + &((struct hpuxsigframe *)(&fp[1]))->hsf_sc; + hkfp->hsf_sc.hsc_syscall = 0; /* XXX */ + hkfp->hsf_sc.hsc_action = 0; /* XXX */ + hkfp->hsf_sc.hsc_pad1 = hkfp->hsf_sc.hsc_pad2 = 0; + hkfp->hsf_sc.hsc_onstack = kfp->sf_sc.sc_onstack; + hkfp->hsf_sc.hsc_mask = kfp->sf_sc.sc_mask; + hkfp->hsf_sc.hsc_sp = kfp->sf_sc.sc_sp; + hkfp->hsf_sc.hsc_ps = kfp->sf_sc.sc_ps; + hkfp->hsf_sc.hsc_pc = kfp->sf_sc.sc_pc; + hkfp->hsf_sc.hsc_pad = 0; + hkfp->hsf_sc.hsc_magic = 0xdeadbeef; + hkfp->hsf_sc.hsc_realsc = kfp->sf_scp; + bcopy((caddr_t)frame->f_regs, (caddr_t)hkfp->hsf_regs, + sizeof (hkfp->hsf_regs)); + + kfp->sf_signum = hkfp->hsf_signum; + kfp->sf_scp = hkfp->hsf_scp; + } +#endif + (void) copyout((caddr_t)kfp, (caddr_t)fp, fsize); + frame->f_regs[SP] = (int)fp; +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sendsig(%d): sig %d scp %x fp %x sc_sp %x sc_ap %x\n", + p->p_pid, sig, kfp->sf_scp, fp, + kfp->sf_sc.sc_sp, kfp->sf_sc.sc_ap); +#endif + /* + * Signal trampoline code is at base of user stack. + */ + frame->f_pc = (int)PS_STRINGS - (esigcode - sigcode); +#ifdef DEBUG + if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d returns\n", + p->p_pid, sig); +#endif + free((caddr_t)kfp, M_TEMP); +} + +/* + * System call to cleanup state after a signal + * has been taken. Reset signal mask and + * stack state from context left by sendsig (above). + * Return to previous pc and psl as specified by + * context left by sendsig. Check carefully to + * make sure that the user has not modified the + * psl to gain improper priviledges or to cause + * a machine fault. + */ +/* ARGSUSED */ +sigreturn(p, uap, retval) + struct proc *p; + struct sigreturn_args /* { + syscallarg(struct sigcontext *) sigcntxp; + } */ *uap; + register_t *retval; +{ + register struct sigcontext *scp; + register struct frame *frame; + register int rf; + struct sigcontext tsigc; + struct sigstate tstate; + int flags; + + scp = SCARG(uap, sigcntxp); +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); +#endif + if ((int)scp & 1) + return (EINVAL); +#ifdef COMPAT_HPUX + /* + * Grab context as an HP-UX style context and determine if it + * was one that we contructed in sendsig. + */ + if (p->p_emul == &emul_hpux) { + struct hpuxsigcontext *hscp = (struct hpuxsigcontext *)scp; + struct hpuxsigcontext htsigc; + + if (useracc((caddr_t)hscp, sizeof (*hscp), B_WRITE) == 0 || + copyin((caddr_t)hscp, (caddr_t)&htsigc, sizeof htsigc)) + return (EINVAL); + /* + * If not generated by sendsig or we cannot restore the + * BSD-style sigcontext, just restore what we can -- state + * will be lost, but them's the breaks. + */ + hscp = &htsigc; + if (hscp->hsc_magic != 0xdeadbeef || + (scp = hscp->hsc_realsc) == 0 || + useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || + copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) { + if (hscp->hsc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + p->p_sigmask = hscp->hsc_mask &~ sigcantmask; + frame = (struct frame *) p->p_md.md_regs; + frame->f_regs[SP] = hscp->hsc_sp; + frame->f_pc = hscp->hsc_pc; + frame->f_sr = hscp->hsc_ps &~ PSL_USERCLR; + return (EJUSTRETURN); + } + /* + * Otherwise, overlay BSD context with possibly modified + * HP-UX values. + */ + tsigc.sc_onstack = hscp->hsc_onstack; + tsigc.sc_mask = hscp->hsc_mask; + tsigc.sc_sp = hscp->hsc_sp; + tsigc.sc_ps = hscp->hsc_ps; + tsigc.sc_pc = hscp->hsc_pc; + } else +#endif + /* + * Test and fetch the context structure. + * We grab it all at once for speed. + */ + if (useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || + copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) + return (EINVAL); + scp = &tsigc; + if ((scp->sc_ps & (PSL_MBZ|PSL_IPL|PSL_S)) != 0) + return (EINVAL); + /* + * Restore the user supplied information + */ + if (scp->sc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + p->p_sigmask = scp->sc_mask &~ sigcantmask; + frame = (struct frame *) p->p_md.md_regs; + frame->f_regs[SP] = scp->sc_sp; + frame->f_regs[A6] = scp->sc_fp; + frame->f_pc = scp->sc_pc; + frame->f_sr = scp->sc_ps; + /* + * Grab pointer to hardware state information. + * If zero, the user is probably doing a longjmp. + */ + if ((rf = scp->sc_ap) == 0) + return (EJUSTRETURN); + /* + * See if there is anything to do before we go to the + * expense of copying in close to 1/2K of data + */ + flags = fuword((caddr_t)rf); +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn(%d): sc_ap %x flags %x\n", + p->p_pid, rf, flags); +#endif + /* + * fuword failed (bogus sc_ap value). + */ + if (flags == -1) + return (EINVAL); + if (flags == 0 || copyin((caddr_t)rf, (caddr_t)&tstate, sizeof tstate)) + return (EJUSTRETURN); +#ifdef DEBUG + if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sigreturn(%d): ssp %x usp %x scp %x ft %d\n", + p->p_pid, &flags, scp->sc_sp, SCARG(uap, sigcntxp), + (flags&SS_RTEFRAME) ? tstate.ss_frame.f_format : -1); +#endif + /* + * Restore most of the users registers except for A6 and SP + * which were handled above. + */ + if (flags & SS_USERREGS) + bcopy((caddr_t)tstate.ss_frame.f_regs, + (caddr_t)frame->f_regs, sizeof(frame->f_regs)-2*NBPW); + /* + * Restore long stack frames. Note that we do not copy + * back the saved SR or PC, they were picked up above from + * the sigcontext structure. + */ + if (flags & SS_RTEFRAME) { + register int sz; + + /* grab frame type and validate */ + sz = tstate.ss_frame.f_format; + if (sz > 15 || (sz = exframesize[sz]) < 0) + return (EINVAL); + frame->f_stackadj -= sz; + frame->f_format = tstate.ss_frame.f_format; + frame->f_vector = tstate.ss_frame.f_vector; + bcopy((caddr_t)&tstate.ss_frame.F_u, (caddr_t)&frame->F_u, sz); +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn(%d): copy in %d of frame type %d\n", + p->p_pid, sz, tstate.ss_frame.f_format); +#endif + } +#ifdef FPCOPROC + /* + * Finally we restore the original FP context + */ + if (flags & SS_FPSTATE) + m68881_restore(&tstate.ss_fpstate); +#ifdef DEBUG + if ((sigdebug & SDB_FPSTATE) && *(char *)&tstate.ss_fpstate) + printf("sigreturn(%d): copied in FP state (%x) at %x\n", + p->p_pid, *(u_int *)&tstate.ss_fpstate, + &tstate.ss_fpstate); +#endif +#endif +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) || + ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)) + printf("sigreturn(%d): returns\n", p->p_pid); +#endif + return (EJUSTRETURN); +} + +int waittime = -1; + +void +boot(howto) + register int howto; +{ + /* take a snap shot before clobbering any registers */ + if (curproc && curproc->p_addr) + savectx(curproc->p_addr); + + 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. + */ + resettodr(); + } + splhigh(); /* extreme priority */ + if (howto&RB_HALT) { + printf("halted\n\n"); + doboot(RB_HALT); + /*NOTREACHED*/ + } else { + if (howto & RB_DUMP) + dumpsys(); + doboot(RB_AUTOBOOT); + /*NOTREACHED*/ + } + /*NOTREACHED*/ +} + +/* + * 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; + + /* + * XXX include the final RAM page which is not included in physmem. + */ + dumpsize = physmem + 1; + + /* 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. + */ +dumpsys() +{ + + msgbufmapped = 0; + if (dumpdev == NODEV) + return; + if (dumpsize == 0) { + dumpconf(); + if (dumpsize == 0) + return; + } + printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); + + printf("dump "); + switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { + + case ENXIO: + printf("device bad\n"); + break; + + case EFAULT: + printf("device not ready\n"); + break; + + case EINVAL: + printf("area improper\n"); + break; + + case EIO: + printf("i/o error\n"); + break; + + case EINTR: + printf("aborted from console\n"); + break; + + default: + printf("succeeded\n"); + break; + } +} + +initcpu() +{ +#ifdef MAPPEDCOPY + extern u_int mappedcopysize; + + /* + * Initialize lower bound for doing copyin/copyout using + * page mapping (if not already set). We don't do this on + * VAC machines as it loses big time. + */ + if (mappedcopysize == 0) { + mappedcopysize = NBPG; + } +#endif +} + +straytrap(pc, evec) + int pc; + u_short evec; +{ + printf("unexpected trap (vector offset %x) from %x\n", + evec & 0xFFF, pc); +} + +int *nofault; + +badaddr(addr) + register caddr_t addr; +{ + register int i; + label_t faultbuf; + +#ifdef lint + i = *addr; if (i) return(0); +#endif + nofault = (int *) &faultbuf; + if (setjmp((label_t *)nofault)) { + nofault = (int *) 0; + return(1); + } + i = *(volatile short *)addr; + nofault = (int *) 0; + return(0); +} + +badbaddr(addr) + register caddr_t addr; +{ + register int i; + label_t faultbuf; + +#ifdef lint + i = *addr; if (i) return(0); +#endif + nofault = (int *) &faultbuf; + if (setjmp((label_t *)nofault)) { + nofault = (int *) 0; + return(1); + } + i = *(volatile char *)addr; + nofault = (int *) 0; + return(0); +} + +netintr() +{ +#ifdef INET + if (netisr & (1 << NETISR_ARP)) { + netisr &= ~(1 << NETISR_ARP); + arpintr(); + } + if (netisr & (1 << NETISR_IP)) { + netisr &= ~(1 << NETISR_IP); + ipintr(); + } +#endif +#ifdef NS + if (netisr & (1 << NETISR_NS)) { + netisr &= ~(1 << NETISR_NS); + nsintr(); + } +#endif +#ifdef ISO + if (netisr & (1 << NETISR_ISO)) { + netisr &= ~(1 << NETISR_ISO); + clnlintr(); + } +#endif +#ifdef CCITT + if (netisr & (1 << NETISR_CCITT)) { + netisr &= ~(1 << NETISR_CCITT); + ccittintr(); + } +#endif +#include "ppp.h" +#if NPPP > 0 + if (netisr & (1 << NETISR_PPP)) { + netisr &= ~(1 << NETISR_PPP); + pppintr(); + } +#endif +} + +intrhand(sr) + int sr; +{ + register struct isr *isr; + register int found = 0; + register int ipl; + extern struct isr isrqueue[]; + static int straycount; + + ipl = (sr >> 8) & 7; +printf("intrhand\n"); + switch (ipl) { + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + ipl = ISRIPL(ipl); + isr = isrqueue[ipl].isr_forw; + for (; isr != &isrqueue[ipl]; isr = isr->isr_forw) { + if ((isr->isr_intr)(isr->isr_arg)) { + found++; + break; + } + } + if (found) + straycount = 0; + else if (++straycount > 50) + panic("intrhand: stray interrupt"); + else + printf("stray interrupt, sr 0x%x\n", sr); + break; + + case 0: + case 7: + if (++straycount > 50) + panic("intrhand: unexpected sr"); + else + printf("intrhand: unexpected sr 0x%x\n", sr); + break; + } +} + +#if (defined(DDB) || defined(DEBUG)) && !defined(PANICBUTTON) +#define PANICBUTTON +#endif + +#ifdef PANICBUTTON +int panicbutton = 1; /* non-zero if panic buttons are enabled */ +int crashandburn = 0; +int candbdelay = 50; /* give em half a second */ + +void +candbtimer(arg) + void *arg; +{ + + crashandburn = 0; +} +#endif + +/* + * Level 7 interrupts can't be caused by anything + */ +nmihand(frame) + struct frame frame; +{ + /* panic?? */ + printf("unexpected level 7 interrupt ignored\n"); +} + +regdump(fp, sbytes) + struct frame *fp; /* must not be register */ + int sbytes; +{ + static int doingdump = 0; + register int i; + int s; + extern char *hexstr(); + + if (doingdump) + return; + s = splhigh(); + doingdump = 1; + printf("pid = %d, pc = %s, ", + curproc ? curproc->p_pid : -1, hexstr(fp->f_pc, 8)); + printf("ps = %s, ", hexstr(fp->f_sr, 4)); + printf("sfc = %s, ", hexstr(getsfc(), 4)); + printf("dfc = %s\n", hexstr(getdfc(), 4)); + printf("Registers:\n "); + for (i = 0; i < 8; i++) + printf(" %d", i); + printf("\ndreg:"); + for (i = 0; i < 8; i++) + printf(" %s", hexstr(fp->f_regs[i], 8)); + printf("\nareg:"); + for (i = 0; i < 8; i++) + printf(" %s", hexstr(fp->f_regs[i+8], 8)); + if (sbytes > 0) { + if (fp->f_sr & PSL_S) { + printf("\n\nKernel stack (%s):", + hexstr((int)(((int *)&fp)-1), 8)); + dumpmem(((int *)&fp)-1, sbytes, 0); + } else { + printf("\n\nUser stack (%s):", hexstr(fp->f_regs[SP], 8)); + dumpmem((int *)fp->f_regs[SP], sbytes, 1); + } + } + doingdump = 0; + splx(s); +} + +#define KSADDR ((int *)((u_int)curproc->p_addr + USPACE - NBPG)) + +dumpmem(ptr, sz, ustack) + register int *ptr; + int sz, ustack; +{ + register int i, val; + extern char *hexstr(); + + for (i = 0; i < sz; i++) { + if ((i & 7) == 0) + printf("\n%s: ", hexstr((int)ptr, 6)); + else + printf(" "); + if (ustack == 1) { + if ((val = fuword(ptr++)) == -1) + break; + } else { + if (ustack == 0 && + (ptr < KSADDR || ptr > KSADDR+(NBPG/4-1))) + break; + val = *ptr++; + } + printf("%s", hexstr(val, 8)); + } + printf("\n"); +} + +char * +hexstr(val, len) + register int val; + int len; +{ + static char nbuf[9]; + register int x, i; + + if (len > 8) + return(""); + nbuf[len] = '\0'; + for (i = len-1; i >= 0; --i) { + x = val & 0xF; + if (x > 9) + nbuf[i] = x - 10 + 'A'; + else + nbuf[i] = x + '0'; + val >>= 4; + } + return(nbuf); +} + +#ifdef STACKCHECK +char oflowmsg[] = "k-stack overflow"; +char uflowmsg[] = "k-stack underflow"; + +badkstack(oflow, fr) + int oflow; + struct frame fr; +{ + extern char kstackatbase[]; + + printf("%s: sp should be %x\n", + oflow ? oflowmsg : uflowmsg, + kstackatbase - (exframesize[fr.f_format] + 8)); + regdump(&fr, 0); + panic(oflow ? oflowmsg : uflowmsg); +} +#endif + +/* + * cpu_exec_aout_makecmds(): + * cpu-dependent a.out format hook for execve(). + * + * Determine of the given exec package refers to something which we + * understand and, if so, set up the vmcmds for it. + */ +cpu_exec_aout_makecmds(p, epp) + struct proc *p; + struct exec_package *epp; +{ + int error = ENOEXEC; +#ifdef COMPAT_SUNOS + extern sunos_exec_aout_makecmds + __P((struct proc *, struct exec_package *)); + if ((error = sunos_exec_aout_makecmds(p, epp)) == 0) + return 0; +#endif + return error; +} + +void +myetheraddr(ether) + char *ether; +{ + int e = myea; + + ether[0] = 0x08; + ether[1] = 0x00; + ether[2] = 0x3e; + e = e >> 8; + ether[5] = e & 0xff; + e = e >> 8; + ether[4] = e & 0xff; + e = e >> 8; + ether[3] = e; +} diff --git a/sys/arch/mvme68k/mvme68k/mainbus.c b/sys/arch/mvme68k/mvme68k/mainbus.c new file mode 100644 index 0000000000000..484e37d9580c5 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/mainbus.c @@ -0,0 +1,29 @@ +void mainbus_attach __P((struct device *, struct device *, void *)); +int mainbus_match __P((struct device *, void *, void *)); + +struct mainbus_softc { + struct device sc_dev; +}; + +struct cfdriver mainbus_cd = { + NULL, "mainbus_", mainbus_match, mainbus_attach, + DV_DULL, sizeof(struct mainbus_softc), 0 +}; + +int +mainbus_match(parent, cf, args) + struct device *parent; + void *cf; + void *args; +{ + return 1; +} + +void +mainbus_attach(parent, self, args) + struct device *parent, *self; + void *args; +{ + while (config_found(self, NULL, NULL)) + ; +} diff --git a/sys/arch/mvme68k/mvme68k/mem.c b/sys/arch/mvme68k/mvme68k/mem.c new file mode 100644 index 0000000000000..52d8123a24c75 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/mem.c @@ -0,0 +1,222 @@ +/* $NetBSD: mem.c,v 1.1.1.1 1995/07/25 23:11:58 chuck 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 +#include +#include +#include +#include +#include + +#include + +#include + +extern u_int lowram; +caddr_t zeropage; + +/*ARGSUSED*/ +int +mmopen(dev, flag, mode) + dev_t dev; + int flag, mode; +{ + + return (0); +} + +/*ARGSUSED*/ +int +mmclose(dev, flag, mode) + dev_t dev; + int flag, mode; +{ + + return (0); +} + +/*ARGSUSED*/ +int +mmrw(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + register vm_offset_t o, v; + register int c; + register struct iovec *iov; + int error = 0; + static int physlock; + + 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; +#ifndef DEBUG + /* allow reads only in RAM (except for DEBUG) */ + if (v >= 0xFFFFFFFC || v < lowram) { + error = EFAULT; + goto unlock; + } +#endif + 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); + +/* 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; + } + /* + * On the first call, allocate and zero a page + * of memory for use with /dev/zero. + * + * XXX on the hp300 we already know where there + * is a global zeroed page, the null segment table. + */ + if (zeropage == NULL) { +#if CLBYTES == NBPG + extern caddr_t Segtabzero; + zeropage = Segtabzero; +#else + zeropage = (caddr_t) + malloc(CLBYTES, M_TEMP, M_WAITOK); + bzero(zeropage, CLBYTES); +#endif + } + 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; +{ + /* + * /dev/mem is the only one that makes sense through this + * interface. For /dev/kmem any physaddr we return here + * could be transient and hence incorrect or invalid at + * a later time. /dev/null just doesn't make any sense + * and /dev/zero is a hack that is handled via the default + * pager in mmap(). + */ + if (minor(dev) != 0) + return (-1); + /* + * Allow access only in RAM. + * + * XXX could be extended to allow access to IO space but must + * be very careful. + */ + if ((unsigned)off < lowram || (unsigned)off >= 0xFFFFFFFC) + return (-1); + return (m68k_btop(off)); +} diff --git a/sys/arch/mvme68k/mvme68k/pmap.c b/sys/arch/mvme68k/mvme68k/pmap.c new file mode 100644 index 0000000000000..3cdf42f1c7ebd --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/pmap.c @@ -0,0 +1,2659 @@ +/* $NetBSD: pmap.c,v 1.1.1.1 1995/07/25 23:11:59 chuck Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)pmap.c 8.6 (Berkeley) 5/27/94 + */ + +/* + * HP9000/300 series physical map management code. + * + * Supports: + * 68020 with HP MMU models 320, 350 + * 68020 with 68551 MMU models 318, 319, 330 (all untested) + * 68030 with on-chip MMU models 340, 360, 370, 345, 375, 400 + * 68040 with on-chip MMU models 380, 425, 433 + * + * Notes: + * Don't even pay lip service to multiprocessor support. + * + * We assume TLB entries don't have process tags (except for the + * supervisor/user distinction) so we only invalidate TLB entries + * when changing mappings for the current (or kernel) pmap. This is + * technically not true for the 68551 but we flush the TLB on every + * context switch, so it effectively winds up that way. + * + * Bitwise and/or operations are significantly faster than bitfield + * references so we use them when accessing STE/PTEs in the pmap_pte_* + * macros. Note also that the two are not always equivalent; e.g.: + * (*pte & PG_PROT) [4] != pte->pg_prot [1] + * and a couple of routines that deal with protection and wiring take + * some shortcuts that assume the and/or definitions. + * + * This implementation will only work for PAGE_SIZE == NBPG + * (i.e. 4096 bytes). + */ + +/* + * 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 +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#ifdef PMAPSTATS +struct { + int collectscans; + int collectpages; + int kpttotal; + int kptinuse; + int kptmaxuse; +} kpt_stats; +struct { + int kernel; /* entering kernel mapping */ + int user; /* entering user mapping */ + int ptpneeded; /* needed to allocate a PT page */ + int nochange; /* no change at all */ + int pwchange; /* no mapping change, just wiring or protection */ + int wchange; /* no mapping change, just wiring */ + int pchange; /* no mapping change, just protection */ + 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; +struct { + int calls; + int changed; + int alreadyro; + int alreadyrw; +} protect_stats; +struct chgstats { + int setcalls; + int sethits; + int setmiss; + int clrcalls; + int clrhits; + int clrmiss; +} changebit_stats[16]; +#endif + +#ifdef DEBUG +int debugmap = 0; +int pmapdebug = 0x2000; +#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_SEGTAB 0x0400 +#define PDB_MULTIMAP 0x0800 +#define PDB_PARANOIA 0x2000 +#define PDB_WIRING 0x4000 +#define PDB_PVDUMP 0x8000 + +#ifdef HAVEVAC +int pmapvacflush = 0; +#define PVF_ENTER 0x01 +#define PVF_REMOVE 0x02 +#define PVF_PROTECT 0x04 +#define PVF_TOTAL 0x80 +#endif + +#if defined(M68040) +int dowriteback = 1; /* 68040: enable writeback caching */ +int dokwriteback = 1; /* 68040: enable writeback caching of kernel AS */ +#endif + +extern vm_offset_t pager_sva, pager_eva; +#endif + +/* + * Get STEs and PTEs for user/kernel address space + */ +#if defined(M68040) +#define pmap_ste1(m, v) \ + (&((m)->pm_stab[(vm_offset_t)(v) >> SG4_SHIFT1])) +/* XXX assumes physically contiguous ST pages (if more than one) */ +#define pmap_ste2(m, v) \ + (&((m)->pm_stab[(st_entry_t *)(*(u_int *)pmap_ste1(m, v) & SG4_ADDR1) \ + - (m)->pm_stpa + (((v) & SG4_MASK2) >> SG4_SHIFT2)])) +#define pmap_ste(m, v) \ + (&((m)->pm_stab[(vm_offset_t)(v) \ + >> (mmutype == MMU_68040 ? SG4_SHIFT1 : SG_ISHIFT)])) +#define pmap_ste_v(m, v) \ + (mmutype == MMU_68040 \ + ? ((*pmap_ste1(m, v) & SG_V) && \ + (*pmap_ste2(m, v) & SG_V)) \ + : (*pmap_ste(m, v) & SG_V)) +#else +#define pmap_ste(m, v) (&((m)->pm_stab[(vm_offset_t)(v) >> SG_ISHIFT])) +#define pmap_ste_v(m, v) (*pmap_ste(m, v) & SG_V) +#endif + +#define pmap_pte(m, v) (&((m)->pm_ptab[(vm_offset_t)(v) >> PG_SHIFT])) +#define pmap_pte_pa(pte) (*(pte) & PG_FRAME) +#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_prot(pte) (*(pte) & PG_PROT) +#define pmap_pte_v(pte) (*(pte) & PG_V) + +#define pmap_pte_set_w(pte, v) \ + if (v) *(pte) |= PG_W; else *(pte) &= ~PG_W +#define pmap_pte_set_prot(pte, v) \ + if (v) *(pte) |= PG_PROT; else *(pte) &= ~PG_PROT +#define pmap_pte_w_chg(pte, nw) ((nw) ^ pmap_pte_w(pte)) +#define pmap_pte_prot_chg(pte, np) ((np) ^ pmap_pte_prot(pte)) + +/* + * Given a map and a machine independent protection code, + * convert to an m68k protection code. + */ +#define pte_prot(m, p) (protection_codes[p]) +int protection_codes[8]; + +/* + * Kernel page table page management. + */ +struct kpt_page { + struct kpt_page *kpt_next; /* link on either used or free list */ + vm_offset_t kpt_va; /* always valid kernel VA */ + vm_offset_t kpt_pa; /* PA of this page (for speed) */ +}; +struct kpt_page *kpt_free_list, *kpt_used_list; +struct kpt_page *kpt_pages; + +/* + * Kernel segment/page table and page table map. + * The page table map gives us a level of indirection we need to dynamically + * expand the page table. It is essentially a copy of the segment table + * with PTEs instead of STEs. All are initialized in locore at boot time. + * Sysmap will initially contain VM_KERNEL_PT_PAGES pages of PTEs. + * Segtabzero is an empty segment table which all processes share til they + * reference something. + */ +st_entry_t *Sysseg; +pt_entry_t *Sysmap, *Sysptmap; +st_entry_t *Segtabzero, *Segtabzeropa; +vm_size_t Sysptsize = VM_KERNEL_PT_PAGES; + +struct pmap kernel_pmap_store; +vm_map_t st_map, pt_map; + +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 npages; + +boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ +struct pv_entry *pv_table; +char *pmap_attributes; /* reference and modify bits */ +TAILQ_HEAD(pv_page_list, pv_page) pv_page_freelist; +int pv_nfree; + +#ifdef HAVEVAC +int pmap_aliasmask; /* seperation at which VA aliasing ok */ +#endif +#if defined(M68040) +int protostfree; /* prototype (default) free ST map */ +#endif + +/* + * Internal routines + */ +void pmap_remove_mapping __P((pmap_t, vm_offset_t, pt_entry_t *, int)); +boolean_t pmap_testbit __P((vm_offset_t, int)); +void pmap_changebit __P((vm_offset_t, int, boolean_t)); +void pmap_enter_ptpage __P((pmap_t, vm_offset_t)); +#ifdef DEBUG +void pmap_pvdump __P((vm_offset_t)); +void pmap_check_wiring __P((char *, vm_offset_t)); +#endif + +/* pmap_remove_mapping flags */ +#define PRM_TFLUSH 1 +#define PRM_CFLUSH 2 + +/* + * 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); +} + +/* + * 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; +{ + vm_offset_t addr, addr2; + vm_size_t s; + int rv; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_init(%x, %x)\n", phys_start, phys_end); +#endif + /* + * Now that kernel map has been allocated, we can mark as + * unavailable regions which we have mapped in locore. + */ + addr = (vm_offset_t) intiobase; + (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0, + &addr, m68k_ptob(IIOMAPSIZE+EIOMAPSIZE), FALSE); + if (addr != (vm_offset_t)intiobase) + goto bogons; + addr = (vm_offset_t) Sysmap; + vm_object_reference(kernel_object); + (void) vm_map_find(kernel_map, kernel_object, addr, + &addr, HP_MAX_PTSIZE, FALSE); + /* + * If this fails it is probably because the static portion of + * the kernel page table isn't big enough and we overran the + * page table map. Need to adjust pmap_size() in m68k_init.c. + */ + if (addr != (vm_offset_t)Sysmap) +bogons: + panic("pmap_init: bogons in the VM system!\n"); + +#ifdef DEBUG + if (pmapdebug & PDB_INIT) { + printf("pmap_init: Sysseg %x, Sysmap %x, Sysptmap %x\n", + Sysseg, Sysmap, Sysptmap); + printf(" pstart %x, pend %x, vstart %x, vend %x\n", + avail_start, avail_end, virtual_avail, virtual_end); + } +#endif + + /* + * Allocate memory for random pmap data structures. Includes the + * initial segment table, pv_head_table and pmap_attributes. + */ + npages = atop(phys_end - phys_start); + s = (vm_size_t) (HP_STSIZE + sizeof(struct pv_entry) * npages + npages); + s = round_page(s); + addr = (vm_offset_t) kmem_alloc(kernel_map, s); + Segtabzero = (st_entry_t *) addr; + Segtabzeropa = (st_entry_t *) pmap_extract(pmap_kernel(), addr); + addr += HP_STSIZE; + pv_table = (struct pv_entry *) addr; + addr += sizeof(struct pv_entry) * npages; + pmap_attributes = (char *) addr; +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: %x bytes: npages %x s0 %x(%x) tbl %x atr %x\n", + s, npages, Segtabzero, Segtabzeropa, + pv_table, pmap_attributes); +#endif + + /* + * Allocate physical memory for kernel PT pages and their management. + * We need 1 PT page per possible task plus some slop. + */ + npages = min(atop(HP_MAX_KPTSIZE), maxproc+16); + s = ptoa(npages) + round_page(npages * sizeof(struct kpt_page)); + + /* + * Verify that space will be allocated in region for which + * we already have kernel PT pages. + */ + addr = 0; + rv = vm_map_find(kernel_map, NULL, 0, &addr, s, TRUE); + if (rv != KERN_SUCCESS || addr + s >= (vm_offset_t)Sysmap) + panic("pmap_init: kernel PT too small"); + vm_map_remove(kernel_map, addr, addr + s); + + /* + * Now allocate the space and link the pages together to + * form the KPT free list. + */ + addr = (vm_offset_t) kmem_alloc(kernel_map, s); + s = ptoa(npages); + addr2 = addr + s; + kpt_pages = &((struct kpt_page *)addr2)[npages]; + kpt_free_list = (struct kpt_page *) 0; + do { + addr2 -= NBPG; + (--kpt_pages)->kpt_next = kpt_free_list; + kpt_free_list = kpt_pages; + kpt_pages->kpt_va = addr2; + kpt_pages->kpt_pa = pmap_extract(pmap_kernel(), addr2); + } while (addr != addr2); +#ifdef PMAPSTATS + kpt_stats.kpttotal = atop(s); +#endif +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: KPT: %d pages from %x to %x\n", + atop(s), addr, addr + s); +#endif + + /* + * Allocate the segment table map + */ + s = maxproc * HP_STSIZE; + st_map = kmem_suballoc(kernel_map, &addr, &addr2, s, TRUE); + + /* + * Slightly modified version of kmem_suballoc() to get page table + * map where we want it. + */ + addr = HP_PTBASE; + s = min(HP_PTMAXSIZE, maxproc*HP_MAX_PTSIZE); + addr2 = addr + s; + rv = vm_map_find(kernel_map, NULL, 0, &addr, s, TRUE); + if (rv != KERN_SUCCESS) + panic("pmap_init: cannot allocate space for PT map"); + pmap_reference(vm_map_pmap(kernel_map)); + pt_map = vm_map_create(vm_map_pmap(kernel_map), addr, addr2, TRUE); + if (pt_map == NULL) + panic("pmap_init: cannot create pt_map"); + rv = vm_map_submap(kernel_map, addr, addr2, pt_map); + if (rv != KERN_SUCCESS) + panic("pmap_init: cannot map range to pt_map"); +#ifdef DEBUG + if (pmapdebug & PDB_INIT) + printf("pmap_init: pt_map [%x - %x)\n", addr, addr2); +#endif + +#if defined(M68040) + if (mmutype == MMU_68040) { + protostfree = ~l2tobm(0); + for (rv = MAXUL2SIZE; rv < sizeof(protostfree)*NBBY; rv++) + protostfree &= ~l2tobm(rv); + } +#endif + + /* + * Now it is safe to enable pv_table recording. + */ + vm_first_phys = phys_start; + vm_last_phys = phys_end; + pmap_initialized = TRUE; +} + +struct pv_entry * +pmap_alloc_pv() +{ + struct pv_page *pvp; + struct pv_entry *pv; + int i; + + if (pv_nfree == 0) { + pvp = (struct pv_page *)kmem_alloc(kernel_map, NBPG); + if (pvp == 0) + panic("pmap_alloc_pv: kmem_alloc() failed"); + pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1]; + for (i = NPVPPG - 2; i; i--, pv++) + pv->pv_next = pv + 1; + pv->pv_next = 0; + pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG - 1; + TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + pv = &pvp->pvp_pv[0]; + } else { + --pv_nfree; + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + } + pv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (pv == 0) + panic("pmap_alloc_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = pv->pv_next; + } + return pv; +} + +void +pmap_free_pv(pv) + struct pv_entry *pv; +{ + register struct pv_page *pvp; + register int i; + + pvp = (struct pv_page *) trunc_page(pv); + switch (++pvp->pvp_pgi.pgi_nfree) { + case 1: + TAILQ_INSERT_TAIL(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + default: + pv->pv_next = pvp->pvp_pgi.pgi_freelist; + pvp->pvp_pgi.pgi_freelist = pv; + ++pv_nfree; + break; + case NPVPPG: + pv_nfree -= NPVPPG - 1; + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + kmem_free(kernel_map, (vm_offset_t)pvp, NBPG); + break; + } +} + +void +pmap_collect_pv() +{ + struct pv_page_list pv_page_collectlist; + struct pv_page *pvp, *npvp; + struct pv_entry *ph, *ppv, *pv, *npv; + int s; + + TAILQ_INIT(&pv_page_collectlist); + + for (pvp = pv_page_freelist.tqh_first; pvp; pvp = npvp) { + if (pv_nfree < NPVPPG) + break; + npvp = pvp->pvp_pgi.pgi_list.tqe_next; + if (pvp->pvp_pgi.pgi_nfree > NPVPPG / 3) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + TAILQ_INSERT_TAIL(&pv_page_collectlist, pvp, pvp_pgi.pgi_list); + pv_nfree -= pvp->pvp_pgi.pgi_nfree; + pvp->pvp_pgi.pgi_nfree = -1; + } + } + + if (pv_page_collectlist.tqh_first == 0) + return; + + for (ph = &pv_table[npages - 1]; ph >= &pv_table[0]; ph--) { + if (ph->pv_pmap == 0) + continue; + s = splimp(); + for (ppv = ph; (pv = ppv->pv_next) != 0; ) { + pvp = (struct pv_page *) trunc_page(pv); + if (pvp->pvp_pgi.pgi_nfree == -1) { + pvp = pv_page_freelist.tqh_first; + if (--pvp->pvp_pgi.pgi_nfree == 0) { + TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list); + } + npv = pvp->pvp_pgi.pgi_freelist; +#ifdef DIAGNOSTIC + if (npv == 0) + panic("pmap_collect_pv: pgi_nfree inconsistent"); +#endif + pvp->pvp_pgi.pgi_freelist = npv->pv_next; + *npv = *pv; + ppv->pv_next = npv; + ppv = npv; + } else + ppv = pv; + } + splx(s); + } + + for (pvp = pv_page_collectlist.tqh_first; pvp; pvp = npvp) { + npvp = pvp->pvp_pgi.pgi_list.tqe_next; + kmem_free(kernel_map, (vm_offset_t)pvp, NBPG); + } +} + +/* + * 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(va, spa, epa, prot) + vm_offset_t va, spa, epa; + int prot; +{ + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_map(%x, %x, %x, %x)\n", va, spa, epa, prot); +#endif + + while (spa < epa) { + pmap_enter(pmap_kernel(), va, spa, prot, FALSE); + va += NBPG; + spa += NBPG; + } + return (va); +} + +/* + * Create and return a physical map. + * + * If the size specified for the map + * is zero, the map is an actual physical + * map, and may be referenced by the + * hardware. + * + * If the size specified is non-zero, + * the map will be used in software only, and + * is bounded by that size. + */ +pmap_t +pmap_create(size) + vm_size_t size; +{ + register pmap_t pmap; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_create(%x)\n", size); +#endif + + /* + * Software use map does not need a pmap + */ + if (size) + return (NULL); + + /* XXX: is it ok to wait here? */ + pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); +#ifdef notifwewait + if (pmap == NULL) + panic("pmap_create: cannot allocate a pmap"); +#endif + bzero(pmap, sizeof(*pmap)); + pmap_pinit(pmap); + return (pmap); +} + +/* + * Initialize a preallocated and zeroed pmap structure, + * such as one in a vmspace structure. + */ +void +pmap_pinit(pmap) + register struct pmap *pmap; +{ + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) + printf("pmap_pinit(%x)\n", pmap); +#endif + + /* + * No need to allocate page table space yet but we do need a + * valid segment table. Initially, we point everyone at the + * "null" segment table. On the first pmap_enter, a real + * segment table will be allocated. + */ + pmap->pm_stab = Segtabzero; + pmap->pm_stpa = Segtabzeropa; +#if defined(M68040) + if (mmutype == MMU_68040) + pmap->pm_stfree = protostfree; +#endif + pmap->pm_stchanged = TRUE; + 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; + + if (pmap == NULL) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_destroy(%x)\n", pmap); +#endif + + 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) + printf("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 + + if (pmap->pm_ptab) + kmem_free_wakeup(pt_map, (vm_offset_t)pmap->pm_ptab, + HP_MAX_PTSIZE); + if (pmap->pm_stab != Segtabzero) + kmem_free_wakeup(st_map, (vm_offset_t)pmap->pm_stab, + HP_STSIZE); +} + +/* + * Add a reference to the specified pmap. + */ +void +pmap_reference(pmap) + pmap_t pmap; +{ + + if (pmap == NULL) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_reference(%x)\n", pmap); +#endif + + simple_lock(&pmap->pm_lock); + pmap->pm_count++; + simple_unlock(&pmap->pm_lock); +} + +void +pmap_activate(pmap, pcb) + register pmap_t pmap; + struct pcb *pcb; +{ + + if (pmap == NULL) + return; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_SEGTAB)) + printf("pmap_activate(%x, %x)\n", pmap, pcb); +#endif + + PMAP_ACTIVATE(pmap, pcb, pmap == curproc->p_vmspace->vm_map.pmap); +} + +void +pmap_deactivate(pmap, pcb) + register pmap_t pmap; + struct pcb *pcb; +{ +} + +/* + * Remove the given range of addresses from the specified map. + * + * It is assumed that the start and end are properly + * rounded to the page size. + */ +void +pmap_remove(pmap, sva, eva) + register pmap_t pmap; + register vm_offset_t sva, eva; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + boolean_t firstpage, needcflush; + int flags; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva); +#endif + + if (pmap == NULL) + return; + +#ifdef PMAPSTATS + remove_stats.calls++; +#endif + firstpage = TRUE; + needcflush = FALSE; + flags = active_pmap(pmap) ? PRM_TFLUSH : 0; + while (sva < eva) { + nssva = m68k_trunc_seg(sva) + HP_SEG_SIZE; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!pmap_ste_v(pmap, sva)) { + sva = nssva; + continue; + } + /* + * Invalidate every valid mapping within this segment. + */ + pte = pmap_pte(pmap, sva); + while (sva < nssva) { + if (pmap_pte_v(pte)) { +#ifdef HAVEVAC + if (pmap_aliasmask) { + /* + * Purge kernel side of VAC to ensure + * we get the correct state of any + * hardware maintained bits. + */ + if (firstpage) { + DCIS(); +#ifdef PMAPSTATS + remove_stats.sflushes++; +#endif + } + /* + * Remember if we may need to + * flush the VAC due to a non-CI + * mapping. + */ + if (!needcflush && !pmap_pte_ci(pte)) + needcflush = TRUE; + + } +#endif + pmap_remove_mapping(pmap, sva, pte, flags); + firstpage = FALSE; + } + pte++; + sva += NBPG; + } + } + /* + * Didn't do anything, no need for cache flushes + */ + if (firstpage) + return; +#ifdef HAVEVAC + /* + * In a couple of cases, we don't need to worry about flushing + * the VAC: + * 1. if this is a kernel mapping, + * we have already done it + * 2. if it is a user mapping not for the current process, + * it won't be there + */ + if (pmap_aliasmask && + (pmap == pmap_kernel() || pmap != curproc->p_vmspace->vm_map.pmap)) + needcflush = FALSE; +#ifdef DEBUG + if (pmap_aliasmask && (pmapvacflush & PVF_REMOVE)) { + if (pmapvacflush & PVF_TOTAL) + DCIA(); + else if (pmap == pmap_kernel()) + DCIS(); + else + DCIU(); + } else +#endif + if (needcflush) { + if (pmap == pmap_kernel()) { + DCIS(); +#ifdef PMAPSTATS + remove_stats.sflushes++; +#endif + } else { + DCIU(); +#ifdef PMAPSTATS + remove_stats.uflushes++; +#endif + } + } +#endif +} + +/* + * pmap_page_protect: + * + * Lower the permission for all mappings to a given page. + */ +void +pmap_page_protect(pa, prot) + vm_offset_t pa; + vm_prot_t prot; +{ + register struct pv_entry *pv; + int s; + +#ifdef DEBUG + if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || + prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE)) + printf("pmap_page_protect(%x, %x)\n", pa, prot); +#endif + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + + switch (prot) { + case VM_PROT_READ|VM_PROT_WRITE: + case VM_PROT_ALL: + return; + /* copy_on_write */ + case VM_PROT_READ: + case VM_PROT_READ|VM_PROT_EXECUTE: + pmap_changebit(pa, PG_RO, TRUE); + return; + /* remove_all */ + default: + break; + } + pv = pa_to_pvh(pa); + s = splimp(); + while (pv->pv_pmap != NULL) { + register pt_entry_t *pte; + + pte = pmap_pte(pv->pv_pmap, pv->pv_va); +#ifdef DEBUG + if (!pmap_ste_v(pv->pv_pmap, pv->pv_va) || + pmap_pte_pa(pte) != pa) + panic("pmap_page_protect: bad mapping"); +#endif + if (!pmap_pte_w(pte)) + pmap_remove_mapping(pv->pv_pmap, pv->pv_va, + pte, PRM_TFLUSH|PRM_CFLUSH); + else { + pv = pv->pv_next; +#ifdef DEBUG + if (pmapdebug & PDB_PARANOIA) + printf("%s wired mapping for %x not removed\n", + "pmap_page_protect:", pa); +#endif + } + } + splx(s); +} + +/* + * Set the physical protection on the + * specified range of this map as requested. + */ +void +pmap_protect(pmap, sva, eva, prot) + register pmap_t pmap; + register vm_offset_t sva, eva; + vm_prot_t prot; +{ + register vm_offset_t nssva; + register pt_entry_t *pte; + boolean_t firstpage, needtflush; + int isro; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) + printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot); +#endif + + if (pmap == NULL) + return; + +#ifdef PMAPSTATS + protect_stats.calls++; +#endif + if ((prot & VM_PROT_READ) == VM_PROT_NONE) { + pmap_remove(pmap, sva, eva); + return; + } + if (prot & VM_PROT_WRITE) + return; + + isro = pte_prot(pmap, prot); + needtflush = active_pmap(pmap); + firstpage = TRUE; + while (sva < eva) { + nssva = m68k_trunc_seg(sva) + HP_SEG_SIZE; + if (nssva == 0 || nssva > eva) + nssva = eva; + /* + * If VA belongs to an unallocated segment, + * skip to the next segment boundary. + */ + if (!pmap_ste_v(pmap, sva)) { + sva = nssva; + continue; + } + /* + * Change protection on mapping if it is valid and doesn't + * already have the correct protection. + */ + pte = pmap_pte(pmap, sva); + while (sva < nssva) { + if (pmap_pte_v(pte) && pmap_pte_prot_chg(pte, isro)) { +#ifdef HAVEVAC + /* + * Purge kernel side of VAC to ensure we + * get the correct state of any hardware + * maintained bits. + * + * XXX do we need to clear the VAC in + * general to reflect the new protection? + */ + if (firstpage && pmap_aliasmask) + DCIS(); +#endif +#if defined(M68040) + /* + * Clear caches if making RO (see section + * "7.3 Cache Coherency" in the manual). + */ + if (isro && mmutype == MMU_68040) { + vm_offset_t pa = pmap_pte_pa(pte); + + DCFP(pa); + ICPP(pa); + } +#endif + pmap_pte_set_prot(pte, isro); + if (needtflush) + TBIS(sva); +#ifdef PMAPSTATS + protect_stats.changed++; +#endif + firstpage = FALSE; + } +#ifdef PMAPSTATS + else if (pmap_pte_v(pte)) { + if (isro) + protect_stats.alreadyro++; + else + protect_stats.alreadyrw++; + } +#endif + pte++; + sva += NBPG; + } + } +#if defined(HAVEVAC) && defined(DEBUG) + if (pmap_aliasmask && (pmapvacflush & PVF_PROTECT)) { + if (pmapvacflush & PVF_TOTAL) + DCIA(); + else if (pmap == pmap_kernel()) + DCIS(); + else + DCIU(); + } +#endif +} + +/* + * 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; + 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; + +#ifdef PMAPSTATS + if (pmap == pmap_kernel()) + enter_stats.kernel++; + else + enter_stats.user++; +#endif + /* + * For user mapping, allocate kernel VM resources if necessary. + */ + if (pmap->pm_ptab == NULL) + pmap->pm_ptab = (pt_entry_t *) + kmem_alloc_wait(pt_map, HP_MAX_PTSIZE); + + /* + * Segment table entry not valid, we need a new PT page + */ + if (!pmap_ste_v(pmap, va)) + pmap_enter_ptpage(pmap, va); + + pa = m68k_trunc_page(pa); + pte = pmap_pte(pmap, va); + opa = pmap_pte_pa(pte); +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: pte %x, *pte %x\n", pte, *pte); +#endif + + /* + * Mapping has not changed, must be protection or wiring change. + */ + if (opa == pa) { +#ifdef PMAPSTATS + 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 (pmap_pte_w_chg(pte, wired ? PG_W : 0)) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: wiring change -> %x\n", wired); +#endif + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; +#ifdef PMAPSTATS + if (pmap_pte_prot(pte) == pte_prot(pmap, prot)) + enter_stats.wchange++; +#endif + } +#ifdef PMAPSTATS + else if (pmap_pte_prot(pte) != pte_prot(pmap, prot)) + enter_stats.pchange++; + else + enter_stats.nochange++; +#endif + /* + * Retain cache inhibition status + */ + checkpv = FALSE; + if (pmap_pte_ci(pte)) + cacheable = FALSE; + goto validate; + } + + /* + * Mapping has changed, invalidate old range and fall through to + * handle validating new mapping. + */ + if (opa) { +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: removing old mapping %x\n", va); +#endif + pmap_remove_mapping(pmap, va, pte, PRM_TFLUSH|PRM_CFLUSH); +#ifdef PMAPSTATS + enter_stats.mchange++; +#endif + } + + /* + * If this is a new user mapping, increment the wiring count + * on this PT page. PT pages are wired down as long as there + * is a valid mapping in the page. + */ + if (pmap != pmap_kernel()) + (void) vm_map_pageable(pt_map, trunc_page(pte), + round_page(pte+1), FALSE); + + /* + * 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 (pa >= vm_first_phys && pa < vm_last_phys) { + register struct pv_entry *pv, *npv; + int s; + +#ifdef PMAPSTATS + 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 PMAPSTATS + enter_stats.firstpv++; +#endif + pv->pv_va = va; + pv->pv_pmap = pmap; + pv->pv_next = NULL; + pv->pv_ptste = NULL; + pv->pv_ptpmap = NULL; + pv->pv_flags = 0; + } + /* + * There is at least one other VA mapping this page. + * Place this entry after the header. + */ + else { +#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 = pmap_alloc_pv(); + npv->pv_va = va; + npv->pv_pmap = pmap; + npv->pv_next = pv->pv_next; + npv->pv_ptste = NULL; + npv->pv_ptpmap = NULL; + npv->pv_flags = 0; + pv->pv_next = npv; +#ifdef PMAPSTATS + if (!npv->pv_next) + enter_stats.secondpv++; +#endif +#ifdef HAVEVAC + /* + * Since there is another logical mapping for the + * same page we may need to cache-inhibit the + * descriptors on those CPUs with external VACs. + * We don't need to CI if: + * + * - No two mappings belong to the same user pmaps. + * Since the cache is flushed on context switches + * there is no problem between user processes. + * + * - Mappings within a single pmap are a certain + * magic distance apart. VAs at these appropriate + * boundaries map to the same cache entries or + * otherwise don't conflict. + * + * To keep it simple, we only check for these special + * cases if there are only two mappings, otherwise we + * punt and always CI. + * + * Note that there are no aliasing problems with the + * on-chip data-cache when the WA bit is set. + */ + if (pmap_aliasmask) { + if (pv->pv_flags & PV_CI) { +#ifdef DEBUG + if (pmapdebug & PDB_CACHE) + printf("enter: pa %x already CI'ed\n", + pa); +#endif + checkpv = cacheable = FALSE; + } else if (npv->pv_next || + ((pmap == pv->pv_pmap || + pmap == pmap_kernel() || + pv->pv_pmap == pmap_kernel()) && + ((pv->pv_va & pmap_aliasmask) != + (va & pmap_aliasmask)))) { +#ifdef DEBUG + if (pmapdebug & PDB_CACHE) + printf("enter: pa %x CI'ing all\n", + pa); +#endif + cacheable = FALSE; + pv->pv_flags |= PV_CI; +#ifdef PMAPSTATS + enter_stats.ci++; +#endif + } + } +#endif + } + splx(s); + } + /* + * Assumption: if it is not part of our managed memory + * then it must be device memory which may be volitile. + */ + else if (pmap_initialized) { + checkpv = cacheable = FALSE; +#ifdef PMAPSTATS + enter_stats.unmanaged++; +#endif + } + + /* + * Increment counters + */ + pmap->pm_stats.resident_count++; + if (wired) + pmap->pm_stats.wired_count++; + +validate: +#ifdef HAVEVAC + /* + * Purge kernel side of VAC to ensure we get correct state + * of HW bits so we don't clobber them. + */ + if (pmap_aliasmask) + DCIS(); +#endif + /* + * Build the new PTE. + */ + npte = pa | pte_prot(pmap, prot) | (*pte & (PG_M|PG_U)) | PG_V; + if (wired) + npte |= PG_W; + if (!checkpv && !cacheable) + npte |= PG_CI; +#if defined(M68040) + if (mmutype == MMU_68040 && (npte & (PG_PROT|PG_CI)) == PG_RW) +#ifdef DEBUG + if (dowriteback && (dokwriteback || pmap != pmap_kernel())) +#endif + npte |= PG_CCB; +#endif +#ifdef DEBUG + if (pmapdebug & PDB_ENTER) + printf("enter: new pte value %x\n", npte); +#endif + /* + * Remember if this was a wiring-only change. + * If so, we need not flush the TLB and caches. + */ + wired = ((*pte ^ npte) == PG_W); +#if defined(M68040) + if (mmutype == MMU_68040 && !wired) { + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (!wired && active_pmap(pmap)) + TBIS(va); +#ifdef HAVEVAC + /* + * The following is executed if we are entering a second + * (or greater) mapping for a physical page and the mappings + * may create an aliasing problem. In this case we must + * cache inhibit the descriptors involved and flush any + * external VAC. + */ + if (checkpv && !cacheable) { + pmap_changebit(pa, PG_CI, TRUE); + DCIA(); +#ifdef PMAPSTATS + enter_stats.flushes++; +#endif +#ifdef DEBUG + if ((pmapdebug & (PDB_CACHE|PDB_PVDUMP)) == + (PDB_CACHE|PDB_PVDUMP)) + pmap_pvdump(pa); +#endif + } +#ifdef DEBUG + else if (pmapvacflush & PVF_ENTER) { + if (pmapvacflush & PVF_TOTAL) + DCIA(); + else if (pmap == pmap_kernel()) + DCIS(); + else + DCIU(); + } +#endif +#endif +#ifdef DEBUG + if ((pmapdebug & PDB_WIRING) && pmap != pmap_kernel()) + pmap_check_wiring("enter", trunc_page(pmap_pte(pmap, va))); +#endif +} + +/* + * Routine: pmap_change_wiring + * Function: Change the wiring attribute for a map/virtual-address + * pair. + * In/out conditions: + * The mapping must already exist in the pmap. + */ +void +pmap_change_wiring(pmap, va, wired) + register pmap_t pmap; + vm_offset_t va; + boolean_t wired; +{ + register pt_entry_t *pte; + +#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_ste_v(pmap, va)) { + if (pmapdebug & PDB_PARANOIA) + printf("pmap_change_wiring: invalid STE 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) + printf("pmap_change_wiring: invalid PTE for %x\n", va); + } +#endif + /* + * If wiring actually changed (always?) set the wire bit and + * update the wire count. Note that wiring is not a hardware + * characteristic so there is no need to invalidate the TLB. + */ + if (pmap_pte_w_chg(pte, wired ? PG_W : 0)) { + pmap_pte_set_w(pte, wired); + if (wired) + pmap->pm_stats.wired_count++; + else + pmap->pm_stats.wired_count--; + } +} + +/* + * Routine: pmap_extract + * Function: + * Extract the physical page address associated + * with the given map/virtual_address pair. + */ + +vm_offset_t +pmap_extract(pmap, va) + register pmap_t pmap; + vm_offset_t va; +{ + register vm_offset_t pa; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_extract(%x, %x) -> ", pmap, va); +#endif + pa = 0; + if (pmap && pmap_ste_v(pmap, va)) + pa = *pmap_pte(pmap, va); + if (pa) + pa = (pa & PG_FRAME) | (va & ~PG_FRAME); +#ifdef DEBUG + 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; +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy(%x, %x, %x, %x, %x)\n", + dst_pmap, src_pmap, dst_addr, len, src_addr); +#endif +} + +/* + * Require that all active physical maps contain no + * incorrect entries NOW. [This update includes + * forcing updates of any address map caching.] + * + * Generally used to insure that a thread about + * to run will see a semantically correct world. + */ +void pmap_update() +{ +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_update()\n"); +#endif + TBIA(); +} + +/* + * Routine: pmap_collect + * Function: + * Garbage collects the physical map system for + * pages which are no longer used. + * Success need not be guaranteed -- that is, there + * may well be pages which are not referenced, but + * others may be collected. + * Usage: + * Called by the pageout daemon when pages are scarce. + */ +void +pmap_collect(pmap) + pmap_t pmap; +{ + register vm_offset_t pa; + register struct pv_entry *pv; + register pt_entry_t *pte; + vm_offset_t kpa; + int s; + +#ifdef DEBUG + st_entry_t *ste; + int opmapdebug; +#endif + if (pmap != pmap_kernel()) + return; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_collect(%x)\n", pmap); +#endif +#ifdef PMAPSTATS + kpt_stats.collectscans++; +#endif + s = splimp(); + for (pa = vm_first_phys; pa < vm_last_phys; pa += NBPG) { + register struct kpt_page *kpt, **pkpt; + + /* + * Locate physical pages which are being used as kernel + * page table pages. + */ + pv = pa_to_pvh(pa); + if (pv->pv_pmap != pmap_kernel() || !(pv->pv_flags & PV_PTPAGE)) + continue; + do { + if (pv->pv_ptste && pv->pv_ptpmap == pmap_kernel()) + break; + } while (pv = pv->pv_next); + if (pv == NULL) + continue; +#ifdef DEBUG + if (pv->pv_va < (vm_offset_t)Sysmap || + pv->pv_va >= (vm_offset_t)Sysmap + HP_MAX_PTSIZE) + printf("collect: kernel PT VA out of range\n"); + else + goto ok; + pmap_pvdump(pa); + continue; +ok: +#endif + pte = (pt_entry_t *)(pv->pv_va + NBPG); + while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) + ; + if (pte >= (pt_entry_t *)pv->pv_va) + continue; + +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) { + printf("collect: freeing KPT page at %x (ste %x@%x)\n", + pv->pv_va, *pv->pv_ptste, pv->pv_ptste); + opmapdebug = pmapdebug; + pmapdebug |= PDB_PTPAGE; + } + + ste = pv->pv_ptste; +#endif + /* + * If all entries were invalid we can remove the page. + * We call pmap_remove_entry to take care of invalidating + * ST and Sysptmap entries. + */ + kpa = pmap_extract(pmap, pv->pv_va); + pmap_remove_mapping(pmap, pv->pv_va, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); + /* + * Use the physical address to locate the original + * (kmem_alloc assigned) address for the page and put + * that page back on the free list. + */ + for (pkpt = &kpt_used_list, kpt = *pkpt; + kpt != (struct kpt_page *)0; + pkpt = &kpt->kpt_next, kpt = *pkpt) + if (kpt->kpt_pa == kpa) + break; +#ifdef DEBUG + if (kpt == (struct kpt_page *)0) + panic("pmap_collect: lost a KPT page"); + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + printf("collect: %x (%x) to free list\n", + kpt->kpt_va, kpa); +#endif + *pkpt = kpt->kpt_next; + kpt->kpt_next = kpt_free_list; + kpt_free_list = kpt; +#ifdef PMAPSTATS + kpt_stats.kptinuse--; + kpt_stats.collectpages++; +#endif +#ifdef DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + pmapdebug = opmapdebug; + + if (*ste != SG_NV) + printf("collect: kernel STE at %x still valid (%x)\n", + ste, *ste); + ste = &Sysptmap[ste - pmap_ste(pmap_kernel(), 0)]; + if (*ste != SG_NV) + printf("collect: kernel PTmap at %x still valid (%x)\n", + ste, *ste); +#endif + } + splx(s); +} + +/* + * 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. + * + * XXX this is a bad implementation for virtual cache machines + * (320/350) because pmap_enter doesn't cache-inhibit the temporary + * kernel mapping and we wind up with data cached for that KVA. + * It is probably a win for physical cache machines (370/380) + * as the cache loading is not wasted. + */ +void +pmap_zero_page(phys) + vm_offset_t phys; +{ + register vm_offset_t kva; + extern caddr_t CADDR1; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_zero_page(%x)\n", phys); +#endif + kva = (vm_offset_t) CADDR1; + pmap_enter(pmap_kernel(), kva, phys, VM_PROT_READ|VM_PROT_WRITE, TRUE); + bzero((caddr_t)kva, NBPG); + pmap_remove_mapping(pmap_kernel(), kva, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); +} + +/* + * 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. + * + * + * XXX this is a bad implementation for virtual cache machines + * (320/350) because pmap_enter doesn't cache-inhibit the temporary + * kernel mapping and we wind up with data cached for that KVA. + * It is probably a win for physical cache machines (370/380) + * as the cache loading is not wasted. + */ +void +pmap_copy_page(src, dst) + vm_offset_t src, dst; +{ + register vm_offset_t skva, dkva; + extern caddr_t CADDR1, CADDR2; + +#ifdef DEBUG + if (pmapdebug & PDB_FOLLOW) + printf("pmap_copy_page(%x, %x)\n", src, dst); +#endif + skva = (vm_offset_t) CADDR1; + dkva = (vm_offset_t) CADDR2; + pmap_enter(pmap_kernel(), skva, src, VM_PROT_READ, TRUE); + pmap_enter(pmap_kernel(), dkva, dst, VM_PROT_READ|VM_PROT_WRITE, TRUE); + copypage((caddr_t)skva, (caddr_t)dkva); + /* CADDR1 and CADDR2 are virtually contiguous */ + pmap_remove(pmap_kernel(), skva, skva+2*NBPG); +} + +/* + * 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 + NBPG == eva) { + register struct pv_entry *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_ste_v(pmap, sva)) + 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 (pv->pv_ptste == NULL) + return; +#ifdef DEBUG + if (pv->pv_va != sva || pv->pv_next) { + printf("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_changebit(pa, PG_M, FALSE); +#ifdef DEBUG + if ((PHYS_TO_VM_PAGE(pa)->flags & PG_CLEAN) == 0) { + printf("pa %x: flags=%x: not clean\n", + pa, PHYS_TO_VM_PAGE(pa)->flags); + PHYS_TO_VM_PAGE(pa)->flags |= PG_CLEAN; + } + if (pmapdebug & PDB_PTPAGE) + printf("pmap_pageable: PT page %x(%x) unmodified\n", + sva, *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)\n", 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)\n", 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\n", 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(m68k_ptob(ppn)); +} + +#ifdef COMPAT_HPUX +/* + * 'PUX hack for dealing with the so called multi-mapped address space. + * The first 256mb is mapped in at every 256mb region from 0x10000000 + * up to 0xF0000000. This allows for 15 bits of tag information. + * + * We implement this at the segment table level, the machine independent + * VM knows nothing about it. + */ +pmap_mapmulti(pmap, va) + pmap_t pmap; + vm_offset_t va; +{ + st_entry_t *ste, *bste; + +#ifdef DEBUG + if (pmapdebug & PDB_MULTIMAP) { + ste = pmap_ste(pmap, HPMMBASEADDR(va)); + printf("pmap_mapmulti(%x, %x): bste %x(%x)", + pmap, va, ste, *ste); + ste = pmap_ste(pmap, va); + printf(" ste %x(%x)\n", ste, *ste); + } +#endif + bste = pmap_ste(pmap, HPMMBASEADDR(va)); + ste = pmap_ste(pmap, va); + if (*ste == SG_NV && (*bste & SG_V)) { + *ste = *bste; + TBIAU(); + return (KERN_SUCCESS); + } + return (KERN_INVALID_ADDRESS); +} +#endif + +/* + * Miscellaneous support routines follow + */ + +/* + * Invalidate a single page denoted by pmap/va. + * If (pte != NULL), it is the already computed PTE for the page. + * If (flags & PRM_TFLUSH), we must invalidate any TLB information. + * If (flags & PRM_CFLUSH), we must flush/invalidate any cache information. + */ +/* static */ +void +pmap_remove_mapping(pmap, va, pte, flags) + register pmap_t pmap; + register vm_offset_t va; + register pt_entry_t *pte; + int flags; +{ + register vm_offset_t pa; + register struct pv_entry *pv, *npv; + pmap_t ptpmap; + st_entry_t *ste; + int s, bits; +#ifdef DEBUG + pt_entry_t opte; + + if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) + printf("pmap_remove_mapping(%x, %x, %x, %x)\n", + pmap, va, pte, flags); +#endif + + /* + * PTE not provided, compute it from pmap and va. + */ + if (pte == PT_ENTRY_NULL) { + pte = pmap_pte(pmap, va); + if (*pte == PG_NV) + return; + } +#ifdef HAVEVAC + if (pmap_aliasmask && (flags & PRM_CFLUSH)) { + /* + * Purge kernel side of VAC to ensure we get the correct + * state of any hardware maintained bits. + */ + DCIS(); +#ifdef PMAPSTATS + remove_stats.sflushes++; +#endif + /* + * If this is a non-CI user mapping for the current process, + * flush the VAC. Note that the kernel side was flushed + * above so we don't worry about non-CI kernel mappings. + */ + if (pmap == curproc->p_vmspace->vm_map.pmap && + !pmap_pte_ci(pte)) { + DCIU(); +#ifdef PMAPSTATS + remove_stats.uflushes++; +#endif + } + } +#endif + pa = pmap_pte_pa(pte); +#ifdef DEBUG + opte = *pte; +#endif +#ifdef PMAPSTATS + remove_stats.removes++; +#endif + /* + * Update statistics + */ + if (pmap_pte_w(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + /* + * Invalidate the PTE after saving the reference modify info. + */ +#ifdef DEBUG + if (pmapdebug & PDB_REMOVE) + printf("remove: invalidating pte at %x\n", pte); +#endif + bits = *pte & (PG_U|PG_M); + *pte = PG_NV; + if ((flags & PRM_TFLUSH) && active_pmap(pmap)) + TBIS(va); + /* + * For user mappings decrement the wiring count on + * the PT page. We do this after the PTE has been + * invalidated because vm_map_pageable winds up in + * pmap_pageable which clears the modify bit for the + * PT page. + */ + if (pmap != pmap_kernel()) { + (void) vm_map_pageable(pt_map, trunc_page(pte), + round_page(pte+1), TRUE); +#ifdef DEBUG + if (pmapdebug & PDB_WIRING) + pmap_check_wiring("remove", trunc_page(pte)); +#endif + } + /* + * If this isn't a managed page, we are all done. + */ + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + /* + * Otherwise remove it from the PV table + * (raise IPL since we may be called at interrupt time). + */ + pv = pa_to_pvh(pa); + ste = ST_ENTRY_NULL; + 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) { + ste = pv->pv_ptste; + ptpmap = pv->pv_ptpmap; + npv = pv->pv_next; + if (npv) { + npv->pv_flags = pv->pv_flags; + *pv = *npv; + pmap_free_pv(npv); + } else + pv->pv_pmap = NULL; +#ifdef PMAPSTATS + remove_stats.pvfirst++; +#endif + } else { + for (npv = pv->pv_next; npv; npv = npv->pv_next) { +#ifdef PMAPSTATS + remove_stats.pvsearch++; +#endif + if (pmap == npv->pv_pmap && va == npv->pv_va) + break; + pv = npv; + } +#ifdef DEBUG + if (npv == NULL) + panic("pmap_remove: PA not in pv_tab"); +#endif + ste = npv->pv_ptste; + ptpmap = npv->pv_ptpmap; + pv->pv_next = npv->pv_next; + pmap_free_pv(npv); + pv = pa_to_pvh(pa); + } +#ifdef HAVEVAC + /* + * If only one mapping left we no longer need to cache inhibit + */ + if (pmap_aliasmask && + pv->pv_pmap && pv->pv_next == NULL && (pv->pv_flags & PV_CI)) { +#ifdef DEBUG + if (pmapdebug & PDB_CACHE) + printf("remove: clearing CI for pa %x\n", pa); +#endif + pv->pv_flags &= ~PV_CI; + pmap_changebit(pa, PG_CI, FALSE); +#ifdef DEBUG + if ((pmapdebug & (PDB_CACHE|PDB_PVDUMP)) == + (PDB_CACHE|PDB_PVDUMP)) + pmap_pvdump(pa); +#endif + } +#endif + /* + * If this was a PT page we must also remove the + * mapping from the associated segment table. + */ + if (ste) { +#ifdef PMAPSTATS + remove_stats.ptinvalid++; +#endif +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_PTPAGE)) + printf("remove: ste was %x@%x pte was %x@%x\n", + *ste, ste, opte, pmap_pte(pmap, va)); +#endif +#if defined(M68040) + if (mmutype == MMU_68040) { + st_entry_t *este = &ste[NPTEPG/SG4_LEV3SIZE]; + + while (ste < este) + *ste++ = SG_NV; +#ifdef DEBUG + ste -= NPTEPG/SG4_LEV3SIZE; +#endif + } else +#endif + *ste = SG_NV; + /* + * If it was a user PT page, we decrement the + * reference count on the segment table as well, + * freeing it if it is now empty. + */ + if (ptpmap != pmap_kernel()) { +#ifdef DEBUG + if (pmapdebug & (PDB_REMOVE|PDB_SEGTAB)) + printf("remove: stab %x, refcnt %d\n", + ptpmap->pm_stab, ptpmap->pm_sref - 1); + if ((pmapdebug & PDB_PARANOIA) && + ptpmap->pm_stab != (st_entry_t *)trunc_page(ste)) + panic("remove: bogus ste"); +#endif + if (--(ptpmap->pm_sref) == 0) { +#ifdef DEBUG + if (pmapdebug&(PDB_REMOVE|PDB_SEGTAB)) + printf("remove: free stab %x\n", + ptpmap->pm_stab); +#endif + kmem_free_wakeup(st_map, + (vm_offset_t)ptpmap->pm_stab, + HP_STSIZE); + ptpmap->pm_stab = Segtabzero; + ptpmap->pm_stpa = Segtabzeropa; +#if defined(M68040) + if (mmutype == MMU_68040) + ptpmap->pm_stfree = protostfree; +#endif + ptpmap->pm_stchanged = TRUE; + /* + * XXX may have changed segment table + * pointer for current process so + * update now to reload hardware. + */ + if (curproc != NULL && + ptpmap == curproc->p_vmspace->vm_map.pmap) + PMAP_ACTIVATE(ptpmap, + &curproc->p_addr->u_pcb, 1); + } +#ifdef DEBUG + else if (ptpmap->pm_sref < 0) + panic("remove: sref < 0"); +#endif + } +#if 0 + /* + * XXX this should be unnecessary as we have been + * flushing individual mappings as we go. + */ + if (ptpmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pv->pv_flags &= ~PV_PTPAGE; + ptpmap->pm_ptpages--; + } + /* + * Update saved attributes for managed page + */ + pmap_attributes[pmap_page_index(pa)] |= bits; + splx(s); +} + +/* static */ +boolean_t +pmap_testbit(pa, bit) + register vm_offset_t pa; + int bit; +{ + register struct pv_entry *pv; + register pt_entry_t *pte; + 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[pmap_page_index(pa)] & bit) { + splx(s); + return(TRUE); + } +#ifdef HAVEVAC + /* + * Flush VAC to get correct state of any hardware maintained bits. + */ + if (pmap_aliasmask && (bit & (PG_U|PG_M))) + DCIS(); +#endif + /* + * Not found, check current mappings returning + * immediately if found. + */ + if (pv->pv_pmap != NULL) { + for (; pv; pv = pv->pv_next) { + pte = pmap_pte(pv->pv_pmap, pv->pv_va); + if (*pte & bit) { + splx(s); + return(TRUE); + } + } + } + splx(s); + return(FALSE); +} + +/* static */ +void +pmap_changebit(pa, bit, setem) + register vm_offset_t pa; + int bit; + boolean_t setem; +{ + register struct pv_entry *pv; + register pt_entry_t *pte, npte; + vm_offset_t va; + int s; + boolean_t firstpage = TRUE; +#ifdef PMAPSTATS + struct chgstats *chgp; +#endif + +#ifdef DEBUG + if (pmapdebug & PDB_BITS) + printf("pmap_changebit(%x, %x, %s)\n", + pa, bit, setem ? "set" : "clear"); +#endif + if (pa < vm_first_phys || pa >= vm_last_phys) + return; + +#ifdef PMAPSTATS + chgp = &changebit_stats[(bit>>2)-1]; + if (setem) + chgp->setcalls++; + else + chgp->clrcalls++; +#endif + pv = pa_to_pvh(pa); + s = splimp(); + /* + * Clear saved attributes (modify, reference) + */ + if (!setem) + pmap_attributes[pmap_page_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 = pmap_pte(pv->pv_pmap, va); +#ifdef HAVEVAC + /* + * Flush VAC to ensure we get correct state of HW bits + * so we don't clobber them. + */ + if (firstpage && pmap_aliasmask) { + firstpage = FALSE; + DCIS(); + } +#endif + if (setem) + npte = *pte | bit; + else + npte = *pte & ~bit; + if (*pte != npte) { +#if defined(M68040) + /* + * If we are changing caching status or + * protection make sure the caches are + * flushed (but only once). + */ + if (firstpage && mmutype == MMU_68040 && + (bit == PG_RO && setem || + (bit & PG_CMASK))) { + firstpage = FALSE; + DCFP(pa); + ICPP(pa); + } +#endif + *pte = npte; + if (active_pmap(pv->pv_pmap)) + TBIS(va); +#ifdef PMAPSTATS + if (setem) + chgp->sethits++; + else + chgp->clrhits++; +#endif + } +#ifdef PMAPSTATS + else { + if (setem) + chgp->setmiss++; + else + chgp->clrmiss++; + } +#endif + } +#if defined(HAVEVAC) && defined(DEBUG) + 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); +} + +/* static */ +void +pmap_enter_ptpage(pmap, va) + register pmap_t pmap; + register vm_offset_t va; +{ + register vm_offset_t ptpa; + register struct pv_entry *pv; + st_entry_t *ste; + int s; + +#ifdef DEBUG + if (pmapdebug & (PDB_FOLLOW|PDB_ENTER|PDB_PTPAGE)) + printf("pmap_enter_ptpage: pmap %x, va %x\n", pmap, va); +#endif +#ifdef PMAPSTATS + enter_stats.ptpneeded++; +#endif + /* + * Allocate a segment table if necessary. Note that it is allocated + * from a private map and not pt_map. This keeps user page tables + * aligned on segment boundaries in the kernel address space. + * The segment table is wired down. It will be freed whenever the + * reference count drops to zero. + */ + if (pmap->pm_stab == Segtabzero) { + pmap->pm_stab = (st_entry_t *) + kmem_alloc(st_map, HP_STSIZE); + pmap->pm_stpa = (st_entry_t *) + pmap_extract(pmap_kernel(), (vm_offset_t)pmap->pm_stab); +#if defined(M68040) + if (mmutype == MMU_68040) { +#ifdef DEBUG + if (dowriteback && dokwriteback) +#endif + pmap_changebit((vm_offset_t)pmap->pm_stpa, PG_CCB, 0); + pmap->pm_stfree = protostfree; + } +#endif + pmap->pm_stchanged = TRUE; + /* + * XXX may have changed segment table pointer for current + * process so update now to reload hardware. + */ + if (pmap == curproc->p_vmspace->vm_map.pmap) + PMAP_ACTIVATE(pmap, &curproc->p_addr->u_pcb, 1); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: pmap %x stab %x(%x)\n", + pmap, pmap->pm_stab, pmap->pm_stpa); +#endif + } + + ste = pmap_ste(pmap, va); +#if defined(M68040) + /* + * Allocate level 2 descriptor block if necessary + */ + if (mmutype == MMU_68040) { + if (*ste == SG_NV) { + int ix; + caddr_t addr; + + ix = bmtol2(pmap->pm_stfree); + if (ix == -1) + panic("enter: out of address space"); /* XXX */ + pmap->pm_stfree &= ~l2tobm(ix); + addr = (caddr_t)&pmap->pm_stab[ix*SG4_LEV2SIZE]; + bzero(addr, SG4_LEV2SIZE*sizeof(st_entry_t)); + addr = (caddr_t)&pmap->pm_stpa[ix*SG4_LEV2SIZE]; + *ste = (u_int)addr | SG_RW | SG_U | SG_V; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: alloc ste2 %d(%x)\n", ix, addr); +#endif + } + ste = pmap_ste2(pmap, va); + /* + * Since a level 2 descriptor maps a block of SG4_LEV3SIZE + * level 3 descriptors, we need a chunk of NPTEPG/SG4_LEV3SIZE + * (16) such descriptors (NBPG/SG4_LEV3SIZE bytes) to map a + * PT page--the unit of allocation. We set `ste' to point + * to the first entry of that chunk which is validated in its + * entirety below. + */ + ste = (st_entry_t *)((int)ste & ~(NBPG/SG4_LEV3SIZE-1)); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: ste2 %x (%x)\n", + pmap_ste2(pmap, va), ste); +#endif + } +#endif + va = trunc_page((vm_offset_t)pmap_pte(pmap, va)); + + /* + * In the kernel we allocate a page from the kernel PT page + * free list and map it into the kernel page table map (via + * pmap_enter). + */ + if (pmap == pmap_kernel()) { + register struct kpt_page *kpt; + + s = splimp(); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) { + /* + * No PT pages available. + * Try once to free up unused ones. + */ +#ifdef DEBUG + if (pmapdebug & PDB_COLLECT) + printf("enter: no KPT pages, collecting...\n"); +#endif + pmap_collect(pmap_kernel()); + if ((kpt = kpt_free_list) == (struct kpt_page *)0) + panic("pmap_enter_ptpage: can't get KPT page"); + } +#ifdef PMAPSTATS + if (++kpt_stats.kptinuse > kpt_stats.kptmaxuse) + kpt_stats.kptmaxuse = kpt_stats.kptinuse; +#endif + kpt_free_list = kpt->kpt_next; + kpt->kpt_next = kpt_used_list; + kpt_used_list = kpt; + ptpa = kpt->kpt_pa; + bzero((caddr_t)kpt->kpt_va, NBPG); + pmap_enter(pmap, va, ptpa, VM_PROT_DEFAULT, TRUE); +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) { + int ix = pmap_ste(pmap, va) - pmap_ste(pmap, 0); + + printf("enter: add &Sysptmap[%d]: %x (KPT page %x)\n", + ix, Sysptmap[ix], kpt->kpt_va); + } +#endif + splx(s); + } + /* + * For user processes we just simulate a fault on that location + * letting the VM system allocate a zero-filled page. + */ + else { +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf("enter: about to fault UPT pg at %x\n", va); +#endif + s = vm_fault(pt_map, va, VM_PROT_READ|VM_PROT_WRITE, FALSE); + if (s != KERN_SUCCESS) { + printf("vm_fault(pt_map, %x, RW, 0) -> %d\n", va, s); + panic("pmap_enter: vm_fault failed"); + } + ptpa = pmap_extract(pmap_kernel(), va); + /* + * Mark the page clean now to avoid its pageout (and + * hence creation of a pager) between now and when it + * is wired; i.e. while it is on a paging queue. + */ + PHYS_TO_VM_PAGE(ptpa)->flags |= PG_CLEAN; +#ifdef DEBUG + PHYS_TO_VM_PAGE(ptpa)->flags |= PG_PTPAGE; +#endif + } +#if defined(M68040) + /* + * Turn off copyback caching of page table pages, + * could get ugly otherwise. + */ +#ifdef DEBUG + if (dowriteback && dokwriteback) +#endif + if (mmutype == MMU_68040) { + pt_entry_t *pte = pmap_pte(pmap_kernel(), va); +#ifdef DEBUG + if ((pmapdebug & PDB_PARANOIA) && (*pte & PG_CCB) == 0) + printf("%s PT no CCB: kva=%x ptpa=%x pte@%x=%x\n", + pmap == pmap_kernel() ? "Kernel" : "User", + va, ptpa, pte, *pte); +#endif + pmap_changebit(ptpa, PG_CCB, 0); + } +#endif + /* + * Locate the PV entry in the kernel for this PT page and + * record the STE address. This is so that we can invalidate + * the STE when we remove the mapping for the page. + */ + pv = pa_to_pvh(ptpa); + s = splimp(); + if (pv) { + pv->pv_flags |= PV_PTPAGE; + do { + if (pv->pv_pmap == pmap_kernel() && pv->pv_va == va) + break; + } while (pv = pv->pv_next); + } +#ifdef DEBUG + if (pv == NULL) + panic("pmap_enter_ptpage: PT page not entered"); +#endif + pv->pv_ptste = ste; + pv->pv_ptpmap = pmap; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) + printf("enter: new PT page at PA %x, ste at %x\n", ptpa, ste); +#endif + + /* + * Map the new PT page into the segment table. + * Also increment the reference count on the segment table if this + * was a user page table page. Note that we don't use vm_map_pageable + * to keep the count like we do for PT pages, this is mostly because + * it would be difficult to identify ST pages in pmap_pageable to + * release them. We also avoid the overhead of vm_map_pageable. + */ +#if defined(M68040) + if (mmutype == MMU_68040) { + st_entry_t *este; + + for (este = &ste[NPTEPG/SG4_LEV3SIZE]; ste < este; ste++) { + *ste = ptpa | SG_U | SG_RW | SG_V; + ptpa += SG4_LEV3SIZE * sizeof(st_entry_t); + } + } else +#endif + *ste = (ptpa & SG_FRAME) | SG_RW | SG_V; + if (pmap != pmap_kernel()) { + pmap->pm_sref++; +#ifdef DEBUG + if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) + printf("enter: stab %x refcnt %d\n", + pmap->pm_stab, pmap->pm_sref); +#endif + } +#if 0 + /* + * Flush stale TLB info. + */ + if (pmap == pmap_kernel()) + TBIAS(); + else + TBIAU(); +#endif + pmap->pm_ptpages++; + splx(s); +} + +#ifdef DEBUG +/* static */ +void +pmap_pvdump(pa) + vm_offset_t pa; +{ + register struct pv_entry *pv; + + printf("pa %x", pa); + for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) + printf(" -> pmap %x, va %x, ptste %x, ptpmap %x, flags %x", + pv->pv_pmap, pv->pv_va, pv->pv_ptste, pv->pv_ptpmap, + pv->pv_flags); + printf("\n"); +} + +/* static */ +void +pmap_check_wiring(str, va) + char *str; + vm_offset_t va; +{ + vm_map_entry_t entry; + register int count; + register pt_entry_t *pte; + + va = trunc_page(va); + if (!pmap_ste_v(pmap_kernel(), va) || + !pmap_pte_v(pmap_pte(pmap_kernel(), va))) + return; + + if (!vm_map_lookup_entry(pt_map, va, &entry)) { + printf("wired_check: entry for %x not found\n", va); + return; + } + count = 0; + for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va + NBPG); pte++) + if (*pte) + count++; + if (entry->wired_count != count) + printf("*%s*: %x: w%d/a%d\n", + str, va, entry->wired_count, count); +} +#endif diff --git a/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c b/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c new file mode 100644 index 0000000000000..bdd0064289aaa --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/pmap_bootstrap.c @@ -0,0 +1,505 @@ +/* $NetBSD: pmap_bootstrap.c,v 1.1.1.1 1995/07/25 23:12:02 chuck Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * 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. + * + * @(#)pmap_bootstrap.c 8.1 (Berkeley) 6/10/93 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define RELOC(v, t) *((t*)((u_int)&(v) + firstpa)) + +extern char *etext; +extern int Sysptsize; +extern char *extiobase, *proc0paddr; +extern st_entry_t *Sysseg; +extern pt_entry_t *Sysptmap, *Sysmap; + +extern int maxmem, physmem; +extern vm_offset_t avail_start, avail_end, virtual_avail, virtual_end; +extern vm_size_t mem_size; +extern int protection_codes[]; +#ifdef HAVEVAC +extern int pmap_aliasmask; +#endif + +/* + * Special purpose kernel virtual addresses, used for mapping + * physical pages for a variety of temporary or permanent purposes: + * + * CADDR1, CADDR2: pmap zero/copy operations + * vmmap: /dev/mem, crash dumps, parity error checking + * ledbase: SPU LEDs + * msgbufp: kernel message buffer + */ +caddr_t CADDR1, CADDR2, vmmap, ledbase; +struct msgbuf *msgbufp; +extern void *ledatabuf; /* XXXCDC */ + +/* + * Bootstrap the VM system. + * + * Called with MMU off so we must relocate all global references by `firstpa' + * (don't call any functions here!) `nextpa' is the first available physical + * memory address. Returns an updated first PA reflecting the memory we + * have allocated. MMU is still off when we return. + * + * XXX assumes sizeof(u_int) == sizeof(pt_entry_t) + * XXX a PIC compiler would make this much easier. + */ +void +pmap_bootstrap(nextpa, firstpa) + vm_offset_t nextpa; + register vm_offset_t firstpa; +{ + vm_offset_t kstpa, kptpa, iiopa, eiopa, kptmpa, lkptpa, p0upa; + u_int nptpages, kstsize; + register st_entry_t protoste, *ste; + register pt_entry_t protopte, *pte, *epte; + + /* + * Calculate important physical addresses: + * + * kstpa kernel segment table 1 page (!040) + * N pages (040) + * + * kptpa statically allocated + * kernel PT pages Sysptsize+ pages + * + * iiopa internal IO space + * PT pages IIOMAPSIZE pages + * + * eiopa external IO space + * PT pages EIOMAPSIZE pages + * + * [ Sysptsize is the number of pages of PT, IIOMAPSIZE and + * EIOMAPSIZE are the number of PTEs, hence we need to round + * the total to a page boundary with IO maps at the end. ] + * + * kptmpa kernel PT map 1 page + * + * lkptpa last kernel PT page 1 page + * + * p0upa proc 0 u-area UPAGES pages + * + * The KVA corresponding to any of these PAs is: + * (PA - firstpa + KERNBASE). + */ + if (RELOC(mmutype, int) == MMU_68040) + kstsize = MAXKL2SIZE / (NPTEPG/SG4_LEV2SIZE); + else + kstsize = 1; + kstpa = nextpa; + nextpa += kstsize * NBPG; + kptpa = nextpa; + nptpages = RELOC(Sysptsize, int) + + (IIOMAPSIZE + EIOMAPSIZE + NPTEPG - 1) / NPTEPG; + nextpa += nptpages * NBPG; + eiopa = nextpa - EIOMAPSIZE * sizeof(pt_entry_t); + iiopa = eiopa - IIOMAPSIZE * sizeof(pt_entry_t); + kptmpa = nextpa; + nextpa += NBPG; + lkptpa = nextpa; + nextpa += NBPG; + p0upa = nextpa; + nextpa += USPACE; + { /* XXXCDC */ + ledatabuf = (void *)nextpa; + nextpa += 4 * NBPG; + } /* XXXCDC */ + + /* + * Initialize segment table and kernel page table map. + * + * On 68030s and earlier MMUs the two are identical except for + * the valid bits so both are initialized with essentially the + * same values. On the 68040, which has a mandatory 3-level + * structure, the segment table holds the level 1 table and part + * (or all) of the level 2 table and hence is considerably + * different. Here the first level consists of 128 descriptors + * (512 bytes) each mapping 32mb of address space. Each of these + * points to blocks of 128 second level descriptors (512 bytes) + * each mapping 256kb. Note that there may be additional "segment + * table" pages depending on how large MAXKL2SIZE is. + * + * Portions of the last segment of KVA space (0xFFF00000 - + * 0xFFFFFFFF) are mapped for a couple of purposes. 0xFFF00000 + * for UPAGES is used for mapping the current process u-area + * (u + kernel stack). The very last page (0xFFFFF000) is mapped + * to the last physical page of RAM to give us a region in which + * PA == VA. We use the first part of this page for enabling + * and disabling mapping. The last part of this page also contains + * info left by the boot ROM. + * + * XXX cramming two levels of mapping into the single "segment" + * table on the 68040 is intended as a temporary hack to get things + * working. The 224mb of address space that this allows will most + * likely be insufficient in the future (at least for the kernel). + */ + if (RELOC(mmutype, int) == MMU_68040) { + register int num; + + /* + * First invalidate the entire "segment table" pages + * (levels 1 and 2 have the same "invalid" value). + */ + pte = (u_int *)kstpa; + epte = &pte[kstsize * NPTEPG]; + while (pte < epte) + *pte++ = SG_NV; + /* + * Initialize level 2 descriptors (which immediately + * follow the level 1 table). We need: + * NPTEPG / SG4_LEV3SIZE + * level 2 descriptors to map each of the nptpages+1 + * pages of PTEs. Note that we set the "used" bit + * now to save the HW the expense of doing it. + */ + num = (nptpages + 1) * (NPTEPG / SG4_LEV3SIZE); + pte = &((u_int *)kstpa)[SG4_LEV1SIZE]; + epte = &pte[num]; + protoste = kptpa | SG_U | SG_RW | SG_V; + while (pte < epte) { + *pte++ = protoste; + protoste += (SG4_LEV3SIZE * sizeof(st_entry_t)); + } + /* + * Initialize level 1 descriptors. We need: + * roundup(num, SG4_LEV2SIZE) / SG4_LEV2SIZE + * level 1 descriptors to map the `num' level 2's. + */ + pte = (u_int *)kstpa; + epte = &pte[roundup(num, SG4_LEV2SIZE) / SG4_LEV2SIZE]; + protoste = (u_int)&pte[SG4_LEV1SIZE] | SG_U | SG_RW | SG_V; + while (pte < epte) { + *pte++ = protoste; + protoste += (SG4_LEV2SIZE * sizeof(st_entry_t)); + } + /* + * Initialize the final level 1 descriptor to map the last + * block of level 2 descriptors. + */ + ste = &((u_int *)kstpa)[SG4_LEV1SIZE-1]; + pte = &((u_int *)kstpa)[kstsize*NPTEPG - SG4_LEV2SIZE]; + *ste = (u_int)pte | SG_U | SG_RW | SG_V; + /* + * Now initialize the final portion of that block of + * descriptors to map the "last PT page". + */ + pte = &((u_int *)kstpa)[kstsize*NPTEPG - NPTEPG/SG4_LEV3SIZE]; + epte = &pte[NPTEPG/SG4_LEV3SIZE]; + protoste = lkptpa | SG_U | SG_RW | SG_V; + while (pte < epte) { + *pte++ = protoste; + protoste += (SG4_LEV3SIZE * sizeof(st_entry_t)); + } + /* + * Initialize Sysptmap + */ + pte = (u_int *)kptmpa; + epte = &pte[nptpages+1]; + protopte = kptpa | PG_RW | PG_CI | PG_V; + while (pte < epte) { + *pte++ = protopte; + protopte += NBPG; + } + pte = &((u_int *)kptmpa)[NPTEPG-1]; + *pte = lkptpa | PG_RW | PG_CI | PG_V; + } else { + /* + * Map the page table pages in both the HW segment table + * and the software Sysptmap. Note that Sysptmap is also + * considered a PT page hence the +1. + */ + ste = (u_int *)kstpa; + pte = (u_int *)kptmpa; + epte = &pte[nptpages+1]; + protoste = kptpa | SG_RW | SG_V; + protopte = kptpa | PG_RW | PG_CI | PG_V; + while (pte < epte) { + *ste++ = protoste; + *pte++ = protopte; + protoste += NBPG; + protopte += NBPG; + } + /* + * Invalidate all but the last remaining entries in both. + */ + epte = &((u_int *)kptmpa)[NPTEPG-1]; + while (pte < epte) { + *ste++ = SG_NV; + *pte++ = PG_NV; + } + /* + * Initialize the last to point to point to the page + * table page allocated earlier. + */ + *ste = lkptpa | SG_RW | SG_V; + *pte = lkptpa | PG_RW | PG_CI | PG_V; + } + /* + * Invalidate all but the final entry in the last kernel PT page + * (u-area PTEs will be validated later). The final entry maps + * the last page of physical memory. + */ + pte = (u_int *)lkptpa; + epte = &pte[NPTEPG-1]; + while (pte < epte) + *pte++ = PG_NV; +#ifdef MAXADDR + /* tmp double-map for cpu's with physmem at the end of memory */ + *pte = MAXADDR | PG_RW | PG_CI | PG_V; +#endif + /* + * Initialize kernel page table. + * Start by invalidating the `nptpages' that we have allocated. + */ + pte = (u_int *)kptpa; + epte = &pte[nptpages * NPTEPG]; + while (pte < epte) + *pte++ = PG_NV; + /* + * Validate PTEs for kernel text (RO) + */ + pte = &((u_int *)kptpa)[m68k_btop(KERNBASE)]; + epte = &pte[m68k_btop(m68k_trunc_page(&etext))]; +#if defined(KGDB) || defined(DDB) + protopte = firstpa | PG_RW | PG_V; /* XXX RW for now */ +#else + protopte = firstpa | PG_RO | PG_V; +#endif + while (pte < epte) { + *pte++ = protopte; + protopte += NBPG; + } + /* + * Validate PTEs for kernel data/bss, dynamic data allocated + * by us so far (nextpa - firstpa bytes), and pages for proc0 + * u-area and page table allocated below (RW). + */ + epte = &((u_int *)kptpa)[m68k_btop(nextpa - firstpa)]; + protopte = (protopte & ~PG_PROT) | PG_RW; + /* + * Enable copy-back caching of data pages + */ + if (RELOC(mmutype, int) == MMU_68040) + protopte |= PG_CCB; + while (pte < epte) { + *pte++ = protopte; + protopte += NBPG; + } + { /* XXXCDC -- uncache lebuf */ + u_int *lepte = &((u_int *)kptpa)[m68k_btop(ledatabuf)]; + + lepte[0] = lepte[0] | PG_CI; + lepte[1] = lepte[1] | PG_CI; + lepte[2] = lepte[2] | PG_CI; + lepte[3] = lepte[3] | PG_CI; + } /* XXXCDC yuck */ + + /* + * Finally, validate the internal IO space PTEs (RW+CI). + * We do this here since the 320/350 MMU registers (also + * used, but to a lesser extent, on other models) are mapped + * in this range and it would be nice to be able to access + * them after the MMU is turned on. + */ + pte = (u_int *)iiopa; + epte = (u_int *)eiopa; + protopte = INTIOBASE | PG_RW | PG_CI | PG_V; + while (pte < epte) { + *pte++ = protopte; + protopte += NBPG; + } + + /* + * Calculate important exported kernel virtual addresses + */ + /* + * Sysseg: base of kernel segment table + */ + RELOC(Sysseg, st_entry_t *) = + (st_entry_t *)(kstpa - firstpa); + /* + * Sysptmap: base of kernel page table map + */ + RELOC(Sysptmap, pt_entry_t *) = + (pt_entry_t *)(kptmpa - firstpa); + /* + * Sysmap: kernel page table (as mapped through Sysptmap) + * Immediately follows `nptpages' of static kernel page table. + */ + RELOC(Sysmap, pt_entry_t *) = + (pt_entry_t *)m68k_ptob(nptpages * NPTEPG); + /* + * intiobase, intiolimit: base and end of internal (DIO) IO space. + * IIOMAPSIZE pages prior to external IO space at end of static + * kernel page table. + */ + RELOC(intiobase, char *) = + (char *)m68k_ptob(nptpages*NPTEPG - (IIOMAPSIZE+EIOMAPSIZE)); + RELOC(intiolimit, char *) = + (char *)m68k_ptob(nptpages*NPTEPG - EIOMAPSIZE); + /* + * extiobase: base of external (DIO-II) IO space. + * EIOMAPSIZE pages at the end of the static kernel page table. + */ + RELOC(extiobase, char *) = + (char *)m68k_ptob(nptpages*NPTEPG - EIOMAPSIZE); + + /* + * Setup u-area for process 0. + */ + /* + * Zero the u-area. + * NOTE: `pte' and `epte' aren't PTEs here. + */ + pte = (u_int *)p0upa; + epte = (u_int *)(p0upa + USPACE); + while (pte < epte) + *pte++ = 0; + /* + * Remember the u-area address so it can be loaded in the + * proc struct p_addr field later. + */ + RELOC(proc0paddr, char *) = (char *)(p0upa - firstpa); + + /* + * VM data structures are now initialized, set up data for + * the pmap module. + */ + RELOC(avail_start, vm_offset_t) = nextpa; + RELOC(avail_end, vm_offset_t) = + m68k_ptob(RELOC(maxmem, int)) + /* XXX allow for msgbuf */ + - m68k_round_page(sizeof(struct msgbuf)); + RELOC(mem_size, vm_size_t) = m68k_ptob(RELOC(physmem, int)); + RELOC(virtual_avail, vm_offset_t) = + VM_MIN_KERNEL_ADDRESS + (nextpa - firstpa); + RELOC(virtual_end, vm_offset_t) = VM_MAX_KERNEL_ADDRESS; + +#ifdef HAVEVAC + /* + * Determine VA aliasing distance if any + */ + if (RELOC(ectype, int) == EC_VIRT) + if (RELOC(machineid, int) == HP_320) + RELOC(pmap_aliasmask, int) = 0x3fff; /* 16k */ + else if (RELOC(machineid, int) == HP_350) + RELOC(pmap_aliasmask, int) = 0x7fff; /* 32k */ +#endif + + /* + * Initialize protection array. + * XXX don't use a switch statement, it might produce an + * absolute "jmp" table. + */ + { + register int *kp; + + kp = &RELOC(protection_codes, int); + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_NONE] = 0; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_NONE] = PG_RO; + kp[VM_PROT_READ|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_NONE|VM_PROT_EXECUTE] = PG_RO; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_NONE|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_NONE] = PG_RW; + kp[VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW; + } + + /* + * Kernel page/segment table allocated in locore, + * just initialize pointers. + */ + { + struct pmap *kpm = &RELOC(kernel_pmap_store, struct pmap); + + kpm->pm_stab = RELOC(Sysseg, st_entry_t *); + kpm->pm_ptab = RELOC(Sysmap, pt_entry_t *); + simple_lock_init(&kpm->pm_lock); + kpm->pm_count = 1; + kpm->pm_stpa = (st_entry_t *)kstpa; + /* + * For the 040 we also initialize the free level 2 + * descriptor mask noting that we have used: + * 0: level 1 table + * 1 to `num': map page tables + * MAXKL2SIZE-1: maps last-page page table + */ + if (RELOC(mmutype, int) == MMU_68040) { + register int num; + + kpm->pm_stfree = ~l2tobm(0); + num = roundup((nptpages + 1) * (NPTEPG / SG4_LEV3SIZE), + SG4_LEV2SIZE) / SG4_LEV2SIZE; + while (num) + kpm->pm_stfree &= ~l2tobm(num--); + kpm->pm_stfree &= ~l2tobm(MAXKL2SIZE-1); + for (num = MAXKL2SIZE; + num < sizeof(kpm->pm_stfree)*NBBY; + num++) + kpm->pm_stfree &= ~l2tobm(num); + } + } + + /* + * Allocate some fixed, special purpose kernel virtual addresses + */ + { + vm_offset_t va = RELOC(virtual_avail, vm_offset_t); + + RELOC(CADDR1, caddr_t) = (caddr_t)va; + va += NBPG; + RELOC(CADDR2, caddr_t) = (caddr_t)va; + va += NBPG; + RELOC(vmmap, caddr_t) = (caddr_t)va; + va += NBPG; + RELOC(ledbase, caddr_t) = (caddr_t)va; + va += NBPG; + RELOC(msgbufp, struct msgbuf *) = (struct msgbuf *)va; + va += NBPG; + RELOC(virtual_avail, vm_offset_t) = va; + } +} diff --git a/sys/arch/mvme68k/mvme68k/swapgeneric.c b/sys/arch/mvme68k/mvme68k/swapgeneric.c new file mode 100644 index 0000000000000..a48e0954402ab --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/swapgeneric.c @@ -0,0 +1,170 @@ +/* $NetBSD: swapgeneric.c,v 1.1.1.1 1995/07/25 23:12:00 chuck Exp $ */ + +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)swapgeneric.c 7.5 (Berkeley) 5/7/91 + */ + +#include +#include +#include +#include +#include +#include + +/* + * Generic configuration; all in one + */ +dev_t rootdev = NODEV; +dev_t argdev = NODEV; +dev_t dumpdev = NODEV; +int nswap; +struct swdevt swdevt[] = { + { -1, 1, 0 }, + { 0, 0, 0 }, +}; +int dmmin, dmmax, dmtext; + +extern struct cfdriver sdcd; +extern struct cfdriver wdcd; +extern struct cfdriver idcd; + +struct genericconf { + struct cfdriver *gc_driver; + char *gc_name; + dev_t gc_root; +} genericconf[] = { + { &sdcd, "sd", makedev(1, 0), }, + { &wdcd, "wd", makedev(2, 0), }, + { &idcd, "id", makedev(4, 0), }, + { 0 }, +}; + +extern int ffs_mountroot(); +int (*mountroot)() = ffs_mountroot; + +setconf() +{ + register struct genericconf *gc; + register struct bus_device *device; + register char *cp; + int unit, swaponroot = 0; + + if (rootdev != NODEV) + goto doswap; + unit = 0; + 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; + printf("use one of:"); + for (gc = genericconf; gc->gc_driver; gc++) + printf(" %s%%d", gc->gc_name); + printf("\n"); + goto retry; +gotit: + cp = &name[2]; + if (*cp < '0' || *cp > '9') { + printf("bad/missing unit number\n"); + goto retry; + } + while (*cp >= '0' && *cp <= '9') + unit = 10 * unit + *cp++ - '0'; + if (*cp == '*') + swaponroot++; + goto found; + } + for (gc = genericconf; gc->gc_driver; gc++) { + for (cfp = cfdata; cfp->cf_driver; ++cfp) { + if (cfp->state == FSTATE_FOUND && cfp->unit == 0 + && cfp->cf_driver == gc->gc_driver) { + printf("root on %s0\n", device->name); + goto found; + } + } + } + printf("no suitable root\n"); + asm("stop #0x2700"); +found: + gc->gc_root = makedev(major(gc->gc_root), unit*8); + rootdev = gc->gc_root; +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 (;;) { + cnputc(c = cngetc()); + switch (c) { + case '\n': + case '\r': + *lp++ = '\0'; + return; + case '\b': + case '\177': + if (lp > cp) { + lp--; + cnputc(' '); + cnputc('\b'); + } + continue; + case '#': + lp--; + if (lp < cp) + lp = cp; + continue; + case '@': + case 'u'&037: + lp = cp; + cnputc('\n'); + continue; + default: + *lp++ = c; + } + } +} diff --git a/sys/arch/mvme68k/mvme68k/sys_machdep.c b/sys/arch/mvme68k/mvme68k/sys_machdep.c new file mode 100644 index 0000000000000..f2498d0c8eea1 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/sys_machdep.c @@ -0,0 +1,263 @@ +/* $NetBSD: sys_machdep.c,v 1.1.1.1 1995/07/25 23:12:00 chuck Exp $ */ + +/* + * Copyright (c) 1982, 1986, 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. + * + * @(#)sys_machdep.c 8.2 (Berkeley) 1/13/94 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef TRACE +int nvualarm; + +vtrace(p, uap, retval) + struct proc *p; + register struct vtrace_args /* { + syscallarg(int) request; + syscallarg(int) value; + } */ *uap; + register_t *retval; +{ + int vdoualarm(); + + switch (SCARG(uap, request)) { + + case VTR_DISABLE: /* disable a trace point */ + case VTR_ENABLE: /* enable a trace point */ + if (SCARG(uap, value) < 0 || SCARG(uap, value) >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[SCARG(uap, value)]; + traceflags[SCARG(uap, value)] = SCARG(uap, request); + break; + + case VTR_VALUE: /* return a trace point setting */ + if (SCARG(uap, value) < 0 || SCARG(uap, value) >= TR_NFLAGS) + return (EINVAL); + *retval = traceflags[SCARG(uap, value)]; + break; + + case VTR_UALARM: /* set a real-time ualarm, less than 1 min */ + if (SCARG(uap, value) <= 0 || SCARG(uap, value) > 60 * hz || + nvualarm > 5) + return (EINVAL); + nvualarm++; + timeout(vdoualarm, (void *)p->p_pid, SCARG(uap, value)); + break; + + case VTR_STAMP: + trace(TR_STAMP, SCARG(uap, value), p->p_pid); + break; + } + return (0); +} + +vdoualarm(arg) + void *arg; +{ + register int pid = (int)arg; + register struct proc *p; + + p = pfind(pid); + if (p) + psignal(p, 16); + nvualarm--; +} +#endif + +#include + +/* XXX should be in an include file somewhere */ +#define CC_PURGE 1 +#define CC_FLUSH 2 +#define CC_IPURGE 4 +#define CC_EXTPURGE 0x80000000 +/* XXX end should be */ + +/* + * Note that what we do here for a 68040 is different than HP-UX. + * + * In 'pux they either act on a line (len == 16), a page (len == NBPG) + * or the whole cache (len == anything else). + * + * In BSD we attempt to be more optimal when acting on "odd" sizes. + * For lengths up to 1024 we do all affected lines, up to 2*NBPG we + * do pages, above that we do the entire cache. + */ +/*ARGSUSED1*/ +cachectl(req, addr, len) + int req; + caddr_t addr; + int len; +{ + int error = 0; + +#if defined(M68040) + if (mmutype == MMU_68040) { + register int inc = 0; + int pa = 0, doall = 0; + caddr_t end; +#ifdef COMPAT_HPUX + extern struct emul emul_hpux; + + if ((curproc->p_emul == &emul_hpux) && + len != 16 && len != NBPG) + doall = 1; +#endif + + if (addr == 0 || + (req & ~CC_EXTPURGE) != CC_PURGE && len > 2*NBPG) + doall = 1; + + if (!doall) { + end = addr + len; + if (len <= 1024) { + addr = (caddr_t)((int)addr & ~0xF); + inc = 16; + } else { + addr = (caddr_t)((int)addr & ~PGOFSET); + inc = NBPG; + } + } + do { + /* + * Convert to physical address if needed. + * If translation fails, we perform operation on + * entire cache (XXX is this a rational thing to do?) + */ + if (!doall && + (pa == 0 || ((int)addr & PGOFSET) == 0)) { + pa = pmap_extract(&curproc->p_vmspace->vm_pmap, + (vm_offset_t)addr); + if (pa == 0) + doall = 1; + } + switch (req) { + case CC_EXTPURGE|CC_IPURGE: + case CC_IPURGE: + if (doall) { + DCFA(); + ICPA(); + } else if (inc == 16) { + DCFL(pa); + ICPL(pa); + } else if (inc == NBPG) { + DCFP(pa); + ICPP(pa); + } + break; + + case CC_EXTPURGE|CC_PURGE: + case CC_PURGE: + if (doall) + DCFA(); /* note: flush not purge */ + else if (inc == 16) + DCPL(pa); + else if (inc == NBPG) + DCPP(pa); + break; + + case CC_EXTPURGE|CC_FLUSH: + case CC_FLUSH: + if (doall) + DCFA(); + else if (inc == 16) + DCFL(pa); + else if (inc == NBPG) + DCFP(pa); + break; + + default: + error = EINVAL; + break; + } + if (doall) + break; + pa += inc; + addr += inc; + } while (addr < end); + return(error); + } +#endif + switch (req) { + case CC_EXTPURGE|CC_PURGE: + case CC_EXTPURGE|CC_FLUSH: +#if defined(HP370) + if (ectype == EC_PHYS) + PCIA(); + /* fall into... */ +#endif + case CC_PURGE: + case CC_FLUSH: + DCIU(); + break; + case CC_EXTPURGE|CC_IPURGE: +#if defined(HP370) + if (ectype == EC_PHYS) + PCIA(); + else +#endif + DCIU(); + /* fall into... */ + case CC_IPURGE: + ICIA(); + break; + default: + error = EINVAL; + break; + } + return(error); +} + +int +sysarch(p, uap, retval) + struct proc *p; + struct sysarch_args /* { + syscallarg(int) op; + syscallarg(char *) parms; + } */ *uap; + register_t *retval; +{ + return ENOSYS; +} diff --git a/sys/arch/mvme68k/mvme68k/trap.c b/sys/arch/mvme68k/mvme68k/trap.c new file mode 100644 index 0000000000000..aef56203a49f0 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/trap.c @@ -0,0 +1,1084 @@ +/* $NetBSD: trap.c,v 1.1.1.1 1995/07/25 23:12:00 chuck 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. + * + * from: Utah $Hdr: trap.c 1.37 92/12/20$ + * + * @(#)trap.c 8.5 (Berkeley) 1/4/94 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KTRACE +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#ifdef COMPAT_HPUX +#include +#endif +#ifdef COMPAT_SUNOS +#include + extern struct emul emul_sunos; +#endif + +char *trap_type[] = { + "Bus error", + "Address error", + "Illegal instruction", + "Zero divide", + "CHK instruction", + "TRAPV instruction", + "Privilege violation", + "Trace trap", + "MMU fault", + "SSIR trap", + "Format error", + "68881 exception", + "Coprocessor violation", + "Async system trap" +}; +int trap_types = sizeof trap_type / sizeof trap_type[0]; + +/* + * Size of various exception stack frames (minus the standard 8 bytes) + */ +short exframesize[] = { + FMT0SIZE, /* type 0 - normal (68020/030/040) */ + FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ + FMT2SIZE, /* type 2 - normal 6-word (68020/030/040) */ + FMT3SIZE, /* type 3 - FP post-instruction (68040) */ + -1, -1, -1, /* type 4-6 - undefined */ + FMT7SIZE, /* type 7 - access error (68040) */ + 58, /* type 8 - bus fault (68010) */ + FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ + FMTASIZE, /* type A - short bus fault (68020/030) */ + FMTBSIZE, /* type B - long bus fault (68020/030) */ + -1, -1, -1, -1 /* type C-F - undefined */ +}; + +#ifdef M68040 +#define KDFAULT(c) (mmutype == MMU_68040 ? \ + ((c) & SSW4_TMMASK) == SSW4_TMKD : \ + ((c) & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD)) +#define WRFAULT(c) (mmutype == MMU_68040 ? \ + ((c) & SSW4_RW) == 0 : \ + ((c) & (SSW_DF|SSW_RW)) == SSW_DF) +#else +#define KDFAULT(c) (((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD)) +#define WRFAULT(c) (((c) & (SSW_DF|SSW_RW)) == SSW_DF) +#endif + +#ifdef DEBUG +int mmudebug = 0; +int mmupid = -1; +#define MDB_FOLLOW 1 +#define MDB_WBFOLLOW 2 +#define MDB_WBFAILED 4 +#define MDB_ISPID(p) (p) == mmupid +#endif + +#define NSIR 32 +void (*sir_routines[NSIR])(); +void *sir_args[NSIR]; +int next_sir; + +/* + * trap and syscall both need the following work done before returning + * to user mode. + */ +static inline void +userret(p, fp, oticks, faultaddr, fromtrap) + register struct proc *p; + register struct frame *fp; + u_quad_t oticks; + u_int faultaddr; + int fromtrap; +{ + int sig, s; +#ifdef M68040 + int beenhere = 0; + +again: +#endif + /* take pending signals */ + while ((sig = CURSIG(p)) != 0) + postsig(sig); + 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 put ourselves on the run queue + * but before we mi_switch()'ed, we might not be on the queue + * indicated by our priority. + */ + s = splstatclock(); + setrunqueue(p); + p->p_stats->p_ru.ru_nivcsw++; + mi_switch(); + splx(s); + while ((sig = CURSIG(p)) != 0) + postsig(sig); + } + + /* + * If profiling, charge system time to the trapped pc. + */ + if (p->p_flag & P_PROFIL) { + extern int psratio; + + addupc_task(p, fp->f_pc, + (int)(p->p_sticks - oticks) * psratio); + } +#ifdef M68040 + /* + * Deal with user mode writebacks (from trap, or from sigreturn). + * If any writeback fails, go back and attempt signal delivery. + * unless we have already been here and attempted the writeback + * (e.g. bad address with user ignoring SIGSEGV). In that case + * we just return to the user without sucessfully completing + * the writebacks. Maybe we should just drop the sucker? + */ + if (mmutype == MMU_68040 && fp->f_format == FMT7) { + if (beenhere) { +#ifdef DEBUG + if (mmudebug & MDB_WBFAILED) + printf(fromtrap ? + "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" : + "pid %d(%s): writeback aborted in sigreturn, pc=%x\n", + p->p_pid, p->p_comm, fp->f_pc, faultaddr); +#endif + } else if (sig = writeback(fp, fromtrap)) { + beenhere = 1; + oticks = p->p_sticks; + trapsignal(p, sig, faultaddr); + goto again; + } + } +#endif + curpriority = p->p_priority; +} + +/* + * Trap is called from locore to handle most types of processor traps, + * including events such as simulated software interrupts/AST's. + * System calls are broken out for efficiency. + */ +/*ARGSUSED*/ +trap(type, code, v, frame) + int type; + unsigned code; + register unsigned v; + struct frame frame; +{ + extern char fubail[], subail[]; +#ifdef DDB + extern char trap0[], trap1[], trap2[], trap12[], trap15[], illinst[]; +#endif + register struct proc *p; + register int i; + u_int ucode; + u_quad_t sticks; +#ifdef COMPAT_HPUX + extern struct emul emul_hpux; +#endif + int bit; + + cnt.v_trap++; + p = curproc; + ucode = 0; + if (USERMODE(frame.f_sr)) { + type |= T_USER; + sticks = p->p_sticks; + p->p_md.md_regs = frame.f_regs; + } + switch (type) { + + default: +dopanic: + printf("trap type %d, code = %x, v = %x\n", type, code, v); +#ifdef DDB + if (kdb_trap(type, &frame)) + return; +#endif + regdump(&frame, 128); + type &= ~T_USER; + if ((unsigned)type < trap_types) + panic(trap_type[type]); + panic("trap"); + + case T_BUSERR: /* kernel bus error */ + if (!p->p_addr->u_pcb.pcb_onfault) + goto dopanic; + /* + * If we have arranged to catch this fault in any of the + * copy to/from user space routines, set PC to return to + * indicated location and set flag informing buserror code + * that it may need to clean up stack frame. + */ +copyfault: + frame.f_stackadj = exframesize[frame.f_format]; + frame.f_format = frame.f_vector = 0; + frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault; + return; + + case T_BUSERR|T_USER: /* bus error */ + case T_ADDRERR|T_USER: /* address error */ + ucode = v; + i = SIGBUS; + break; + +#ifdef FPCOPROC + case T_COPERR: /* kernel coprocessor violation */ +#endif + case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ + case T_FMTERR: /* ...just in case... */ + /* + * The user has most likely trashed the RTE or FP state info + * in the stack frame of a signal handler. + */ + printf("pid %d: kernel %s exception\n", p->p_pid, + type==T_COPERR ? "coprocessor" : "format"); + type |= T_USER; + p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL; + i = sigmask(SIGILL); + p->p_sigignore &= ~i; + p->p_sigcatch &= ~i; + p->p_sigmask &= ~i; + i = SIGILL; + ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ + break; + +#ifdef FPCOPROC + case T_COPERR|T_USER: /* user coprocessor violation */ + /* What is a proper response here? */ + ucode = 0; + i = SIGFPE; + break; + + case T_FPERR|T_USER: /* 68881 exceptions */ + /* + * We pass along the 68881 status register which locore stashed + * in code for us. Note that there is a possibility that the + * bit pattern of this register will conflict with one of the + * FPE_* codes defined in signal.h. Fortunately for us, the + * only such codes we use are all in the range 1-7 and the low + * 3 bits of the status register are defined as 0 so there is + * no clash. + */ + ucode = code; + i = SIGFPE; + break; +#endif + +#ifdef M68040 + case T_FPEMULI|T_USER: /* unimplemented FP instuction */ + case T_FPEMULD|T_USER: /* unimplemented FP data type */ + /* XXX need to FSAVE */ + printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n", + p->p_pid, p->p_comm, + frame.f_format == 2 ? "instruction" : "data type", + frame.f_pc, frame.f_fmt2.f_iaddr); + /* XXX need to FRESTORE */ + i = SIGFPE; + break; +#endif + + case T_ILLINST|T_USER: /* illegal instruction fault */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) { + ucode = HPUX_ILL_ILLINST_TRAP; + i = SIGILL; + break; + } + /* fall through */ +#endif + case T_PRIVINST|T_USER: /* privileged instruction fault */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) + ucode = HPUX_ILL_PRIV_TRAP; + else +#endif + ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ + i = SIGILL; + break; + + case T_ZERODIV|T_USER: /* Divide by zero */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) + ucode = HPUX_FPE_INTDIV_TRAP; + else +#endif + ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */ + i = SIGFPE; + break; + + case T_CHKINST|T_USER: /* CHK instruction trap */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) { + /* handled differently under hp-ux */ + i = SIGILL; + ucode = HPUX_ILL_CHK_TRAP; + break; + } +#endif + ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */ + i = SIGFPE; + break; + + case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ +#ifdef COMPAT_HPUX + if (p->p_emul == &emul_hpux) { + /* handled differently under hp-ux */ + i = SIGILL; + ucode = HPUX_ILL_TRAPV_TRAP; + break; + } +#endif + ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */ + i = SIGFPE; + break; + + /* + * XXX: Trace traps are a nightmare. + * + * HP-UX uses trap #1 for breakpoints, + * HPBSD uses trap #2, + * SUN 3.x uses trap #15, + * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). + * + * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE. + * SUN 3.x traps get passed through as T_TRAP15 and are not really + * supported yet. + */ + case T_TRACE: /* kernel trace trap */ + case T_TRAP15: /* SUN trace trap */ +#ifdef DDB + if (type == T_TRAP15 || + (frame.f_pc != trap0 && frame.f_pc != trap1 && + frame.f_pc != trap2 && frame.f_pc != trap12 && + frame.f_pc != trap15 && frame.f_pc != illinst)) { + if (kdb_trap(type, &frame)) + return; + } +#endif + frame.f_sr &= ~PSL_T; + i = SIGTRAP; + break; + + case T_TRACE|T_USER: /* user trace trap */ + case T_TRAP15|T_USER: /* SUN user trace trap */ + frame.f_sr &= ~PSL_T; + i = SIGTRAP; + break; + + case T_ASTFLT: /* system async trap, cannot happen */ + goto dopanic; + + case T_ASTFLT|T_USER: /* user async trap */ + astpending = 0; + /* + * We check for software interrupts first. This is because + * they are at a higher level than ASTs, and on a VAX would + * interrupt the AST. We assume that if we are processing + * an AST that we must be at IPL0 so we don't bother to + * check. Note that we ensure that we are at least at SIR + * IPL while processing the SIR. + */ + spl1(); + /* fall into... */ + + case T_SSIR: /* software interrupt */ + case T_SSIR|T_USER: + while (bit = ffs(ssir)) { + --bit; + ssir &= ~(1 << bit); + cnt.v_soft++; + if (sir_routines[bit]) + sir_routines[bit](sir_args[bit]); + } + + /* + * If this was not an AST trap, we are all done. + */ + if (type != (T_ASTFLT|T_USER)) { + cnt.v_trap--; + return; + } + spl0(); + if (p->p_flag & P_OWEUPC) { + p->p_flag &= ~P_OWEUPC; + ADDUPROF(p); + } + goto out; + + case T_MMUFLT: /* kernel mode page fault */ + /* + * If we were doing profiling ticks or other user mode + * stuff from interrupt code, Just Say No. + */ + if (p->p_addr->u_pcb.pcb_onfault == fubail || + p->p_addr->u_pcb.pcb_onfault == subail) + goto copyfault; + /* fall into ... */ + + case T_MMUFLT|T_USER: /* page fault */ + { + 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; + +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) + printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", + p->p_pid, code, v, frame.f_pc, frame.f_sr); +#endif + /* + * 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 data fault + * The last can occur during an exec() copyin where the + * argument space is lazy-allocated. + */ + if (type == T_MMUFLT && + (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code))) + map = kernel_map; + else + map = &vm->vm_map; + if (WRFAULT(code)) + ftype = VM_PROT_READ | VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + va = trunc_page((vm_offset_t)v); +#ifdef DEBUG + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %x\n", v); + goto dopanic; + } +#endif +#ifdef COMPAT_HPUX + if (ISHPMMADDR(va)) { + vm_offset_t bva; + + rv = pmap_mapmulti(map->pmap, va); + if (rv != KERN_SUCCESS) { + bva = HPMMBASEADDR(va); + rv = vm_fault(map, bva, ftype, FALSE); + if (rv == KERN_SUCCESS) + (void) pmap_mapmulti(map->pmap, va); + } + } else +#endif + rv = vm_fault(map, va, ftype, FALSE); +#ifdef DEBUG + if (rv && MDB_ISPID(p->p_pid)) + printf("vm_fault(%x, %x, %x, 0) -> %x\n", + map, va, ftype, rv); +#endif + /* + * If this was a stack access we keep track of the maximum + * accessed stack size. Also, if vm_fault gets a protection + * failure it is due to accessing the stack region outside + * the current limit and we need to reflect that as an access + * error. + */ + if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) { + if (rv == KERN_SUCCESS) { + unsigned nss; + + nss = clrnd(btoc(USRSTACK-(unsigned)va)); + if (nss > vm->vm_ssize) + vm->vm_ssize = nss; + } else if (rv == KERN_PROTECTION_FAILURE) + rv = KERN_INVALID_ADDRESS; + } + if (rv == KERN_SUCCESS) { + if (type == T_MMUFLT) { +#if defined(M68040) + if (mmutype == MMU_68040) + (void) writeback(&frame, 1); +#endif + return; + } + goto out; + } + if (type == T_MMUFLT) { + if (p->p_addr->u_pcb.pcb_onfault) + goto copyfault; + printf("vm_fault(%x, %x, %x, 0) -> %x\n", + map, va, ftype, rv); + printf(" type %x, code [mmu,,ssw]: %x\n", + type, code); + goto dopanic; + } + ucode = v; + i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; + break; + } + } + trapsignal(p, i, ucode); + if ((type & T_USER) == 0) + return; +out: + userret(p, &frame, sticks, v, 1); +} + +#ifdef M68040 +#ifdef DEBUG +struct writebackstats { + int calls; + int cpushes; + int move16s; + int wb1s, wb2s, wb3s; + int wbsize[4]; +} wbstats; + +char *f7sz[] = { "longword", "byte", "word", "line" }; +char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" }; +char *f7tm[] = { "d-push", "u-data", "u-code", "M-data", + "M-code", "k-data", "k-code", "RES" }; +char wberrstr[] = + "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n"; +#endif + +writeback(fp, docachepush) + struct frame *fp; + int docachepush; +{ + register struct fmt7 *f = &fp->f_fmt7; + register struct proc *p = curproc; + int err = 0; + u_int fa; + caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault; + +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { + printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa); + dumpssw(f->f_ssw); + } + wbstats.calls++; +#endif + /* + * Deal with special cases first. + */ + if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) { + /* + * Dcache push fault. + * Line-align the address and write out the push data to + * the indicated physical address. + */ +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { + printf(" pushing %s to PA %x, data %x", + f7sz[(f->f_ssw & SSW4_SZMASK) >> 5], + f->f_fa, f->f_pd0); + if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN) + printf("/%x/%x/%x", + f->f_pd1, f->f_pd2, f->f_pd3); + printf("\n"); + } + if (f->f_wb1s & SSW4_WBSV) + panic("writeback: cache push with WB1S valid"); + wbstats.cpushes++; +#endif + /* + * XXX there are security problems if we attempt to do a + * cache push after a signal handler has been called. + */ + if (docachepush) { + pmap_enter(pmap_kernel(), (vm_offset_t)vmmap, + trunc_page(f->f_fa), VM_PROT_WRITE, TRUE); + fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF]; + bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16); + DCFL(pmap_extract(pmap_kernel(), (vm_offset_t)fa)); + pmap_remove(pmap_kernel(), (vm_offset_t)vmmap, + (vm_offset_t)&vmmap[NBPG]); + } else + printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n", + p->p_pid, p->p_comm, p->p_ucred->cr_uid); + } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) { + /* + * MOVE16 fault. + * Line-align the address and write out the push data to + * the indicated virtual address. + */ +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) + printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n", + f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1, + f->f_pd2, f->f_pd3); + if (f->f_wb1s & SSW4_WBSV) + panic("writeback: MOVE16 with WB1S valid"); + wbstats.move16s++; +#endif + if (KDFAULT(f->f_wb1s)) + bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16); + else + err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0); + if (err) { + fa = f->f_fa & ~0xF; +#ifdef DEBUG + if (mmudebug & MDB_WBFAILED) + printf(wberrstr, p->p_pid, p->p_comm, + "MOVE16", fp->f_pc, f->f_fa, + f->f_fa & ~0xF, f->f_pd0); +#endif + } + } else if (f->f_wb1s & SSW4_WBSV) { + /* + * Writeback #1. + * Position the "memory-aligned" data and write it out. + */ + register u_int wb1d = f->f_wb1d; + register int off; + +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) + dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d); + wbstats.wb1s++; + wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; +#endif + off = (f->f_wb1a & 3) * 8; + switch (f->f_wb1s & SSW4_SZMASK) { + case SSW4_SZLW: + if (off) + wb1d = (wb1d >> (32 - off)) | (wb1d << off); + if (KDFAULT(f->f_wb1s)) + *(long *)f->f_wb1a = wb1d; + else + err = suword((caddr_t)f->f_wb1a, wb1d); + break; + case SSW4_SZB: + off = 24 - off; + if (off) + wb1d >>= off; + if (KDFAULT(f->f_wb1s)) + *(char *)f->f_wb1a = wb1d; + else + err = subyte((caddr_t)f->f_wb1a, wb1d); + break; + case SSW4_SZW: + off = (off + 16) % 32; + if (off) + wb1d = (wb1d >> (32 - off)) | (wb1d << off); + if (KDFAULT(f->f_wb1s)) + *(short *)f->f_wb1a = wb1d; + else + err = susword((caddr_t)f->f_wb1a, wb1d); + break; + } + if (err) { + fa = f->f_wb1a; +#ifdef DEBUG + if (mmudebug & MDB_WBFAILED) + printf(wberrstr, p->p_pid, p->p_comm, + "#1", fp->f_pc, f->f_fa, + f->f_wb1a, f->f_wb1d); +#endif + } + } + /* + * Deal with the "normal" writebacks. + * + * XXX writeback2 is known to reflect a LINE size writeback after + * a MOVE16 was already dealt with above. Ignore it. + */ + if (err == 0 && (f->f_wb2s & SSW4_WBSV) && + (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) { +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) + dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); + wbstats.wb2s++; + wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; +#endif + switch (f->f_wb2s & SSW4_SZMASK) { + case SSW4_SZLW: + if (KDFAULT(f->f_wb2s)) + *(long *)f->f_wb2a = f->f_wb2d; + else + err = suword((caddr_t)f->f_wb2a, f->f_wb2d); + break; + case SSW4_SZB: + if (KDFAULT(f->f_wb2s)) + *(char *)f->f_wb2a = f->f_wb2d; + else + err = subyte((caddr_t)f->f_wb2a, f->f_wb2d); + break; + case SSW4_SZW: + if (KDFAULT(f->f_wb2s)) + *(short *)f->f_wb2a = f->f_wb2d; + else + err = susword((caddr_t)f->f_wb2a, f->f_wb2d); + break; + } + if (err) { + fa = f->f_wb2a; +#ifdef DEBUG + if (mmudebug & MDB_WBFAILED) { + printf(wberrstr, p->p_pid, p->p_comm, + "#2", fp->f_pc, f->f_fa, + f->f_wb2a, f->f_wb2d); + dumpssw(f->f_ssw); + dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); + } +#endif + } + } + if (err == 0 && (f->f_wb3s & SSW4_WBSV)) { +#ifdef DEBUG + if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) + dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d); + wbstats.wb3s++; + wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++; +#endif + switch (f->f_wb3s & SSW4_SZMASK) { + case SSW4_SZLW: + if (KDFAULT(f->f_wb3s)) + *(long *)f->f_wb3a = f->f_wb3d; + else + err = suword((caddr_t)f->f_wb3a, f->f_wb3d); + break; + case SSW4_SZB: + if (KDFAULT(f->f_wb3s)) + *(char *)f->f_wb3a = f->f_wb3d; + else + err = subyte((caddr_t)f->f_wb3a, f->f_wb3d); + break; + case SSW4_SZW: + if (KDFAULT(f->f_wb3s)) + *(short *)f->f_wb3a = f->f_wb3d; + else + err = susword((caddr_t)f->f_wb3a, f->f_wb3d); + break; +#ifdef DEBUG + case SSW4_SZLN: + panic("writeback: wb3s indicates LINE write"); +#endif + } + if (err) { + fa = f->f_wb3a; +#ifdef DEBUG + if (mmudebug & MDB_WBFAILED) + printf(wberrstr, p->p_pid, p->p_comm, + "#3", fp->f_pc, f->f_fa, + f->f_wb3a, f->f_wb3d); +#endif + } + } + p->p_addr->u_pcb.pcb_onfault = oonfault; + /* + * Determine the cause of the failure if any translating to + * a signal. If the corresponding VA is valid and RO it is + * a protection fault (SIGBUS) otherwise consider it an + * illegal reference (SIGSEGV). + */ + if (err) { + if (vm_map_check_protection(&p->p_vmspace->vm_map, + trunc_page(fa), round_page(fa), + VM_PROT_READ) && + !vm_map_check_protection(&p->p_vmspace->vm_map, + trunc_page(fa), round_page(fa), + VM_PROT_WRITE)) + err = SIGBUS; + else + err = SIGSEGV; + } + return(err); +} + +#ifdef DEBUG +dumpssw(ssw) + register u_short ssw; +{ + printf(" SSW: %x: ", ssw); + if (ssw & SSW4_CP) + printf("CP,"); + if (ssw & SSW4_CU) + printf("CU,"); + if (ssw & SSW4_CT) + printf("CT,"); + if (ssw & SSW4_CM) + printf("CM,"); + if (ssw & SSW4_MA) + printf("MA,"); + if (ssw & SSW4_ATC) + printf("ATC,"); + if (ssw & SSW4_LK) + printf("LK,"); + if (ssw & SSW4_RW) + printf("RW,"); + printf(" SZ=%s, TT=%s, TM=%s\n", + f7sz[(ssw & SSW4_SZMASK) >> 5], + f7tt[(ssw & SSW4_TTMASK) >> 3], + f7tm[ssw & SSW4_TMMASK]); +} + +dumpwb(num, s, a, d) + int num; + u_short s; + u_int a, d; +{ + register struct proc *p = curproc; + vm_offset_t pa; + + printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n", + num, a, d, f7sz[(s & SSW4_SZMASK) >> 5], + f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]); + printf(" PA "); + pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)a); + if (pa == 0) + printf(""); + else + printf("%x, current value %x", pa, fuword((caddr_t)a)); + printf("\n"); +} +#endif +#endif + +/* + * Process a system call. + */ +syscall(code, frame) + register_t code; + struct frame frame; +{ + register caddr_t params; + register struct sysent *callp; + register struct proc *p; + int error, opc, nsys; + size_t argsize; + register_t args[8], rval[2]; + u_quad_t sticks; + + cnt.v_syscall++; + if (!USERMODE(frame.f_sr)) + panic("syscall"); + p = curproc; + sticks = p->p_sticks; + p->p_md.md_regs = frame.f_regs; + opc = frame.f_pc; + + nsys = p->p_emul->e_nsysent; + callp = p->p_emul->e_sysent; + +#ifdef COMPAT_SUNOS + if (p->p_emul == &emul_sunos) { + /* + * SunOS passes the syscall-number on the stack, whereas + * BSD passes it in D0. So, we have to get the real "code" + * from the stack, and clean up the stack, as SunOS glue + * code assumes the kernel pops the syscall argument the + * glue pushed on the stack. Sigh... + */ + code = fuword((caddr_t)frame.f_regs[SP]); + + /* + * XXX + * Don't do this for sunos_sigreturn, as there's no stored pc + * on the stack to skip, the argument follows the syscall + * number without a gap. + */ + if (code != SUNOS_SYS_sunos_sigreturn) { + frame.f_regs[SP] += sizeof (int); + /* + * remember that we adjusted the SP, + * might have to undo this if the system call + * returns ERESTART. + */ + p->p_md.md_flags |= MDP_STACKADJ; + } else + p->p_md.md_flags &= ~MDP_STACKADJ; + } +#endif + + params = (caddr_t)frame.f_regs[SP] + sizeof(int); + + switch (code) { + case SYS_syscall: + /* + * Code is first argument, followed by actual args. + */ + code = fuword(params); + params += sizeof(int); + /* + * XXX sigreturn requires special stack manipulation + * that is only done if entered via the sigreturn + * trap. Cannot allow it here so make sure we fail. + */ + if (code == SYS_sigreturn) + code = nsys; + break; + case SYS___syscall: + /* + * Like syscall, but code is a quad, so as to maintain + * quad alignment for the rest of the arguments. + */ + if (callp != sysent) + break; + code = fuword(params + _QUAD_LOWWORD * sizeof(int)); + params += sizeof(quad_t); + break; + default: + break; + } + if (code < 0 || code >= nsys) + callp += p->p_emul->e_nosys; /* illegal */ + else + callp += code; + argsize = callp->sy_argsize; + if (argsize) + error = copyin(params, (caddr_t)args, argsize); + else + error = 0; +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p->p_tracep, code, argsize, args); +#endif + if (error) + goto bad; + rval[0] = 0; + rval[1] = frame.f_regs[D1]; + error = (*callp->sy_call)(p, args, rval); + switch (error) { + case 0: + frame.f_regs[D0] = rval[0]; + frame.f_regs[D1] = rval[1]; + frame.f_sr &= ~PSL_C; /* carry bit */ + break; + case ERESTART: + /* + * We always enter through a `trap' instruction, which is 2 + * bytes, so adjust the pc by that amount. + */ + frame.f_pc = opc - 2; + break; + case EJUSTRETURN: + /* nothing to do */ + break; + default: + bad: + if (p->p_emul->e_errno) + error = p->p_emul->e_errno[error]; + frame.f_regs[D0] = error; + frame.f_sr |= PSL_C; /* carry bit */ + break; + } + +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, error, rval); +#endif +#ifdef COMPAT_SUNOS + /* need new p-value for this */ + if (error == ERESTART && (p->p_md.md_flags & MDP_STACKADJ)) + frame.f_regs[SP] -= sizeof (int); +#endif + userret(p, &frame, sticks, (u_int)0, 0); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, code, error, rval[0]); +#endif +} + +void +child_return(p, frame) + struct proc *p; + struct frame frame; +{ + + frame.f_regs[D0] = 0; + frame.f_sr &= ~PSL_C; + frame.f_format = FMT0; + + userret(p, &frame, p->p_sticks, (u_int)0, 0); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) + ktrsysret(p->p_tracep, SYS_fork, 0, 0); +#endif +} + +/* + * Allocation routines for software interrupts. + */ +u_long +allocate_sir(proc, arg) + void (*proc)(); + void *arg; +{ + int bit; + + if( next_sir >= NSIR ) + panic("allocate_sir: none left"); + bit = next_sir++; + sir_routines[bit] = proc; + sir_args[bit] = arg; + return (1 << bit); +} + +void +init_sir() +{ + extern void netintr(); + + sir_routines[0] = netintr; + sir_routines[1] = softclock; + next_sir = 2; +} diff --git a/sys/arch/mvme68k/mvme68k/vectors.s b/sys/arch/mvme68k/mvme68k/vectors.s new file mode 100644 index 0000000000000..4dc7abf7ffadf --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/vectors.s @@ -0,0 +1,160 @@ +| $NetBSD: vectors.s,v 1.1.1.1 1995/07/25 23:12:01 chuck Exp $ + +| Copyright (c) 1988 University of Utah +| 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. +| +| @(#)vectors.s 8.2 (Berkeley) 1/21/94 +| + + .text + .globl _buserr,_addrerr + .globl _illinst,_zerodiv,_chkinst,_trapvinst,_privinst,_trace + .globl _badtrap + .globl _spurintr,_lev1intr,_lev2intr,_lev3intr + .globl _lev4intr,_lev5intr,_lev6intr,_lev7intr + .globl _pcctrap + .globl _trap0,_trap1,_trap2,_trap15 + .globl _fpfline, _fpunsupp + .globl _trap12 + +Lvectab: + .long 0x4ef88400 /* 0: jmp 0x8400:w (unused reset SSP) */ + .long 0 /* 1: NOT USED (reset PC) */ + .long _buserr /* 2: bus error */ + .long _addrerr /* 3: address error */ + .long _illinst /* 4: illegal instruction */ + .long _zerodiv /* 5: zero divide */ + .long _chkinst /* 6: CHK instruction */ + .long _trapvinst /* 7: TRAPV instruction */ + .long _privinst /* 8: privilege violation */ + .long _trace /* 9: trace */ + .long _illinst /* 10: line 1010 emulator */ + .long _fpfline /* 11: line 1111 emulator */ + .long _badtrap /* 12: unassigned, reserved */ + .long _coperr /* 13: coprocessor protocol violation */ + .long _fmterr /* 14: format error */ + .long _badtrap /* 15: uninitialized interrupt vector */ + .long _badtrap /* 16: unassigned, reserved */ + .long _badtrap /* 17: unassigned, reserved */ + .long _badtrap /* 18: unassigned, reserved */ + .long _badtrap /* 19: unassigned, reserved */ + .long _badtrap /* 20: unassigned, reserved */ + .long _badtrap /* 21: unassigned, reserved */ + .long _badtrap /* 22: unassigned, reserved */ + .long _badtrap /* 23: unassigned, reserved */ + .long _spurintr /* 24: spurious interrupt */ + .long _lev1intr /* 25: level 1 interrupt autovector */ + .long _lev2intr /* 26: level 2 interrupt autovector */ + .long _lev3intr /* 27: level 3 interrupt autovector */ + .long _lev4intr /* 28: level 4 interrupt autovector */ + .long _lev5intr /* 29: level 5 interrupt autovector */ + .long _lev6intr /* 30: level 6 interrupt autovector */ + .long _lev7intr /* 31: level 7 interrupt autovector */ + .long _trap0 /* 32: syscalls */ + .long _trap1 /* 33: sigreturn syscall or breakpoint */ + .long _trap2 /* 34: breakpoint or sigreturn syscall */ + .long _illinst /* 35: TRAP instruction vector */ + .long _illinst /* 36: TRAP instruction vector */ + .long _illinst /* 37: TRAP instruction vector */ + .long _illinst /* 38: TRAP instruction vector */ + .long _illinst /* 39: TRAP instruction vector */ + .long _illinst /* 40: TRAP instruction vector */ + .long _illinst /* 41: TRAP instruction vector */ + .long _illinst /* 42: TRAP instruction vector */ + .long _illinst /* 43: TRAP instruction vector */ + .long _trap12 /* 44: TRAP instruction vector */ + .long _illinst /* 45: TRAP instruction vector */ + .long _illinst /* 46: TRAP instruction vector */ + .long _trap15 /* 47: TRAP instruction vector */ +#ifdef FPSP + .globl bsun, inex, dz, unfl, operr, ovfl, snan + .long bsun /* 48: FPCP branch/set on unordered cond */ + .long inex /* 49: FPCP inexact result */ + .long dz /* 50: FPCP divide by zero */ + .long unfl /* 51: FPCP underflow */ + .long operr /* 52: FPCP operand error */ + .long ovfl /* 53: FPCP overflow */ + .long snan /* 54: FPCP signalling NAN */ +#else + .globl _fpfault + .long _fpfault /* 48: FPCP branch/set on unordered cond */ + .long _fpfault /* 49: FPCP inexact result */ + .long _fpfault /* 50: FPCP divide by zero */ + .long _fpfault /* 51: FPCP underflow */ + .long _fpfault /* 52: FPCP operand error */ + .long _fpfault /* 53: FPCP overflow */ + .long _fpfault /* 54: FPCP signalling NAN */ +#endif + + .long _fpunsupp /* 55: FPCP unimplemented data type */ + .long _badtrap /* 56: unassigned, reserved */ + .long _badtrap /* 57: unassigned, reserved */ + .long _badtrap /* 58: unassigned, reserved */ + .long _badtrap /* 59: unassigned, reserved */ + .long _badtrap /* 60: unassigned, reserved */ + .long _badtrap /* 61: unassigned, reserved */ + .long _badtrap /* 62: unassigned, reserved */ + .long _badtrap /* 63: unassigned, reserved */ + + /* PCC traps (0x40 to start, configured from pccreg.h) */ + .long _pcctrap /* 64: AC fail */ + .long _pcctrap /* 65: BERR */ + .long _pcctrap /* 66: abort */ + .long _pcctrap /* 67: serial port */ + .long _pcctrap /* 68: lance */ + .long _pcctrap /* 69: SCSI port */ + .long _pcctrap /* 70: SCSI dma */ + .long _pcctrap /* 71: printer port */ + .long _pcctrap /* 72: timer #1 */ + .long _pcctrap /* 73: timer #2 */ + .long _pcctrap /* 74: software intr #1 */ + .long _pcctrap /* 75: software intr #2 */ + + .long _badtrap /* 76: unassigned, reserved */ + .long _badtrap /* 77: unassigned, reserved */ + .long _badtrap /* 78: unassigned, reserved */ + .long _badtrap /* 79: unassigned, reserved */ +#define BADTRAP16 .long _badtrap,_badtrap,_badtrap,_badtrap,\ + _badtrap,_badtrap,_badtrap,_badtrap,\ + _badtrap,_badtrap,_badtrap,_badtrap,\ + _badtrap,_badtrap,_badtrap,_badtrap + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ + BADTRAP16 /* 64-255: user interrupt vectors */ diff --git a/sys/arch/mvme68k/mvme68k/vm_machdep.c b/sys/arch/mvme68k/mvme68k/vm_machdep.c new file mode 100644 index 0000000000000..e8dfc8a9fb198 --- /dev/null +++ b/sys/arch/mvme68k/mvme68k/vm_machdep.c @@ -0,0 +1,412 @@ +/* $NetBSD: vm_machdep.c,v 1.1.1.1 1995/07/25 23:12:02 chuck 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. + * + * from: Utah $Hdr: vm_machdep.c 1.21 91/04/06$ + * + * @(#)vm_machdep.c 8.6 (Berkeley) 1/12/94 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* + * 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. + */ +int +cpu_fork(p1, p2) + register struct proc *p1, *p2; +{ + register struct pcb *pcb = &p2->p_addr->u_pcb; + register struct trapframe *tf; + register struct switchframe *sf; + extern struct pcb *curpcb; + extern void proc_trampoline(), child_return(); + + p2->p_md.md_flags = p1->p_md.md_flags & ~MDP_HPUXTRACE; + + /* Sync curpcb (which is presumably p1's PCB) and copy it to p2. */ + savectx(curpcb); + *pcb = p1->p_addr->u_pcb; + + PMAP_ACTIVATE(&p2->p_vmspace->vm_pmap, pcb, 0); + + /* + * Copy the trap frame, and arrange for the child to return directly + * through return_to_user(). + */ + tf = (struct trapframe *)((u_int)p2->p_addr + USPACE) - 1; + p2->p_md.md_regs = (int *)tf; + *tf = *(struct trapframe *)p1->p_md.md_regs; + sf = (struct switchframe *)tf - 1; + sf->sf_pc = (u_int)proc_trampoline; + pcb->pcb_regs[6] = (int)child_return; /* A2 */ + pcb->pcb_regs[7] = (int)p2; /* A3 */ + pcb->pcb_regs[11] = (int)sf; /* SSP */ + + return (0); +} + +void +cpu_set_kpc(p, pc) + struct proc *p; + u_long pc; +{ + + p->p_addr->u_pcb.pcb_regs[6] = pc; /* A2 */ +} + +/* + * cpu_exit is called as the last action during exit. + * We release the address space and machine-dependent resources, + * including the memory for the user structure and kernel stack. + * Once finished, we call switch_exit, which switches to a temporary + * pcb and stack and never returns. We block memory allocation + * until switch_exit has made things safe again. + */ +void +cpu_exit(p) + struct proc *p; +{ + + vmspace_free(p->p_vmspace); + + (void) splhigh(); + cnt.v_swtch++; + switch_exit(p); + /* NOTREACHED */ +} + +void +cpu_cleanup(p) + struct proc *p; +{ + +} + +/* + * Dump the machine specific header information at the start of a core dump. + */ +int +cpu_coredump(p, vp, cred) + struct proc *p; + struct vnode *vp; + struct ucred *cred; +{ + +#ifdef COMPAT_HPUX + extern struct emul emul_hpux; + + /* + * If we loaded from an HP-UX format binary file we dump enough + * of an HP-UX style user struct so that the HP-UX debuggers can + * grok it. + */ + if (p->p_emul == &emul_hpux) + return (hpux_dumpu(vp, cred)); +#endif + return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, USPACE, + (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, + p)); +} + +/* + * Move pages from one kernel virtual address to another. + * Both addresses are assumed to reside in the Sysmap, + * and size must be a multiple of CLSIZE. + */ +pagemove(from, to, size) + register caddr_t from, to; + int size; +{ + register vm_offset_t pa; + +#ifdef DEBUG + if (size & CLOFSET) + panic("pagemove"); +#endif + while (size > 0) { + pa = pmap_extract(pmap_kernel(), (vm_offset_t)from); +#ifdef DEBUG + if (pa == 0) + panic("pagemove 2"); + if (pmap_extract(pmap_kernel(), (vm_offset_t)to) != 0) + panic("pagemove 3"); +#endif + pmap_remove(pmap_kernel(), + (vm_offset_t)from, (vm_offset_t)from + PAGE_SIZE); + pmap_enter(pmap_kernel(), + (vm_offset_t)to, pa, VM_PROT_READ|VM_PROT_WRITE, 1); + from += PAGE_SIZE; + to += PAGE_SIZE; + size -= PAGE_SIZE; + } +} + +/* + * Map `size' bytes of physical memory starting at `paddr' into + * kernel VA space at `vaddr'. Read/write and cache-inhibit status + * are specified by `prot'. + */ +physaccess(vaddr, paddr, size, prot) + caddr_t vaddr, paddr; + register int size, prot; +{ + register pt_entry_t *pte; + register u_int page; + + pte = kvtopte(vaddr); + page = (u_int)paddr & PG_FRAME; + for (size = btoc(size); size; size--) { + *pte++ = PG_V | prot | page; + page += NBPG; + } + TBIAS(); +} + +physunaccess(vaddr, size) + caddr_t vaddr; + register int size; +{ + register pt_entry_t *pte; + + pte = kvtopte(vaddr); + for (size = btoc(size); size; size--) + *pte++ = PG_NV; + TBIAS(); +} + +/* + * Set a red zone in the kernel stack after the u. area. + * We don't support a redzone right now. It really isn't clear + * that it is a good idea since, if the kernel stack were to roll + * into a write protected page, the processor would lock up (since + * it cannot create an exception frame) and we would get no useful + * post-mortem info. Currently, under the DEBUG option, we just + * check at every clock interrupt to see if the current k-stack has + * gone too far (i.e. into the "redzone" page) and if so, panic. + * Look at _lev6intr in locore.s for more details. + */ +/*ARGSUSED*/ +setredzone(pte, vaddr) + pt_entry_t *pte; + caddr_t vaddr; +{ +} + +/* + * 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. + * + * XXX we allocate KVA space by using kmem_alloc_wait which we know + * allocates space without backing physical memory. This implementation + * is a total crock, the multiple mappings of these physical pages should + * be reflected in the higher-level VM structures to avoid problems. + */ +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_data; + 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_data = (caddr_t)(kva + off); + while (npf--) { + pa = pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), + (vm_offset_t)addr); + if (pa == 0) + panic("vmapbuf: null page frame"); + pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa), + VM_PROT_READ|VM_PROT_WRITE, TRUE); + addr += PAGE_SIZE; + kva += PAGE_SIZE; + } +} + +/* + * Free the io map PTEs associated with this IO operation. + */ +vunmapbuf(bp) + register struct buf *bp; +{ + register caddr_t addr; + register int npf; + vm_offset_t kva; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + addr = bp->b_data; + 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_data = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} + +#ifdef MAPPEDCOPY +u_int mappedcopysize = 4096; + +mappedcopyin(fromp, top, count) + register char *fromp, *top; + register int count; +{ + register vm_offset_t kva, upa; + register int off, len; + int alignable; + pmap_t upmap; + extern caddr_t CADDR1; + + kva = (vm_offset_t) CADDR1; + off = (vm_offset_t)fromp & PAGE_MASK; + alignable = (off == ((vm_offset_t)top & PAGE_MASK)); + upmap = vm_map_pmap(&curproc->p_vmspace->vm_map); + while (count > 0) { + /* + * First access of a page, use fubyte to make sure + * page is faulted in and read access allowed. + */ + if (fubyte(fromp) == -1) + return (EFAULT); + /* + * Map in the page and bcopy data in from it + */ + upa = pmap_extract(upmap, trunc_page(fromp)); + if (upa == 0) + panic("mappedcopyin"); + len = min(count, PAGE_SIZE-off); + pmap_enter(pmap_kernel(), kva, upa, VM_PROT_READ, TRUE); + if (len == PAGE_SIZE && alignable && off == 0) + copypage(kva, top); + else + bcopy((caddr_t)(kva+off), top, len); + fromp += len; + top += len; + count -= len; + off = 0; + } + pmap_remove(pmap_kernel(), kva, kva+PAGE_SIZE); + return (0); +} + +mappedcopyout(fromp, top, count) + register char *fromp, *top; + register int count; +{ + register vm_offset_t kva, upa; + register int off, len; + int alignable; + pmap_t upmap; + extern caddr_t CADDR2; + + kva = (vm_offset_t) CADDR2; + off = (vm_offset_t)top & PAGE_MASK; + alignable = (off == ((vm_offset_t)fromp & PAGE_MASK)); + upmap = vm_map_pmap(&curproc->p_vmspace->vm_map); + while (count > 0) { + /* + * First access of a page, use subyte to make sure + * page is faulted in and write access allowed. + */ + if (subyte(top, *fromp) == -1) + return (EFAULT); + /* + * Map in the page and bcopy data out to it + */ + upa = pmap_extract(upmap, trunc_page(top)); + if (upa == 0) + panic("mappedcopyout"); + len = min(count, PAGE_SIZE-off); + pmap_enter(pmap_kernel(), kva, upa, + VM_PROT_READ|VM_PROT_WRITE, TRUE); + if (len == PAGE_SIZE && alignable && off == 0) + copypage(fromp, kva); + else + bcopy(fromp, (caddr_t)(kva+off), len); + fromp += len; + top += len; + count -= len; + off = 0; + } + pmap_remove(pmap_kernel(), kva, kva+PAGE_SIZE); + return (0); +} +#endif diff --git a/sys/arch/mvme68k/stand/Makefile b/sys/arch/mvme68k/stand/Makefile new file mode 100644 index 0000000000000..a52741c8337de --- /dev/null +++ b/sys/arch/mvme68k/stand/Makefile @@ -0,0 +1,5 @@ +# $NetBSD: Makefile,v 1.1.1.1 1995/07/25 23:12:20 chuck Exp $ + +SUBDIR= libsa netboot + +.include diff --git a/sys/arch/mvme68k/stand/Makefile.inc b/sys/arch/mvme68k/stand/Makefile.inc new file mode 100644 index 0000000000000..8f75687d6d265 --- /dev/null +++ b/sys/arch/mvme68k/stand/Makefile.inc @@ -0,0 +1,37 @@ +# $NetBSD: Makefile.inc,v 1.1.1.1 1995/07/25 23:12:21 chuck Exp $ + +.if defined(SA_PROG) + +# Must have S=/usr/src/sys (or equivalent) +# But note: this is w.r.t. a subdirectory +S= ../../../.. + +RELOC?= 240000 +DEFS?= -DSTANDALONE +INCL?= -I. -I../libsa -I${S}/lib/libsa -I${S} +COPTS?= -msoft-float ${DEFS} ${INCL} + +LIBSA?= ../libsa +SRTOBJ?= ${LIBSA}/SRT0.o ${LIBSA}/SRT1.o +LIBS?= ${LIBSA}/libsa.a +MDEC_DIR?=/usr/mdec + +SRCS?= ${SA_PROG}.c +OBJS?= ${SRTOBJ} ${SRCS:S/.c/.o/g} + +${SA_PROG}.bin : ${SA_PROG} + cp ${SA_PROG} a.out ; strip a.out + dd ibs=32 skip=1 if=a.out of=$@ + -rm -f a.out + +${SA_PROG} : ${OBJS} ${LIBS} + ${LD} -N -T ${RELOC} -e start -o $@ ${OBJS} ${LIBS} + @size $@ + +.if !target(clean) +clean: + -rm -f a.out [Ee]rrs mklog core *.core + -rm -f ${SA_PROG} ${SA_PROG}.bin ${OBJS} ${CLEANFILES} +.endif + +.endif diff --git a/sys/arch/mvme68k/stand/libsa/Makefile b/sys/arch/mvme68k/stand/libsa/Makefile new file mode 100644 index 0000000000000..317525bd0e706 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/Makefile @@ -0,0 +1,41 @@ +# $NetBSD: Makefile,v 1.1.1.1 1995/07/25 23:12:21 chuck Exp $ + +LIB=sa + +NOPIC=nopic +NOPROFILE=noprofile + +# Logically src/sys +S=${.CURDIR}/../../../.. +DIR_SA=$S/lib/libsa +DIR_KERN=$S/lib/libkern + +SRC_net= nfs.c rpc.c net.c ether.c arp.c in_cksum.c \ + bootparam.c rarp.c + +SRC_sa = alloc.c bcopy.c close.c getfile.c open.c \ + printf.c read.c strerror.c ufs.c + +SRC_kern= ashrdi3.c bcmp.c bzero.c strcmp.c strlen.c + +SRC_here= clock.c devopen.c \ + exec.c gets.c netif.c panic.c \ + machdep.c + +SRCS= ${SRC_net} ${SRC_sa} ${SRC_kern} ${SRC_here} + +# DBG= -DDEBUG -DNETIF_DEBUG -DNFS_DEBUG -DRPC_DEBUG \ +# -DNET_DEBUG -DRARP_DEBUG -DETHER_DEBUG + +DEFS= -DCOMPAT_UFS +INCL= -I. -I${S}/lib/libsa -I${S} +COPTS= -msoft-float -fno-defer-pop -fno-omit-frame-pointer +CFLAGS= -O ${COPTS} ${DEFS} ${DBG} ${INCL} + +.PATH: ${DIR_SA} ${DIR_KERN} ../../sun3 + +all: libsa.a SRT0.o SRT1.o + +install: + +.include diff --git a/sys/arch/mvme68k/stand/libsa/SRT0.S b/sys/arch/mvme68k/stand/libsa/SRT0.S new file mode 100644 index 0000000000000..b2114fc3447a1 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/SRT0.S @@ -0,0 +1,86 @@ +| $NetBSD: SRT0.S,v 1.1.1.1 1995/07/25 23:12:21 chuck Exp $ + +| Copyright (c) 1995 Gordon W. Ross +| 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. +| 4. All advertising materials mentioning features or use of this software +| must display the following acknowledgement: +| This product includes software developed by Gordon Ross +| +| 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. + +| SRT0.S - Stand-alone Run-Time startup code, part 0 + .file "SRT0.S" + .text + .globl __estack +__estack: + .globl start +start: +| Check to see if the code is located correctly. +| This SHOULD do a PC-relative load into a0, but... +| lea start, a0 | current location (0x4000) +| XXX - GAS version 1.93 gets the above lea wrong! + .word 0x41fa + .word 0xfffe +| Now force a long (not PC-relative) load to a1 and compare. + lea start:l, a1 | desired location (LINKADDR) + cmpl a0, a1 + beqs restart + +| Relocate the code and data to where they belong. + movl #_edata,d0 | Desired end of program + subl a1,d0 | Calculate length, round up. + lsrl #2,d0 +Lcp: + movl a0@+, a1@+ + dbra d0, Lcp + +| Force a long jump to the relocated code (not pc-relative) + lea restart:l, a0 + jmp a0@ + +restart: +| now in the relocated code + + movl a6@(8), __cmd_buf | get cmd_line from sboot + +| Set up stack (just before relocated text) + lea __estack:l, a0 + movl a0, sp + subl a6, a6 + +| Call the run-time startup C code, which will: +| initialize, call main, call exit + jsr __start:l + +| If _start returns, fall into abort. + .globl _abort +_abort: + jsr 0x4000 + +| If abort returns, fall into reset. + .globl _reset +_reset: + reset + jmp _reset + +| The end. diff --git a/sys/arch/mvme68k/stand/libsa/SRT1.c b/sys/arch/mvme68k/stand/libsa/SRT1.c new file mode 100644 index 0000000000000..e9033244d77ae --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/SRT1.c @@ -0,0 +1,68 @@ +/* $NetBSD: SRT1.c,v 1.1.1.1 1995/07/25 23:12:21 chuck Exp $ */ + +/* + * Copyright (c) 1995 Gordon W. Ross + * 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. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon Ross + * + * 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. + */ + +/* SRT1.c - Stand-alone Run-time startup code, part 1 */ + +#include +#include + +extern int edata[], end[]; +extern volatile void abort(); +char *_cmd_buf = (char *)0; + +volatile void +exit() +{ + abort(); +} + +/* + * This is called by SRT0.S + * to do final prep for main + */ +_start() +{ + register int *p; + + /* Clear BSS */ + p = edata; + do *p++ = 0; + while (p < end); + + main(_cmd_buf); + exit(); +} + +/* + * Boot programs in C++ ? Not likely! + */ +__main() {} diff --git a/sys/arch/mvme68k/stand/libsa/clock.c b/sys/arch/mvme68k/stand/libsa/clock.c new file mode 100644 index 0000000000000..c937a90085d18 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/clock.c @@ -0,0 +1,128 @@ +/* $NetBSD: clock.c,v 1.1.1.1 1995/07/25 23:12:22 chuck Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1993 Adam Glass + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 8.1 (Berkeley) 6/11/93 + */ + +/* + * Clock driver. + */ + +#include +#include "clockreg.h" +static struct clockreg *clockreg = (struct clockreg *) CLOCK_ADDR; + +int hz = 1; /* XXX ? */ + +/* + * BCD to decimal and decimal to BCD. + */ +#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) +#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10)) + +#define SECDAY (24 * 60 * 60) +#define SECYR (SECDAY * 365) +#define LEAPYEAR(y) (((y) & 3) == 0) + +/* + * This code is defunct after 2068. + * Will Unix still be here then?? + */ +const short dayyr[12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + +static u_long chiptotime(sec, min, hour, day, mon, year) + register int sec, min, hour, day, mon, year; +{ + register int days, yr; + + sec = FROMBCD(sec); + min = FROMBCD(min); + hour = FROMBCD(hour); + day = FROMBCD(day); + mon = FROMBCD(mon); + year = FROMBCD(year) + YEAR0; + if (year < 70) year = 70; + + /* simple sanity checks */ + if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31) + return (0); + days = 0; + for (yr = 70; yr < year; yr++) + days += LEAPYEAR(yr) ? 366 : 365; + days += dayyr[mon - 1] + day - 1; + if (LEAPYEAR(yr) && mon > 2) + days++; + /* now have days since Jan 1, 1970; the rest is easy... */ + return (days * SECDAY + hour * 3600 + min * 60 + sec); +} + +/* + * Set up the system's time, given a `reasonable' time value. + */ +time_t getsecs() +{ + register struct clockreg *cl = clockreg; + int sec, min, hour, day, mon, year; + + cl->cl_csr |= CLK_READ; /* enable read (stop time) */ + sec = cl->cl_sec; + min = cl->cl_min; + hour = cl->cl_hour; + day = cl->cl_mday; + mon = cl->cl_month; + year = cl->cl_year; + cl->cl_csr &= ~CLK_READ; /* time wears on */ + return(chiptotime(sec, min, hour, day, mon, year)); +} + +/* + * delay + */ + +int getticks() +{ + return((int)getsecs()); +} diff --git a/sys/arch/mvme68k/stand/libsa/clock.h b/sys/arch/mvme68k/stand/libsa/clock.h new file mode 100644 index 0000000000000..d61bc9b03b821 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/clock.h @@ -0,0 +1,6 @@ + +extern int hz; + +time_t getsecs(); +int getticks(); + diff --git a/sys/arch/mvme68k/stand/libsa/clockreg.h b/sys/arch/mvme68k/stand/libsa/clockreg.h new file mode 100644 index 0000000000000..5ada963e3b9d2 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/clockreg.h @@ -0,0 +1,71 @@ +/* $NetBSD: clockreg.h,v 1.1.1.1 1995/07/25 23:12:24 chuck Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + * + * @(#)clockreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Mostek MK48T02 clock. + */ +struct clockreg { + volatile u_char cl_csr; /* control register */ + volatile u_char cl_sec; /* seconds (0..59; BCD) */ + volatile u_char cl_min; /* minutes (0..59; BCD) */ + volatile u_char cl_hour; /* hour (0..23; BCD) */ + volatile u_char cl_wday; /* weekday (1..7) */ + volatile u_char cl_mday; /* day in month (1..31; BCD) */ + volatile u_char cl_month; /* month (1..12; BCD) */ + volatile u_char cl_year; /* year (0..99; BCD) */ +}; + +/* bits in cl_csr */ +#define CLK_WRITE 0x80 /* want to write */ +#define CLK_READ 0x40 /* want to read (freeze clock) */ + +/* + * Sun chose the year `68' as their base count, so that + * cl_year==0 means 1968. + */ +#define YEAR0 68 + +#define CLOCK_ADDR (0xfffe07f8) /* VME147 PA of clock */ diff --git a/sys/arch/mvme68k/stand/libsa/config.h b/sys/arch/mvme68k/stand/libsa/config.h new file mode 100644 index 0000000000000..9161fd14efd97 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/config.h @@ -0,0 +1,10 @@ +/* $NetBSD: config.h,v 1.1.1.1 1995/07/25 23:12:24 chuck Exp $ */ + +/* configuration information for base-line code */ + +#define COMMON_ETHERADDR + +#define CONS_ZS_ADDR (0xfffe3002) +#define ETHER_ADDR (0xfffe0778) +#define ERAM_ADDR (0xfffe0774) +#define LANCE_REG_ADDR (0xfffe1800) diff --git a/sys/arch/mvme68k/stand/libsa/devopen.c b/sys/arch/mvme68k/stand/libsa/devopen.c new file mode 100644 index 0000000000000..f64b196c5395a --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/devopen.c @@ -0,0 +1,24 @@ + +#include +#include + +/* + * Open the device + */ +int +devopen(f, fname, file) + struct open_file *f; + const char *fname; + char **file; +{ + struct devsw *dp; + char *cp, *path, *devname; + int error; + + *file = (char*)fname; + dp = &devsw[0]; + f->f_dev = dp; + error = (*dp->dv_open)(f, NULL); + + return (error); +} diff --git a/sys/arch/mvme68k/stand/libsa/exec.c b/sys/arch/mvme68k/stand/libsa/exec.c new file mode 100644 index 0000000000000..92c5aa971a4a1 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/exec.c @@ -0,0 +1,176 @@ +/* $NetBSD: exec.c,v 1.1.1.1 1995/07/25 23:12:24 chuck 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 + */ + +#include +#include + +#include "stand.h" + +extern int debug; + +/*ARGSUSED*/ +exec_mvme(file, loadaddr, boothowto) + char *file; + char *loadaddr; + int boothowto; +{ + register int io; + struct exec x; + int cc, magic; + void (*entry)(); + register char *cp; + register int *ip; + +#ifdef DEBUG + printf("exec: file=%s loadaddr=0x%x\n", file, loadaddr); +#endif + + io = open(file, 0); + if (io < 0) + return(-1); + + /* + * Read in the exec header, and validate it. + */ + if (read(io, (char *)&x, sizeof(x)) != sizeof(x)) + goto shread; + if (N_BADMAG(x)) { + errno = EFTYPE; + goto closeout; + } + + cp = loadaddr; + magic = N_GETMAGIC(x); + if (magic == ZMAGIC) + cp += sizeof(x); + entry = (void (*)())x.a_entry; + + /* + * Leave a copy of the exec header before the text. + * The kernel may use this to verify that the + * symbols were loaded by this boot program. + */ + bcopy(&x, cp - sizeof(x), sizeof(x)); + + /* + * Read in the text segment. + */ + printf("%d", x.a_text); + if (read(io, cp, x.a_text) != x.a_text) + goto shread; + cp += x.a_text; + + /* + * NMAGIC may have a gap between text and data. + */ + if (magic == NMAGIC) { + register int mask = N_PAGSIZ(x) - 1; + while ((int)cp & mask) + *cp++ = 0; + } + + /* + * Read in the data segment. + */ + printf("+%d", x.a_data); + if (read(io, cp, x.a_data) != x.a_data) + goto shread; + cp += x.a_data; + + /* + * Zero out the BSS section. + * (Kernel doesn't care, but do it anyway.) + */ + printf("+%d", x.a_bss); + cc = x.a_bss; + while ((int)cp & 3) { + *cp++ = 0; + --cc; + } + ip = (int*)cp; + cp += cc; + while ((char*)ip < cp) + *ip++ = 0; + + /* + * Read in the symbol table and strings. + * (Always set the symtab size word.) + */ + *ip++ = x.a_syms; + cp = (char*) ip; + + if (x.a_syms > 0) { + + /* Symbol table and string table length word. */ + cc = x.a_syms; + printf("+[%d", cc); + cc += sizeof(int); /* strtab length too */ + if (read(io, cp, cc) != cc) + goto shread; + cp += x.a_syms; + ip = (int*)cp; /* points to strtab length */ + cp += sizeof(int); + + /* String table. Length word includes itself. */ + cc = *ip; + printf("+%d]", cc); + cc -= sizeof(int); + if (cc <= 0) + goto shread; + if (read(io, cp, cc) != cc) + goto shread; + cp += cc; + } + printf("=0x%x\n", cp - loadaddr); + close(io); + + if (debug) { + printf("Debug mode - enter c to continue\n"); + asm(" trap #0"); + } + + printf("Start @ 0x%x ...\n", (int)entry); + (*entry)(boothowto); + panic("exec returned"); + +shread: + printf("exec: short read\n"); + errno = EIO; +closeout: + close(io); + return(-1); +} diff --git a/sys/arch/mvme68k/stand/libsa/gets.c b/sys/arch/mvme68k/stand/libsa/gets.c new file mode 100644 index 0000000000000..cddf88b79254f --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/gets.c @@ -0,0 +1,117 @@ +/* $NetBSD: gets.c,v 1.1.1.1 1995/07/25 23:12:21 chuck 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 + */ + +#include "stand.h" + +/* + * This implementation assumes that getchar() does echo, because + * on some machines, it is hard to keep echo from being done. + * Those that need it can do echo in their getchar() function. + * + * Yes, the code below will echo CR, DEL, and other control chars, + * but sending CR or DEL here is harmless. All the other editing + * characters will be followed by a newline, so it doesn't matter. + * (Most terminals will not show them anyway.) + */ +#define GETS_MUST_ECHO /* Preserved in case someone wants it... */ + +void +gets(buf) + char *buf; +{ + register int c; + register char *lp; + +top: + lp = buf; + + for (;;) { + c = getchar() & 0177; + +#ifdef GETS_MUST_ECHO /* Preserved in case someone wants it... */ + putchar(c); +#endif + + switch (c) { + + default: + *lp++ = c; + continue; + + case '\177': + putchar('\b'); + /* fall through */ + case '\b': + putchar(' '); + putchar('\b'); + /* fall through */ + case '#': + if (lp > buf) + lp--; + continue; + +#ifdef GETS_REPRINT + /* + * This is not very useful in a boot program. + * (It costs you 52 bytes on m68k, gcc -O3). + */ + case 'r'&037: { + register char *p; + putchar('\n'); + for (p = buf; p < lp; ++p) + putchar(*p); + continue; + } +#endif + + case '@': + case 'u'&037: + case 'w'&037: + putchar('\n'); + goto top; + + case '\r': + putchar('\n'); + /* fall through */ + case '\n': + *lp = '\0'; + return; + + } /* switch */ + } + /*NOTREACHED*/ +} diff --git a/sys/arch/mvme68k/stand/libsa/if_lereg.h b/sys/arch/mvme68k/stand/libsa/if_lereg.h new file mode 100644 index 0000000000000..3aee758cabc8c --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/if_lereg.h @@ -0,0 +1,176 @@ +/* $NetBSD: if_lereg.h,v 1.1.1.1 1995/07/25 23:12:23 chuck Exp $ */ + +/*- + * Copyright (c) 1982, 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. + * + * @(#)if_lereg.h 8.2 (Berkeley) 10/30/93 + */ + +#define LEMTU 1518 +#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */ +#define LERBUF 8 +#define LERBUFLOG2 3 +#define LE_RLEN (LERBUFLOG2 << 13) +#define LETBUF 1 +#define LETBUFLOG2 0 +#define LE_TLEN (LETBUFLOG2 << 13) + +/* Local Area Network Controller for Ethernet (LANCE) registers */ +struct lereg1 { + volatile u_short ler1_rdp; /* register data port */ + volatile u_short ler1_rap; /* register address port */ +}; + +/* register addresses */ +#define LE_CSR0 0 /* Control and status register */ +#define LE_CSR1 1 /* low address of init block */ +#define LE_CSR2 2 /* high address of init block */ +#define LE_CSR3 3 /* Bus master and control */ + +/* Control and status register 0 (csr0) */ +#define LE_C0_ERR 0x8000 /* error summary */ +#define LE_C0_BABL 0x4000 /* transmitter timeout error */ +#define LE_C0_CERR 0x2000 /* collision */ +#define LE_C0_MISS 0x1000 /* missed a packet */ +#define LE_C0_MERR 0x0800 /* memory error */ +#define LE_C0_RINT 0x0400 /* receiver interrupt */ +#define LE_C0_TINT 0x0200 /* transmitter interrupt */ +#define LE_C0_IDON 0x0100 /* initalization done */ +#define LE_C0_INTR 0x0080 /* interrupt condition */ +#define LE_C0_INEA 0x0040 /* interrupt enable */ +#define LE_C0_RXON 0x0020 /* receiver on */ +#define LE_C0_TXON 0x0010 /* transmitter on */ +#define LE_C0_TDMD 0x0008 /* transmit demand */ +#define LE_C0_STOP 0x0004 /* disable all external activity */ +#define LE_C0_STRT 0x0002 /* enable external activity */ +#define LE_C0_INIT 0x0001 /* begin initalization */ + +#define LE_C0_BITS \ + "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\ +\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT" + +/* Control and status register 3 (csr3) */ +#define LE_C3_BSWP 0x4 /* byte swap */ +#define LE_C3_ACON 0x2 /* ALE control, eh? */ +#define LE_C3_BCON 0x1 /* byte control */ +/* + * Current size is 13,758 bytes with 8 x 1518 receive buffers and + * 1 x 1518 transmit buffer. + */ +struct lereg2 { + /* initialization block */ + volatile u_short ler2_mode; /* mode */ + volatile u_char ler2_padr[6]; /* physical address */ +#ifdef new_code + volatile u_short ler2_ladrf[4]; /* logical address filter */ +#else + volatile u_long ler2_ladrf0; /* logical address filter */ + volatile u_long ler2_ladrf1; /* logical address filter */ +#endif + volatile u_short ler2_rdra; /* receive descriptor addr */ + volatile u_short ler2_rlen; /* rda high and ring size */ + volatile u_short ler2_tdra; /* transmit descriptor addr */ + volatile u_short ler2_tlen; /* tda high and ring size */ + /* receive message descriptors. bits/hadr are byte order dependent. */ + struct lermd { + volatile u_short rmd0; /* low address of packet */ + volatile u_char rmd1_bits; /* descriptor bits */ + volatile u_char rmd1_hadr; /* high address of packet */ + volatile short rmd2; /* buffer byte count */ + volatile u_short rmd3; /* message byte count */ + } ler2_rmd[LERBUF]; + /* transmit message descriptors */ + struct letmd { + volatile u_short tmd0; /* low address of packet */ + volatile u_char tmd1_bits; /* descriptor bits */ + volatile u_char tmd1_hadr; /* high address of packet */ + volatile short tmd2; /* buffer byte count */ + volatile u_short tmd3; /* transmit error bits */ + } ler2_tmd[LETBUF]; + volatile char ler2_rbuf[LERBUF][LEMTU]; + volatile char ler2_tbuf[LETBUF][LEMTU]; +}; + +/* Initialzation block (mode) */ +#define LE_MODE_PROM 0x8000 /* promiscuous mode */ +/* 0x7f80 reserved, must be zero */ +#define LE_MODE_INTL 0x0040 /* internal loopback */ +#define LE_MODE_DRTY 0x0020 /* disable retry */ +#define LE_MODE_COLL 0x0010 /* force a collision */ +#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */ +#define LE_MODE_LOOP 0x0004 /* loopback mode */ +#define LE_MODE_DTX 0x0002 /* disable transmitter */ +#define LE_MODE_DRX 0x0001 /* disable receiver */ +#define LE_MODE_NORMAL 0 /* none of the above */ + + +/* Receive message descriptor 1 (rmd1_bits) */ +#define LE_R1_OWN 0x80 /* LANCE owns the packet */ +#define LE_R1_ERR 0x40 /* error summary */ +#define LE_R1_FRAM 0x20 /* framing error */ +#define LE_R1_OFLO 0x10 /* overflow error */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUFF 0x04 /* buffer error */ +#define LE_R1_STP 0x02 /* start of packet */ +#define LE_R1_ENP 0x01 /* end of packet */ + +#define LE_R1_BITS \ + "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP" + +/* Transmit message descriptor 1 (tmd1_bits) */ +#define LE_T1_OWN 0x80 /* LANCE owns the packet */ +#define LE_T1_ERR 0x40 /* error summary */ +#define LE_T1_MORE 0x10 /* multiple collisions */ +#define LE_T1_ONE 0x08 /* single collision */ +#define LE_T1_DEF 0x04 /* defferred transmit */ +#define LE_T1_STP 0x02 /* start of packet */ +#define LE_T1_ENP 0x01 /* end of packet */ + +#define LE_T1_BITS \ + "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP" + +/* Transmit message descriptor 3 (tmd3) */ +#define LE_T3_BUFF 0x8000 /* buffer error */ +#define LE_T3_UFLO 0x4000 /* underflow error */ +#define LE_T3_LCOL 0x1000 /* late collision */ +#define LE_T3_LCAR 0x0800 /* loss of carrier */ +#define LE_T3_RTRY 0x0400 /* retry error */ +#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */ + +#define LE_XMD2_ONES 0xf000 + +#define LE_T3_BITS \ + "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY" + + +#define LE_ADDR_LOW_MASK (0xffff) + diff --git a/sys/arch/mvme68k/stand/libsa/machdep.c b/sys/arch/mvme68k/stand/libsa/machdep.c new file mode 100644 index 0000000000000..c47d2ecc43ebd --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/machdep.c @@ -0,0 +1,154 @@ +/* $NetBSD: machdep.c,v 1.1.1.1 1995/07/25 23:12:22 chuck Exp $ */ + +#include +#include +#include + +#include + +#include "config.h" + +/* + * get_boothowto: boothowto for kernel + */ + +static int get_boothowto(cmd_flags) + +char *cmd_flags; + +{ + int result = 0; + + if (cmd_flags == NULL) return(0); + + while (*cmd_flags) { + switch (*cmd_flags) { + case 's': result |= RB_SINGLE; break; + case 'a': result |= RB_ASKNAME; break; + default: break; + } + cmd_flags++; + } + + return(result); +} + +/* + * cmd_parse: parse command line + * expected format: "b[oot] [kernel_name] [-flags]" + */ + +char *cmd_parse(cmd_buf, howto) +char *cmd_buf; +int *howto; +{ + char *cmd_kernel, *cmd_flags; + u_char *cp; + *howto = 0; + + cp = cmd_buf+1; /* skip 'b' */ + while (*cp && *cp != ' ') cp++; /* skip to end or space */ + while (*cp == ' ') cp++; /* skip spaces */ + if (*cp == '\0') return(NULL); /* no args */ + if (*cp == '-') { /* only flags? */ + *howto = get_boothowto(cp); + return(NULL); + } + cmd_kernel = cp; /* got kernel name */ + while (*cp && *cp != ' ') cp++; /* skip to end or space */ + if (*cp == ' ') *cp++ = 0; /* null terminate kernel */ + while (*cp == ' ') cp++; /* skip spaces */ + if (*cp == '\0') return(cmd_kernel); /* no flags */ + if (*cp != '-') return(cmd_kernel); /* garbage flags */ + cmd_flags = cp; /* save flags */ + + while (*cp && *cp != ' ') cp++; /* skip to end or space */ + if (*cp == ' ') *cp++ = 0; /* null terminate flags */ + + *howto = get_boothowto(cmd_flags); + + return(cmd_kernel); +} + + +/* + * machdep_common_ether: get ethernet address + */ + +void machdep_common_ether(ether) + unsigned char *ether; +{ + caddr_t addr; + int *ea = (int *) ETHER_ADDR; + int e = *ea; + if (( e & 0x2fffff00 ) == 0x2fffff00) + panic("ERROR: ethernet address not set!\r\n"); + ether[0] = 0x08; + ether[1] = 0x00; + ether[2] = 0x3e; + e = e >> 8; + ether[5] = e & 0xff; + e = e >> 8; + ether[4] = e & 0xff; + e = e >> 8; + ether[3] = e; +} + +/* + * console i/o + */ + +/* + * hardware + */ + +struct zs_hw { + volatile u_char ctl; + volatile u_char data; +}; + +struct zs_hw *zs = (struct zs_hw *)CONS_ZS_ADDR; + +/* + * putchar: put char to console + */ + +void putchar(char c) +{ + if (c == '\n') putchar('\r'); + zs->ctl = 0; + while ((zs->ctl & 0x04) == 0) { + zs->ctl = 0; + } + zs->ctl = 8; + zs->ctl = c; +} + +/* + * getchar: get char from console + */ + +int +getchar() +{ + int i; + while (1) { + zs->ctl = 0; + if ((zs->ctl & 0x1) != 0) break; + for (i = 100 ; i > 0 ; i--) + ; + } + zs->ctl = 8; + return(zs->ctl); +} + +/* + * peekchar + */ + +peekchar() +{ + zs->ctl = 0; + return(zs->ctl & 0x1); +} + diff --git a/sys/arch/mvme68k/stand/libsa/netif.c b/sys/arch/mvme68k/stand/libsa/netif.c new file mode 100644 index 0000000000000..4ac10d59f8220 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/netif.c @@ -0,0 +1,530 @@ +/* $NetBSD: netif.c,v 1.1.1.1 1995/07/25 23:12:24 chuck Exp $ */ + +/* + * Copyright (c) 1995 Gordon W. Ross + * 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. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon W. Ross + * + * 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 +#include +#include +#include + +#include + +#include +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "config.h" + +static struct netif netif_prom; + +#ifdef NETIF_DEBUG +int netif_debug; +#endif + +struct iodesc sockets[SOPEN_MAX]; + +struct iodesc * +socktodesc(sock) + int sock; +{ + if (sock != 0) { + return(NULL); + } + return (sockets); +} + +int +netif_open(machdep_hint) + void *machdep_hint; +{ + struct saioreq *si; + struct iodesc *io; + int fd, error; + + /* find a free socket */ + io = sockets; + if (io->io_netif) { +#ifdef DEBUG + printf("netif_open: device busy\n"); +#endif + return (-1); + } + bzero(io, sizeof(*io)); + + if ((netif_prom.devdata = le_init(io)) == NULL) { + printf("le_init failed\n"); + return(-1); + } + + io->io_netif = &netif_prom; + + return(0); +} + +int +netif_close(fd) + int fd; +{ + struct iodesc *io; + struct netif *ni; + + if (fd != 0) { + errno = EBADF; + return(-1); + } + + io = sockets; + ni = io->io_netif; + if (ni != NULL) { + le_end(ni); + ni->devdata = NULL; + io->io_netif = NULL; + } + return(0); +} + +/* + * Send a packet. The ether header is already there. + * Return the length sent (or -1 on error). + */ +int +netif_put(desc, pkt, len) + struct iodesc *desc; + void *pkt; + int len; +{ + +#ifdef NETIF_DEBUG + if (netif_debug) { + struct ether_header *eh; + + printf("netif_put: desc=0x%x pkt=0x%x len=%d\n", + desc, pkt, len); + eh = pkt; + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xFFFF); + } +#endif + + return(le_put(desc, pkt, len)); +} + +/* + * Receive a packet, including the ether header. + * Return the total length received (or -1 on error). + */ +int +netif_get(desc, pkt, maxlen, timo) + struct iodesc *desc; + void *pkt; + int maxlen; + time_t timo; +{ + struct saioreq *si; + struct saif *sif; + char *dmabuf; + int tick0, tmo_ticks; + int len; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_get: pkt=0x%x, maxlen=%d, tmo=%d\n", + pkt, maxlen, timo); +#endif + + len = le_get(desc, pkt, maxlen, timo); + +#ifdef NETIF_DEBUG + if (netif_debug) { + struct ether_header *eh = pkt; + + printf("dst: %s ", ether_sprintf(eh->ether_dhost)); + printf("src: %s ", ether_sprintf(eh->ether_shost)); + printf("type: 0x%x\n", eh->ether_type & 0xFFFF); + } +#endif + + return len; +} + +/* the rest of this file imported from le_poll.c */ + +/* + * Copyright (c) 1993 Adam Glass + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass. + * 4. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL 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. + */ + +#include "if_lereg.h" + +struct { + struct lereg1 *sc_r1; /* LANCE registers */ + struct lereg2 *sc_r2; /* RAM */ + int next_rmd; + int next_tmd; +} le_softc; + +int le_debug = 0; + +/* + * init le device. return 0 on failure, 1 if ok. + */ + +void * +le_init(io) + struct iodesc *io; +{ + u_long *eram = (u_long *) ERAM_ADDR; + + if (le_debug) + printf("le: le_init called\n"); + machdep_common_ether(io->myea); + bzero(&le_softc, sizeof(le_softc)); + le_softc.sc_r1 = (struct lereg1 *) LANCE_REG_ADDR; + le_softc.sc_r2 = (struct lereg2 *) (*eram - (1024*1024)); + le_reset(io->io_netif, io->myea); + + return(&le_softc); +} + +/* + * close device + * XXX le_softc + */ + +void le_end(nif) + + struct netif *nif; +{ + struct lereg1 *ler1 = le_softc.sc_r1; + + if (le_debug) + printf("le: le_end called\n"); + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STOP; +} + + +/* + * reset device + * XXX le_softc + */ + +void le_reset(nif, myea) + struct netif *nif; + u_char *myea; +{ + struct lereg1 *ler1 = le_softc.sc_r1; + struct lereg2 *ler2 = le_softc.sc_r2; + unsigned int a; + int timo = 100000, stat, i; + + if (le_debug) + printf("le: le_reset called\n"); + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */ + + bzero(ler2, sizeof(*ler2)); + + ler2->ler2_mode = LE_MODE_NORMAL; + ler2->ler2_padr[0] = myea[1]; + ler2->ler2_padr[1] = myea[0]; + ler2->ler2_padr[2] = myea[3]; + ler2->ler2_padr[3] = myea[2]; + ler2->ler2_padr[4] = myea[5]; + ler2->ler2_padr[5] = myea[4]; + + + ler2->ler2_ladrf0 = 0; + ler2->ler2_ladrf1 = 0; + + a = (u_int)ler2->ler2_rmd; + ler2->ler2_rlen = LE_RLEN | (a >> 16); + ler2->ler2_rdra = a & LE_ADDR_LOW_MASK; + + a = (u_int)ler2->ler2_tmd; + ler2->ler2_tlen = LE_TLEN | (a >> 16); + ler2->ler2_tdra = a & LE_ADDR_LOW_MASK; + + ler1->ler1_rap = LE_CSR1; + a = (u_int)ler2; + ler1->ler1_rdp = a & LE_ADDR_LOW_MASK; + ler1->ler1_rap = LE_CSR2; + ler1->ler1_rdp = a >> 16; + + for (i = 0; i < LERBUF; i++) { + a = (u_int)&ler2->ler2_rbuf[i]; + ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK; + ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; + ler2->ler2_rmd[i].rmd1_hadr = a >> 16; + ler2->ler2_rmd[i].rmd2 = -LEMTU; + ler2->ler2_rmd[i].rmd3 = 0; + } + for (i = 0; i < LETBUF; i++) { + a = (u_int)&ler2->ler2_tbuf[i]; + ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK; + ler2->ler2_tmd[i].tmd1_bits = 0; + ler2->ler2_tmd[i].tmd1_hadr = a >> 16; + ler2->ler2_tmd[i].tmd2 = 0; + ler2->ler2_tmd[i].tmd3 = 0; + } + + ler1->ler1_rap = LE_CSR3; + ler1->ler1_rdp = LE_C3_BSWP; + + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_INIT; + do { + if (--timo == 0) { + printf("le: init timeout, stat = 0x%x\n", stat); + break; + } + stat = ler1->ler1_rdp; + } while ((stat & LE_C0_IDON) == 0); + + ler1->ler1_rdp = LE_C0_IDON; + le_softc.next_rmd = 0; + le_softc.next_tmd = 0; + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STRT; +} + +/* + * le_error + * XXX le_softc + */ + +void le_error(nif, str, vler1) + struct netif *nif; + char *str; + volatile void *vler1; +{ + volatile struct lereg1 *ler1 = vler1; + /* ler1->ler1_rap = LE_CSRO done in caller */ + if (ler1->ler1_rdp & LE_C0_BABL) + panic("le: been babbling, found by '%s'\n", str); + if (ler1->ler1_rdp & LE_C0_CERR) { + ler1->ler1_rdp = LE_C0_CERR; + } + if (ler1->ler1_rdp & LE_C0_MISS) { + ler1->ler1_rdp = LE_C0_MISS; + } + if (ler1->ler1_rdp & LE_C0_MERR) { + printf("le: memory error in '%s'\n", str); + panic("memory error"); + } +} + +/* + * put a packet + * XXX le_softc + */ + +int le_put(desc, pkt, len) + struct iodesc *desc; + void *pkt; + int len; +{ + volatile struct lereg1 *ler1 = le_softc.sc_r1; + volatile struct lereg2 *ler2 = le_softc.sc_r2; + volatile struct letmd *tmd; + int timo = 100000, stat, i; + unsigned int a; + + ler1->ler1_rap = LE_CSR0; + if (ler1->ler1_rdp & LE_C0_ERR) + le_error(desc->io_netif, "le_put(way before xmit)", ler1); + tmd = &ler2->ler2_tmd[le_softc.next_tmd]; + while(tmd->tmd1_bits & LE_T1_OWN) { + printf("le: output buffer busy\n"); + } + bcopy(pkt, ler2->ler2_tbuf[le_softc.next_tmd], len); + if (len < 64) + tmd->tmd2 = -64; + else + tmd->tmd2 = -len; + tmd->tmd3 = 0; + if (ler1->ler1_rdp & LE_C0_ERR) + le_error(desc->io_netif, "le_put(before xmit)", ler1); + tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN; + a = (u_int)&ler2->ler2_tbuf[le_softc.next_tmd]; + tmd->tmd0 = a & LE_ADDR_LOW_MASK; + tmd->tmd1_hadr = a >> 16; + ler1->ler1_rdp = LE_C0_TDMD; + if (ler1->ler1_rdp & LE_C0_ERR) + le_error(desc->io_netif, "le_put(after xmit)", ler1); + do { + if (--timo == 0) { + printf("le: transmit timeout, stat = 0x%x\n", stat); + if (ler1->ler1_rdp & LE_C0_ERR) + le_error(desc->io_netif, "le_put(timeout)", ler1); + break; + } + stat = ler1->ler1_rdp; + } while ((stat & LE_C0_TINT) == 0); + ler1->ler1_rdp = LE_C0_TINT; + if (ler1->ler1_rdp & LE_C0_ERR) { + if ((ler1->ler1_rdp & (LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR)) != + LE_C0_CERR) + printf("le_put: xmit error, buf %d\n", le_softc.next_tmd); + le_error(desc->io_netif, "le_put(xmit error)", ler1); + } + le_softc.next_tmd = 0; +/* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/ + if (tmd->tmd1_bits & LE_T1_ERR) { + printf("le: transmit error, error = 0x%x\n", tmd->tmd3); + return -1; + } + if (le_debug) { + printf("le: le_put() successful: sent %d\n", len); + printf("le: le_put(): tmd1_bits: %x tmd3: %x\n", + (unsigned int) tmd->tmd1_bits, + (unsigned int) tmd->tmd3); + } + return len; +} + + +/* + * le_get + */ + +int le_get(desc, pkt, len, timeout) + struct iodesc *desc; + void *pkt; + int len; + time_t timeout; +{ + time_t t; + int cc; + + t = getsecs(); + cc = 0; + while (((getsecs() - t) < timeout) && !cc) { + cc = le_poll(desc, pkt, len); + } + return cc; +} + + +/* + * le_poll + * XXX softc + */ + +int le_poll(desc, pkt, len) + struct iodesc *desc; + void *pkt; + int len; +{ + struct lereg1 *ler1 = le_softc.sc_r1; + struct lereg2 *ler2 = le_softc.sc_r2; + unsigned int a; + int length; + struct lermd *rmd; + + + ler1->ler1_rap = LE_CSR0; + if ((ler1->ler1_rdp & LE_C0_RINT) != 0) + ler1->ler1_rdp = LE_C0_RINT; + rmd = &ler2->ler2_rmd[le_softc.next_rmd]; + if (rmd->rmd1_bits & LE_R1_OWN) { + return(0); + } + if (ler1->ler1_rdp & LE_C0_ERR) + le_error(desc->io_netif, "le_poll", ler1); + if (rmd->rmd1_bits & LE_R1_ERR) { + printf("le_poll: rmd status 0x%x\n", rmd->rmd1_bits); + length = 0; + goto cleanup; + } + if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != (LE_R1_STP|LE_R1_ENP)) + panic("le_poll: chained packet\n"); + + length = rmd->rmd3; + if (length >= LEMTU) { + length = 0; + panic("csr0 when bad things happen: %x\n", ler1->ler1_rdp); + goto cleanup; + } + if (!length) goto cleanup; + length -= 4; + if (length > 0) { + + /* + * if buffer is smaller than the packet truncate it. + * (is this wise?) + */ + if (length > len) + length = len; + + bcopy((void *)&ler2->ler2_rbuf[le_softc.next_rmd], pkt, length); + } + + cleanup: + a = (u_int)&ler2->ler2_rbuf[le_softc.next_rmd]; + rmd->rmd0 = a & LE_ADDR_LOW_MASK; + rmd->rmd1_hadr = a >> 16; + rmd->rmd2 = -LEMTU; + le_softc.next_rmd = + (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1); + rmd->rmd1_bits = LE_R1_OWN; + return length; +} diff --git a/sys/arch/mvme68k/stand/libsa/netif.h b/sys/arch/mvme68k/stand/libsa/netif.h new file mode 100644 index 0000000000000..811974d9c4b1f --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/netif.h @@ -0,0 +1,22 @@ + +#include "iodesc.h" + +struct netif { + void *devdata; +}; + +int netif_get __P((struct iodesc *, void *, int, time_t)); +int netif_put __P((struct iodesc *, void *, int)); + +int netif_open __P((void *)); +int netif_close __P((int)); + +struct iodesc *socktodesc __P((int)); + +void le_end __P((struct netif *)); +void le_error __P((struct netif *, char *, volatile void *)); +int le_get __P((struct iodesc *, void *, int, time_t)); +void *le_init __P((struct iodesc *)); +int le_poll __P((struct iodesc *, void *, int)); +int le_put __P((struct iodesc *, void *, int)); +void le_reset __P((struct netif *, u_char *)); diff --git a/sys/arch/mvme68k/stand/libsa/panic.c b/sys/arch/mvme68k/stand/libsa/panic.c new file mode 100644 index 0000000000000..41dabf8fbf7d7 --- /dev/null +++ b/sys/arch/mvme68k/stand/libsa/panic.c @@ -0,0 +1,31 @@ + +#include +#include "stand.h" + +extern volatile void abort(); +extern int _estack[]; + +volatile void +panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + printf(fmt, ap); + printf("\n"); + va_end(ap); + stackdump(0); + abort(); +} + +stackdump(dummy) + int dummy; +{ + int *ip; + + printf("stackdump:\n"); + for (ip = &dummy; ip < _estack; ip += 4) { + printf("%08x: %08x %08x %08x %08x\n", + (int)ip, ip[0], ip[1], ip[2], ip[3]); + } +} diff --git a/sys/arch/mvme68k/stand/netboot/Makefile b/sys/arch/mvme68k/stand/netboot/Makefile new file mode 100644 index 0000000000000..03fbaa7f7878c --- /dev/null +++ b/sys/arch/mvme68k/stand/netboot/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.1.1.1 1995/07/25 23:12:24 chuck Exp $ + +SA_PROG= netboot +SRCS= boot.c conf.c version.c dev_net.c + +DEFS= -DSTANDALONE -DSUN_BOOTPARAMS + +all: ${SA_PROG}.bin + +.include + +install: ${SA_PROG}.bin + install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \ + ${SA_PROG}.bin ${DESTDIR}${MDEC_DIR}/${SA_PROG} + diff --git a/sys/arch/mvme68k/stand/netboot/boot.c b/sys/arch/mvme68k/stand/netboot/boot.c new file mode 100644 index 0000000000000..a1bae2af5a309 --- /dev/null +++ b/sys/arch/mvme68k/stand/netboot/boot.c @@ -0,0 +1,77 @@ +/* $NetBSD: boot.c,v 1.1.1.1 1995/07/25 23:12:25 chuck 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 + */ + +#include +#include + +#include "stand.h" + +/* + * Boot device is derived from ROM provided information. + */ +#define LOADADDR 0x8000 + +extern char *version; +extern char *cmd_parse(); +char defname[32] = "netbsd"; +char line[80]; +int boothowto; + + +main(cline) +char *cline; +{ + char *cp, *file; + int io; + + printf(">> NetBSD netboot [%s]\n", version); + file = cmd_parse(cline, &boothowto); + if (file == NULL) + file = defname; + + for (;;) { + if (boothowto & RB_ASKNAME) { + printf("boot: "); + gets(line); + if (line[0]) + file = line; + } + exec_mvme(file, LOADADDR, boothowto); + printf("boot: %s\n", strerror(errno)); + boothowto |= RB_ASKNAME; + } +} diff --git a/sys/arch/mvme68k/stand/netboot/conf.c b/sys/arch/mvme68k/stand/netboot/conf.c new file mode 100644 index 0000000000000..26053e45ffa98 --- /dev/null +++ b/sys/arch/mvme68k/stand/netboot/conf.c @@ -0,0 +1,21 @@ +/* $NetBSD: conf.c,v 1.1.1.1 1995/07/25 23:12:25 chuck Exp $ */ + +#include +#include +#include +#include + +struct fs_ops file_system[] = { + { nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat }, +}; +int nfsys = 1; + +struct devsw devsw[] = { + { "net", net_strategy, net_open, net_close, net_ioctl }, +}; +int ndevs = 1; + +/* XXX */ +int netif_debug; +int debug; +int errno; diff --git a/sys/arch/mvme68k/stand/netboot/dev_net.c b/sys/arch/mvme68k/stand/netboot/dev_net.c new file mode 100644 index 0000000000000..b084341996b2c --- /dev/null +++ b/sys/arch/mvme68k/stand/netboot/dev_net.c @@ -0,0 +1,175 @@ +/* $NetBSD: dev_net.c,v 1.1.1.1 1995/07/25 23:12:26 chuck Exp $ */ + +/* + * Copyright (c) 1995 Gordon W. Ross + * 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. + * 4. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Gordon W. Ross + * + * 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. + */ + +/* + * This module implements a "raw device" interface suitable for + * use by the stand-alone I/O library NFS code. This interface + * does not support any "block" access, and exists only for the + * purpose of initializing the network interface, getting boot + * parameters, and performing the NFS mount. + * + * At open time, this does: + * + * find interface - netif_open() + * RARP for IP address - rarp_getipaddress() + * RPC/bootparams - callrpc(d, RPC_BOOTPARAMS, ...) + * RPC/mountd - nfs_mount(sock, ip, path) + * + * the root file handle from mountd is saved in a global + * for use by the NFS open code (NFS/lookup). + */ + +#include +#include +#include +#include +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "bootparam.h" + +extern int nfs_root_node[]; /* XXX - get from nfs_mount() */ + +u_int32_t myip, rootip, gateip, mask; +char rootpath[FNAME_SIZE]; + +int netdev_sock = -1; +static int open_count; + +/* + * Called by devopen after it sets f->f_dev to our devsw entry. + * This opens the low-level device and sets f->f_devdata. + */ +int +net_open(f, devname) + struct open_file *f; + char *devname; /* Device part of file name (or NULL). */ +{ + int error = 0; + + /* On first open, do netif open, mount, etc. */ + if (open_count == 0) { + /* Find network interface. */ + if ((netdev_sock = netif_open(devname)) < 0) + return (error=ENXIO); + if ((error = net_mountroot(f, devname)) != 0) + return (error); + } + open_count++; + f->f_devdata = nfs_root_node; + return (error); +} + +int +net_close(f) + struct open_file *f; +{ + /* On last close, do netif close, etc. */ + if (open_count > 0) + if (--open_count == 0) + netif_close(netdev_sock); + f->f_devdata = NULL; +} + +int +net_ioctl() +{ + return EIO; +} + +int +net_strategy() +{ + return EIO; +} + +int +net_mountroot(f, devname) + struct open_file *f; + char *devname; /* Device part of file name (or NULL). */ +{ + int error; + +#ifdef DEBUG + printf("net_mountroot: %s\n", devname); +#endif + + /* + * Get info for NFS boot: our IP address, our hostname, + * server IP address, and our root path on the server. + * There are two ways to do this: The old, Sun way, + * and the more modern, BOOTP way. (RFC951, RFC1048) + */ + +#ifdef SUN_BOOTPARAMS + /* Get boot info using RARP and Sun bootparams. */ + + /* Get our IP address. (rarp.c) */ + if ((myip = rarp_getipaddress(netdev_sock)) == 0) + return (EIO); + printf("boot: client IP address: %s\n", intoa(myip)); + + /* Get our hostname, server IP address. */ + if (bp_whoami(netdev_sock)) + return (EIO); + printf("boot: client name: %s\n", hostname); + + /* Get the root pathname. */ + if (bp_getfile(netdev_sock, "root", &rootip, rootpath)) + return (EIO); + +#else + + /* Get boot info using BOOTP way. (RFC951, RFC1048) */ + bootp(netdev_sock); + + printf("Using IP address: %s\n", intoa(myip)); + + printf("myip: %s (%s)", hostname, intoa(myip)); + if (gateip) + printf(", gateip: %s", intoa(gateip)); + if (mask) + printf(", mask: %s", intoa(mask)); + printf("\n"); + +#endif + + printf("root addr=%s path=%s\n", intoa(rootip), rootpath); + + /* Get the NFS file handle (mount). */ + error = nfs_mount(netdev_sock, rootip, rootpath); + + return (error); +} diff --git a/sys/arch/mvme68k/stand/netboot/dev_net.h b/sys/arch/mvme68k/stand/netboot/dev_net.h new file mode 100644 index 0000000000000..093ba193bfd38 --- /dev/null +++ b/sys/arch/mvme68k/stand/netboot/dev_net.h @@ -0,0 +1,6 @@ + +int net_open __P((struct open_file *, ...)); +int net_close __P((struct open_file *)); +int net_ioctl(); +int net_strategy(); + diff --git a/sys/arch/mvme68k/stand/netboot/version.c b/sys/arch/mvme68k/stand/netboot/version.c new file mode 100644 index 0000000000000..49e514c01a9d7 --- /dev/null +++ b/sys/arch/mvme68k/stand/netboot/version.c @@ -0,0 +1,9 @@ +/* $NetBSD: version.c,v 1.1.1.1 1995/07/25 23:12:26 chuck Exp $ */ + +/* + * NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. + * + * 1.1 + */ + +char *version = "$Revision: 1.1.1.1 $"; diff --git a/sys/arch/mvme68k/stand/sboot/Makefile b/sys/arch/mvme68k/stand/sboot/Makefile new file mode 100644 index 0000000000000..fb80ad4e86fef --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile,v 1.1.1.1 1995/07/25 23:12:28 chuck Exp $ + +# +# sboot needs GNU ld because it can generate S-Records +# + +COMPILE.s= $(AS) $(ASFLAGS) -o $*.o +GNU_LD=/usr/local/bin/ld +LDFLAGS=-oformat srec -x -N -Ttext 0x4000 -e start +NOMAN= +PROG= sboot +SRCS= start.s clock.c console.c etherfun.c le_poll.c libc_sa.c \ + oc_cksum.s sboot.c + +${PROG}: ${OBJS} + ${GNU_LD} ${LDFLAGS} -o ${.TARGET} ${OBJS} + +.include + diff --git a/sys/arch/mvme68k/stand/sboot/clock.c b/sys/arch/mvme68k/stand/sboot/clock.c new file mode 100644 index 0000000000000..f6e344b7b9d2e --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/clock.c @@ -0,0 +1,117 @@ +/* $NetBSD: clock.c,v 1.1.1.1 1995/07/25 23:12:28 chuck Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1993 Adam Glass + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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 8.1 (Berkeley) 6/11/93 + */ + +/* + * Clock driver. + */ + +#include "sboot.h" +#include "clockreg.h" +static struct clockreg *clockreg = (struct clockreg *) CLOCK_ADDR; + +/* + * BCD to decimal and decimal to BCD. + */ +#define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) +#define TOBCD(x) (((x) / 10 * 16) + ((x) % 10)) + +#define SECDAY (24 * 60 * 60) +#define SECYR (SECDAY * 365) +#define LEAPYEAR(y) (((y) & 3) == 0) + +/* + * This code is defunct after 2068. + * Will Unix still be here then?? + */ +const short dayyr[12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + +static u_long chiptotime(sec, min, hour, day, mon, year) + register int sec, min, hour, day, mon, year; +{ + register int days, yr; + + sec = FROMBCD(sec); + min = FROMBCD(min); + hour = FROMBCD(hour); + day = FROMBCD(day); + mon = FROMBCD(mon); + year = FROMBCD(year) + YEAR0; + if (year < 70) year = 70; + + /* simple sanity checks */ + if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31) + return (0); + days = 0; + for (yr = 70; yr < year; yr++) + days += LEAPYEAR(yr) ? 366 : 365; + days += dayyr[mon - 1] + day - 1; + if (LEAPYEAR(yr) && mon > 2) + days++; + /* now have days since Jan 1, 1970; the rest is easy... */ + return (days * SECDAY + hour * 3600 + min * 60 + sec); +} + +/* + * Set up the system's time, given a `reasonable' time value. + */ +u_long time() +{ + register struct clockreg *cl = clockreg; + int sec, min, hour, day, mon, year; + + cl->cl_csr |= CLK_READ; /* enable read (stop time) */ + sec = cl->cl_sec; + min = cl->cl_min; + hour = cl->cl_hour; + day = cl->cl_mday; + mon = cl->cl_month; + year = cl->cl_year; + cl->cl_csr &= ~CLK_READ; /* time wears on */ + return(chiptotime(sec, min, hour, day, mon, year)); +} diff --git a/sys/arch/mvme68k/stand/sboot/clockreg.h b/sys/arch/mvme68k/stand/sboot/clockreg.h new file mode 100644 index 0000000000000..dbbf313f3d11d --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/clockreg.h @@ -0,0 +1,69 @@ +/* $NetBSD: clockreg.h,v 1.1.1.1 1995/07/25 23:12:29 chuck Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + * + * @(#)clockreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Mostek MK48T02 clock. + */ +struct clockreg { + volatile u_char cl_csr; /* control register */ + volatile u_char cl_sec; /* seconds (0..59; BCD) */ + volatile u_char cl_min; /* minutes (0..59; BCD) */ + volatile u_char cl_hour; /* hour (0..23; BCD) */ + volatile u_char cl_wday; /* weekday (1..7) */ + volatile u_char cl_mday; /* day in month (1..31; BCD) */ + volatile u_char cl_month; /* month (1..12; BCD) */ + volatile u_char cl_year; /* year (0..99; BCD) */ +}; + +/* bits in cl_csr */ +#define CLK_WRITE 0x80 /* want to write */ +#define CLK_READ 0x40 /* want to read (freeze clock) */ + +/* + * Sun chose the year `68' as their base count, so that + * cl_year==0 means 1968. + */ +#define YEAR0 68 diff --git a/sys/arch/mvme68k/stand/sboot/console.c b/sys/arch/mvme68k/stand/sboot/console.c new file mode 100644 index 0000000000000..19f01dcada80b --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/console.c @@ -0,0 +1,139 @@ +/* + * + * Copyright (c) 1995 Charles D. Cranor and Seth Widoff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor + * and Seth Widoff. + * 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. + */ +/* + * console i/o + */ + +#include "sboot.h" + +/* + * hardware + */ + +struct zs_hw { + volatile u_char ctl; + volatile u_char data; +}; + +struct zs_hw *zs = (struct zs_hw *)CONS_ZS_ADDR; + +/* + * consinit: init console + */ + +consinit() + +{ + register int mark = time(); + register int rr1; + while (1) { + if (time() > mark + 5) break; + zs->ctl = 1; rr1 = zs->ctl; + zs->ctl = 0; + if ((rr1 & 0x1) == 1 && (zs->ctl & 0x4) == 4) break; /* zs_drain! */ + } + zs->ctl = 9; zs->ctl = 0x00; /* clear interrupt */ + zs->ctl = 4; zs->ctl = 0x44; /* 16x clk, 1 stop bit */ + zs->ctl = 5; zs->ctl = 0xea; /* DTR on, 8 bit xmit, xmit on, RTS on */ + zs->ctl = 3; zs->ctl = 0xc1; /* 8 bit recv, auto cd_cts, recv on */ + zs->ctl = 1; zs->ctl = 0x00; /* no intrs */ + zs->ctl = 2; zs->ctl = 0x00; /* no vector */ + zs->ctl = 10; zs->ctl = 0x00; /* */ + zs->ctl = 11; zs->ctl = 0x50; /* clocking options */ + zs->ctl = 12; zs->ctl = 0x0e; /* 9600 baud, part 1 */ + zs->ctl = 13; zs->ctl = 0x00; /* 9600 baud, part 2 */ + zs->ctl = 14; zs->ctl = 0x03; /* more clocking options */ + zs->ctl = 15; zs->ctl = 0x00; /* clear intrs */ +} + +/* + * putchar: put char to console + */ + +void putchar(char c) +{ + if (c == '\n') putchar('\r'); /* avoid the need for \r\n in printf */ + zs->ctl = 0; + while ((zs->ctl & 0x04) == 0) { + zs->ctl = 0; + } + zs->ctl = 8; + zs->ctl = c; +} + +/* + * cngetc: get 1 char from console + */ + +char cngetc () +{ + zs->ctl = 0; + while ((zs->ctl & 0x1) == 0) { + zs->ctl = 0; + } + zs->ctl = 8; + return zs->ctl; +} + +/* + * puts: put string to console + */ + +void puts ( char * str ) +{ + while ( *str != '\0' ) { + putchar(*str); + str++; + } +} + +/* + * ngets: get string from console + */ + +void ngets ( char * str, int size ) +{ + int i = 0; + while ( (i < size - 1) && (str[i] = cngetc()) != '\r') { + if ( str[i] == '\b' || str[i] == 0x7F ) { + if ( i == 0) continue; + i--; + puts("\b \b"); + continue; + } + putchar(str[i]); + i++; + } + puts("\n"); + str[i] = '\0'; +} + diff --git a/sys/arch/mvme68k/stand/sboot/etherfun.c b/sys/arch/mvme68k/stand/sboot/etherfun.c new file mode 100644 index 0000000000000..7c107b00e8a0b --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/etherfun.c @@ -0,0 +1,213 @@ +/* + * + * Copyright (c) 1995 Charles D. Cranor and Seth Widoff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor + * and Seth Widoff. + * 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. + */ +/* etherfun.c */ + +#include "sboot.h" +#include "etherfun.h" + +/* Construct and send a rev arp packet */ +void +do_rev_arp () +{ + int i; + + for ( i = 0; i < 6; i++ ) { + eh->ether_dhost[i] = 0xff; + } + bcopy(myea, eh->ether_shost, 6); + eh->ether_type = ETYPE_RARP; + + rarp->ar_hrd = 1; /* hardware type is 1 */ + rarp->ar_pro = PTYPE_IP; + rarp->ar_hln = 6; /* length of hardware address is 6 bytes */ + rarp->ar_pln = 4; /* length of ip address is 4 byte */ + rarp->ar_op = OPCODE_RARP; + bcopy(myea, rarp->arp_sha, sizeof(myea)); + bcopy(myea, rarp->arp_tha, sizeof(myea)); + for ( i = 0; i < 4; i++ ) { + rarp->arp_spa[i] = rarp->arp_tpa[i] = 0x00; + } + + le_put(buf, 76); +} + +/* Recieve and disassemble the rev_arp reply */ + +int +get_rev_arp () +{ + le_get(buf, sizeof(buf), 6); + if ( eh->ether_type == ETYPE_RARP && rarp->ar_op == OPCODE_REPLY ) { + bcopy(rarp->arp_tpa, myip, sizeof(rarp->arp_tpa)); + bcopy(rarp->arp_spa, servip, sizeof(rarp->arp_spa)); + bcopy(rarp->arp_sha, servea, sizeof(rarp->arp_sha)); + return 1; + } + return 0; +} + +/* Try to get a reply to a rev arp request */ + +int +rev_arp () +{ + int tries = 0; + while ( tries < 5 ) { + do_rev_arp(); + if ( get_rev_arp() ) { + return 1; + } + tries++; + } + return 0; +} + +/* Send a tftp read request or acknowledgement + mesgtype 0 is a read request, 1 is an aknowledgement */ + +void +do_send_tftp ( int mesgtype ) +{ + u_long res, iptmp, lcv; + char *tot; + + if ( mesgtype == 0 ) { + tot = tftp_r + (sizeof(MSG)-1); + myport = (u_short)time(); + if (myport < 1000) myport += 1000; + servport = FTP_PORT; /* to start */ + } else { + tot = (char *)tftp_a + 4; + } + + bcopy (servea, eh->ether_dhost, sizeof(servea)); + bcopy (myea, eh->ether_shost, sizeof(myea)); + eh->ether_type = ETYPE_IP; + + iph->ip_v = IP_VERSION; + iph->ip_hl = IP_HLEN; + iph->ip_tos = 0; /* type of service is 0 */ + iph->ip_id = 0; /* id field is 0 */ + iph->ip_off = IP_DF; + iph->ip_ttl = 3; /* time to live is 3 seconds/hops */ + iph->ip_p = IPP_UDP; + bcopy(myip, iph->ip_src, sizeof(myip)); + bcopy(servip, iph->ip_dst, sizeof(servip)); + iph->ip_sum = 0; + iph->ip_len = tot - (char *)iph; + res = oc_cksum(iph, sizeof(struct ip), 0); + iph->ip_sum = 0xffff & ~res; + udph->uh_sport = myport; + udph->uh_dport = servport; + udph->uh_sum = 0; + + if ( mesgtype ) { + tftp_a->op_code = FTPOP_ACKN; + tftp_a->block = (u_short)(mesgtype); + } else { + bcopy (myip, &iptmp, sizeof(iptmp)); + bcopy(MSG, tftp_r, (sizeof(MSG)-1)); + for (lcv = 9; lcv >= 2; lcv--) { + tftp_r[lcv] = "0123456789ABCDEF"[iptmp & 0xF]; + + iptmp = iptmp >> 4; + } + } + + udph->uh_ulen = tot - (char *)udph; + + le_put( buf, tot - buf); +} + +/* Attempt to tftp a file and read it into memory */ + +int +do_get_file () +{ + int fail = 0, oldlen; + char *loadat = (char *)LOAD_ADDR; + last_ack = 0; + + do_send_tftp( READ ); + while (1) { + if ( le_get(buf, sizeof(buf), 5) == 0) { /* timeout occured */ + if ( last_ack ) { + do_send_tftp( last_ack ); + } else { + do_send_tftp( READ ); + } + fail++; + if ( fail > 5 ) { + printf("\n"); + return 1; + } + } else { + printf("%x \r", tftp->info.block*512); + if ((eh->ether_type != ETYPE_IP) || (iph->ip_p != IPP_UDP)) { + fail++; + continue; + } + if (servport == FTP_PORT) servport = udph->uh_sport; + if (tftp->info.op_code == FTPOP_ERR) { + printf("TFTP: Download error %d: %s\n", + tftp->info.block, tftp->data); + return 1; + } + if (tftp->info.block != last_ack + 1) { /* we recieved the wrong block */ + if (tftp->info.block < last_ack +1) { + do_send_tftp(tftp->info.block); /* ackn whatever we recieved */ + } else { + do_send_tftp( last_ack ); /* ackn the last confirmed block */ + } + fail++; + } else { /* we got the right block */ + fail = 0; + last_ack++; + oldlen = udph->uh_ulen; + do_send_tftp( last_ack ); + /*printf("bcopy %x %x %d\n", &tftp->data, loadat, oldlen - 12);*/ + bcopy(&tftp->data, loadat, oldlen - 12); + loadat += oldlen - 12; + if (oldlen < (8 + 4 + 512)) { + printf("\n"); + return 0; + } + } + } + } + printf("\n"); + return 0; +} + + + + diff --git a/sys/arch/mvme68k/stand/sboot/etherfun.h b/sys/arch/mvme68k/stand/sboot/etherfun.h new file mode 100644 index 0000000000000..2b6a14d69a5e9 --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/etherfun.h @@ -0,0 +1,124 @@ +/* + * + * Copyright (c) 1995 Charles D. Cranor and Seth Widoff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor + * and Seth Widoff. + * 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. + */ +/* etherfun.h */ + +/* constants */ +/* ether header */ +#define ETYPE_RARP 0x8035 /* ethertype is RARP */ +#define ETYPE_IP 0x800 /* ethertype is IP */ + +/* rev arp */ +#define PTYPE_IP 0x800 /* Protocol type is IP */ +#define OPCODE_RARP 3 /* Optype is REVARP request */ +#define OPCODE_REPLY 4 /* Optype is REVARP reply */ + +/* ip header */ +#define IPP_UDP 17 /* IP Protocol is UDP */ +#define IP_VERSION 4 /* IP version number */ +#define IP_HLEN 5 /* IP header length is a fixed 50 bytes */ +#define N 1536 + +/* tftp header */ +#define FTPOP_ACKN 4 /* Opcode is acknowledge */ +#define FTPOP_ERR 5 /* Opcode is Error */ +#define FTP_PORT 69 /* Standard TFTP port number */ +#define MSG "\0\1xxxxxxxx.147\0octet\0" /* implicit NULL */ + +/* data structures */ + +struct ether_header { + u_char ether_dhost[6]; + u_char ether_shost[6]; + u_short ether_type; +}; + +struct ether_arp { + u_short ar_hrd; /* format of hardware address */ + u_short ar_pro; /* format of protocol address */ + u_char ar_hln; /* length of hardware address */ + u_char ar_pln; /* length of protocol address */ + u_short ar_op; + u_char arp_sha[6]; /* sender hardware address */ + u_char arp_spa[4]; /* sender protocol address */ + u_char arp_tha[6]; /* target hardware address */ + u_char arp_tpa[4]; /* target protocol address */ +}; + +struct ip { + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ + u_char ip_tos; /* type of service */ + short ip_len; /* total length */ + u_short ip_id; /* identification */ + short ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* dont fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + u_char ip_src[4]; + u_char ip_dst[4]; /* source and dest address */ +}; + +struct udp { + u_short uh_sport; + u_short uh_dport; + short uh_ulen; + u_short uh_sum; +}; + +struct tftph { + u_short op_code; + u_short block; +}; + +struct tftphr { + struct tftph info; + char data[1]; +}; + +/* globals */ +int last_ack; +char buf[N]; +struct ether_header *eh = (struct ether_header *)buf; +struct ether_arp *rarp = + (struct ether_arp *)(buf + sizeof(struct ether_header)); +struct ip *iph = (struct ip *)(buf + sizeof(struct ether_header)); +struct udp *udph = (struct udp *)(buf + sizeof(struct ether_header) + + sizeof(struct ip)); +char *tftp_r = buf + sizeof(struct ether_header) + sizeof(struct ip) + + sizeof(struct udp); +struct tftph *tftp_a = (struct tftph *)(buf + sizeof(struct ether_header) + + sizeof(struct ip) + sizeof(struct udp)); +struct tftphr *tftp = (struct tftphr *)(buf + sizeof(struct ether_header) + + sizeof(struct ip) + sizeof(struct udp)); diff --git a/sys/arch/mvme68k/stand/sboot/if_lereg.h b/sys/arch/mvme68k/stand/sboot/if_lereg.h new file mode 100644 index 0000000000000..bae9a85fbd524 --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/if_lereg.h @@ -0,0 +1,176 @@ +/* $NetBSD: if_lereg.h,v 1.1.1.1 1995/07/25 23:12:31 chuck Exp $ */ + +/*- + * Copyright (c) 1982, 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. + * + * @(#)if_lereg.h 8.2 (Berkeley) 10/30/93 + */ + +#define LEMTU 1518 +#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */ +#define LERBUF 8 +#define LERBUFLOG2 3 +#define LE_RLEN (LERBUFLOG2 << 13) +#define LETBUF 1 +#define LETBUFLOG2 0 +#define LE_TLEN (LETBUFLOG2 << 13) + +/* Local Area Network Controller for Ethernet (LANCE) registers */ +struct lereg1 { + volatile u_short ler1_rdp; /* register data port */ + volatile u_short ler1_rap; /* register address port */ +}; + +/* register addresses */ +#define LE_CSR0 0 /* Control and status register */ +#define LE_CSR1 1 /* low address of init block */ +#define LE_CSR2 2 /* high address of init block */ +#define LE_CSR3 3 /* Bus master and control */ + +/* Control and status register 0 (csr0) */ +#define LE_C0_ERR 0x8000 /* error summary */ +#define LE_C0_BABL 0x4000 /* transmitter timeout error */ +#define LE_C0_CERR 0x2000 /* collision */ +#define LE_C0_MISS 0x1000 /* missed a packet */ +#define LE_C0_MERR 0x0800 /* memory error */ +#define LE_C0_RINT 0x0400 /* receiver interrupt */ +#define LE_C0_TINT 0x0200 /* transmitter interrupt */ +#define LE_C0_IDON 0x0100 /* initalization done */ +#define LE_C0_INTR 0x0080 /* interrupt condition */ +#define LE_C0_INEA 0x0040 /* interrupt enable */ +#define LE_C0_RXON 0x0020 /* receiver on */ +#define LE_C0_TXON 0x0010 /* transmitter on */ +#define LE_C0_TDMD 0x0008 /* transmit demand */ +#define LE_C0_STOP 0x0004 /* disable all external activity */ +#define LE_C0_STRT 0x0002 /* enable external activity */ +#define LE_C0_INIT 0x0001 /* begin initalization */ + +#define LE_C0_BITS \ + "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\ +\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT" + +/* Control and status register 3 (csr3) */ +#define LE_C3_BSWP 0x4 /* byte swap */ +#define LE_C3_ACON 0x2 /* ALE control, eh? */ +#define LE_C3_BCON 0x1 /* byte control */ +/* + * Current size is 13,758 bytes with 8 x 1518 receive buffers and + * 1 x 1518 transmit buffer. + */ +struct lereg2 { + /* initialization block */ + volatile u_short ler2_mode; /* mode */ + volatile u_char ler2_padr[6]; /* physical address */ +#ifdef new_code + volatile u_short ler2_ladrf[4]; /* logical address filter */ +#else + volatile u_long ler2_ladrf0; /* logical address filter */ + volatile u_long ler2_ladrf1; /* logical address filter */ +#endif + volatile u_short ler2_rdra; /* receive descriptor addr */ + volatile u_short ler2_rlen; /* rda high and ring size */ + volatile u_short ler2_tdra; /* transmit descriptor addr */ + volatile u_short ler2_tlen; /* tda high and ring size */ + /* receive message descriptors. bits/hadr are byte order dependent. */ + struct lermd { + volatile u_short rmd0; /* low address of packet */ + volatile u_char rmd1_bits; /* descriptor bits */ + volatile u_char rmd1_hadr; /* high address of packet */ + volatile short rmd2; /* buffer byte count */ + volatile u_short rmd3; /* message byte count */ + } ler2_rmd[LERBUF]; + /* transmit message descriptors */ + struct letmd { + volatile u_short tmd0; /* low address of packet */ + volatile u_char tmd1_bits; /* descriptor bits */ + volatile u_char tmd1_hadr; /* high address of packet */ + volatile short tmd2; /* buffer byte count */ + volatile u_short tmd3; /* transmit error bits */ + } ler2_tmd[LETBUF]; + volatile char ler2_rbuf[LERBUF][LEMTU]; + volatile char ler2_tbuf[LETBUF][LEMTU]; +}; + +/* Initialzation block (mode) */ +#define LE_MODE_PROM 0x8000 /* promiscuous mode */ +/* 0x7f80 reserved, must be zero */ +#define LE_MODE_INTL 0x0040 /* internal loopback */ +#define LE_MODE_DRTY 0x0020 /* disable retry */ +#define LE_MODE_COLL 0x0010 /* force a collision */ +#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */ +#define LE_MODE_LOOP 0x0004 /* loopback mode */ +#define LE_MODE_DTX 0x0002 /* disable transmitter */ +#define LE_MODE_DRX 0x0001 /* disable receiver */ +#define LE_MODE_NORMAL 0 /* none of the above */ + + +/* Receive message descriptor 1 (rmd1_bits) */ +#define LE_R1_OWN 0x80 /* LANCE owns the packet */ +#define LE_R1_ERR 0x40 /* error summary */ +#define LE_R1_FRAM 0x20 /* framing error */ +#define LE_R1_OFLO 0x10 /* overflow error */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUFF 0x04 /* buffer error */ +#define LE_R1_STP 0x02 /* start of packet */ +#define LE_R1_ENP 0x01 /* end of packet */ + +#define LE_R1_BITS \ + "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP" + +/* Transmit message descriptor 1 (tmd1_bits) */ +#define LE_T1_OWN 0x80 /* LANCE owns the packet */ +#define LE_T1_ERR 0x40 /* error summary */ +#define LE_T1_MORE 0x10 /* multiple collisions */ +#define LE_T1_ONE 0x08 /* single collision */ +#define LE_T1_DEF 0x04 /* defferred transmit */ +#define LE_T1_STP 0x02 /* start of packet */ +#define LE_T1_ENP 0x01 /* end of packet */ + +#define LE_T1_BITS \ + "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP" + +/* Transmit message descriptor 3 (tmd3) */ +#define LE_T3_BUFF 0x8000 /* buffer error */ +#define LE_T3_UFLO 0x4000 /* underflow error */ +#define LE_T3_LCOL 0x1000 /* late collision */ +#define LE_T3_LCAR 0x0800 /* loss of carrier */ +#define LE_T3_RTRY 0x0400 /* retry error */ +#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */ + +#define LE_XMD2_ONES 0xf000 + +#define LE_T3_BITS \ + "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY" + + +#define LE_ADDR_LOW_MASK (0xffff) + diff --git a/sys/arch/mvme68k/stand/sboot/le_poll.c b/sys/arch/mvme68k/stand/sboot/le_poll.c new file mode 100644 index 0000000000000..a958b746a36eb --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/le_poll.c @@ -0,0 +1,320 @@ +/* $NetBSD: le_poll.c,v 1.1.1.1 1995/07/25 23:12:31 chuck Exp $ */ + +/* + * Copyright (c) 1993 Adam Glass + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass. + * 4. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL 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. + */ + +#include "sboot.h" +#include "if_lereg.h" + +struct { + struct lereg1 *sc_r1; /* LANCE registers */ + struct lereg2 *sc_r2; /* RAM */ + int next_rmd; + int next_tmd; +} le_softc; + +void le_error(str, ler1) + char *str; + struct lereg1 *ler1; +{ + /* ler1->ler1_rap = LE_CSRO done in caller */ + if (ler1->ler1_rdp & LE_C0_BABL) { + printf("le0: been babbling, found by '%s'\n", str); + callrom(); + } + if (ler1->ler1_rdp & LE_C0_CERR) { + ler1->ler1_rdp = LE_C0_CERR; + } + if (ler1->ler1_rdp & LE_C0_MISS) { + ler1->ler1_rdp = LE_C0_MISS; + } + if (ler1->ler1_rdp & LE_C0_MERR) { + printf("le0: memory error in '%s'\n", str); + callrom(); + } + +} + +void le_reset(myea) + u_char *myea; +{ + struct lereg1 *ler1 = le_softc.sc_r1; + struct lereg2 *ler2 = le_softc.sc_r2; + unsigned int a; + int timo = 100000, stat, i; + + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */ + + bzero(ler2, sizeof(*ler2)); + + ler2->ler2_mode = LE_MODE_NORMAL; + ler2->ler2_padr[0] = myea[1]; + ler2->ler2_padr[1] = myea[0]; + ler2->ler2_padr[2] = myea[3]; + ler2->ler2_padr[3] = myea[2]; + ler2->ler2_padr[4] = myea[5]; + ler2->ler2_padr[5] = myea[4]; + + + ler2->ler2_ladrf0 = 0; + ler2->ler2_ladrf1 = 0; + + a = (u_int)ler2->ler2_rmd; + ler2->ler2_rlen = LE_RLEN | (a >> 16); + ler2->ler2_rdra = a & LE_ADDR_LOW_MASK; + + a = (u_int)ler2->ler2_tmd; + ler2->ler2_tlen = LE_TLEN | (a >> 16); + ler2->ler2_tdra = a & LE_ADDR_LOW_MASK; + + ler1->ler1_rap = LE_CSR1; + a = (u_int)ler2; + ler1->ler1_rdp = a & LE_ADDR_LOW_MASK; + ler1->ler1_rap = LE_CSR2; + ler1->ler1_rdp = a >> 16; + + for (i = 0; i < LERBUF; i++) { + a = (u_int)&ler2->ler2_rbuf[i]; + ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK; + ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; + ler2->ler2_rmd[i].rmd1_hadr = a >> 16; + ler2->ler2_rmd[i].rmd2 = -LEMTU; + ler2->ler2_rmd[i].rmd3 = 0; + } + for (i = 0; i < LETBUF; i++) { + a = (u_int)&ler2->ler2_tbuf[i]; + ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK; + ler2->ler2_tmd[i].tmd1_bits = 0; + ler2->ler2_tmd[i].tmd1_hadr = a >> 16; + ler2->ler2_tmd[i].tmd2 = 0; + ler2->ler2_tmd[i].tmd3 = 0; + } + + ler1->ler1_rap = LE_CSR3; + ler1->ler1_rdp = LE_C3_BSWP; + + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_INIT; + do { + if (--timo == 0) { + printf("le0: init timeout, stat = 0x%x\n", stat); + break; + } + stat = ler1->ler1_rdp; + } while ((stat & LE_C0_IDON) == 0); + + ler1->ler1_rdp = LE_C0_IDON; + le_softc.next_rmd = 0; + le_softc.next_tmd = 0; + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STRT; +} + +int le_poll(pkt, len) + void *pkt; + int len; +{ + struct lereg1 *ler1 = le_softc.sc_r1; + struct lereg2 *ler2 = le_softc.sc_r2; + unsigned int a; + int length; + struct lermd *rmd; + + ler1->ler1_rap = LE_CSR0; + if ((ler1->ler1_rdp & LE_C0_RINT) != 0) + ler1->ler1_rdp = LE_C0_RINT; + rmd = &ler2->ler2_rmd[le_softc.next_rmd]; + if (rmd->rmd1_bits & LE_R1_OWN) { + return(0); + } + if (ler1->ler1_rdp & LE_C0_ERR) + le_error("le_poll", ler1); + if (rmd->rmd1_bits & LE_R1_ERR) { + printf("le0_poll: rmd status 0x%x\n", rmd->rmd1_bits); + length = 0; + goto cleanup; + } + if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != (LE_R1_STP|LE_R1_ENP)) { + printf("le_poll: chained packet\n"); + callrom(); + } + + length = rmd->rmd3; + if (length >= LEMTU) { + length = 0; + printf("csr0 when bad things happen: %x\n", ler1->ler1_rdp); + callrom(); + goto cleanup; + } + if (!length) goto cleanup; + length -= 4; + if (length > 0) + bcopy((char *)&ler2->ler2_rbuf[le_softc.next_rmd], pkt, length); + + cleanup: + a = (u_int)&ler2->ler2_rbuf[le_softc.next_rmd]; + rmd->rmd0 = a & LE_ADDR_LOW_MASK; + rmd->rmd1_hadr = a >> 16; + rmd->rmd2 = -LEMTU; + le_softc.next_rmd = + (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1); + rmd->rmd1_bits = LE_R1_OWN; + return length; +} + +int le_put(pkt, len) + u_char *pkt; + size_t len; +{ + struct lereg1 *ler1 = le_softc.sc_r1; + struct lereg2 *ler2 = le_softc.sc_r2; + struct letmd *tmd; + int timo = 100000, stat, i; + unsigned int a; + + ler1->ler1_rap = LE_CSR0; + if (ler1->ler1_rdp & LE_C0_ERR) + le_error("le_put(way before xmit)", ler1); + tmd = &ler2->ler2_tmd[le_softc.next_tmd]; + while(tmd->tmd1_bits & LE_T1_OWN) { + printf("le0: output buffer busy\n"); + } + bcopy(pkt, (char *)ler2->ler2_tbuf[le_softc.next_tmd], len); + if (len < 64) + tmd->tmd2 = -64; + else + tmd->tmd2 = -len; + tmd->tmd3 = 0; + if (ler1->ler1_rdp & LE_C0_ERR) + le_error("le_put(before xmit)", ler1); + tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN; + a = (u_int)&ler2->ler2_tbuf[le_softc.next_tmd]; + tmd->tmd0 = a & LE_ADDR_LOW_MASK; + tmd->tmd1_hadr = a >> 16; + ler1->ler1_rdp = LE_C0_TDMD; + if (ler1->ler1_rdp & LE_C0_ERR) + le_error("le_put(after xmit)", ler1); + do { + if (--timo == 0) { + printf("le0: transmit timeout, stat = 0x%x\n", + stat); + if (ler1->ler1_rdp & LE_C0_ERR) + le_error("le_put(timeout)", ler1); + break; + } + stat = ler1->ler1_rdp; + } while ((stat & LE_C0_TINT) == 0); + ler1->ler1_rdp = LE_C0_TINT; + if (ler1->ler1_rdp & LE_C0_ERR) { + if ((ler1->ler1_rdp & (LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR)) != + LE_C0_CERR) + printf("le_put: xmit error, buf %d\n", le_softc.next_tmd); + le_error("le_put(xmit error)", ler1); + } + le_softc.next_tmd = 0; +/* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/ + if (tmd->tmd1_bits & LE_T1_ERR) { + printf("le0: transmit error, error = 0x%x\n", + tmd->tmd3); + return -1; + } + return len; +} + +int le_get(pkt, len, timeout) + u_char *pkt; + size_t len; + u_long timeout; +{ + int cc; + int now, then; + int stopat = time() + timeout; + then = 0; + + cc = 0; + while ((now = time()) < stopat && !cc) { + cc = le_poll(pkt, len); + if (then != now) { +#ifdef LE_DEBUG + printf("%d \r", stopat - now); +#endif + then = now; + } + if (cc && (pkt[0] != myea[0] || pkt[1] != myea[1] || + pkt[2] != myea[2] || pkt[3] != myea[3] || + pkt[4] != myea[4] || pkt[5] != myea[5])) { + cc = 0; /* ignore broadcast / multicast */ +#ifdef LE_DEBUG + printf("reject (%d sec left)\n", stopat - now); +#endif + } + } +#ifdef LE_DEBUG + printf("\n"); +#endif + return cc; +} + +void le_init() +{ + caddr_t addr; + int *ea = (int *) LANCE_ADDR; + u_long *eram = (u_long *) ERAM_ADDR; + u_long e = *ea; + if (( e & 0x2fffff00 ) == 0x2fffff00) { + printf("ERROR: ethernet address not set! Use LSAD.\n"); + callrom(); + } + myea[0] = 0x08; + myea[1] = 0x00; + myea[2] = 0x3e; + e = e >> 8; + myea[5] = e & 0xff; + e = e >> 8; + myea[4] = e & 0xff; + e = e >> 8; + myea[3] = e; + printf("le0: ethernet address: %x:%x:%x:%x:%x:%x\n", + myea[0], myea[1], myea[2], myea[3], myea[4], myea[5]); + bzero(&le_softc, sizeof(le_softc)); + le_softc.sc_r1 = (struct lereg1 *) LANCE_REG_ADDR; + le_softc.sc_r2 = (struct lereg2 *)(*eram - (1024*1024)); + le_reset(myea); +} + +void le_end() +{ + struct lereg1 *ler1 = le_softc.sc_r1; + + ler1->ler1_rap = LE_CSR0; + ler1->ler1_rdp = LE_C0_STOP; +} diff --git a/sys/arch/mvme68k/stand/sboot/libc_sa.c b/sys/arch/mvme68k/stand/sboot/libc_sa.c new file mode 100644 index 0000000000000..5a178ad2930b1 --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/libc_sa.c @@ -0,0 +1,348 @@ +/* $NetBSD: libc_sa.c,v 1.1.1.1 1995/07/25 23:12:33 chuck Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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. + */ + +#include "sboot.h" + +/* + * sizeof(word) MUST BE A POWER OF TWO + * SO THAT wmask BELOW IS ALL ONES + */ +typedef int word; /* "word" used for optimal copy speed */ + +#define wsize sizeof(word) +#define wmask (wsize - 1) + +/* + * Copy a block of memory, handling overlap. + * This is the routine that actually implements + * (the portable versions of) bcopy, memcpy, and memmove. + */ +void +bcopy(src0, dst0, length) + void *dst0; + const void *src0; + register size_t length; +{ + register char *dst = dst0; + register const char *src = src0; + register size_t t; + + if (length == 0 || dst == src) /* nothing to do */ + goto done; + + /* + * Macros: loop-t-times; and loop-t-times, t>0 + */ +#define TLOOP(s) if (t) TLOOP1(s) +#define TLOOP1(s) do { s; } while (--t) + + if ((unsigned long)dst < (unsigned long)src) { + /* + * Copy forward. + */ + t = (long)src; /* only need low bits */ + if ((t | (long)dst) & wmask) { + /* + * Try to align operands. This cannot be done + * unless the low bits match. + */ + if ((t ^ (long)dst) & wmask || length < wsize) + t = length; + else + t = wsize - (t & wmask); + length -= t; + TLOOP1(*dst++ = *src++); + } + /* + * Copy whole words, then mop up any trailing bytes. + */ + t = length / wsize; + TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize); + t = length & wmask; + TLOOP(*dst++ = *src++); + } else { + /* + * Copy backwards. Otherwise essentially the same. + * Alignment works as before, except that it takes + * (t&wmask) bytes to align, not wsize-(t&wmask). + */ + src += length; + dst += length; + t = (long)src; + if ((t | (long)dst) & wmask) { + if ((t ^ (long)dst) & wmask || length <= wsize) + t = length; + else + t &= wmask; + length -= t; + TLOOP1(*--dst = *--src); + } + t = length / wsize; + TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src); + t = length & wmask; + TLOOP(*--dst = *--src); + } +done: + return; +} + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * 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. + */ + +void * +bzero(dst, n) + void *dst; + register size_t n; +{ + + if (n != 0) { + register char *d = dst; + + do + *d++ = 0; + while (--n != 0); + } + return (dst); +} +/* $NetBSD: libc_sa.c,v 1.1.1.1 1995/07/25 23:12:33 chuck 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. + * + * @(#)printf.c 5.6 (Berkeley) 5/25/91 + */ + +/* + * Scaled down version of printf(3). + * + * One additional format: + * + * The format %b is supported to decode error registers. + * Its usage is: + * + * printf("reg=%b\n", regval, "*"); + * + * where is the output base expressed as a control character, e.g. + * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, + * the first of which gives the bit number to be inspected (origin 1), and + * the next characters (up to a control character, i.e. a character <= 32), + * give the name of the register. Thus: + * + * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * + * would produce output: + * + * reg=3 + */ + +/* + * Note that stdarg.h and the ANSI style va_start macro is used for both + * ANSI and traditional C compilers. + */ +#define _KERNEL +#include +#undef _KERNEL + +static void +kprintn(ul, base) + unsigned long ul; + int base; +{ + /* hold a long in base 8 */ + char *p, buf[(sizeof(long) * 8 / 3) + 1]; + + p = buf; + do { + *p++ = "0123456789abcdef"[ul % base]; + } while (ul /= base); + do { + putchar(*--p); + } while (p > buf); +} + +void +#if __STDC__ +printf(const char *fmt, ...) +#else +printf(fmt /* , va_alist */) + char *fmt; +#endif +{ + register char *p; + register int ch, n; + unsigned long ul; + int lflag, set; + va_list ap; + + va_start(ap, fmt); + for (;;) { + while ((ch = *fmt++) != '%') { + if (ch == '\0') + return; + putchar(ch); + } + lflag = 0; +reswitch: switch (ch = *fmt++) { + case 'l': + lflag = 1; + goto reswitch; + case 'b': + ul = va_arg(ap, int); + p = va_arg(ap, char *); + kprintn(ul, *p++); + + if (!ul) + break; + + for (set = 0; n = *p++;) { + if (ul & (1 << (n - 1))) { + putchar(set ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + putchar(n); + set = 1; + } else + for (; *p > ' '; ++p); + } + if (set) + putchar('>'); + break; + case 'c': + ch = va_arg(ap, int); + putchar(ch & 0x7f); + break; + case 's': + p = va_arg(ap, char *); + while (ch = *p++) + putchar(ch); + break; + case 'd': + ul = lflag ? + va_arg(ap, long) : va_arg(ap, int); + if ((long)ul < 0) { + putchar('-'); + ul = -(long)ul; + } + kprintn(ul, 10); + break; + case 'o': + ul = lflag ? + va_arg(ap, u_long) : va_arg(ap, u_int); + kprintn(ul, 8); + break; + case 'u': + ul = lflag ? + va_arg(ap, u_long) : va_arg(ap, u_int); + kprintn(ul, 10); + break; + case 'x': + ul = lflag ? + va_arg(ap, u_long) : va_arg(ap, u_int); + kprintn(ul, 16); + break; + default: + putchar('%'); + if (lflag) + putchar('l'); + putchar(ch); + } + } + va_end(ap); +} + diff --git a/sys/arch/mvme68k/stand/sboot/oc_cksum.s b/sys/arch/mvme68k/stand/sboot/oc_cksum.s new file mode 100644 index 0000000000000..3718a0c48687a --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/oc_cksum.s @@ -0,0 +1,187 @@ +| $NetBSD: oc_cksum.s,v 1.1.1.1 1995/07/25 23:12:31 chuck Exp $ + +| Copyright (c) 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. +| +| @(#)oc_cksum.s 7.2 (Berkeley) 11/3/90 +| +| +| oc_cksum: ones complement 16 bit checksum for MC68020. +| +| 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). +| +| It simplifies life in in_cksum if strtval can be >= 2^16. +| This routine will work as long as strtval is < 2^31. +| +| Performance +| ----------- +| This routine is intended for MC 68020s but should also work +| for 68030s. It (deliberately) doesn't worry about the alignment +| of the buffer so will only work on a 68010 if the buffer is +| aligned on an even address. (Also, a routine written to use +| 68010 "loop mode" would almost certainly be faster than this +| code on a 68010). +| +| We don't worry about alignment because this routine is frequently +| called with small counts: 20 bytes for IP header checksums and 40 +| bytes for TCP ack checksums. For these small counts, testing for +| bad alignment adds ~10% to the per-call cost. Since, by the nature +| of the kernel's allocator, the data we're called with is almost +| always longword aligned, there is no benefit to this added cost +| and we're better off letting the loop take a big performance hit +| in the rare cases where we're handed an unaligned buffer. +| +| Loop unrolling constants of 2, 4, 8, 16, 32 and 64 times were +| tested on random data on four different types of processors (see +| list below -- 64 was the largest unrolling because anything more +| overflows the 68020 Icache). On all the processors, the +| throughput asymptote was located between 8 and 16 (closer to 8). +| However, 16 was substantially better than 8 for small counts. +| (It's clear why this happens for a count of 40: unroll-8 pays a +| loop branch cost and unroll-16 doesn't. But the tests also showed +| that 16 was better than 8 for a count of 20. It's not obvious to +| me why.) So, since 16 was good for both large and small counts, +| the loop below is unrolled 16 times. +| +| The processors tested and their average time to checksum 1024 bytes +| of random data were: +| Sun 3/50 (15MHz) 190 us/KB +| Sun 3/180 (16.6MHz) 175 us/KB +| Sun 3/60 (20MHz) 134 us/KB +| Sun 3/280 (25MHz) 95 us/KB +| +| The cost of calling this routine was typically 10% of the per- +| kilobyte cost. E.g., checksumming zero bytes on a 3/60 cost 9us +| and each additional byte cost 125ns. With the high fixed cost, +| it would clearly be a gain to "inline" this routine -- the +| subroutine call adds 400% overhead to an IP header checksum. +| However, in absolute terms, inlining would only gain 10us per +| packet -- a 1% effect for a 1ms ethernet packet. This is not +| enough gain to be worth the effort. + +#include + + .text + + .text; .even; .globl _oc_cksum; _oc_cksum: + movl sp@(4),a0 | get buffer ptr + movl sp@(8),d1 | get byte count + movl sp@(12),d0 | get starting value + movl d2,sp@- | free a reg + + | test for possible 1, 2 or 3 bytes of excess at end + | of buffer. The usual case is no excess (the usual + | case is header checksums) so we give that the faster + | 'not taken' leg of the compare. (We do the excess + | first because we're about the trash the low order + | bits of the count in d1.) + + btst #0,d1 + jne L5 | if one or three bytes excess + btst #1,d1 + jne L7 | if two bytes excess +L1: + movl d1,d2 + lsrl #6,d1 | make cnt into # of 64 byte chunks + andl #0x3c,d2 | then find fractions of a chunk + negl d2 + andb #0xf,cc | clear X + jmp pc@(L3-.-2:b,d2) +L2: + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 + movl a0@+,d2 + addxl d2,d0 +L3: + dbra d1,L2 | (NB- dbra doesn't affect X) + + movl d0,d1 | fold 32 bit sum to 16 bits + swap d1 | (NB- swap doesn't affect X) + addxw d1,d0 + jcc L4 + addw #1,d0 +L4: + andl #0xffff,d0 + movl sp@+,d2 + rts + +L5: | deal with 1 or 3 excess bytes at the end of the buffer. + btst #1,d1 + jeq L6 | if 1 excess + + | 3 bytes excess + clrl d2 + movw a0@(-3,d1:l),d2 | add in last full word then drop + addl d2,d0 | through to pick up last byte + +L6: | 1 byte excess + clrl d2 + movb a0@(-1,d1:l),d2 + lsll #8,d2 + addl d2,d0 + jra L1 + +L7: | 2 bytes excess + clrl d2 + movw a0@(-2,d1:l),d2 + addl d2,d0 + jra L1 diff --git a/sys/arch/mvme68k/stand/sboot/sboot.c b/sys/arch/mvme68k/stand/sboot/sboot.c new file mode 100644 index 0000000000000..3a8d1bf8a3468 --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/sboot.c @@ -0,0 +1,150 @@ +/* + * + * Copyright (c) 1995 Charles D. Cranor and Seth Widoff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor + * and Seth Widoff. + * 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. + */ +/* + * main driver, plus machdep stuff + */ + +#include "sboot.h" + +void sboot() + +{ + char * mesg; + char buf[128]; + buf[0] = '0'; + consinit(); + printf("\nsboot: serial line bootstrap program (&end = %x)\n\n", &end); + if (reboot) { /* global flag from AAstart.s */ + reboot = 0; + printf("[rebooting...]\n"); + do_cmd("b"); + } + while (1) { + printf(">>> "); + ngets(buf, sizeof(buf)); + do_cmd(buf); + } + /* not reached */ +} + +/* + * exit to rom + */ + +void callrom () +{ + asm("trap #15; .word 0x0063"); +} + +/* + * do_cmd: do a command + */ + +void do_cmd(buf) + +char *buf; + +{ + switch (*buf) { + case '\0': + return; + case 'a': + if ( rev_arp() ) { + printf ("My ip address is: %d.%d.%d.%d\n", myip[0], + myip[1], myip[2], myip[3]); + printf ("Server ip address is: %d.%d.%d.%d\n", servip[0], + servip[1], servip[2], servip[3]); + } else { + printf ("Failed.\n"); + } + return; + case 'e': + printf("exiting to ROM\n"); + callrom(); + return; + case 'f': + if (do_get_file() == 1) { + printf("Download Failed\n"); + } else { + printf("Download was a success!\n"); + } + return; + case 'b': + le_init(); + if ( rev_arp() ) { + printf ("My ip address is: %d.%d.%d.%d\n", myip[0], + myip[1], myip[2], myip[3]); + printf ("Server ip address is: %d.%d.%d.%d\n", servip[0], + servip[1], servip[2], servip[3]); + } else { + printf ("REVARP: Failed.\n"); + return; + } + if (do_get_file() == 1) { + printf("Download Failed\n"); + return; + } else { + printf("Download was a success!\n"); + } + go(buf); + return; + case 'h': + case '?': + printf("valid commands\n"); + printf("a - send a RARP\n"); + printf("b - boot the system\n"); + printf("e - exit to ROM\n"); + printf("f - ftp the boot file\n"); + printf("g - execute the boot file\n"); + printf("h - help\n"); + printf("i - init LANCE enet chip\n"); + return; + case 'i': + le_init(); + return; + case 'g': + go(buf); + return; + default: + printf("sboot: %s: Unknown command\n", buf); + } +} + +go(buf) +char *buf; + +{ + void (*entry)() = (void (*)) LOAD_ADDR ; + printf("Start @ 0x%x ... \n", entry); + (*entry)(buf); +} + diff --git a/sys/arch/mvme68k/stand/sboot/sboot.h b/sys/arch/mvme68k/stand/sboot/sboot.h new file mode 100644 index 0000000000000..01085b17b9064 --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/sboot.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 1995 Charles D. Cranor and Seth Widoff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor + * and Seth Widoff. + * 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. + */ + +/* + * sboot.h: stuff for MVME147's serial line boot + */ + +typedef unsigned short u_short; +typedef unsigned long u_long; +typedef unsigned char u_char; +typedef unsigned int u_int; +typedef u_long size_t; +typedef char *caddr_t; +extern caddr_t end; + +#define NULL ((char *)0) + +void bcopy(const void *, void *, size_t); /* libc_sa */ +void *memset(void *, int, size_t); /* libc_sa */ +void printf(const char *, ...); /* libc_sa */ + +/* console */ +void puts(char *); +void putchar(char); +char cngetc(); +void ngets(char *, int); + +/* sboot */ +void callrom(); +void do_cmd(char *); + +/* le */ +#define LANCE_ADDR 0xfffe0778 +#define ERAM_ADDR 0xfffe0774 +#define LANCE_REG_ADDR 0xfffe1800 +void le_end(void); +void le_init(void); +int le_get(u_char *, size_t, u_long); +int le_put(u_char *, size_t); + +/* etherfun */ +#define READ 0 +#define ACKN 1 +void do_rev_arp(); +int get_rev_arp(); +int rev_arp(); +void do_send_tftp( int ); +int do_get_file(); +void tftp_file(char *, u_long); + +/* clock */ +u_long time(void); + +/* checksum */ +u_long oc_cksum (void *, u_long, u_long); + +#define CONS_ZS_ADDR (0xfffe3002) +#define CLOCK_ADDR (0xfffe07f8) +#define LOAD_ADDR 0x8000 + +unsigned char myea[6]; /* my ether addr */ +unsigned char myip[4]; +unsigned char servip[4]; +unsigned char servea[6]; +u_short myport; +u_short servport; +unsigned char reboot; diff --git a/sys/arch/mvme68k/stand/sboot/start.s b/sys/arch/mvme68k/stand/sboot/start.s new file mode 100644 index 0000000000000..d878f94ea2347 --- /dev/null +++ b/sys/arch/mvme68k/stand/sboot/start.s @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 1995 Charles D. Cranor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles D. Cranor. + * 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. + */ +/* + * start: at address 0x4000, load at 0xa000 (so put stack at 0x9ff0) + * note this file is named "AAstart" so that it gets linked FIRST + */ + +.text +.globl start +start: + movb #0,_reboot + jra Ldoit +restart: + movb #1,_reboot | fall through + +Ldoit: + movl #0x00006ff0,sp + jsr _sboot +