diff -u --recursive --new-file v1.3.43/linux/Documentation/cdrom/aztcd linux/Documentation/cdrom/aztcd --- v1.3.43/linux/Documentation/cdrom/aztcd Sun Oct 29 11:38:47 1995 +++ linux/Documentation/cdrom/aztcd Sat Nov 25 17:28:41 1995 @@ -1,9 +1,9 @@ -$Id: README.aztcd,v 1.90 1995/10/21 17:52:16 root Exp root $ - Readme-File README.aztcd +$Id: README.aztcd,v 2.0 1995/11/10 19:37:18 root Exp root $ + Readme-File /usr/src/Documentation/cdrom/aztcd for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110, Conrad TXC CD-ROM Driver - Version 1.9 and newer + Version 2.0 and newer (for other drives see 6.-8.) NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE @@ -53,7 +53,7 @@ 2. INSTALLATION The driver consists of a header file 'aztcd.h', which normally should reside in /usr/include/linux and the source code 'aztcd.c', which normally resides in -/usr/src/linux/drivers/block. It uses /dev/aztcd (/dev/aztcd0 in some distri- +/usr/src/linux/drivers/cdrom. It uses /dev/aztcd (/dev/aztcd0 in some distri- butions), which must be a valid block device with major number 29 and reside in directory /dev. To mount a CD-ROM, your kernel needs to have the ISO9660- filesystem support included. @@ -163,7 +163,7 @@ insmod /lib/modules/X.X.X/fs/isofs.o The mount procedure works as described in 4. above. (In all commands 'X.X.X' is the current linux kernel version number. For details -see file README.modules in /usr/src/linux.) +see file modules.txt in /usr/src/linux/Documentation) 4.2 CDROM CONNECTED TO A SOUNDCARD Most soundcards do have a bus interface to the CDROM-drive. In many cases @@ -460,7 +460,7 @@ Reinhard Max delivered the information for the CDROM-interface of the SoundWave32 soundcards. -Jochen Koch and Olaf ? delivered the information for supporting Conrad's TXC +Jochen Koch and Olaf Koluza delivered the information for supporting Conrad's TXC drive. Anybody, who is interested in these items should have a look at 'ftp.gwdg.de', diff -u --recursive --new-file v1.3.43/linux/MAGIC linux/MAGIC --- v1.3.43/linux/MAGIC Mon Oct 23 18:02:00 1995 +++ linux/MAGIC Sat Nov 25 17:29:47 1995 @@ -85,6 +85,7 @@ 'T' asm/termios.h conflict! 'V' linux/vt.h 'Y' linux/cyclades.h codes in 0x004359NN +'a' various, see http://lrcwww.epfl.ch/linux-atm/magic.html 'f' linux/ext2_fs.h 'm' linux/mtio.h conflict! 'm' linux/soundcard.h conflict! diff -u --recursive --new-file v1.3.43/linux/Makefile linux/Makefile --- v1.3.43/linux/Makefile Tue Nov 21 13:22:04 1995 +++ linux/Makefile Fri Nov 24 07:17:26 1995 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 43 +SUBLEVEL = 44 ARCH = i386 @@ -282,7 +282,7 @@ mrproper: clean rm -f include/linux/autoconf.h include/linux/version.h - rm -f drivers/sound/local.h + rm -f drivers/sound/local.h drivers/sound/.defines rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash rm -f .version .config* config.in config.old diff -u --recursive --new-file v1.3.43/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v1.3.43/linux/arch/alpha/defconfig Mon Nov 13 12:36:42 1995 +++ linux/arch/alpha/defconfig Thu Nov 23 11:26:03 1995 @@ -58,7 +58,7 @@ # # CONFIG_INET_PCTCP is not set # CONFIG_INET_RARP is not set -CONFIG_INET_SNARL=y +# CONFIG_NO_PATH_MTU_DISCOVERY is not set # CONFIG_TCP_NAGLE_OFF is not set CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y @@ -128,7 +128,6 @@ CONFIG_NET_EISA=y # CONFIG_APRICOT is not set CONFIG_DE4X5=y -# CONFIG_ETH16 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_TR is not set diff -u --recursive --new-file v1.3.43/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v1.3.43/linux/arch/i386/kernel/entry.S Tue Nov 21 13:22:05 1995 +++ linux/arch/i386/kernel/entry.S Fri Nov 24 16:13:59 1995 @@ -656,7 +656,7 @@ .long SYMBOL_NAME(sys_msync) .long SYMBOL_NAME(sys_readv) /* 145 */ .long SYMBOL_NAME(sys_writev) - .long 0 + .long SYMBOL_NAME(sys_getsid) .long 0 .long 0 .long SYMBOL_NAME(sys_mlock) /* 150 */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v1.3.43/linux/arch/sparc/Makefile Tue Jun 27 14:11:30 1995 +++ linux/arch/sparc/Makefile Sat Nov 25 02:57:32 1995 @@ -1,4 +1,4 @@ -# +# $Id: Makefile,v 1.6 1995/11/25 00:57:30 davem Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -7,21 +7,19 @@ # Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) # - # If the solaris /bin/sh wasn't so broken, I wouldn't need the following # line... SHELL =/bin/bash # -# How to link, we send the linker the address at which the text section -# is to start. The prom loads us at 0x0-kernel_size. There is also an -# alias of this address space at 0xf8000000-(0xf8000000+kernel_size) but -# I ignore it and eliminate those mappings during vm initialization and -# just leave the low mapping. -# -LINKFLAGS = -N -Ttext 0xf0004000 +# Uncomment the first CFLAGS if you are doing kgdb source level +# debugging of the kernel to get the proper debugging information. + +#CFLAGS := $(CFLAGS) -g -pipe CFLAGS := $(CFLAGS) -pipe +LINKFLAGS = -N -Ttext 0xf0004000 + HEAD := arch/sparc/kernel/head.o SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm \ @@ -29,13 +27,11 @@ ARCHIVES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(ARCHIVES) +LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ + $(TOPDIR)/arch/sparc/lib/lib.a + aoutimage: vmlinux elftoaout -o aoutimage vmlinux - - -LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/lib/lib.a \ - $(TOPDIR)/arch/sparc/prom/promlib.a - archclean: rm -f $(TOPDIR)/arch/sparc/boot/boot diff -u --recursive --new-file v1.3.43/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile --- v1.3.43/linux/arch/sparc/boot/Makefile Tue Aug 15 20:39:00 1995 +++ linux/arch/sparc/boot/Makefile Sat Nov 25 02:57:38 1995 @@ -1,3 +1,4 @@ +# $Id: Makefile,v 1.2 1995/11/25 00:57:37 davem Exp $ # Makefile for the Sparc low level /boot module. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -18,5 +19,3 @@ dep: $(CPP) -M *.c > .depend $(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend - -include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.43/linux/arch/sparc/boot/bare.S linux/arch/sparc/boot/bare.S --- v1.3.43/linux/arch/sparc/boot/bare.S Tue Jun 27 14:11:30 1995 +++ linux/arch/sparc/boot/bare.S Sat Nov 25 02:57:40 1995 @@ -1,4 +1,5 @@ -/* base.S: Ugly low-level boot program entry code. The job of this +/* $Id: bare.S,v 1.2 1995/11/25 00:57:39 davem Exp $ + * base.S: Ugly low-level boot program entry code. The job of this * module is to parse the boot flags, try to mount the remote * root filesystem and load the kernel into virtual memory. * @@ -6,6 +7,7 @@ */ #include "bare.h" +#include .data .globl C_LABEL(romvec) @@ -49,7 +51,7 @@ start_of_execution: sethi %hi(C_LABEL(first_adr_in_text)), %o1 ! This is our top or %o1, %lo(C_LABEL(first_adr_in_text)), %o1 ! of stack too. - sub %o1, C_STACK, %o1 + sub %o1, STACKFRAME_SZ, %o1 add %o1, 0x7, %o1 andn %o1, 0x7, %o1 save %o1, 0x0, %sp ! save is an add diff -u --recursive --new-file v1.3.43/linux/arch/sparc/boot/bare.h linux/arch/sparc/boot/bare.h --- v1.3.43/linux/arch/sparc/boot/bare.h Tue Jun 27 14:11:30 1995 +++ linux/arch/sparc/boot/bare.h Sat Nov 25 02:57:42 1995 @@ -1,4 +1,5 @@ -/* bare.h: Defines for the low level entry code of the BOOT program. +/* $Id: bare.h,v 1.2 1995/11/25 00:57:41 davem Exp $ + * bare.h: Defines for the low level entry code of the BOOT program. * We include in the head.h stuff that the real kernel uses * and this saves a lot of repetition here. * diff -u --recursive --new-file v1.3.43/linux/arch/sparc/boot/imperical.h linux/arch/sparc/boot/imperical.h --- v1.3.43/linux/arch/sparc/boot/imperical.h Tue Jun 27 14:11:30 1995 +++ linux/arch/sparc/boot/imperical.h Sat Nov 25 02:57:44 1995 @@ -1,4 +1,5 @@ -/* imperical.h: Nasty hacks.... +/* $Id: imperical.h,v 1.2 1995/11/25 00:57:42 davem Exp $ + * imperical.h: Nasty hacks.... * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/boot/init_me.c linux/arch/sparc/boot/init_me.c --- v1.3.43/linux/arch/sparc/boot/init_me.c Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/boot/init_me.c Sat Nov 25 02:57:45 1995 @@ -1,4 +1,5 @@ -/* init_me.c: Initialize imperical constants and gather some info from +/* $Id: init_me.c,v 1.2 1995/11/25 00:57:44 davem Exp $ + * init_me.c: Initialize imperical constants and gather some info from * the boot prom. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v1.3.43/linux/arch/sparc/config.in Mon Oct 16 18:38:21 1995 +++ linux/arch/sparc/config.in Sat Nov 25 02:57:34 1995 @@ -1,134 +1,54 @@ -# -# arch/sparc/config.in -# -# Bare minimum configuration file for the Sparc. -# -# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) -# +# $Id: config.in,v 1.5 1995/11/25 00:57:32 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # -mainmenu_name 'Sparc Linux Kernel Configuration' - -echo "#define CONFIG_SPARCDEVS 1" >> $CONFIG_H -echo "CONFIG_SPARCDEVS=y" >> $CONFIG +mainmenu_name "Kernel configuration of Linux for SparcStations" mainmenu_option next_comment -comment 'Sparc Kernel setup' +comment 'General setup' -bool 'Sun floppy controller support' CONFIG_BLK_DEV_SUNFD n -bool 'Networking support' CONFIG_NET n -bool 'Limit memory to low 16MB' CONFIG_MAX_16M n -bool 'System V IPC' CONFIG_SYSVIPC y -bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y +# Global things across all Sparc machines. +define_bool CONFIG_SBUS y +define_bool CONFIG_SUN_MOUSE y +define_bool CONFIG_SUN_SERIAL y +define_bool CONFIG_SUN_KEYBOARD y +define_bool CONFIG_SUN_CONSOLE y + +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF + +source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then -mainmenu_option next_comment -comment 'Networking options' -bool 'TCP/IP networking' CONFIG_INET y -if [ "$CONFIG_INET" "=" "y" ]; then -bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n -bool 'IP multicasting (ALPHA)' CONFIG_IP_MULTICAST n -bool 'IP firewalling' CONFIG_IP_FIREWALL n -bool 'IP accounting' CONFIG_IP_ACCT n -comment '(it is safe to leave these untouched)' -bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n -bool 'Reverse ARP' CONFIG_INET_RARP n -bool 'Assume subnets are local' CONFIG_INET_SNARL y -bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n -fi -bool 'The IPX protocol' CONFIG_IPX n -#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n + source net/Config.in fi mainmenu_option next_comment comment 'SCSI support' -bool 'SCSI support?' CONFIG_SCSI n - -if [ "$CONFIG_SCSI" = "n" ]; then - -comment 'Skipping SCSI configuration options...' - -else - -comment 'SCSI support type (disk, tape, CDrom)' - -bool 'SCSI disk support' CONFIG_BLK_DEV_SD y -bool 'SCSI tape support' CONFIG_CHR_DEV_ST n -bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR n -bool 'SCSI generic support' CONFIG_CHR_DEV_SG n - -comment 'SCSI low-level drivers' - -bool 'Sun ESP Scsi support' CONFIG_SCSI_SUN_ESP n +tristate 'SCSI support' CONFIG_SCSI +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in fi - if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' -mainmenu_option next_comment -comment 'Network device support' - -bool 'Network device support?' CONFIG_NETDEVICES y -if [ "$CONFIG_NETDEVICES" = "n" ]; then - -comment 'Skipping network driver configuration options...' - -else -bool 'Dummy net driver support' CONFIG_DUMMY n -bool 'SLIP (serial line) support' CONFIG_SLIP n -if [ "$CONFIG_SLIP" = "y" ]; then - bool ' CSLIP compressed headers' SL_COMPRESSED y -# bool ' SLIP debugging on' SL_DUMP y -fi -bool 'PPP (point-to-point) support' CONFIG_PPP n -bool 'PLIP (parallel port) support' CONFIG_PLIP n -bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n -bool 'Sun LANCE Ethernet support' CONFIG_SUN_LANCE n -bool 'Sun Intel Ethernet support' CONFIG_SUN_INTEL n -fi + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + fi fi -mainmenu_option next_comment -comment 'Filesystems' - -bool 'Standard (minix) fs support' CONFIG_MINIX_FS n -bool 'Extended fs support' CONFIG_EXT_FS n -bool 'Second extended fs support' CONFIG_EXT2_FS y -bool 'xiafs filesystem support' CONFIG_XIA_FS n -bool 'msdos fs support' CONFIG_MSDOS_FS n -bool '/proc filesystem support' CONFIG_PROC_FS n -if [ "$CONFIG_INET" = "y" ]; then -bool 'NFS filesystem support' CONFIG_NFS_FS n -fi -if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then - bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n -else - bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n -fi -bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n -bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n - - -mainmenu_option next_comment -comment 'character devices' - -bool 'Zilog serial support' CONFIG_SUN_ZS n - -comment 'Sound' - -bool 'Sun Audio support' CONFIG_SUN_AUDIO n +source fs/Config.in mainmenu_option next_comment comment 'Kernel hacking' -bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n -bool 'Kernel profiling support' CONFIG_PROFILE n +bool 'Kernel profiling support' CONFIG_PROFILE if [ "$CONFIG_PROFILE" = "y" ]; then - int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 -fi -if [ "$CONFIG_SCSI" = "y" ]; then -bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y + int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi diff -u --recursive --new-file v1.3.43/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v1.3.43/linux/arch/sparc/defconfig Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/defconfig Tue Nov 21 12:23:18 1995 @@ -0,0 +1,98 @@ +# +# Automatically generated make config: don't edit +# + +# +# General setup +# +CONFIG_SBUS=y +CONFIG_SUN_MOUSE=y +CONFIG_SUN_SERIAL=y +CONFIG_SUN_KEYBOARD=y +CONFIG_SUN_CONSOLE=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BINFMT_ELF is not set + +# +# block devices +# +# CONFIG_BLK_DEV_FD is not set + +# +# Networking options +# +# CONFIG_FIREWALL is not set +CONFIG_INET=y +# CONFIG_IP_FORWARD is not set +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ACCT is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_INET_PCTCP is not set +# CONFIG_INET_RARP is not set +# CONFIG_NO_PATH_MTU_DISCOVERY is not set +# CONFIG_TCP_NAGLE_OFF is not set +CONFIG_IP_NOSR=y +# CONFIG_SKB_LARGE is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_AX25 is not set +# CONFIG_NETLINK is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CDrom) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y + +# +# SCSI low-level drivers +# +CONFIG_SCSI_SUNESP=y + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +# CONFIG_SLIP is not set +# CONFIG_PPP is not set +CONFIG_SUNLANCE=y + +# +# Filesystems +# +# CONFIG_MINIX_FS is not set +# CONFIG_EXT_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_XIA_FS is not set +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_ISO9660_FS=y +# CONFIG_HPFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SMB_FS is not set + +# +# Kernel hacking +# +# CONFIG_PROFILE is not set diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v1.3.43/linux/arch/sparc/kernel/Makefile Tue Aug 15 20:39:00 1995 +++ linux/arch/sparc/kernel/Makefile Sat Nov 25 02:57:50 1995 @@ -1,4 +1,4 @@ -# +# $Id: Makefile,v 1.18 1995/11/25 00:57:48 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -12,15 +12,15 @@ .S.o: $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o -OBJS = entry.o traps.o irq.o process.o signal.o ioport.o setup.o \ - idprom.o probe.o mp.o c_mp.o +OBJS = entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o irq.o \ + process.o signal.o ioport.o setup.o idprom.o probe.o mp.o \ + c_mp.o sys_sparc.o sunos_asm.o sparc-stub.o systbls.o \ + sys_sunos.o sunos_ioctl.o time.o all: kernel.o head.o -head.o: head.s - -head.s: head.S - $(CPP) -D__KERNEL__ -D__ASSEMBLY__ -ansi -o $*.s $< +head.o: head.S + $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o kernel.o: $(OBJS) $(LD) -r -o kernel.o $(OBJS) @@ -28,6 +28,5 @@ dep: $(CPP) -M *.c > .depend - $(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/V9head.S linux/arch/sparc/kernel/V9head.S --- v1.3.43/linux/arch/sparc/kernel/V9head.S Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/V9head.S Thu Jan 1 02:00:00 1970 @@ -1,16 +0,0 @@ -/* V9head.S: Initial boot code for the V9 Sparc under Linux. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - */ - -#include - - .text - - .globl start - .globl _start - .globl C_LABEL(trapbase) -_start: -start: -C_LABEL(trapbase): diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/c_mp.c linux/arch/sparc/kernel/c_mp.c --- v1.3.43/linux/arch/sparc/kernel/c_mp.c Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/c_mp.c Sat Nov 25 02:57:52 1995 @@ -1,7 +1,10 @@ -/* mp.c: SMP cpu idling and dispatch on the Sparc. +/* $Id: c_mp.c,v 1.3 1995/11/25 00:57:50 davem Exp $ + * mp.c: SMP cpu idling and dispatch on the Sparc. * * Copyright (C) 1995 David S. Miller */ + +#include #include #include diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v1.3.43/linux/arch/sparc/kernel/entry.S Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/entry.S Sat Nov 25 02:57:55 1995 @@ -1,1950 +1,887 @@ -/* arch/sparc/kernel/entry.S: Sparc trap low-level entry points. - * - * Sparc traps are so ugly, this code is going to go through a lot - * of changes as I find out more interesting things. See head.S for - * the trap table and how it works, this will show you how we get - * to these routines. +/* $Id: entry.S,v 1.64 1995/11/25 00:57:53 davem Exp $ + * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include +#include #include +#include #include #include #include #include #include +#include +#include +#include #define NR_SYSCALLS 255 /* Each OS is different... */ -/* A debugging macro, it just prints a dot on the screen. For now - * it is only used in the context switch code since it is so delicate - * I need to use the prom putchar() routines and reload the pointers - * every time. This clobbers %l7 and %o0. - */ -#define DO_SPARC_DOT \ - sethi %hi(C_LABEL(romvec)), %l7; \ - ld [%l7 + %lo(C_LABEL(romvec))], %l7; \ - ld [%l7 + 0x54], %l7; \ - or %g0, '.', %o0; \ - call %l7; \ - nop; \ - nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \ - -/* Another macro, the name speaks for itself. */ -#define DROP_THE_BOMB \ - sethi %hi(C_LABEL(romvec)), %l7; \ - ld [%l7 + %lo(C_LABEL(romvec))], %l7; \ - ld [%l7 + 0x74], %l7; \ - call %l7; \ - nop; \ - -/* Turn off interrupts while we change contexts. Clobbers %l7 */ -#define TRAPS_OFF \ - rd %psr, %l7; \ - andn %l7, (PSR_ET), %l7; \ - wr %l7, 0x0, %psr; \ - -/* Here are macros for routines we do often, this allows me to inline this - * without making the code look real ugly. Well, the macro looks ugly too - * but makes the trap entry code easier to understand. +/* All trap entry points _must_ begin with this macro or else you + * lose. It makes sure the kernel has a proper window so that + * c-code can be called. Some day for SMP we'll grab klock here. + */ +#define SAVE_ALL \ + sethi %hi(trap_setup), %l4; \ + jmpl %l4 + %lo(trap_setup), %l6; \ + nop; + +/* All traps low-level code here must end with this macro. + * For SMP configurations the ret_trap_entry routine will + * have to appropriate code to actually release the kernel + * entry lock. + */ +#define RESTORE_ALL \ + b ret_trap_entry; \ + nop; + +/* First, KGDB low level things. This is a rewrite + * of the routines found in the sparc-stub.c asm() statement + * from the gdb distribution. This is also dual-purpose + * as a software trap for userlevel programs. */ + .data + .align 4 -/* I really don't like synthetic instructions. So I avoid them like the - * plague. - */ +in_trap_handler: + .word 0 -/* Note that when I have to write a window out, and it is a user's window, I - * have to check that the pages of memory that I am going to throw the window(s) - * onto are valid and are writable by the user (this is %sp to %sp + 64) before - * I start dumping stuff there. We always assume that kernels stack is ok. - * XXX Will change on MP's XXX - * - * If we have to save a kernel window, only one branch is taken. This should - * make trap handlers quicker in this scenario. - * - * Once 'current' is loaded into %g6, it stays there until we leave - * this macro. - */ + .text + .align 4 -/* I will document how this works real soon. TODO */ +! This function is called when any SPARC trap (except window overflow or +! underflow) occurs. It makes sure that the invalid register window is still +! available before jumping into C code. It will also restore the world if you +! return from handle_exception. -#define TRAP_WIN_CLEAN \ - or %g0, %g5, %l5; /* we need the globals to do our work */ \ - or %g0, %g6, %l6; /* and %l0 to %l4 are loaded with important */ \ - or %g0, %g7, %l7; /* information like the psr and pc's to return to */ \ - sethi %hi( C_LABEL(current) ), %g6; \ - ld [%g6 + %lo( C_LABEL(current) )], %g6; \ - ld [%g6 + THREAD_UWINDOWS], %g7; /* how many user wins are active? */ \ - subcc %g7, 0x0, %g0; \ - bne 2f; /* If there are any, branch. */ \ - save %g0, %g0, %g0; /* Save into that window either way. */ \ - std %l0, [%sp]; /* If above shows only kernel windows */ \ -1: std %l2, [%sp + 0x8]; /* then we get here. */ \ - std %l4, [%sp + 0x10]; \ - std %l6, [%sp + 0x18]; \ - std %i0, [%sp + 0x20]; \ - std %i2, [%sp + 0x28]; \ - std %i4, [%sp + 0x30]; \ - std %i6, [%sp + 0x38]; \ - or %g0, 0x1, %g5; \ - rd %psr, %g7; \ - sll %g5, %g7, %g5; \ - wr %g5, 0x0, %wim; /* update %wim to 'now' invalid */ \ - and %g7, 0x1f, %g7; \ - sethi %hi( C_LABEL(current) ), %g6; \ - ld [%g6 + %lo( C_LABEL(current) )], %g6; \ - st %g7, [%g6 + THREAD_WIM]; /* save 'this' threads mask */ \ - restore %g0, %g0, %g0; \ - or %g0, %l5, %g5; /* restore the globals we used */ \ - or %g0, %l6, %g6; \ - b 8f; /* we are done */ \ - or %g0, %l7, %g7; \ -2: sub %g7, 0x1, %g7; \ - sethi %hi( C_LABEL(current) ), %g6; \ - ld [%g6 + %lo( C_LABEL(current) )], %g6; \ - st %g7, [%g6 + THREAD_UWINDOWS]; /* There are user windows if we */ \ - andcc %sp, 0x7, %g0; /* get here. Check for stack alignment. */ \ - bne 5f; /* Stack is unaligned, yuck. */ \ - sra %sp, 0x1e, %g7; /* This stuff checks to see if top 3-bits */ \ - subcc %g7, 0x0, %g0; /* of stack pointer address are ok. */ \ - be,a 3f; \ - andn %sp, 0xfff, %g7; \ - subcc %g7, -1, %g0; \ - bne 5f; /* bad stack pointer, ugh */ \ - andn %sp, 0xfff, %g7; \ -3: lda [%g7] ASI_PTE, %g7; /* Ok, user stack is a valid address */ \ - srl %g7, 0x1d, %g7; \ - subcc %g7, 0x6, %g0; /* Can the user write to it? */ \ - bne 5f; \ - and %sp, 0xfff, %g7; \ - subcc %g7, 0xfc1, %g0; /* Is our save area on one page? */ \ - bl,a 1b; \ - std %l0, [%sp]; \ - add %sp, 0x38, %g5; /* Nope, have to check both pages */ \ - sra %g5, 0x1e, %g7; \ - subcc %g7, 0x0, %g0; \ - be,a 4f; \ - andn %g5, 0xfff, %g7; \ - subcc %g7, -1, %g0; \ - bne 5f; \ - andn %g5, 0xfff, %g7; \ -4: lda [%g7] ASI_PTE, %g7; /* Stack space in 2nd page is valid */ \ - srl %g7, 0x1d, %g7; \ - subcc %g7, 0x6, %g0; /* Can user write here too? */ \ - be,a 1b; \ - std %l0, [%sp]; \ -5: ld [%g6 + THREAD_UWINDOWS], %g7; /* This is due to either bad page perms */ \ - add %g6, THREAD_REG_WINDOW, %g5; /* for the users stack area, or the stack */ \ -6: std %l0, [%g5]; /* pointer is misaligned. See above. */ \ - std %l2, [%g5 + 0x8]; \ - std %l4, [%g5 + 0x10]; \ - std %l6, [%g5 + 0x18]; \ - std %i0, [%g5 + 0x20]; \ - std %i2, [%g5 + 0x28]; \ - std %i4, [%g5 + 0x30]; \ - std %i6, [%g5 + 0x38]; \ - subcc %g7, 0x1, %g7; \ - bge,a 6b; /* while(uwindows>=0) { write_win(); */ \ - save %g5, 0x40, %g5; /* uwindows--; } */ \ - st %sp, [%g6 + THREAD_USP]; \ - or %g0, 0x1, %g5; \ - rd %psr, %g7; \ - sll %g5, %g7, %g5; \ - wr %g5, 0x0, %wim; \ - and %g7, 0x1f, %g7; \ - st %g7, [%g6 + THREAD_WIM]; /* Update thread_struct fields */ \ - ld [%g6 + THREAD_UWINDOWS], %g7; \ - add %g7, 0x1, %g5; \ - st %g5, [%g6 + THREAD_W_SAVED]; \ - st %g0, [%g6 + THREAD_UWINDOWS]; \ -7: subcc %g7, 0x1, %g7; /* Restore back to where we started. */ \ - bge 7b; \ - restore %g0, %g0, %g0; \ - or %g0, %l5, %g5; /* Restore the globals. */ \ - or %g0, %l6, %g6; \ - or %g0, %l7, %g7; \ -8: nop; /* We are done when we get here. */ \ - -/* As if the last macro wasn't enough, we have to go through a very similar routine - * upon entry to most traps and interrupts. This is save away the current window - * if it is the trap window, clean it, and adjust the stack for the handler c-code - * to work. - * - * See asm-sparc/cprefix.h to see how the CONCAT macros work. - */ -/* NOTE: The system call entry code ASSUMES that the ENTER_TRAP macro - * does NOT touch register %l7 and leaves the same contents after - * the macro is done. Keep in mind if you change this code. - */ - -#define ENTER_TRAP(label) \ - rd %wim, %l4; \ - or %g0, 0x1, %l5; \ - sll %l5, %l0, %l5; \ - andcc %l0, PSR_PS, %g0; \ - bz CONCAT1(label, 1); \ - andcc %l4, %l5, %g0; \ - bz,a CONCAT1(label, 3); \ - sub %fp, 0xb0, %sp; \ - TRAP_WIN_CLEAN \ - b CONCAT1(label, 3); \ - sub %fp, 0xb0, %sp; \ -CONCAT1(label, 1): \ - sethi %hi( C_LABEL(current) ), %l6; \ - ld [%l6 + %lo( C_LABEL(current) )], %l6; \ - ld [%l6 + THREAD_WIM], %l5; \ - and %l0, 0x1f, %l4; \ - cmp %l5, %l3; \ - ble,a CONCAT1(label, 4); \ - sethi %hi( C_LABEL(nwindowsm1) ), %l4; \ - sub %l5, %l3, %l3; \ - b CONCAT1(label, 5); \ - sub %l3, 0x1, %l5; \ -CONCAT1(label, 4): \ - ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \ - sub %l4, %l3, %l4; \ - add %l5, %l4, %l5; \ -CONCAT1(label, 5): \ - st %l5, [%l6 + THREAD_UWINDOWS]; \ - bz,a CONCAT1(label, 2); \ - sethi %hi(C_LABEL(current)), %l6; \ - TRAP_WIN_CLEAN \ - sethi %hi(C_LABEL(current)), %l6; \ -CONCAT1(label, 2): \ - ld [%l6 + %lo(C_LABEL(current))], %l6; \ - ld [%l6 + TASK_KSTACK_PG], %l6; \ - add %l6, (PAGE_SIZE - 96 - 80), %l6; \ - andn %l6, 0x7, %l6; \ - or %g0, %l6, %sp; \ -CONCAT1(label, 3): + .globl C_LABEL(trap_low) +C_LABEL(trap_low): + rd %wim, %l3 + SAVE_ALL -/* What needs to be executed upon entry to an interrupt. - * - * See asm-sparc/cprefix.h to see how the CONCAT macros work. - */ + sethi %hi(in_trap_handler), %l4 + ld [%lo(in_trap_handler) + %l4], %l5 + inc %l5 + st %l5, [%lo(in_trap_handler) + %l4] + + /* Make sure kgdb sees the same state we just saved. */ + LOAD_PT_GLOBALS(sp) + LOAD_PT_INS(sp) + ld [%sp + STACKFRAME_SZ + PT_Y], %l4 + ld [%sp + STACKFRAME_SZ + PT_WIM], %l3 + ld [%sp + STACKFRAME_SZ + PT_PSR], %l0 + ld [%sp + STACKFRAME_SZ + PT_PC], %l1 + ld [%sp + STACKFRAME_SZ + PT_NPC], %l2 + rd %tbr, %l5 /* Never changes... */ + + /* Make kgdb exception frame. */ + sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals + ! + hidden arg + arg spill + ! + doubleword alignment + ! + registers[72] local var + SAVE_KGDB_GLOBALS(sp) + SAVE_KGDB_INS(sp) + SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) + + /* We are increasing PIL, so two writes. */ + or %l0, PSR_PIL, %l0 + wr %l0, 0, %psr + wr %l0, PSR_ET, %psr + WRITE_PAUSE -#define ENTER_IRQ(label) \ - rd %wim, %l4; \ - or %g0, 0x1, %l5; \ - sll %l5, %l0, %l5; \ - andcc %l0, PSR_PS, %g0; \ - bz CONCAT1(label, 1); \ - andcc %l4, %l5, %g0; \ - bz,a CONCAT1(label, 0); \ - sethi %hi( C_LABEL(eintstack) ), %l7; \ - TRAP_WIN_CLEAN \ - sethi %hi( C_LABEL(eintstack) ), %l7; \ -CONCAT1(label, 0): \ - subcc %fp, %l7, %g0; \ - bge,a CONCAT1(label, 3); \ - sub %l7, 0xb0, %sp; \ - b CONCAT1(label, 3); \ - sub %fp, 0xb0, %sp; \ -CONCAT1(label, 1): \ - sethi %hi( C_LABEL(current) ), %l6; \ - ld [%l6 + %lo( C_LABEL(current) )], %l6; \ - ld [%l6 + THREAD_WIM], %l5; \ - and %l0, 0x1f, %l7; \ - cmp %l5, %l7; \ - ble,a CONCAT1(label, 4); \ - sethi %hi( C_LABEL(nwindowsm1) ), %l4; \ - sub %l5, %l7, %l7; \ - b CONCAT1(label, 5); \ - sub %l7, 0x1, %l5; \ -CONCAT1(label, 4): \ - ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \ - sub %l4, %l7, %l4; \ - add %l5, %l4, %l5; \ -CONCAT1(label, 5): \ - st %l5, [%l6 + THREAD_UWINDOWS]; \ - bz,a CONCAT1(label, 2); \ - sethi %hi( C_LABEL(eintstack) ), %l7; \ - TRAP_WIN_CLEAN \ - sethi %hi( C_LABEL(eintstack) ), %l7; \ -CONCAT1(label, 2): \ - sub %l7, 0xb0, %sp; \ -CONCAT1(label, 3): + call C_LABEL(handle_exception) + add %sp, STACKFRAME_SZ, %o0 ! Pass address of registers + /* Load new kgdb register set. */ + LOAD_KGDB_GLOBALS(sp) + LOAD_KGDB_INS(sp) + LOAD_KGDB_SREGS(sp, l0, l2) + ld [%sp + STACKFRAME_SZ + KGDB_WIM], %l6 + wr %l0, 0x0, %y + + sethi %hi(in_trap_handler), %l4 + ld [%lo(in_trap_handler) + %l4], %l5 + dec %l5 + st %l5, [%lo(in_trap_handler) + %l4] + + add %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame. + + /* Now take what kgdb did and place it into the pt_regs + * frame which SparcLinux RESTORE_ALL understands., + */ + STORE_PT_INS(sp) + STORE_PT_GLOBALS(sp) + STORE_PT_YREG(sp, g2) + STORE_PT_PRIV(sp, l1, l2, l3, l6) + + /* Cross your fingers... */ + RESTORE_ALL + + +#ifdef CONFIG_BLK_DEV_FD + .align 4 + .globl C_LABEL(floppy_hardint) +C_LABEL(floppy_hardint): + /* Can only use regs %l3->%l7: + * %l3 -- base address of fdc registers + * %l4 -- doing_pdma upon entry, AUXIO reg vaddr after + * %l5 -- pdma_vaddr + * %l6 -- pdma_size + * %l7 -- floppy_softint + */ + + /* Do we have work to do? */ + sethi %hi(C_LABEL(doing_pdma)), %l4 + ld [%l4 + %lo(C_LABEL(doing_pdma))], %l4 + cmp %l4, 0 + be floppy_dosoftint + nop + + /* Load fdc register base */ + sethi %hi(C_LABEL(fdc_status)), %l3 + ld [%l3 + %lo(C_LABEL(fdc_status))], %l3 + + /* Setup register addresses */ + sethi %hi(C_LABEL(pdma_vaddr)), %l5 ! transfer buffer + ld [%l5 + %lo(C_LABEL(pdma_vaddr))], %l4 + sethi %hi(C_LABEL(pdma_size)), %l5 ! bytes to go + ld [%l5 + %lo(C_LABEL(pdma_size))], %l6 +next_byte: + ldub [%l3], %l7 + andcc %l7, 0x80, %g0 ! Does fifo still have data + bz floppy_fifo_emptied ! fifo has been emptied... + andcc %l7, 0x20, %g0 ! in non-dma mode still? + bz floppy_overrun ! nope, overrun + andcc %l7, 0x40, %g0 ! 0=write 1=read + bz floppy_write + sub %l6, 0x1, %l6 + + /* Ok, actually read this byte */ + ldub [%l3 + 1], %l7 + orcc %g0, %l6, %g0 + stb %l7, [%l4] + bne next_byte + add %l4, 0x1, %l4 + + b floppy_tdone + nop + +floppy_write: + /* Ok, actually write this byte */ + ldub [%l4], %l7 + orcc %g0, %l6, %g0 + stb %l7, [%l3 + 1] + bne next_byte + add %l4, 0x1, %l4 + + /* fall through... */ +floppy_tdone: + sethi %hi(C_LABEL(pdma_vaddr)), %l5 + st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] + sethi %hi(C_LABEL(pdma_size)), %l5 + st %l6, [%l5 + %lo(C_LABEL(pdma_size))] + /* Flip terminal count pin */ + sethi %hi(AUXIO_VADDR), %l4 + ldub [%l4 + %lo(AUXIO_VADDR) + 0x3], %l5 + or %l5, 0xf4, %l5 + stb %l5, [%l4 + %lo(AUXIO_VADDR) + 0x3] + + /* Kill some time so the bits set */ + WRITE_PAUSE + WRITE_PAUSE + + ldub [%l4 + %lo(AUXIO_VADDR) + 0x3], %l5 + andn %l5, 0x04, %l5 + or %l5, 0xf0, %l5 + stb %l5, [%l4 + %lo(AUXIO_VADDR) + 0x3] + + /* Prevent recursion */ + sethi %hi(C_LABEL(doing_pdma)), %l4 + b floppy_dosoftint + st %g0, [%l4 + %lo(C_LABEL(doing_pdma))] + + /* We emptied the FIFO, but we haven't read everything + * as of yet. Store the current transfer address and + * bytes left to read so we can continue when the next + * fast IRQ comes in. + */ +floppy_fifo_emptied: + sethi %hi(C_LABEL(pdma_vaddr)), %l5 + st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] + sethi %hi(C_LABEL(pdma_size)), %l7 + st %l6, [%l7 + %lo(C_LABEL(pdma_size))] - .text - .align 4 + /* Restore condition codes */ + wr %l0, 0x0, %psr + WRITE_PAUSE -/* Bad trap handler */ - .globl bad_trap_handler -bad_trap_handler: - ENTER_TRAP(bad_trap_handler) + jmp %l1 + rett %l2 - or %g0, %l3, %o0 - or %g0, %l0, %o1 - call C_LABEL(do_hw_interrupt) - or %g0, %l1, %o2 +floppy_overrun: + sethi %hi(C_LABEL(pdma_vaddr)), %l5 + st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] + sethi %hi(C_LABEL(pdma_size)), %l5 + st %l6, [%l5 + %lo(C_LABEL(pdma_size))] + /* Prevent recursion */ + sethi %hi(C_LABEL(doing_pdma)), %l4 + st %g0, [%l4 + %lo(C_LABEL(doing_pdma))] - jmp %l1 - rett % l2 - - .align 4 - .globl sparc_timer -sparc_timer: - ENTER_IRQ(sparc_timer) - - sethi %hi(C_LABEL(master_l10_limit)), %l4 - ld [%l4 + %lo(C_LABEL(master_l10_limit))], %l4 - ld [%l4], %g0 ! read the limit register - - std %g2, [%sp + C_STACK + PT_G2] - or %g0, %g1, %l7 - rd %y, %l6 - std %g4, [%sp + C_STACK + PT_G4] - andn %l0, PSR_PIL, %l4 -/* sll %l3, 0x8, %l5 */ - std %g6, [%sp + C_STACK + PT_G6] -/* or %l5, %l4, %l4 */ + /* fall through... */ +floppy_dosoftint: + rd %wim, %l3 + SAVE_ALL - /* Magic, we can't increase PIL and set ET at the same - * time or the chip calls prom_panic(). - */ -/* wr %l4, 0x0, %psr */ + /* Set all IRQs off. */ + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr wr %l4, PSR_ET, %psr + WRITE_PAUSE - or %g0, 10, %o0 - add %sp, C_STACK, %o1 - call C_LABEL(do_IRQ) - nop - - or %g0, %l7, %g1 - wr %l6, 0x0, %y - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 + mov 11, %o0 ! floppy irq level + call C_LABEL(floppy_interrupt) + add %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs - b ret_trap_entry - wr %l0, 0x0, %psr + RESTORE_ALL + +#endif /* (CONFIG_BLK_DEV_FD) */ + + /* Bad trap handler */ + .globl bad_trap_handler +bad_trap_handler: + SAVE_ALL + wr %l0, PSR_ET, %psr + WRITE_PAUSE + mov %l7, %o0 ! trap number + mov %l0, %o1 ! psr + call C_LABEL(do_hw_interrupt) + mov %l1, %o2 ! pc + RESTORE_ALL + /* For now all IRQ's not registered get sent here. handler_irq() will * see if a routine is registered to handle this interrupt and if not * it will say so on the console. */ - .align 4 - .globl real_irq_entry + .align 4 + .globl real_irq_entry real_irq_entry: - ENTER_IRQ(real_irq_entry) - std %g2, [%sp + C_STACK + PT_G2] - or %g0, %g1, %l7 - rd %y, %l6 - std %g4, [%sp + C_STACK + PT_G4] - andn %l0, PSR_PIL, %l4 - sll %l3, 0x8, %l5 - std %g6, [%sp + C_STACK + PT_G6] - or %l5, %l4, %l4 + SAVE_ALL + /* start atomic operation with respect to software interrupts */ + sethi %hi(C_LABEL(intr_count)), %l4 + ld [%l4 + %lo(C_LABEL(intr_count))], %l5 + add %l5, 0x1, %l5 + st %l5, [%l4 + %lo(C_LABEL(intr_count))] + + /* Enable traps w/IRQs off, so we can call c-code properly. + * Note how we are increasing PIL so we need to do two writes + * to work around a MicroSPARC bug of sorts. + */ + or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr wr %l4, PSR_ET, %psr + WRITE_PAUSE - std %l0, [%sp + C_STACK + PT_PSR] - std %l2, [%sp + C_STACK + PT_NPC] - - or %g0, %l3, %o0 - add %sp, C_STACK, %o1 + mov %l7, %o0 ! irq level call C_LABEL(handler_irq) - nop - - or %g0, %l7, %g1 - wr %l6, 0x0, %y - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l0, 0x0, %psr - - -/* This routine is optimized for kernel window fills. User fills take about two - * or three extra jumps on the average. We'll see how this works out. - */ - -/* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is - * full of them! If you think this routine is hairy, window fills are worse, - * see below. - */ - - .align 4 - .globl spill_window_entry -spill_window_entry: - andcc %l0, PSR_PS, %g0 ! see if this is a user window fill - bz,a spill_from_user - nop - - TRAP_WIN_CLEAN /* danger, danger... */ - wr %l0, 0x0, %psr - nop - jmp %l1 - rett %l2 + add %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr -spill_from_user: - sethi %hi( C_LABEL(current) ), %l6 - ld [%l6 + %lo( C_LABEL(current) )], %l6 - ld [%l6 + THREAD_WIM], %l5 - and %l0, 0x1f, %l3 - -/* I don't know what's worse, the extra comparison here, or an extra load - * from a lookup table, we'll see. - */ - cmp %l5, %l3 - ble,a 1f - sethi %hi( C_LABEL(nwindowsm1) ), %l4 - sub %l5, %l3, %l3 - b 2f - sub %l3, 0x1, %l5 -1: - ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4 - sub %l4, %l3, %l4 - add %l5, %l4, %l5 +rie_checkbh: + sethi %hi(C_LABEL(intr_count)), %l4 + ld [%l4 + %lo(C_LABEL(intr_count))], %l5 + subcc %l5, 0x1, %l5 + bne 2f /* IRQ within IRQ, get out of here... */ + nop + sethi %hi(C_LABEL(bh_active)), %l3 + ld [%l3 + %lo(C_LABEL(bh_active))], %g2 + sethi %hi(C_LABEL(bh_mask)), %l3 + ld [%l3 + %lo(C_LABEL(bh_mask))], %g3 + andcc %g2, %g3, %g0 + be 2f + nop + call C_LABEL(do_bottom_half) + nop + /* Try again... */ + b rie_checkbh + nop + 2: - st %l5, [%l6 + THREAD_UWINDOWS] - - TRAP_WIN_CLEAN /* danger, danger... */ - sethi %hi( C_LABEL(current) ), %l6 - ld [%l6 + %lo( C_LABEL(current) )], %l6 - ld [%l6 + THREAD_KSP], %sp - and %l0, 0x1f, %l3 - sethi %hi(lnx_winmask), %l6 - or %l6, %lo(lnx_winmask), %l6 - ldub [%l6 + %l3], %l5 - rd %wim, %l4 - jmp %l1 - rett %l2 + st %l5, [%l4 + %lo(C_LABEL(intr_count))] + RESTORE_ALL -/* A window spill has occurred. This presents a weird situation, a restore - * was attempted and a trap occurred. Therefore the restore attempt had no - * effect on window movement and the trap saved, which means it went in the - * other direction. :-( We are in a trap window which is two restores away - * from the window we want to un-invalidate so to speak and three away from - * the one which will become invalid after this routine. There are probably - * bugs already this routine. Bugs suck. - */ - -/* This is a very complicated and hairy routine, don't expect to understand - * it the first time. :> - */ - - .align 4 - .globl fill_window_entry -fill_window_entry: - wr %g0, 0, %wim ! Can not enter invalid register without this. - andcc %l0, 0x40, %g0 ! From user? - restore ! restore to where trap occurred - bz fill_from_user - restore ! enter invalid register, whee... - restore %g0, 0x1, %l1 ! enter one-past invalid register - rd %psr, %l0 ! this is the window we need to save - and %l0, 0x1f, %l0 - sll %l1, %l0, %l1 - wr %l1, 0x0, %wim - sethi %hi( C_LABEL(current) ), %l1 - ld [%l1 + %lo( C_LABEL(current) )], %l1 - st %l0, [%l1 + THREAD_WIM] - save %g0, %g0, %g0 ! back to invalid register - ldd [%sp], %l0 ! load the window from stack - ldd [%sp + 8], %l2 - ldd [%sp + 16], %l4 - ldd [%sp + 24], %l6 - ldd [%sp + 32], %i0 - ldd [%sp + 40], %i2 - ldd [%sp + 48], %i4 - ldd [%sp + 56], %i6 - save %g0, %g0, %g0 ! to window where trap happened - save %g0, %g0, %g0 ! back to trap window, so rett works - wr %l0, 0x0, %psr ! load condition codes - nop - jmp %l1 - rett %l2 ! are you as confused as I am? +/* Soft IRQ's are handled just like hard IRQ's except that we + * need to clear the IRQ line ourselves (in the interrupt reg) + * and we don't take care of bottom-half handlers here. We'll + * just deal with it at the next clock tick, and since software + * IRQ's relatively don't happen that often.... + * XXX BIG XXX Turn the software IRQ bit we need to clear into + * XXX BIG XXX an element reference in an array that we can set + * XXX BIG XXX a boot time based upon arch type + * XXX BIG XXX OR... rewrite the appropriate IRQ trap table + * XXX BIG XXX entries once the arch is detected (sun4/4c or sun4m) + * + * XXX EVEN BIGGER XXX Linux has bh_handlers for software interrupts + * XXX EVEN BIGGER XXX so we do not even have to worry about this + * XXX EVEN BIGGER XXX brain damaged software interrupt mechanism. + */ + + .align 4 + .globl soft_irq_entry +soft_irq_entry: + SAVE_ALL + + /* We have tucked the bit to clear in the int reg into + * %l4, take care of it now before we do anything else. + */ + sethi %hi(INTREG_VADDR), %l5 + ldsb [%l5 + %lo(INTREG_VADDR)], %l6 + andn %l6, %l4, %l6 + stb %l6, [%l5 + %lo(INTREG_VADDR)] + + /* start atomic operation with respect to software interrupts */ + sethi %hi(C_LABEL(intr_count)), %l4 + ld [%l4 + %lo(C_LABEL(intr_count))], %l5 + add %l5, 0x1, %l5 + st %l5, [%l4 + %lo(C_LABEL(intr_count))] + + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr ! grrr! + wr %l4, PSR_ET, %psr ! double grrr! -fill_from_user: - andcc %sp, 0x7, %g0 ! check for alignment of user stack - bne fill_bad_stack - sra %sp, 0x1e, %l7 - cmp %l7, 0x0 - be,a 1f - andn %sp, 0xfff, %l7 - cmp %l7, -1 - bne fill_bad_stack - andn %sp, 0xfff, %l7 -1: - lda [%l7] ASI_PTE, %l7 - srl %l7, 0x1d, %l7 - andn %l7, 0x2, %l7 - cmp %l7, 0x4 - bne fill_bad_stack - and %sp, 0xfff, %l7 - cmp %l7, 0xfc1 - bl,a fill_stack_ok - restore %g0, 1, %l1 - add %sp, 0x38, %l5 - sra %sp, 0x1e, %l7 - cmp %l7, 0x0 - be,a 1f - andn %sp, 0xfff, %l7 - cmp %l7, -1 - bne fill_bad_stack - andn %sp, 0xfff, %l7 -1: - lda [%l7] ASI_PTE, %l7 - srl %l7, 0x1d, %l7 - andn %l7, 0x2, %l7 - cmp %l7, 0x4 - be,a fill_stack_ok - restore %g0, 0x1, %l1 - -fill_bad_stack: - save %g0, %g0, %g0 ! save to where restore happened - save %g0, 0x1, %l4 ! save is an add remember? to trap window - sethi %hi( C_LABEL(current) ), %l6 - ld [%l6 + %lo( C_LABEL(current) )], %l6 - st %l4, [%l6 + THREAD_UWINDOWS] ! update current->tss values - ld [%l6 + THREAD_WIM], %l5 - sll %l4, %l5, %l4 - wr %l4, 0x0, %wim - ld [%l6 + THREAD_KSP], %sp ! set to kernel stack pointer - wr %l0, PSR_ET, %psr ! turn off traps - std %l0, [%sp + C_STACK] ! set up thread_frame XXX - rd %y, %l3 - std %l2, [%sp + C_STACK + 0x8] - or %g0, 0x6, %o0 ! so _sparc_trap knows what to do - st %g1, [%sp + C_STACK + 0x14] ! no need to save %g0, always zero - or %g0, %l0, %o1 - std %g2, [%sp + C_STACK + 0x18] - or %g0, %l1, %o2 - std %g4, [%sp + C_STACK + 0x20] - add %sp, C_STACK, %o3 - std %g6, [%sp + C_STACK + 0x28] - std %i0, [%sp + C_STACK + 0x30] - std %i2, [%sp + C_STACK + 0x38] - std %i4, [%sp + C_STACK + 0x40] - nop /* SHould trap here */ - std %i6, [%sp + C_STACK + 0x48] - - ldd [%sp + C_STACK], %l0 - ldd [%sp + C_STACK + 0x8], %l2 - wr %l3, 0, %y - ld [%sp + C_STACK + 0x14], %g1 - ldd [%sp + C_STACK + 0x18], %g2 - ldd [%sp + C_STACK + 0x20], %g4 - ldd [%sp + C_STACK + 0x28], %g6 - ldd [%sp + C_STACK + 0x30], %i0 - ldd [%sp + C_STACK + 0x38], %i2 - ldd [%sp + C_STACK + 0x40], %i4 - wr %l0, 0, %psr ! disable traps again - ldd [%sp + C_STACK + 0x48], %i6 - sethi %hi( C_LABEL(current) ), %l6 - ld [%l6 + %lo( C_LABEL(current) )], %l6 - ld [%l6 + THREAD_W_SAVED], %l7 - cmp %l7, 0x0 - bl,a 1f - wr %g0, 0x0, %wim - /* Should trap here */ + mov %l7, %o0 + add %sp, STACKFRAME_SZ, %o1 + call C_LABEL(handler_irq) + nop -1: - or %g0, %g6, %l3 - or %g0, %l6, %g6 - st %g0, [%g6 + THREAD_W_SAVED] - restore %g0, %g0, %g0 - restore %g0, %g0, %g0 - restore %g0, 0x1, %l1 - rd %psr, %l0 - sll %l1, %l0, %l1 - wr %l1, 0x0, %wim - and %l0, 0x1f, %l0 - st %l0, [%g6 + THREAD_WIM] - nop - save %g0, %g0, %g0 - ldd [%sp], %l0 ! load number one - ldd [%sp + 0x8], %l2 - ldd [%sp + 0x10], %l4 - ldd [%sp + 0x18], %l6 - ldd [%sp + 0x20], %i0 - ldd [%sp + 0x28], %i2 - ldd [%sp + 0x30], %i4 - ldd [%sp + 0x38], %i6 - save %g0, %g0, %g0 - ldd [%sp], %l0 ! load number two - ldd [%sp + 0x8], %l2 - ldd [%sp + 0x10], %l4 - ldd [%sp + 0x18], %l6 - ldd [%sp + 0x20], %i0 - ldd [%sp + 0x28], %i2 - ldd [%sp + 0x30], %i4 - ldd [%sp + 0x38], %i6 - save %g0, %g0, %g0 ! re-enter trap window - wr %l0, 0x0, %psr ! restore condition codes - or %g0, %l3, %g6 ! restore scratch register - jmp %l1 - rett %l2 + sethi %hi(C_LABEL(intr_count)), %l4 + ld [%l4 + %lo(C_LABEL(intr_count))], %l5 + subcc %l5, 0x1, %l5 + st %l5, [%l4 + %lo(C_LABEL(intr_count))] -fill_stack_ok: - rd %psr, %l0 - sll %l1, %l0, %l1 - wr %l1, 0x0, %wim - sethi %hi( C_LABEL(current) ), %l2 - ld [%l2 + %lo( C_LABEL(current) )], %l2 - and %l0, 0x1f, %l0 - st %l0, [%l2 + THREAD_WIM] - save %g0, %g0, %g0 - ldd [%sp], %l0 ! only one load necessary - ldd [%sp + 0x8], %l2 - ldd [%sp + 0x10], %l4 - ldd [%sp + 0x18], %l6 - ldd [%sp + 0x20], %i0 - ldd [%sp + 0x28], %i2 - ldd [%sp + 0x30], %i4 - ldd [%sp + 0x38], %i6 - save %g0, %g0, %g0 - save %g0, %g0, %g0 ! save into trap window - wr %l0, 0x0, %psr ! local number 0 here has cond codes - nop - jmp %l1 - rett %l2 + RESTORE_ALL /* This routine handles illegal isntructions and privileged * instruction attempts from user code. */ - .align 4 - .globl bad_instruction + .align 4 + .globl bad_instruction bad_instruction: - ENTER_TRAP(bad_instruction) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 - cmp %l3, 0x2 - bne 1f call C_LABEL(do_illegal_instruction) - mov %l0, %o3 - b 2f - ld [%sp + C_STACK + PT_G1], %g1 + mov %l0, %o3 + RESTORE_ALL -1: + .align 4 + .globl priv_instruction +priv_instruction: + SAVE_ALL + wr %l0, PSR_ET, %psr + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 + mov %l1, %o1 + mov %l2, %o2 call C_LABEL(do_priv_instruction) - mov %l0, %o3 - ld [%sp + C_STACK + PT_G1], %g1 -2: - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + mov %l0, %o3 + RESTORE_ALL /* This routine handles unaligned data accesses. */ - .align 4 - .globl mna_handler + .align 4 + .globl mna_handler mna_handler: - ENTER_TRAP(mna_handler) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_memaccess_unaligned) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + mov %l0, %o3 + RESTORE_ALL - /* This routine handles floating point disabled traps. - */ - .align 4 - .globl fpd_trap_handler + /* This routine handles floating point disabled traps. */ + .align 4 + .globl fpd_trap_handler fpd_trap_handler: - ENTER_TRAP(fpd_trap_handler) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_fpd_trap) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + mov %l0, %o3 + RESTORE_ALL - /* This routine handles Floating Point Exceptions. - */ - .align 4 - .globl fpe_trap_handler + /* This routine handles Floating Point Exceptions. */ + .align 4 + .globl fpe_trap_handler fpe_trap_handler: - ENTER_TRAP(fpe_trap_handler) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_fpe_trap) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + mov %l0, %o3 + RESTORE_ALL - /* This routine handles Tag Overflow Exceptions. - */ - .align 4 - .globl do_tag_overflow + /* This routine handles Tag Overflow Exceptions. */ + .align 4 + .globl do_tag_overflow do_tag_overflow: - ENTER_TRAP(do_tag_overflow) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(handle_tag_overflow) - mov %l0, %o3 + mov %l0, %o3 + RESTORE_ALL - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y - - /* This routine handles Watchpoint Exceptions. - */ - .align 4 - .globl do_watchpoint + /* This routine handles Watchpoint Exceptions. */ + .align 4 + .globl do_watchpoint do_watchpoint: - ENTER_TRAP(do_watchpoint) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(handle_watchpoint) - mov %l0, %o3 + mov %l0, %o3 + RESTORE_ALL - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y - - /* This routine handles Register Access Exceptions. - */ - .align 4 - .globl do_reg_access + /* This routine handles Register Access Exceptions. */ + .align 4 + .globl do_reg_access do_reg_access: - ENTER_TRAP(do_reg_access) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 - mov %l1, %o1 - mov %l2, %o2 - call C_LABEL(handle_reg_access) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + WRITE_PAUSE - /* This routine handles Instruction Access Errors. - */ - .align 4 - .globl do_iacc_error -do_iacc_error: - ENTER_TRAP(do_iacc_error) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 - call C_LABEL(handle_iacc_error) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + call C_LABEL(handle_reg_access) + mov %l0, %o3 + RESTORE_ALL - /* This routine handles Co-Processor Disabled Exceptions. - */ - .align 4 - .globl do_cp_disabled + /* This routine handles Co-Processor Disabled Exceptions. */ + .align 4 + .globl do_cp_disabled do_cp_disabled: - ENTER_TRAP(do_cp_disabled) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(handle_cp_disabled) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + mov %l0, %o3 + RESTORE_ALL - /* This routine handles Unimplemented FLUSH Exceptions. - */ - .align 4 - .globl do_bad_flush + /* This routine handles Unimplemented FLUSH Exceptions. */ + .align 4 + .globl do_bad_flush do_bad_flush: - ENTER_TRAP(do_bad_flush) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + WRITE_PAUSE + + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(handle_bad_flush) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + mov %l0, %o3 + RESTORE_ALL - /* This routine handles Co-Processor Exceptions. - */ - .align 4 - .globl do_cp_exception + /* This routine handles Co-Processor Exceptions. */ + .align 4 + .globl do_cp_exception do_cp_exception: - ENTER_TRAP(do_cp_exception) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 - mov %l1, %o1 - mov %l2, %o2 - call C_LABEL(handle_cp_exception) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + WRITE_PAUSE - /* This routine handles Data Access Errors. - */ - .align 4 - .globl do_dacc_error -do_dacc_error: - ENTER_TRAP(do_dacc_error) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 - call C_LABEL(handle_dacc_error) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + call C_LABEL(handle_cp_exception) + mov %l0, %o3 + RESTORE_ALL - /* This routine handles Hardware Divide By Zero Exceptions. - */ - .align 4 - .globl do_hw_divzero + /* This routine handles Hardware Divide By Zero Exceptions. */ + .align 4 + .globl do_hw_divzero do_hw_divzero: - ENTER_TRAP(do_hw_divzero) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] + SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 - mov %l1, %o1 - mov %l2, %o2 - call C_LABEL(handle_hw_divzero) - mov %l0, %o3 - - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + WRITE_PAUSE - /* This routine handles Data Store Errors. - */ - .align 4 - .globl do_dstore_err -do_dstore_err: - ENTER_TRAP(do_dstore_err) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 + add %sp, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 - call C_LABEL(handle_dstore_error) - mov %l0, %o3 + call C_LABEL(handle_hw_divzero) + mov %l0, %o3 + RESTORE_ALL - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + .align 4 + .globl do_flush_windows +do_flush_windows: + SAVE_ALL - /* This routine handles Data Access MMU-Miss Exceptions. - */ - .align 4 - .globl do_dacc_mmu_miss -do_dacc_mmu_miss: - ENTER_TRAP(do_dacc_mmu_miss) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 - mov %l1, %o1 - mov %l2, %o2 - call C_LABEL(handle_dacc_mmu_miss) - mov %l0, %o3 + wr %l0, PSR_ET, %psr + WRITE_PAUSE - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + call C_LABEL(flush_user_windows) + nop - /* This routine handles Instruction Access MMU-Miss Exceptions. - */ - .align 4 - .globl do_iacc_mmu_miss -do_iacc_mmu_miss: - ENTER_TRAP(do_iacc_mmu_miss) - st %g1, [%sp + C_STACK + PT_G1] - rd %y, %l4 - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - wr %l0, PSR_ET, %psr ! re-enable traps - add %sp, C_STACK, %o0 - mov %l1, %o1 - mov %l2, %o2 - call C_LABEL(handle_iacc_mmu_miss) - mov %l0, %o3 + /* Advance over the trap instruction. */ + ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 + add %l1, 0x4, %l2 + st %l1, [%sp + STACKFRAME_SZ + PT_PC] + st %l2, [%sp + STACKFRAME_SZ + PT_NPC] - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - b ret_trap_entry - wr %l4, 0, %y + RESTORE_ALL /* The getcc software trap. The user wants the condition codes from * the %psr in register %g1. */ - .align 4 - .globl getcc_trap_handler + .align 4 + .globl getcc_trap_handler getcc_trap_handler: - /* Shit, one more instruction and I could do this inline. */ - sll %l0, 0x8, %g1 - srl %g1, 28, %g1 - jmp %l2 - rett %l2+0x4 + srl %l0, 20, %g1 ! give user + and %g1, 0xf, %g1 ! only ICC bits in %psr + jmp %l2 ! advance over trap instruction + rett %l2 + 0x4 ! like this... /* The setcc software trap. The user has condition codes in %g1 * that it would like placed in the %psr. Be careful not to flip - * any unintention bits! + * any unintentional bits! */ - .align 4 - .globl setcc_trap_handler + .align 4 + .globl setcc_trap_handler setcc_trap_handler: sll %g1, 0x14, %l4 set PSR_ICC, %l5 - andn %l0, %l5, %l0 - or %l4, %l0, %l4 - wr %l4, 0x0, %psr - WRITE_PAUSE - jmp %l2 - rett %l2+0x4 + andn %l0, %l5, %l0 ! clear ICC bits in current %psr + and %l4, %l5, %l4 ! clear non-ICC bits in user value + or %l4, %l0, %l4 ! or them in... mix mix mix + wr %l4, 0x0, %psr ! set new %psr + WRITE_PAUSE ! TI scumbags... - .align 4 -NMI_STRING: .asciz "NMI received, dazed and confused, halting...\n" + jmp %l2 ! advance over trap instruction + rett %l2 + 0x4 ! like this... - .align 4 - .globl linux_trap_nmi - .globl C_LABEL(interrupt_enable) + .align 4 + .globl linux_trap_nmi linux_trap_nmi: - sethi %hi(C_LABEL(prom_vector_p)), %o0 - ld [%o0 + %lo(C_LABEL(prom_vector_p))], %o0 - ld [%o0 + 0x74], %o0 - /* Ugh, until I figure out how to clear the IRQ line ;( */ - call %o0 - nop - - .align 4 - .globl sparc_text_fault -sparc_text_fault: - ENTER_TRAP(sparc_text_fault) - st %g1, [%sp + C_STACK + PT_G1] - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - rd %y, %l4 - sethi %hi(AC_SYNC_ERR), %o0 - lda [%o0] ASI_CONTROL, %o1 - add %o0, 0x4, %o0 ! go to sync vaddr - lda [%o0] ASI_CONTROL, %o2 - andcc %o1, SUN4C_SYNC_NOMEM, %g0 - bz,a normal_page_fault - wr %l0, PSR_ET, %psr ! re-enable traps - - add %o0, 0x4, %o0 ! go to async error register - lda [%o0] ASI_CONTROL, %o3 - add %o0, 0x4, %o0 ! go to async vaddr - subcc %o4, %o2, %g0 - be,a is_sync_fault ! not an async fault - wr %l0, PSR_ET, %psr - - /* crap, an asynchronous error has occurred */ + SAVE_ALL + /* Ugh, we need to clear the IRQ line. This is now + * a very sun4c specific trap hanler... + */ sethi %hi(C_LABEL(interrupt_enable)), %l5 - ldub [%l5 + %lo(C_LABEL(interrupt_enable))], %o0 - andn %o0, INTS_ENAB, %o0 - stb %o0, [%l5 + %lo(C_LABEL(interrupt_enable))] - wr %l0, PSR_ET, %psr ! enable traps - call C_LABEL(sparc_txtmem_error) ! call high level c-code - or %g0, FAULT_ASYNC, %o0 + ld [%l5 + %lo(C_LABEL(interrupt_enable))], %l5 + ldub [%l5], %l6 + andn %l6, INTS_ENAB, %l6 + stb %l6, [%l5] - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldub [%l5 + %lo(C_LABEL(interrupt_enable))], %o1 - or %o1, INTS_ENAB, %o1 - stb %o1, [%l5 + %lo(C_LABEL(interrupt_enable))] - b ret_trap_entry - wr %l4, 0, %y - -is_sync_fault: - call C_LABEL(sparc_txtmem_error) ! call high level c-code - or %g0, FAULT_SYNC, %o0 - - ld [%sp + C_STACK + PT_G1], %g1 - ld [%sp + C_STACK + PT_G2], %g2 - ld [%sp + C_STACK + PT_G4], %g4 - ld [%sp + C_STACK + PT_G6], %g6 - wr %l4, 0x0, %y - b ret_trap_entry - wr %l0, 0x0, %psr - -normal_page_fault: - std %l0, [%sp + C_STACK + PT_PSR] - or %g0, %l3, %o0 - st %l2, [%sp + C_STACK + PT_NPC] - st %l4, [%sp + C_STACK + PT_Y] - or %g0, %l1, %o3 - std %i0, [%sp + C_STACK + PT_I0] - std %i2, [%sp + C_STACK + PT_I2] - or %g0, %l0, %o4 - std %i4, [%sp + C_STACK + PT_I4] - std %i6, [%sp + C_STACK + PT_I6] - call C_LABEL(sparc_text_access_fault) - add %sp, C_STACK, %o5 - - ldd [%sp + C_STACK + PT_PSR], %l0 - ldd [%sp + C_STACK + PT_NPC], %l2 - wr %l3, 0x0, %y - ld [%sp + C_STACK + PT_G1], %g1 - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldd [%sp + C_STACK + PT_I0], %i0 - ldd [%sp + C_STACK + PT_I2], %i2 - ldd [%sp + C_STACK + PT_I4], %i4 - ldd [%sp + C_STACK + PT_I6], %i6 - - b ret_trap_entry - wr %l0, 0x0, %psr + /* Now it is safe to re-enable traps without recursion. */ + or %l0, PSR_PIL, %l0 + wr %l0, PSR_ET, %psr + WRITE_PAUSE - .align 4 - .globl sparc_data_fault -sparc_data_fault: - ENTER_TRAP(sparc_data_fault) - st %g1, [%sp + C_STACK + PT_G1] - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - rd %y, %l4 + /* Now call the c-code with the pt_regs frame ptr and the + * memory error registers as arguments. The ordering chosen + * here is due to unlatching semantics. + */ sethi %hi(AC_SYNC_ERR), %o0 - lda [%o0] ASI_CONTROL, %o1 - add %o0, 0x4, %o0 ! go to sync vaddr - lda [%o0] ASI_CONTROL, %o2 - andcc %o1, SUN4C_SYNC_NOMEM, %g0 - bz,a normal_data_page_fault + add %o0, 0x4, %o0 + lda [%o0] ASI_CONTROL, %o2 ! sync vaddr + sub %o0, 0x4, %o0 + lda [%o0] ASI_CONTROL, %o1 ! sync error + add %o0, 0xc, %o0 + lda [%o0] ASI_CONTROL, %o4 ! async vaddr + sub %o0, 0x4, %o0 + lda [%o0] ASI_CONTROL, %o3 ! async error + call C_LABEL(sparc_lvl15_nmi) + add %sp, STACKFRAME_SZ, %o0 + + RESTORE_ALL + + .align 4 + .globl sparc_fault +sparc_fault: + SAVE_ALL + rd %tbr, %o1 wr %l0, PSR_ET, %psr + WRITE_PAUSE - add %o0, 0x4, %o0 ! go to async error register - lda [%o0] ASI_CONTROL, %o3 - add %o0, 0x4, %o0 ! go to async vaddr - subcc %o4, %o2, %g0 - be,a is_data_sync_fault ! not an async fault - wr %l0, PSR_ET, %psr + call C_LABEL(do_sparc_fault) + add %sp, STACKFRAME_SZ, %o0 + RESTORE_ALL + + /* SunOS uses syscall zero as the 'indirect syscall' it looks + * like indir_syscall(scall_num, arg0, arg1, arg2...); etc. + * This is complete brain damage. + */ + .globl C_LABEL(sunos_indir) +C_LABEL(sunos_indir): + ld [%sp + STACKFRAME_SZ + PT_I0], %g1 + cmp %g1, NR_SYSCALLS + bleu,a 1f + sll %g1, 0x2, %g1 - /* crap, an asynchronous error has occurred */ - sethi %hi(C_LABEL(interrupt_enable)), %l5 - ldub [%l5 + %lo(C_LABEL(interrupt_enable))], %o0 - andn %o0, INTS_ENAB, %o0 - stb %o0, [%l5 + %lo(C_LABEL(interrupt_enable))] - wr %l0, PSR_ET, %psr - call C_LABEL(sparc_datamem_error) ! call high level c-code - or %g0, FAULT_ASYNC, %o0 + set C_LABEL(sunos_nosys), %l6 + b 2f + nop - ld [%sp + C_STACK + PT_G1], %g1 - wr %l0, 0x0, %psr - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldub [%l5 + %lo(C_LABEL(interrupt_enable))], %o1 - or %o1, INTS_ENAB, %o1 - stb %o1, [%l5 + %lo(C_LABEL(interrupt_enable))] - b ret_trap_entry - wr %l4, 0, %y - -is_data_sync_fault: - call C_LABEL(sparc_datamem_error) ! call high level c-code - or %g0, FAULT_SYNC, %o0 - - ld [%sp + C_STACK + PT_G1], %g1 - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - wr %l4, 0x0, %y - b ret_trap_entry - wr %l0, 0x0, %psr +1: + set C_LABEL(sunos_sys_table), %l7 + ld [%l7 + %g1], %l6 -normal_data_page_fault: - std %l0, [%sp + C_STACK + PT_PSR] ! store %psr and pc - or %g0, %l3, %o0 - st %l2, [%sp + C_STACK + PT_NPC] ! store npc - st %l4, [%sp + C_STACK + PT_Y] ! store %y - or %g0, %l1, %o3 - - /* The globals have already been placed on the stack */ - std %i0, [%sp + C_STACK + PT_I0] ! store ins - std %i2, [%sp + C_STACK + PT_I2] - or %g0, %l0, %o4 - std %i4, [%sp + C_STACK + PT_I4] - std %i6, [%sp + C_STACK + PT_I6] - call C_LABEL(sparc_data_access_fault) - add %sp, C_STACK, %o5 - - ldd [%sp + C_STACK + PT_PSR], %l0 - ldd [%sp + C_STACK + PT_NPC], %l2 - wr %l3, 0x0, %y - ld [%sp + C_STACK + PT_G1], %g1 - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldd [%sp + C_STACK + PT_I0], %i0 - ldd [%sp + C_STACK + PT_I2], %i2 - ldd [%sp + C_STACK + PT_I4], %i4 - ldd [%sp + C_STACK + PT_I6], %i6 +2: + ld [%sp + STACKFRAME_SZ + PT_I1], %o0 + ld [%sp + STACKFRAME_SZ + PT_I2], %o1 + ld [%sp + STACKFRAME_SZ + PT_I3], %o2 + ld [%sp + STACKFRAME_SZ + PT_I4], %o3 + call %l6 + ld [%sp + STACKFRAME_SZ + PT_I5], %o4 + + b scall_store_args /* so stupid... */ + nop + + .align 4 + .globl C_LABEL(sys_execve) +C_LABEL(sys_execve): + call C_LABEL(sparc_execve) + add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg + + b scall_store_args + nop + + .align 4 + .globl C_LABEL(sys_pipe) +C_LABEL(sys_pipe): + call C_LABEL(sparc_pipe) + add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg - b ret_trap_entry - wr %l0, 0x0, %psr + b C_LABEL(ret_sys_call) + nop + .align 4 + .globl C_LABEL(sys_sigreturn) +C_LABEL(sys_sigreturn): + call C_LABEL(do_sigreturn) + add %sp, STACKFRAME_SZ, %o0 + + /* We don't want to muck with user registers like a + * normal syscall, just return. + */ + RESTORE_ALL + + /* Now that we have a real sys_clone, sys_fork() is + * implemented in terms of it. Our _real_ implementation + * of SunOS vfork() will use sys_clone() instead. + */ + .align 4 + .globl C_LABEL(sys_fork), C_LABEL(sys_vfork) +C_LABEL(sys_vfork): +C_LABEL(sys_fork): + /* Save the kernel state as of now. */ + FLUSH_ALL_KERNEL_WINDOWS; + STORE_WINDOW(sp) + LOAD_CURRENT(g6) + rd %psr, %g4 + rd %wim, %g5 + std %g4, [%g6 + THREAD_KPSR] + std %sp, [%g6 + THREAD_KSP] + + mov SIGCHLD, %o0 ! arg0: clone flags + mov %fp, %o1 ! arg1: usp + call C_LABEL(do_fork) + add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr - .align 4 - .globl C_LABEL(srmmu_text_fault) -C_LABEL(srmmu_text_fault): - ENTER_TRAP(srmmu_text_fault) - st %g1, [%sp + C_STACK + PT_G1] - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - rd %y, %l4 - set 0x300, %o0 - lda [%o0] ASI_M_MMUREGS, %o1 ! fault status - set 0x400, %o0 - lda [%o0] ASI_M_MMUREGS, %o2 ! fault address - wr %l0, PSR_ET, %psr ! traps back on - WRITE_PAUSE - std %l0, [%sp + C_STACK + PT_PSR] - or %g0, %l3, %o0 - st %l2, [%sp + C_STACK + PT_NPC] - st %l4, [%sp + C_STACK + PT_Y] - or %g0, %l1, %o3 - std %i0, [%sp + C_STACK + PT_I0] - std %i2, [%sp + C_STACK + PT_I2] - or %g0, %l0, %o4 - std %i4, [%sp + C_STACK + PT_I4] - std %i6, [%sp + C_STACK + PT_I6] - call C_LABEL(srmmu_text_access_fault) - add %sp, C_STACK, %o5 - - ldd [%sp + C_STACK + PT_PSR], %l0 - ldd [%sp + C_STACK + PT_NPC], %l2 - wr %l3, 0x0, %y - ld [%sp + C_STACK + PT_G1], %g1 - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldd [%sp + C_STACK + PT_I0], %i0 - ldd [%sp + C_STACK + PT_I2], %i2 - ldd [%sp + C_STACK + PT_I4], %i4 - ldd [%sp + C_STACK + PT_I6], %i6 + b scall_store_args + nop + + /* Whee, kernel threads! */ + .globl C_LABEL(sys_clone) +C_LABEL(sys_clone): + /* Save the kernel state as of now. */ + FLUSH_ALL_KERNEL_WINDOWS; + STORE_WINDOW(sp) + LOAD_CURRENT(g6) + rd %psr, %g4 + rd %wim, %g5 + std %g4, [%g6 + THREAD_KPSR] + std %sp, [%g6 + THREAD_KSP] - b ret_trap_entry - wr %l0, 0x0, %psr + ldd [%sp + STACKFRAME_SZ + PT_I0], %o0 ! arg0,1: flags,usp + cmp %o1, 0x0 ! Is new_usp NULL? + be,a 1f + mov %fp, %o1 ! yes, use current usp +1: + call C_LABEL(do_fork) + add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr - .align 4 - .globl C_LABEL(srmmu_data_fault) -C_LABEL(srmmu_data_fault): - ENTER_TRAP(srmmu_data_fault) - st %g1, [%sp + C_STACK + PT_G1] - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - rd %y, %l4 - - set AC_M_SFSR, %o0 - lda [%o0] ASI_M_MMUREGS, %o1 ! fault status - set AC_M_SFAR, %o0 - lda [%o0] ASI_M_MMUREGS, %o2 ! fault address - set AC_M_AFSR, %o0 - lda [%o0] ASI_M_MMUREGS, %o3 - set AC_M_AFAR, %o0 - lda [%o0] ASI_M_MMUREGS, %o4 - wr %l0, PSR_ET, %psr ! traps back on - WRITE_PAUSE - std %l0, [%sp + C_STACK + PT_PSR] - or %g0, %l3, %o0 - st %l2, [%sp + C_STACK + PT_NPC] - st %l4, [%sp + C_STACK + PT_Y] - std %i0, [%sp + C_STACK + PT_I0] - std %i2, [%sp + C_STACK + PT_I2] - std %i4, [%sp + C_STACK + PT_I4] - std %i6, [%sp + C_STACK + PT_I6] - call C_LABEL(srmmu_data_access_fault) - add %sp, C_STACK, %o5 - - ldd [%sp + C_STACK + PT_PSR], %l0 - ldd [%sp + C_STACK + PT_NPC], %l2 - wr %l3, 0x0, %y - ld [%sp + C_STACK + PT_G1], %g1 - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldd [%sp + C_STACK + PT_I0], %i0 - ldd [%sp + C_STACK + PT_I2], %i2 - ldd [%sp + C_STACK + PT_I4], %i4 - ldd [%sp + C_STACK + PT_I6], %i6 + b scall_store_args + nop - b ret_trap_entry - wr %l0, 0x0, %psr +#if 0 /* XXX Much later... XXX */ + /* Whee, vfork... */ + .globl C_LABEL(sys_vfork) +C_LABEL(sys_vfork): + /* Save the kernel state as of now. */ + FLUSH_ALL_KERNEL_WINDOWS; + STORE_WINDOW(sp) + LOAD_CURRENT(g6) + rd %psr, %g4 + rd %wim, %g5 + std %g4, [%g6 + THREAD_KPSR] + std %sp, [%g6 + THREAD_KSP] -/* Normal Linux system calls enter here... */ -/* Trying to make this as generic and simple as possible. */ + set (0x2100 | SIGCHLD), %o0 ! CLONE_VFORK,CLONE_VM,SIGCHLD + mov %fp, %o1 ! use current usp +1: + call C_LABEL(do_fork) + add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr - .align 4 - .globl linux_sparc_syscall + b scall_store_args + nop +#endif + + /* All system calls enter here... */ + .align 4 + .globl linux_sparc_syscall linux_sparc_syscall: /* Don't dork with %l7, it holds the pointer to the - * system call vector table. ENTER_TRAP does not + * system call vector table. SAVE_ALL does not * modify its value. */ - ENTER_TRAP(linux_sparc_syscall) + rd %wim, %l3 + SAVE_ALL - /* setup pt_regs stack frame, leave ints off... - * First save all but the current window onto the stack. - * This means nwindows-2 saves and nwindows-2 restores. - */ - andn %l0, PSR_PIL, %l5 - wr %l5, 0xf00, %psr - wr %l5, 0xf20, %psr ! no ints, traps on + wr %l0, PSR_ET, %psr /* Turn on traps + interrupts */ WRITE_PAUSE - - .globl nop7 - /* Flush windows */ - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp -nop7: save %sp, -C_STACK, %sp - restore - restore - restore - restore - restore - restore - - rd %psr, %l6 - and %l6, PSR_CWP, %l6 ! only care about CWP - andn %l0, PSR_CWP, %l0 - or %l0, %l6, %l0 ! %l0 is now the new %psr - - std %l0, [%sp + C_STACK + PT_PSR] ! save it away - rd %y, %l3 - std %l2, [%sp + C_STACK + PT_NPC] - - /* Put %wim in %g0 slot, a hack. This way we ensure that %wim - * sits right behind the current window in %psr, which is what - * we want. - */ - rd %wim, %l4 - st %l4, [%sp + C_STACK + PT_G0] - st %g1, [%sp + C_STACK + PT_G1] - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - std %i0, [%sp + C_STACK + PT_I0] - std %i2, [%sp + C_STACK + PT_I2] - std %i4, [%sp + C_STACK + PT_I4] - std %i6, [%sp + C_STACK + PT_I6] - - wr %l0, PSR_ET, %psr /* Turn on traps + interrupts */ - WRITE_PAUSE - - cmp %i0, NR_SYSCALLS - bgu,a C_LABEL(ret_sys_call) - or %g0, -1, %i0 - - cmp %i0, 0x2 ! fork? Same number for all OSs - bne not_fork - nop - call C_LABEL(sys_fork) ! yep, load pt_regs into first arg - add %sp, C_STACK, %o0 - b C_LABEL(ret_sys_call) - nop -not_fork: - /* Remember, trap table entry loaded syscall table ptr in %l7 */ - sll %i0, 0x2, %o0 - add %l7, %o0, %l7 - ld [%l7], %o5 ! load up ptr to syscall handler - - mov %i1, %o0 ! load up arguments - mov %i2, %o1 - mov %i3, %o2 - mov %i4, %o3 - jmpl %o5, %o7 ! Make syscall - mov %i5, %o4 - - .globl C_LABEL(ret_sys_call) /* exported for copy_process() */ -C_LABEL(ret_sys_call): /* Child of a fork returns here */ - /* dump the pt_regs back into their rightful places */ - ldd [%sp + C_STACK + PT_PSR], %l0 - ldd [%sp + C_STACK + PT_NPC], %l2 - wr %l3, 0x0, %y - - ld [%sp + C_STACK + PT_G1], %g1 - ldd [%sp + C_STACK + PT_G2], %g2 - ldd [%sp + C_STACK + PT_G4], %g4 - ldd [%sp + C_STACK + PT_G6], %g6 - ldd [%sp + C_STACK + PT_I0], %i0 - ldd [%sp + C_STACK + PT_I2], %i2 - ldd [%sp + C_STACK + PT_I4], %i4 - ldd [%sp + C_STACK + PT_I6], %i6 - /* %i6 is our frame pointer, the restore done by the rett - * instruction will automatically put us back on the users - * stack. - * Advance the pc and npc past the trap instruction, the copy_process() - * code for fork() depends on this being done right before trap return. - */ - or %l2, 0x0, %l5 +#if 0 /* Trace all system calls... */ + add %sp, STACKFRAME_SZ, %o0 + call C_LABEL(syscall_trace_entry) + nop +#endif - or %l5, 0x0, %l1 /* pc = npc */ - add %l5, 0x4, %l2 /* npc= npc+4 */ + /* SAVE_ALL may have blown away %g1, reload it. */ + ld [%sp + STACKFRAME_SZ + PT_G1], %g1 + cmp %g1, NR_SYSCALLS + bleu,a 1f + sll %g1, 0x2, %g1 - wr %l0, 0x0, %psr - WRITE_PAUSE - - /* Fall through to ret_trap_entry */ - -/* Return from trap code. I realized that I was duplicating a lot - * of logic in the various trap handlers. Traps are off upon entry. - */ - -ret_trap_entry: - and %l0, 0x1f, %l5 - sethi %hi(lnx_winmask), %l6 - or %l6, %lo(lnx_winmask), %l6 - ldub [%l6 + %l5], %l5 - andcc %l0, PSR_PS, %g0 - bnz ret_trap_kernel - rd %wim, %l4 - - sethi %hi(C_LABEL(current)), %l6 - ld [%l6 + %lo(C_LABEL(current))], %l6 - ld [%l6 + THREAD_W_SAVED], %l7 - subcc %g0, %l7, %g0 - bz,a ret_trap_user - nop - - wr %g0, 0, %wim - or %g0, %g6, %l3 - or %g0, %l6, %g6 - st %g0, [%g6 + THREAD_W_SAVED] - restore - restore %g0, 1, %l1 - rd %psr, %l0 - sll %l1, %l0, %l1 - wr %l1, 0x0, %wim - and %l0, 0x1f, %l0 - st %l0, [%g6 + THREAD_WIM] - nop - save %g0, %g0, %g0 - add %g6, THREAD_REG_WINDOW, %g6 - ldd [%g6], %l0 - ldd [%g6 + 0x8], %l2 - ldd [%g6 + 0x10], %l4 - ldd [%g6 + 0x18], %l6 - ldd [%g6 + 0x20], %i0 - ldd [%g6 + 0x28], %i2 - ldd [%g6 + 0x30], %i4 - ldd [%g6 + 0x38], %i6 - - save %g0, %g0, %g0 - wr %l0, 0x0, %psr - or %g0, %l3, %g6 - jmp %l1 - rett %l2 - -ret_trap_kernel: - andcc %l4, %l5, %g0 - bnz 1f - wr %l0, 0x0, %psr ! reset condition codes - nop - jmp %l1 - rett %l2 + set C_LABEL(sys_ni_syscall), %l6 + b 2f + nop 1: - wr %g0, 0x0, %wim - WRITE_PAUSE - restore - restore %g0, 0x1, %l1 - rd %psr, %l0 - and %l0, 0x1f, %l0 - sll %l1, %l0, %l1 - wr %l1, 0x0, %wim - sethi %hi(C_LABEL(current)), %l1 - ld [%l1 + %lo(C_LABEL(current))], %l1 - st %l0, [%l1 + THREAD_WIM] - save %g0, %g0, %g0 - ldd [%sp], %l0 - ldd [%sp + 0x8], %l2 - ldd [%sp + 0x10], %l4 - ldd [%sp + 0x18], %l6 - ldd [%sp + 0x20], %i0 - ldd [%sp + 0x28], %i2 - ldd [%sp + 0x30], %i4 - ldd [%sp + 0x38], %i6 + /* Syscall table ptr is in %l7. */ + ld [%l7 + %g1], %l6 ! load up ptr to syscall handler - save %g0, %g0, %g0 - jmp %l1 - rett %l2 + /* Pt_regs is your friend... Make the syscall... */ +2: + ldd [%sp + STACKFRAME_SZ + PT_I0], %o0 + ldd [%sp + STACKFRAME_SZ + PT_I2], %o2 + ldd [%sp + STACKFRAME_SZ + PT_I4], %o4 + call %l6 + nop + +scall_store_args: + st %o0, [%sp + STACKFRAME_SZ + PT_I0] + + .globl C_LABEL(ret_sys_call) +C_LABEL(ret_sys_call): + ld [%sp + STACKFRAME_SZ + PT_I0], %o0 + set PSR_C, %l6 + cmp %o0, -ELIBSCN + bgeu 1f + ld [%sp + STACKFRAME_SZ + PT_PSR], %l5 -ret_trap_user: - andcc %l4, %l5, %g0 - bnz 1f - wr %l0, 0x0, %psr - nop - jmp %l1 - rett %l2 + /* System call success, clear Carry condition code. */ + andn %l5, %l6, %l5 + b 2f + st %l5, [%sp + STACKFRAME_SZ + PT_PSR] 1: - wr %g0, 0x0, %wim - wr %l0, 0x0, %psr - WRITE_PAUSE - restore - restore %g0, 0x1, %l1 - rd %psr, %l0 - sll %l1, %l0, %l1 - wr %l1, 0x0, %wim - sethi %hi(C_LABEL(current)), %l1 - ld [%l1 + %lo(C_LABEL(current))], %l1 - and %l0, 0x1f, %l0 - st %l0, [%l1 + THREAD_WIM] - save %g0, %g0, %g0 - ldd [%sp], %l0 - ldd [%sp + 0x8], %l2 - ldd [%sp + 0x10], %l4 - ldd [%sp + 0x18], %l6 - ldd [%sp + 0x20], %i0 - ldd [%sp + 0x28], %i2 - ldd [%sp + 0x30], %i4 - ldd [%sp + 0x38], %i6 - save %g0, %g0, %g0 - jmp %l1 - rett %l2 - -/* Context switch code. I don't feel like playing around with - * inline gcc-assembly to do this right, so here it is. The new - * process's task_struct ptr is passed in %o0. - * - * This is still work in progress. - * ONLY MAKE PROM CALLS FOR DIAGNOSTICS WHEN TRAPS ARE ON!!!!! - * - * First successful task switch 05/13/95 21:52:37 - * - */ - .align 4 - .globl C_LABEL(sparc_switch_to) -C_LABEL(sparc_switch_to): - or %g0, %o0, %l5 - sethi %hi(C_LABEL(current)), %l6 - ld [%l6 + %lo(C_LABEL(current))], %l6 - rd %psr, %l0 - - or %g0, %l0, %l4 - andn %l0, PSR_PIL, %l0 /* turn off IRQ level bits leave PSR_ET on */ - - wr %l0, 0xf00, %psr /* NO interrupts */ - WRITE_PAUSE - - /* Save state of old process */ - .globl rnop7 - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp - save %sp, -C_STACK, %sp -rnop7: save %sp, -C_STACK, %sp - restore - restore - restore - restore - restore - restore - - rd %psr, %l3 - and %l3, PSR_CWP, %l3 ! only care about CWP bits now - andn %l0, PSR_CWP, %l0 ! integrate with old %psr - or %l3, %l0, %l0 - - st %l0, [%sp + C_STACK + PT_PSR] ! save new %psr - /* ??? We backtrack the PC two instructions due to retl's semantics ??? */ - /*sub %o7, 0x8, %o7 */ - st %o7, [%sp + C_STACK + PT_PC] ! save return PC - add %o7, 0x4, %l3 - st %l3, [%sp + C_STACK + PT_NPC] ! and NPC - - rd %y, %l3 - st %l3, [%sp + C_STACK + PT_Y] ! save %y - - /* Save the %wim into %g0 slot, ensures that it sits behind CWP */ - rd %wim, %l3 - st %l3, [%sp + C_STACK + PT_G0] ! save new %wim - st %g1, [%sp + C_STACK + PT_G1] - std %g2, [%sp + C_STACK + PT_G2] - std %g4, [%sp + C_STACK + PT_G4] - std %g6, [%sp + C_STACK + PT_G6] - std %i0, [%sp + C_STACK + PT_I0] - std %i2, [%sp + C_STACK + PT_I2] - std %i4, [%sp + C_STACK + PT_I4] - std %i6, [%sp + C_STACK + PT_I6] - - wr %l0, (0xf20), %psr ! no traps, no intrs - WRITE_PAUSE - - /* TRAPS ARE OFF, NO PROM CALLS WHATSOEVER FOR DEBUGGING!!! */ - /* SO what we do is we put an imperical constant in %g2 and - * a 'counter' in %g1 which we increment after every instruction - * so we can figure out where the thing prom panics. Then at the - * prom prompt we print out the saved registers. To drop into the - * prom and look at the registers just execute 7 saves since that - * will induce a window trap before the last one and traps are off, - * thus a watchdog reset will occur. - */ - - /* Grrr, this is hairy... be careful, again NO PROM CALLS YET! */ - /* Load up the new 'current' */ - sethi %hi(C_LABEL(current)), %g1 - st %l5, [%g1 + %lo(C_LABEL(current))] - - /* Load up new processes stack, we always switch onto the kernel stack */ - /* Be CAREFUL, use globals for temporaries, because after we change the - * %psr the window could change and you will most likely be accessing - * different outs, ins, and locals than you origionally were. - */ - or %g0, %l5, %g6 - ld [%l5 + THREAD_KSP], %g3 - - /* New procs %psr */ - ld [%g3 + C_STACK + PT_PSR], %g4 - wr %g4, 0xf00, %psr /* No ints, no traps */ - WRITE_PAUSE - - /* We could be in a different window NOW. Assume nothing about the - * current set of in, out and local registers. + /* System call failure, set Carry condition code. + * Also, get abs(errno) to return to the process. */ + sub %g0, %o0, %o0 + st %o0, [%sp + STACKFRAME_SZ + PT_I0] + or %l5, %l6, %l5 + st %l5, [%sp + STACKFRAME_SZ + PT_PSR] - /* New procs %wim */ - ld [%g3 + C_STACK + PT_G0], %l4 /* %wim is here */ - st %l4, [%g6 + THREAD_WIM] /* Update tss */ - wr %l4, 0x0, %wim /* Use it */ - WRITE_PAUSE - - /* Finally, load the stack */ - or %g0, %g3, %sp - - /* We are now sane, we have a good stack and our state is reflected - * properly in 'current'. Let it rip. - */ - /* Remember, you can't increase PIL and turn on traps at the - * same time. + /* %i6 is our frame pointer, the restore done by the rett + * instruction will automatically put us back on the users + * stack. Advance the pc and npc past the trap instruction. */ - wr %g4, 0xf00, %psr /* Traps on, no interrupts. */ - wr %g4, 0xf20, %psr - WRITE_PAUSE - - sethi %hi(C_LABEL(current)), %o0 - ld [%o0 + %lo(C_LABEL(current))], %o0 - ld [%o0 + THREAD_PC], %o7 /* Setup return address */ - - /* cross fingers */ - retl - nop - -/* The following two things point to window management tables. The first - * one is used to quickly look up how many user windows there are from - * trap-land. The second is used in a trap handler to determine if a rett - * instruction will land us smack inside the invalid window that possibly - * the trap was called to fix-up. - */ - -/* For now these are static tables geared for a 7 window sparc. - * But in head.S after we calculate this table based upon the - * nwindows value. This table is big enough for a 16 window sparc. - */ - +2: + ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ + add %l1, 0x4, %l2 /* npc = npc+4 */ + st %l1, [%sp + STACKFRAME_SZ + PT_PC] + st %l2, [%sp + STACKFRAME_SZ + PT_NPC] + +#if 0 /* Trace all system calls... */ + add %sp, STACKFRAME_SZ, %o0 + call C_LABEL(syscall_trace_exit) + nop +#endif + + RESTORE_ALL + + .globl C_LABEL(flush_user_windows) +C_LABEL(flush_user_windows): + LOAD_CURRENT(g2) + ld [%g2 + THREAD_UMASK], %g1 + orcc %g0, %g1, %g0 + be 3f + clr %g3 +1: + _SV + LOAD_CURRENT(g2) + ld [%g2 + THREAD_UMASK], %g1 + orcc %g0, %g1, %g0 + bne 1b + add %g3, 1, %g3 +2: + subcc %g3, 1, %g3 + bne 2b + _RS +3: + jmp %o7 + 0x8 + nop - .data - .align 4 - .globl lnx_winmask -lnx_winmask: - .byte 2, 4, 8, 16, 32, 64, 1, 0 - .byte 0, 0, 0, 0, 0, 0, 0, 0 - - .align 4 - .globl C_LABEL(sys_call_table) -C_LABEL(sys_call_table): - .long C_LABEL(sys_setup) /* 0 */ - .long C_LABEL(sys_exit) - .long C_LABEL(sys_fork) - .long C_LABEL(sys_read) - .long C_LABEL(sys_write) - .long C_LABEL(sys_open) /* 5 */ - .long C_LABEL(sys_close) - .long C_LABEL(sys_waitpid) - .long C_LABEL(sys_creat) - .long C_LABEL(sys_link) - .long C_LABEL(sys_unlink) /* 10 */ - .long C_LABEL(sys_execve) - .long C_LABEL(sys_chdir) - .long C_LABEL(sys_time) - .long C_LABEL(sys_mknod) - .long C_LABEL(sys_chmod) /* 15 */ - .long C_LABEL(sys_chown) - .long C_LABEL(sys_break) - .long C_LABEL(sys_stat) - .long C_LABEL(sys_lseek) - .long C_LABEL(sys_getpid) /* 20 */ - .long C_LABEL(sys_mount) - .long C_LABEL(sys_umount) - .long C_LABEL(sys_setuid) - .long C_LABEL(sys_getuid) - .long C_LABEL(sys_stime) /* 25 */ - .long C_LABEL(sys_ni_syscall) /* this will be sys_ptrace() */ - .long C_LABEL(sys_alarm) - .long C_LABEL(sys_fstat) - .long C_LABEL(sys_pause) - .long C_LABEL(sys_utime) /* 30 */ - .long C_LABEL(sys_stty) - .long C_LABEL(sys_gtty) - .long C_LABEL(sys_access) - .long C_LABEL(sys_nice) - .long C_LABEL(sys_ftime) /* 35 */ - .long C_LABEL(sys_sync) - .long C_LABEL(sys_kill) - .long C_LABEL(sys_rename) - .long C_LABEL(sys_mkdir) - .long C_LABEL(sys_rmdir) /* 40 */ - .long C_LABEL(sys_dup) - .long C_LABEL(sys_pipe) - .long C_LABEL(sys_times) - .long C_LABEL(sys_prof) - .long C_LABEL(sys_brk) /* 45 */ - .long C_LABEL(sys_setgid) - .long C_LABEL(sys_getgid) - .long C_LABEL(sys_signal) - .long C_LABEL(sys_geteuid) - .long C_LABEL(sys_getegid) /* 50 */ - .long C_LABEL(sys_acct) - .long C_LABEL(sys_phys) - .long C_LABEL(sys_lock) - .long C_LABEL(sys_ioctl) - .long C_LABEL(sys_fcntl) /* 55 */ - .long C_LABEL(sys_mpx) - .long C_LABEL(sys_setpgid) - .long C_LABEL(sys_ulimit) - .long C_LABEL(sys_olduname) - .long C_LABEL(sys_umask) /* 60 */ - .long C_LABEL(sys_chroot) - .long C_LABEL(sys_ustat) - .long C_LABEL(sys_dup2) - .long C_LABEL(sys_getppid) - .long C_LABEL(sys_getpgrp) /* 65 */ - .long C_LABEL(sys_setsid) - .long C_LABEL(sys_sigaction) - .long C_LABEL(sys_sgetmask) - .long C_LABEL(sys_ssetmask) - .long C_LABEL(sys_setreuid) /* 70 */ - .long C_LABEL(sys_setregid) - .long C_LABEL(sys_sigsuspend) - .long C_LABEL(sys_sigpending) - .long C_LABEL(sys_sethostname) - .long C_LABEL(sys_setrlimit) /* 75 */ - .long C_LABEL(sys_getrlimit) - .long C_LABEL(sys_getrusage) - .long C_LABEL(sys_gettimeofday) - .long C_LABEL(sys_settimeofday) - .long C_LABEL(sys_getgroups) /* 80 */ - .long C_LABEL(sys_setgroups) - .long C_LABEL(sys_select) - .long C_LABEL(sys_symlink) - .long C_LABEL(sys_lstat) - .long C_LABEL(sys_readlink) /* 85 */ - .long C_LABEL(sys_uselib) - .long C_LABEL(sys_swapon) - .long C_LABEL(sys_reboot) - .long C_LABEL(sys_readdir) - .long C_LABEL(sys_mmap) /* 90 */ - .long C_LABEL(sys_munmap) - .long C_LABEL(sys_truncate) - .long C_LABEL(sys_ftruncate) - .long C_LABEL(sys_fchmod) - .long C_LABEL(sys_fchown) /* 95 */ - .long C_LABEL(sys_getpriority) - .long C_LABEL(sys_setpriority) - .long C_LABEL(sys_profil) - .long C_LABEL(sys_statfs) - .long C_LABEL(sys_fstatfs) /* 100 */ - .long C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_socketcall) - .long C_LABEL(sys_syslog) - .long C_LABEL(sys_setitimer) - .long C_LABEL(sys_getitimer) /* 105 */ - .long C_LABEL(sys_newstat) - .long C_LABEL(sys_newlstat) - .long C_LABEL(sys_newfstat) - .long C_LABEL(sys_uname) - .long C_LABEL(sys_ni_syscall) /* 110 */ - .long C_LABEL(sys_vhangup) - .long C_LABEL(sys_idle) - .long C_LABEL(sys_ni_syscall) /* was vm86, meaningless on Sparc */ - .long C_LABEL(sys_wait4) - .long C_LABEL(sys_swapoff) /* 115 */ - .long C_LABEL(sys_sysinfo) - .long C_LABEL(sys_ipc) - .long C_LABEL(sys_fsync) - .long C_LABEL(sys_sigreturn) - .long C_LABEL(sys_ni_syscall) /* 120 */ - .long C_LABEL(sys_setdomainname) - .long C_LABEL(sys_newuname) - .long C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_adjtimex) - .long C_LABEL(sys_mprotect) /* 125 */ - .long C_LABEL(sys_sigprocmask) - .long C_LABEL(sys_create_module) - .long C_LABEL(sys_init_module) - .long C_LABEL(sys_delete_module) - .long C_LABEL(sys_get_kernel_syms) /* 130 */ - .long C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_getpgid) - .long C_LABEL(sys_fchdir) - .long C_LABEL(sys_bdflush) - .long C_LABEL(sys_sysfs) /* 135 */ - .long C_LABEL(sys_personality) - .long C_LABEL(sys_ni_syscall) /* for afs_syscall */ - .long C_LABEL(sys_setfsuid) - .long C_LABEL(sys_setfsgid) - .long C_LABEL(sys_llseek) /* 140 */ - .long C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 150 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 160 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 170 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 180 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 190 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 200 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 210 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 220 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 230 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 240 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - - /* 250 */ - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall) /* 255 */ - .align 4 +/* End of entry.S */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/errtbls.c linux/arch/sparc/kernel/errtbls.c --- v1.3.43/linux/arch/sparc/kernel/errtbls.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/errtbls.c Sat Nov 25 02:57:57 1995 @@ -0,0 +1,276 @@ +/* $Id: errtbls.c,v 1.2 1995/11/25 00:57:55 davem Exp $ + * errtbls.c: Error number conversion tables between various syscall + * OS semantics. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Based upon preliminary work which is: + * + * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) + */ + +#include /* NetBSD (bsd4.4) errnos */ +#include /* Solaris errnos */ + +/* Here are tables which convert between Linux/SunOS error number + * values to the equivalent in other OSs. Note that since the Linux + * ones have been set up to match exactly those of SunOS, no + * translation table is needed for that OS. + */ + +int solaris_errno[] = { + 0, + SOL_EPERM, + SOL_ENOENT, + SOL_ESRCH, + SOL_EINTR, + SOL_EIO, + SOL_ENXIO, + SOL_E2BIG, + SOL_ENOEXEC, + SOL_EBADF, + SOL_ECHILD, + SOL_EAGAIN, + SOL_ENOMEM, + SOL_EACCES, + SOL_EFAULT, + SOL_NOTBLK, + SOL_EBUSY, + SOL_EEXIST, + SOL_EXDEV, + SOL_ENODEV, + SOL_ENOTDIR, + SOL_EISDIR, + SOL_EINVAL, + SOL_ENFILE, + SOL_EMFILE, + SOL_ENOTTY, + SOL_ETXTBSY, + SOL_EFBIG, + SOL_ENOSPC, + SOL_ESPIPE, + SOL_EROFS, + SOL_EMLINK, + SOL_EPIPE, + SOL_EDOM, + SOL_ERANGE, + SOL_EWOULDBLOCK, + SOL_EINPROGRESS, + SOL_EALREADY, + SOL_ENOTSOCK, + SOL_EDESTADDRREQ, + SOL_EMSGSIZE, + SOL_EPROTOTYPE, + SOL_ENOPROTOOPT, + SOL_EPROTONOSUPPORT, + SOL_ESOCKTNOSUPPORT, + SOL_EOPNOTSUPP, + SOL_EPFNOSUPPORT, + SOL_EAFNOSUPPORT, + SOL_EADDRINUSE, + SOL_EADDRNOTAVAIL, + SOL_ENETDOWN, + SOL_ENETUNREACH, + SOL_ENETRESET, + SOL_ECONNABORTED, + SOL_ECONNRESET, + SOL_ENOBUFS, + SOL_EISCONN, + SOL_ENOTONN, + SOL_ESHUTDOWN, + SOL_ETOOMANYREFS, + SOL_ETIMEDOUT, + SOL_ECONNREFUSED, + SOL_ELOOP, + SOL_ENAMETOOLONG, + SOL_EHOSTDOWN, + SOL_EHOSTUNREACH, + SOL_ENOTEMPTY, + SOL_EPROCLIM, + SOL_EUSERS, + SOL_EDQUOT, + SOL_ESTALE, + SOL_EREMOTE, + SOL_ENOSTR, + SOL_ETIME, + SOL_ENOSR, + SOL_ENOMSG, + SOL_EBADMSG, + SOL_IDRM, + SOL_EDEADLK, + SOL_ENOLCK, + SOL_ENONET, + SOL_ERREMOTE, + SOL_ENOLINK, + SOL_EADV, + SOL_ESRMNT, + SOL_ECOMM, + SOL_EPROTO, + SOL_EMULTIHOP, + SOL_EINVAL, /* EDOTDOT XXX??? */ + SOL_REMCHG, + SOL_NOSYS, + SOL_STRPIPE, + SOL_EOVERFLOW, + SOL_EBADFD, + SOL_ECHRNG, + SOL_EL2NSYNC, + SOL_EL3HLT, + SOL_EL3RST, + SOL_NRNG, + SOL_EUNATCH, + SOL_ENOCSI, + SOL_EL2HLT, + SOL_EBADE, + SOL_EBADR, + SOL_EXFULL, + SOL_ENOANO, + SOL_EBADRQC, + SOL_EBADSLT, + SOL_EDEADLOCK, + SOL_EBFONT, + SOL_ELIBEXEC, + SOL_ENODATA, + SOL_ELIBBAD, + SOL_ENOPKG, + SOL_ELIBACC, + SOL_ENOTUNIQ, + SOL_ERESTART, + SOL_EUCLEAN, + SOL_ENOTNAM, + SOL_ENAVAIL, + SOL_EISNAM, + SOL_EREMOTEIO, + SOL_EILSEQ, + SOL_ELIBMAX, + SOL_ELIBSCN, +}; + +int netbsd_errno[] = { + 0, + BSD_EPERM, + BSD_ENOENT, + BSD_ESRCH, + BSD_EINTR, + BSD_EIO, + BSD_ENXIO, + BSD_E2BIG, + BSD_ENOEXEC, + BSD_EBADF, + BSD_ECHILD, + BSD_EAGAIN, + BSD_ENOMEM, + BSD_EACCES, + BSD_EFAULT, + BSD_NOTBLK, + BSD_EBUSY, + BSD_EEXIST, + BSD_EXDEV, + BSD_ENODEV, + BSD_ENOTDIR, + BSD_EISDIR, + BSD_EINVAL, + BSD_ENFILE, + BSD_EMFILE, + BSD_ENOTTY, + BSD_ETXTBSY, + BSD_EFBIG, + BSD_ENOSPC, + BSD_ESPIPE, + BSD_EROFS, + BSD_EMLINK, + BSD_EPIPE, + BSD_EDOM, + BSD_ERANGE, + BSD_EWOULDBLOCK, + BSD_EINPROGRESS, + BSD_EALREADY, + BSD_ENOTSOCK, + BSD_EDESTADDRREQ, + BSD_EMSGSIZE, + BSD_EPROTOTYPE, + BSD_ENOPROTOOPT, + BSD_EPROTONOSUPPORT, + BSD_ESOCKTNOSUPPORT, + BSD_EOPNOTSUPP, + BSD_EPFNOSUPPORT, + BSD_EAFNOSUPPORT, + BSD_EADDRINUSE, + BSD_EADDRNOTAVAIL, + BSD_ENETDOWN, + BSD_ENETUNREACH, + BSD_ENETRESET, + BSD_ECONNABORTED, + BSD_ECONNRESET, + BSD_ENOBUFS, + BSD_EISCONN, + BSD_ENOTONN, + BSD_ESHUTDOWN, + BSD_ETOOMANYREFS, + BSD_ETIMEDOUT, + BSD_ECONNREFUSED, + BSD_ELOOP, + BSD_ENAMETOOLONG, + BSD_EHOSTDOWN, + BSD_EHOSTUNREACH, + BSD_ENOTEMPTY, + BSD_EPROCLIM, + BSD_EUSERS, + BSD_EDQUOT, + BSD_ESTALE, + BSD_EREMOTE, + BSD_ENOSTR, + BSD_ETIME, + BSD_ENOSR, + BSD_ENOMSG, + BSD_EBADMSG, + BSD_IDRM, + BSD_EDEADLK, + BSD_ENOLCK, + BSD_ENONET, + BSD_ERREMOTE, + BSD_ENOLINK, + BSD_EADV, + BSD_ESRMNT, + BSD_ECOMM, + BSD_EPROTO, + BSD_EMULTIHOP, + BSD_EINVAL, /* EDOTDOT XXX??? */ + BSD_REMCHG, + BSD_NOSYS, + BSD_STRPIPE, + BSD_EOVERFLOW, + BSD_EBADFD, + BSD_ECHRNG, + BSD_EL2NSYNC, + BSD_EL3HLT, + BSD_EL3RST, + BSD_NRNG, + BSD_EUNATCH, + BSD_ENOCSI, + BSD_EL2HLT, + BSD_EBADE, + BSD_EBADR, + BSD_EXFULL, + BSD_ENOANO, + BSD_EBADRQC, + BSD_EBADSLT, + BSD_EDEADLOCK, + BSD_EBFONT, + BSD_ELIBEXEC, + BSD_ENODATA, + BSD_ELIBBAD, + BSD_ENOPKG, + BSD_ELIBACC, + BSD_ENOTUNIQ, + BSD_ERESTART, + BSD_EUCLEAN, + BSD_ENOTNAM, + BSD_ENAVAIL, + BSD_EISNAM, + BSD_EREMOTEIO, + BSD_EILSEQ, + BSD_ELIBMAX, + BSD_ELIBSCN, +}; + diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S --- v1.3.43/linux/arch/sparc/kernel/etrap.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/etrap.S Sat Nov 25 02:58:00 1995 @@ -0,0 +1,326 @@ +/* $Id: etrap.S,v 1.10 1995/11/25 00:57:58 davem Exp $ + * etrap.S: Sparc trap window preparation for entry into the + * Linux kernel. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include + +/* Registers to not touch at all. */ +#define t_psr l0 /* Set by caller */ +#define t_pc l1 /* Set by caller */ +#define t_npc l2 /* Set by caller */ +#define t_wim l3 /* Set by caller */ +#define t_twinmask l4 /* Set at beginning of this entry routine. */ +#define t_kstack l5 /* Set right before pt_regs frame is built */ +#define t_retpc l6 /* If you change this, change winmacro.h header file */ +#define t_systable l7 /* Never touch this, could be the syscall table ptr. */ +#define curptr g4 /* Set after pt_regs frame is built */ + + .text + .align 4 + + /* SEVEN WINDOW PATCH INSTRUCTIONS */ + .globl tsetup_7win_patch1, tsetup_7win_patch2 + .globl tsetup_7win_patch3, tsetup_7win_patch4 + .globl tsetup_7win_patch5, tsetup_7win_patch6 +tsetup_7win_patch1: sll %t_wim, 0x6, %t_wim +tsetup_7win_patch2: and %g2, 0x7f, %g2 +tsetup_7win_patch3: and %g2, 0x7f, %g2 +tsetup_7win_patch4: and %g1, 0x7f, %g1 +tsetup_7win_patch5: sll %t_wim, 0x6, %t_wim +tsetup_7win_patch6: and %g2, 0x7f, %g2 + /* END OF PATCH INSTRUCTIONS */ + + /* At trap time, interrupts and all generic traps do the + * following: + * + * rd %psr, %l0 + * b some_handler + * rd %wim, %l3 + * nop + * + * Then 'some_handler' if it needs a trap frame (ie. it has + * to call c-code and the trap cannot be handled in-window) + * then it does the SAVE_ALL macro in entry.S which does + * + * sethi %hi(trap_setup), %l4 + * jmpl %l4 + %lo(trap_setup), %l6 + * mov 1, %l4 + */ + + /* 2 3 4 window number + * ----- + * O T S mnemonic + * + * O == Current window before trap + * T == Window entered when trap occurred + * S == Window we will need to save if (1<tss.w_saved */ + LOAD_CURRENT(curptr) + st %g0, [%curptr + THREAD_W_SAVED] + + /* See if we are in the trap window. */ + andcc %t_twinmask, %t_wim, %g0 + bne trap_setup_user_spill ! yep we are + orn %g0, %t_twinmask, %g1 ! negate trap win mask into %g1 + + /* Trap from user, but not into the invalid window. + * Calculate new umask. The way this works is, + * any window from the %wim at trap time until + * the window right before the one we are in now, + * is a user window. A diagram: + * + * 7 6 5 4 3 2 1 0 window number + * --------------- + * I L T mnemonic + * + * Window 'I' is the invalid window in our example, + * window 'L' is the window the user was in when + * the trap occurred, window T is the trap window + * we are in now. So therefore, windows 5, 4 and + * 3 are user windows. The following sequence + * computes the user winmask to represent this. + */ + subcc %t_wim, %t_twinmask, %g2 + bneg,a 1f + sub %g2, 0x1, %g2 +1: + andn %g2, %t_twinmask, %g2 +tsetup_patch3: and %g2, 0xff, %g2 ! patched on 7win Sparcs + st %g2, [%curptr + THREAD_UMASK] ! store new umask + + mov %t_kstack, %sp ! and onto kernel stack + jmpl %t_retpc + 0x8, %g0 ! return to caller + nop + +trap_setup_user_spill: + /* A spill occured from either kernel or user mode + * and there exist some user windows to deal with. + * A mask of the currently valid user windows + * is in %g1 upon entry to here. + */ + +tsetup_patch4: and %g1, 0xff, %g1 ! patched on 7win Sparcs, mask + srl %t_wim, 0x1, %g2 ! compute new %wim +tsetup_patch5: sll %t_wim, 0x7, %t_wim ! patched on 7win Sparcs + or %t_wim, %g2, %g2 ! %g2 is new %wim +tsetup_patch6: and %g2, 0xff, %g2 ! patched on 7win Sparcs + andn %g1, %g2, %g1 ! clear this bit in %g1 + st %g1, [%curptr + THREAD_UMASK] + + save %g0, %g0, %g0 + + wr %g2, 0x0, %wim + WRITE_PAUSE + + /* Call MMU-architecture dependant stack checking + * routine. + */ + .globl C_LABEL(tsetup_mmu_patchme) +C_LABEL(tsetup_mmu_patchme): b C_LABEL(tsetup_sun4c_stackchk) + andcc %sp, 0x7, %g0 + +trap_setup_user_stack_is_bolixed: + /* From user/kernel into invalid window w/bad user + * stack. Save bad user stack, and return to caller. + */ + SAVE_BOLIXED_USER_STACK(curptr, g3) + restore %g0, %g0, %g0 + mov %t_kstack, %sp + jmpl %t_retpc + 0x8, %g0 + nop + +trap_setup_good_ustack: + STORE_WINDOW(sp) + +trap_setup_finish_up: + restore %g0, %g0, %g0 + mov %t_kstack, %sp + jmpl %t_retpc + 0x8, %g0 + nop + + /* Architecture specific stack checking routines. When either + * of these routines are called, the globals are free to use + * as they have been safely stashed on the new kernel stack + * pointer. Thus the definition below for simplicity. + */ +#define glob_tmp g1 + + .globl C_LABEL(tsetup_sun4c_stackchk) + .globl C_LABEL(tsetup_srmmu_stackchk) +C_LABEL(tsetup_sun4c_stackchk): + /* Done by caller: andcc %sp, 0x7, %g0 */ + be 1f + sra %sp, 29, %glob_tmp + + b trap_setup_user_stack_is_bolixed + nop + +1: + add %glob_tmp, 0x1, %glob_tmp + andncc %glob_tmp, 0x1, %g0 + be 1f + and %sp, 0xfff, %glob_tmp ! delay slot + + b trap_setup_user_stack_is_bolixed + nop + + /* See if our dump area will be on more than one + * page. + */ +1: + add %glob_tmp, 0x38, %glob_tmp + andncc %glob_tmp, 0xff8, %g0 + be tsetup_sun4c_onepage ! only one page to check + lda [%sp] ASI_PTE, %glob_tmp ! have to check first page anyways + +tsetup_sun4c_twopages: + /* Is first page ok permission wise? */ + srl %glob_tmp, 29, %glob_tmp + cmp %glob_tmp, 0x6 + be 1f + add %sp, 0x38, %glob_tmp /* Is second page in vma hole? */ + + b trap_setup_user_stack_is_bolixed + nop + +1: + sra %glob_tmp, 29, %glob_tmp + add %glob_tmp, 0x1, %glob_tmp + andncc %glob_tmp, 0x1, %g0 + be 1f + add %sp, 0x38, %glob_tmp + + b trap_setup_user_stack_is_bolixed + nop + +1: + lda [%glob_tmp] ASI_PTE, %glob_tmp + +tsetup_sun4c_onepage: + srl %glob_tmp, 29, %glob_tmp + cmp %glob_tmp, 0x6 ! can user write to it? + be trap_setup_good_ustack ! success + nop + + b trap_setup_user_stack_is_bolixed + nop + +C_LABEL(tsetup_srmmu_stackchk): + /* Check results of callers andcc %sp, 0x7, %g0 */ + bne trap_setup_user_stack_is_bolixed + sethi %hi(KERNBASE), %glob_tmp + cmp %glob_tmp, %sp + bleu trap_setup_user_stack_is_bolixed + nop + + /* Clear the fault status and turn on the no_fault bit. */ + mov AC_M_SFSR, %glob_tmp ! delay from above... + lda [%glob_tmp] ASI_M_MMUREGS, %g0 ! eat SFSR + lda [%g0] ASI_M_MMUREGS, %glob_tmp ! read MMU control + or %glob_tmp, 0x2, %glob_tmp ! or in no_fault bit + sta %glob_tmp, [%g0] ASI_M_MMUREGS ! set it + + /* Dump the registers and cross fingers. */ + STORE_WINDOW(sp) + + /* Clear the no_fault bit and check the status. */ + andn %glob_tmp, 0x2, %glob_tmp + sta %glob_tmp, [%g0] ASI_M_MMUREGS + mov AC_M_SFAR, %glob_tmp + lda [%glob_tmp] ASI_M_MMUREGS, %g0 + mov AC_M_SFSR, %glob_tmp + lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp + andcc %glob_tmp, 0x2, %g0 ! did we fault? + be trap_setup_finish_up ! cool beans, success + nop + + b trap_setup_user_stack_is_bolixed ! we faulted, ugh + nop diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S --- v1.3.43/linux/arch/sparc/kernel/head.S Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/head.S Sat Nov 25 02:58:04 1995 @@ -1,67 +1,23 @@ -/* head.S: The initial boot code for the Sparc port of Linux. +/* $Id: head.S,v 1.39 1995/11/25 00:58:01 davem Exp $ + * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * This file has to serve three purposes. - * - * 1) determine the prom-version and cpu/architecture - * 2) print enough useful info before we start to execute - * c-code that I can possibly begin to debug things - * 3) Hold the vector of trap entry points - * - * The Sparc offers many challenges to kernel design. Here I will - * document those I have come across thus far. Upon bootup the boot - * prom loads your a.out image into memory. This memory the prom has - * already mapped for you in two places, however as far as I can tell - * the virtual address cache is not turned on although the MMU is - * translating things. You get loaded at 0x4000 exactly and you are - * aliased to 0xf8004000 with the appropriate mmu entries. So, when - * you link a boot-loadable object you want to do something like - * - * ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o .... - * - * to produce a proper image. - * - * At boot time you are given (as far as I can tell at this time) - * one key to figure out what machine you are one and what devices - * are available. The prom when it loads you leaves a pointer to - * the 'rom vector' in register %o0 right before it jumps to your - * starting address. This is a pointer to a struct that is full of - * pointer to functions (ie. printf, halt, reboot), pointers to - * linked lists (ie. memory mappings), and pointer to empirical - * constants (ie. stdin and stdout magic cookies + rom version). - * Starting with this piece of information you can figure out - * just about anything you want about the machine you are on. - * - * Although I don't use it now, if you are on a Multiprocessor and - * therefore a v3 or above prom, register %o2 at boot contains a - * function pointer you must call before you proceed to invoke the - * other cpu's on the machine. I have no idea what kind of magic this - * is, give me time. + * Copyright (C) 1995 Peter Zaitcev (Zaitcev@ipmce.su) */ +#include + #include #include -#include #include #include +#include #include #include #include +#include .data - -/* First thing to go in the data segment is the interrupt stack. */ - - .globl C_LABEL(intstack) - .globl C_LABEL(eintstack) - .align 4 -C_LABEL(intstack): - .skip 4 * PAGE_SIZE ! 16k = 128 128-byte stack frames -C_LABEL(eintstack): - - - /* * The following are used with the prom_vector node-ops to figure out * the cpu-type @@ -98,10 +54,7 @@ C_LABEL(cputypvar_sun4m): .asciz "compatible" -/* WARNING: evil messages follow */ - .align 4 - sun4_notsup: .asciz "Sparc-Linux sun4 support not implemented yet\n\n" .align 4 @@ -118,302 +71,112 @@ .asciz "Sparc-Linux sun4u support does not exist\n\n" .align 4 -/* Ok, things start to get interesting. We get linked such that 'start' - * is the entry symbol. However, it is real low in kernel address space - * and as such a nifty place to place the trap table. We achieve this goal - * by just jumping to 'gokernel' for the first trap's entry as the sparc - * never receives the zero trap as it is real special (hw reset). - * - * Each trap entry point is the size of 4 sparc instructions (or 4 bytes - * * 4 insns = 16 bytes). There are 128 hardware traps (some undefined - * or unimplemented) and 128 software traps (sys-calls, etc.). - * - * One of the instructions must be a branch. More often than not this - * will be to a trap handler entry point because it is completely - * impossible to handle any trap in 4 insns. I welcome anyone to - * challenge this theory. :-) - * - * On entry into this table the hardware has loaded the program counter - * at which the trap occurred into register %l1 and the next program - * counter into %l2, this way we can return from the trap with a simple - * - * jmp %l1; rett %l2 ! poof... - * - * after properly servicing the trap. It wouldn't be a bad idea to load - * some more information into the local regs since we have technically - * 2 or 3 instructions to play with besides the jmp to the 'real' trap - * handler (one can even go in the delay slot). For now I am going to put - * the %psr (processor status register) and the trap-type value in %l0 - * and %l3 respectively. Also, for IRQ's I'll put the level in %l4. - */ - + /* The Sparc trap table, bootloader gives us control at _start. */ .text - - .globl start - .globl _start /* warning, solaris hack */ + .globl start, _stext, _start, __stext .globl C_LABEL(trapbase) _start: /* danger danger */ +__stext: +_stext: start: C_LABEL(trapbase): -/* XXX Grrr, this table is basically sun4c specific, sort of... XXX */ /* We get control passed to us here at t_zero. */ t_zero: b gokernel; nop; nop; nop; - -t_tflt: TRAP_ENTRY(0x1, sparc_text_fault) /* Inst. Access Exception */ -t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ -t_pins: TRAP_ENTRY(0x3, bad_instruction) /* Privileged Instruction */ -t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ -t_wovf: TRAP_ENTRY(0x5, spill_window_entry) /* Window Overflow */ -t_wunf: TRAP_ENTRY(0x6, fill_window_entry) /* Window Underflow */ -t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ -t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ -t_dflt: TRAP_ENTRY(0x9, sparc_data_fault) /* Data Miss Exception */ -t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ -t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ -t_badc: TRAP_ENTRY(0xc, bad_trap_handler) /* Undefined... */ -t_badd: TRAP_ENTRY(0xd, bad_trap_handler) /* Undefined... */ -t_bade: TRAP_ENTRY(0xe, bad_trap_handler) /* Undefined... */ -t_badf: TRAP_ENTRY(0xf, bad_trap_handler) /* Undefined... */ -t_bad10:TRAP_ENTRY(0x10, bad_trap_handler) /* Undefined... */ -t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ -t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ -t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ -t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ -t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ -t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ -t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ -t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ -t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ -t_irq10:TRAP_ENTRY_TIMER /* IRQ Timer #1 (one we use) */ -t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ -t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ -t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ -t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ -t_nmi: NMI_TRAP /* Level 15 (NMI) */ -t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ -t_iacce:TRAP_ENTRY(0x21, do_iacc_error) /* Instruction Access Error */ -t_bad22:TRAP_ENTRY(0x22, bad_trap_handler) /* Undefined... */ -t_bad23:TRAP_ENTRY(0x23, bad_trap_handler) /* Undefined... */ -t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ -t_uflsh:TRAP_ENTRY(0x25, do_bad_flush) /* Unimplemented FLUSH inst. */ -t_bad26:TRAP_ENTRY(0x26, bad_trap_handler) /* Undefined... */ -t_bad27:TRAP_ENTRY(0x27, bad_trap_handler) /* Undefined... */ -t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ -t_dacce:TRAP_ENTRY(0x29, do_dacc_error) /* Data Access Error */ -t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ -t_dserr:TRAP_ENTRY(0x2b, do_dstore_err) /* Data Store Error */ -t_daccm:TRAP_ENTRY(0x2c, do_dacc_mmu_miss) /* Data Access MMU-Miss */ -t_bad2d:TRAP_ENTRY(0x2d, bad_trap_handler) /* Undefined... */ -t_bad2e:TRAP_ENTRY(0x2e, bad_trap_handler) /* Undefined... */ -t_bad2f:TRAP_ENTRY(0x2f, bad_trap_handler) /* Undefined... */ -t_bad30:TRAP_ENTRY(0x30, bad_trap_handler) /* Undefined... */ -t_bad31:TRAP_ENTRY(0x31, bad_trap_handler) /* Undefined... */ -t_bad32:TRAP_ENTRY(0x32, bad_trap_handler) /* Undefined... */ -t_bad33:TRAP_ENTRY(0x33, bad_trap_handler) /* Undefined... */ -t_bad34:TRAP_ENTRY(0x34, bad_trap_handler) /* Undefined... */ -t_bad35:TRAP_ENTRY(0x35, bad_trap_handler) /* Undefined... */ -t_bad36:TRAP_ENTRY(0x36, bad_trap_handler) /* Undefined... */ -t_bad37:TRAP_ENTRY(0x37, bad_trap_handler) /* Undefined... */ -t_bad38:TRAP_ENTRY(0x38, bad_trap_handler) /* Undefined... */ -t_bad39:TRAP_ENTRY(0x39, bad_trap_handler) /* Undefined... */ -t_bad3a:TRAP_ENTRY(0x3a, bad_trap_handler) /* Undefined... */ -t_bad3b:TRAP_ENTRY(0x3b, bad_trap_handler) /* Undefined... */ -t_iaccm:TRAP_ENTRY(0x3c, do_iacc_mmu_miss) /* Instruction Access MMU-Miss */ -t_bad3d:TRAP_ENTRY(0x3d, bad_trap_handler) /* Undefined... */ -t_bad3e:TRAP_ENTRY(0x3e, bad_trap_handler) /* Undefined... */ -t_bad3f:TRAP_ENTRY(0x3f, bad_trap_handler) /* Undefined... */ -t_bad40:TRAP_ENTRY(0x40, bad_trap_handler) /* Undefined... */ -t_bad41:TRAP_ENTRY(0x41, bad_trap_handler) /* Undefined... */ -t_bad42:TRAP_ENTRY(0x42, bad_trap_handler) /* Undefined... */ -t_bad43:TRAP_ENTRY(0x43, bad_trap_handler) /* Undefined... */ -t_bad44:TRAP_ENTRY(0x44, bad_trap_handler) /* Undefined... */ -t_bad45:TRAP_ENTRY(0x45, bad_trap_handler) /* Undefined... */ -t_bad46:TRAP_ENTRY(0x46, bad_trap_handler) /* Undefined... */ -t_bad47:TRAP_ENTRY(0x47, bad_trap_handler) /* Undefined... */ -t_bad48:TRAP_ENTRY(0x48, bad_trap_handler) /* Undefined... */ -t_bad49:TRAP_ENTRY(0x49, bad_trap_handler) /* Undefined... */ -t_bad4a:TRAP_ENTRY(0x4a, bad_trap_handler) /* Undefined... */ -t_bad4b:TRAP_ENTRY(0x4b, bad_trap_handler) /* Undefined... */ -t_bad4c:TRAP_ENTRY(0x4c, bad_trap_handler) /* Undefined... */ -t_bad4d:TRAP_ENTRY(0x4d, bad_trap_handler) /* Undefined... */ -t_bad4e:TRAP_ENTRY(0x4e, bad_trap_handler) /* Undefined... */ -t_bad4f:TRAP_ENTRY(0x4f, bad_trap_handler) /* Undefined... */ -t_bad50:TRAP_ENTRY(0x50, bad_trap_handler) /* Undefined... */ -t_bad51:TRAP_ENTRY(0x51, bad_trap_handler) /* Undefined... */ -t_bad52:TRAP_ENTRY(0x52, bad_trap_handler) /* Undefined... */ -t_bad53:TRAP_ENTRY(0x53, bad_trap_handler) /* Undefined... */ -t_bad54:TRAP_ENTRY(0x54, bad_trap_handler) /* Undefined... */ -t_bad55:TRAP_ENTRY(0x55, bad_trap_handler) /* Undefined... */ -t_bad56:TRAP_ENTRY(0x56, bad_trap_handler) /* Undefined... */ -t_bad57:TRAP_ENTRY(0x57, bad_trap_handler) /* Undefined... */ -t_bad58:TRAP_ENTRY(0x58, bad_trap_handler) /* Undefined... */ -t_bad59:TRAP_ENTRY(0x59, bad_trap_handler) /* Undefined... */ -t_bad5a:TRAP_ENTRY(0x5a, bad_trap_handler) /* Undefined... */ -t_bad5b:TRAP_ENTRY(0x5b, bad_trap_handler) /* Undefined... */ -t_bad5c:TRAP_ENTRY(0x5c, bad_trap_handler) /* Undefined... */ -t_bad5d:TRAP_ENTRY(0x5d, bad_trap_handler) /* Undefined... */ -t_bad5e:TRAP_ENTRY(0x5e, bad_trap_handler) /* Undefined... */ -t_bad5f:TRAP_ENTRY(0x5f, bad_trap_handler) /* Undefined... */ -t_bad60:TRAP_ENTRY(0x60, bad_trap_handler) /* Impl-Dep Exception */ -t_bad61:TRAP_ENTRY(0x61, bad_trap_handler) /* Impl-Dep Exception */ -t_bad62:TRAP_ENTRY(0x62, bad_trap_handler) /* Impl-Dep Exception */ -t_bad63:TRAP_ENTRY(0x63, bad_trap_handler) /* Impl-Dep Exception */ -t_bad64:TRAP_ENTRY(0x64, bad_trap_handler) /* Impl-Dep Exception */ -t_bad65:TRAP_ENTRY(0x65, bad_trap_handler) /* Impl-Dep Exception */ -t_bad66:TRAP_ENTRY(0x66, bad_trap_handler) /* Impl-Dep Exception */ -t_bad67:TRAP_ENTRY(0x67, bad_trap_handler) /* Impl-Dep Exception */ -t_bad68:TRAP_ENTRY(0x68, bad_trap_handler) /* Impl-Dep Exception */ -t_bad69:TRAP_ENTRY(0x69, bad_trap_handler) /* Impl-Dep Exception */ -t_bad6a:TRAP_ENTRY(0x6a, bad_trap_handler) /* Impl-Dep Exception */ -t_bad6b:TRAP_ENTRY(0x6b, bad_trap_handler) /* Impl-Dep Exception */ -t_bad6c:TRAP_ENTRY(0x6c, bad_trap_handler) /* Impl-Dep Exception */ -t_bad6d:TRAP_ENTRY(0x6d, bad_trap_handler) /* Impl-Dep Exception */ -t_bad6e:TRAP_ENTRY(0x6e, bad_trap_handler) /* Impl-Dep Exception */ -t_bad6f:TRAP_ENTRY(0x6f, bad_trap_handler) /* Impl-Dep Exception */ -t_bad70:TRAP_ENTRY(0x70, bad_trap_handler) /* Impl-Dep Exception */ -t_bad71:TRAP_ENTRY(0x71, bad_trap_handler) /* Impl-Dep Exception */ -t_bad72:TRAP_ENTRY(0x72, bad_trap_handler) /* Impl-Dep Exception */ -t_bad73:TRAP_ENTRY(0x73, bad_trap_handler) /* Impl-Dep Exception */ -t_bad74:TRAP_ENTRY(0x74, bad_trap_handler) /* Impl-Dep Exception */ -t_bad75:TRAP_ENTRY(0x75, bad_trap_handler) /* Impl-Dep Exception */ -t_bad76:TRAP_ENTRY(0x76, bad_trap_handler) /* Impl-Dep Exception */ -t_bad77:TRAP_ENTRY(0x77, bad_trap_handler) /* Impl-Dep Exception */ -t_bad78:TRAP_ENTRY(0x78, bad_trap_handler) /* Impl-Dep Exception */ -t_bad79:TRAP_ENTRY(0x79, bad_trap_handler) /* Impl-Dep Exception */ -t_bad7a:TRAP_ENTRY(0x7a, bad_trap_handler) /* Impl-Dep Exception */ -t_bad7b:TRAP_ENTRY(0x7b, bad_trap_handler) /* Impl-Dep Exception */ -t_bad7c:TRAP_ENTRY(0x7c, bad_trap_handler) /* Impl-Dep Exception */ -t_bad7d:TRAP_ENTRY(0x7d, bad_trap_handler) /* Impl-Dep Exception */ -t_bad7e:TRAP_ENTRY(0x7e, bad_trap_handler) /* Impl-Dep Exception */ -t_bad7f:TRAP_ENTRY(0x7f, bad_trap_handler) /* Impl-Dep Exception */ -t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ -t_sbkpt:TRAP_ENTRY(0x81, bad_trap_handler) /* Software Breakpoint */ -t_divz: TRAP_ENTRY(0x82, bad_trap_handler) /* Divide by zero trap */ -t_flwin:TRAP_ENTRY(0x83, bad_trap_handler) /* Flush Windows Trap */ -t_clwin:TRAP_ENTRY(0x84, bad_trap_handler) /* Clean Windows Trap */ -t_rchk: TRAP_ENTRY(0x85, bad_trap_handler) /* Range Check */ -t_funal:TRAP_ENTRY(0x86, bad_trap_handler) /* Fix Unaligned Access Trap */ -t_iovf: TRAP_ENTRY(0x87, bad_trap_handler) /* Integer Overflow Trap */ -t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ -t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ -t_bad8a:TRAP_ENTRY(0x8a, bad_trap_handler) /* Software Trap */ -t_bad8b:TRAP_ENTRY(0x8b, bad_trap_handler) /* Software Trap */ -t_bad8c:TRAP_ENTRY(0x8c, bad_trap_handler) /* Software Trap */ -t_bad8d:TRAP_ENTRY(0x8d, bad_trap_handler) /* Software Trap */ -t_bad8e:TRAP_ENTRY(0x8e, bad_trap_handler) /* Software Trap */ -t_bad8f:TRAP_ENTRY(0x8f, bad_trap_handler) /* Software Trap */ -t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ -t_bad91:TRAP_ENTRY(0x91, bad_trap_handler) /* Software Trap */ -t_bad92:TRAP_ENTRY(0x92, bad_trap_handler) /* Software Trap */ -t_bad93:TRAP_ENTRY(0x93, bad_trap_handler) /* Software Trap */ -t_bad94:TRAP_ENTRY(0x94, bad_trap_handler) /* Software Trap */ -t_bad95:TRAP_ENTRY(0x95, bad_trap_handler) /* Software Trap */ -t_bad96:TRAP_ENTRY(0x96, bad_trap_handler) /* Software Trap */ -t_bad97:TRAP_ENTRY(0x97, bad_trap_handler) /* Software Trap */ -t_bad98:TRAP_ENTRY(0x98, bad_trap_handler) /* Software Trap */ -t_bad99:TRAP_ENTRY(0x99, bad_trap_handler) /* Software Trap */ -t_bad9a:TRAP_ENTRY(0x9a, bad_trap_handler) /* Software Trap */ -t_bad9b:TRAP_ENTRY(0x9b, bad_trap_handler) /* Software Trap */ -t_bad9c:TRAP_ENTRY(0x9c, bad_trap_handler) /* Software Trap */ -t_bad9d:TRAP_ENTRY(0x9d, bad_trap_handler) /* Software Trap */ -t_bad9e:TRAP_ENTRY(0x9e, bad_trap_handler) /* Software Trap */ -t_bad9f:TRAP_ENTRY(0x9f, bad_trap_handler) /* Software Trap */ -t_getcc:GETCC_TRAP /* Get Condition Codes */ -t_setcc:SETCC_TRAP /* Set Condition Codes */ -t_bada2:TRAP_ENTRY(0xa2, bad_trap_handler) /* Software Trap */ -t_bada3:TRAP_ENTRY(0xa3, bad_trap_handler) /* Software Trap */ -t_bada4:TRAP_ENTRY(0xa4, bad_trap_handler) /* Software Trap */ -t_bada5:TRAP_ENTRY(0xa5, bad_trap_handler) /* Software Trap */ -t_bada6:TRAP_ENTRY(0xa6, bad_trap_handler) /* Software Trap */ -t_bada7:TRAP_ENTRY(0xa7, bad_trap_handler) /* Software Trap */ -t_bada8:TRAP_ENTRY(0xa8, bad_trap_handler) /* Software Trap */ -t_bada9:TRAP_ENTRY(0xa9, bad_trap_handler) /* Software Trap */ -t_badaa:TRAP_ENTRY(0xaa, bad_trap_handler) /* Software Trap */ -t_badab:TRAP_ENTRY(0xab, bad_trap_handler) /* Software Trap */ -t_badac:TRAP_ENTRY(0xac, bad_trap_handler) /* Software Trap */ -t_badad:TRAP_ENTRY(0xad, bad_trap_handler) /* Software Trap */ -t_badae:TRAP_ENTRY(0xae, bad_trap_handler) /* Software Trap */ -t_badaf:TRAP_ENTRY(0xaf, bad_trap_handler) /* Software Trap */ -t_badb0:TRAP_ENTRY(0xb0, bad_trap_handler) /* Software Trap */ -t_badb1:TRAP_ENTRY(0xb1, bad_trap_handler) /* Software Trap */ -t_badb2:TRAP_ENTRY(0xb2, bad_trap_handler) /* Software Trap */ -t_badb3:TRAP_ENTRY(0xb3, bad_trap_handler) /* Software Trap */ -t_badb4:TRAP_ENTRY(0xb4, bad_trap_handler) /* Software Trap */ -t_badb5:TRAP_ENTRY(0xb5, bad_trap_handler) /* Software Trap */ -t_badb6:TRAP_ENTRY(0xb6, bad_trap_handler) /* Software Trap */ -t_badb7:TRAP_ENTRY(0xb7, bad_trap_handler) /* Software Trap */ -t_badb8:TRAP_ENTRY(0xb8, bad_trap_handler) /* Software Trap */ -t_badb9:TRAP_ENTRY(0xb9, bad_trap_handler) /* Software Trap */ -t_badba:TRAP_ENTRY(0xba, bad_trap_handler) /* Software Trap */ -t_badbb:TRAP_ENTRY(0xbb, bad_trap_handler) /* Software Trap */ -t_badbc:TRAP_ENTRY(0xbc, bad_trap_handler) /* Software Trap */ -t_badbd:TRAP_ENTRY(0xbd, bad_trap_handler) /* Software Trap */ -t_badbe:TRAP_ENTRY(0xbe, bad_trap_handler) /* Software Trap */ -t_badbf:TRAP_ENTRY(0xbf, bad_trap_handler) /* Software Trap */ -t_badc0:TRAP_ENTRY(0xc0, bad_trap_handler) /* Software Trap */ -t_badc1:TRAP_ENTRY(0xc1, bad_trap_handler) /* Software Trap */ -t_badc2:TRAP_ENTRY(0xc2, bad_trap_handler) /* Software Trap */ -t_badc3:TRAP_ENTRY(0xc3, bad_trap_handler) /* Software Trap */ -t_badc4:TRAP_ENTRY(0xc4, bad_trap_handler) /* Software Trap */ -t_badc5:TRAP_ENTRY(0xc5, bad_trap_handler) /* Software Trap */ -t_badc6:TRAP_ENTRY(0xc6, bad_trap_handler) /* Software Trap */ -t_badc7:TRAP_ENTRY(0xc7, bad_trap_handler) /* Software Trap */ -t_badc8:TRAP_ENTRY(0xc8, bad_trap_handler) /* Software Trap */ -t_badc9:TRAP_ENTRY(0xc9, bad_trap_handler) /* Software Trap */ -t_badca:TRAP_ENTRY(0xca, bad_trap_handler) /* Software Trap */ -t_badcb:TRAP_ENTRY(0xcb, bad_trap_handler) /* Software Trap */ -t_badcc:TRAP_ENTRY(0xcc, bad_trap_handler) /* Software Trap */ -t_badcd:TRAP_ENTRY(0xcd, bad_trap_handler) /* Software Trap */ -t_badce:TRAP_ENTRY(0xce, bad_trap_handler) /* Software Trap */ -t_badcf:TRAP_ENTRY(0xcf, bad_trap_handler) /* Software Trap */ -t_badd0:TRAP_ENTRY(0xd0, bad_trap_handler) /* Software Trap */ -t_badd1:TRAP_ENTRY(0xd1, bad_trap_handler) /* Software Trap */ -t_badd2:TRAP_ENTRY(0xd2, bad_trap_handler) /* Software Trap */ -t_badd3:TRAP_ENTRY(0xd3, bad_trap_handler) /* Software Trap */ -t_badd4:TRAP_ENTRY(0xd4, bad_trap_handler) /* Software Trap */ -t_badd5:TRAP_ENTRY(0xd5, bad_trap_handler) /* Software Trap */ -t_badd6:TRAP_ENTRY(0xd6, bad_trap_handler) /* Software Trap */ -t_badd7:TRAP_ENTRY(0xd7, bad_trap_handler) /* Software Trap */ -t_badd8:TRAP_ENTRY(0xd8, bad_trap_handler) /* Software Trap */ -t_badd9:TRAP_ENTRY(0xd9, bad_trap_handler) /* Software Trap */ -t_badda:TRAP_ENTRY(0xda, bad_trap_handler) /* Software Trap */ -t_baddb:TRAP_ENTRY(0xdb, bad_trap_handler) /* Software Trap */ -t_baddc:TRAP_ENTRY(0xdc, bad_trap_handler) /* Software Trap */ -t_baddd:TRAP_ENTRY(0xdd, bad_trap_handler) /* Software Trap */ -t_badde:TRAP_ENTRY(0xde, bad_trap_handler) /* Software Trap */ -t_baddf:TRAP_ENTRY(0xdf, bad_trap_handler) /* Software Trap */ -t_bade0:TRAP_ENTRY(0xe0, bad_trap_handler) /* Software Trap */ -t_bade1:TRAP_ENTRY(0xe1, bad_trap_handler) /* Software Trap */ -t_bade2:TRAP_ENTRY(0xe2, bad_trap_handler) /* Software Trap */ -t_bade3:TRAP_ENTRY(0xe3, bad_trap_handler) /* Software Trap */ -t_bade4:TRAP_ENTRY(0xe4, bad_trap_handler) /* Software Trap */ -t_bade5:TRAP_ENTRY(0xe5, bad_trap_handler) /* Software Trap */ -t_bade6:TRAP_ENTRY(0xe6, bad_trap_handler) /* Software Trap */ -t_bade7:TRAP_ENTRY(0xe7, bad_trap_handler) /* Software Trap */ -t_bade8:TRAP_ENTRY(0xe8, bad_trap_handler) /* Software Trap */ -t_bade9:TRAP_ENTRY(0xe9, bad_trap_handler) /* Software Trap */ -t_badea:TRAP_ENTRY(0xea, bad_trap_handler) /* Software Trap */ -t_badeb:TRAP_ENTRY(0xeb, bad_trap_handler) /* Software Trap */ -t_badec:TRAP_ENTRY(0xec, bad_trap_handler) /* Software Trap */ -t_baded:TRAP_ENTRY(0xed, bad_trap_handler) /* Software Trap */ -t_badee:TRAP_ENTRY(0xee, bad_trap_handler) /* Software Trap */ -t_badef:TRAP_ENTRY(0xef, bad_trap_handler) /* Software Trap */ -t_badf0:TRAP_ENTRY(0xf0, bad_trap_handler) /* Software Trap */ -t_badf1:TRAP_ENTRY(0xf1, bad_trap_handler) /* Software Trap */ -t_badf2:TRAP_ENTRY(0xf2, bad_trap_handler) /* Software Trap */ -t_badf3:TRAP_ENTRY(0xf3, bad_trap_handler) /* Software Trap */ -t_badf4:TRAP_ENTRY(0xf4, bad_trap_handler) /* Software Trap */ -t_badf5:TRAP_ENTRY(0xf5, bad_trap_handler) /* Software Trap */ -t_badf6:TRAP_ENTRY(0xf6, bad_trap_handler) /* Software Trap */ -t_badf7:TRAP_ENTRY(0xf7, bad_trap_handler) /* Software Trap */ -t_badf8:TRAP_ENTRY(0xf8, bad_trap_handler) /* Software Trap */ -t_badf9:TRAP_ENTRY(0xf9, bad_trap_handler) /* Software Trap */ -t_badfa:TRAP_ENTRY(0xfa, bad_trap_handler) /* Software Trap */ -t_badfb:TRAP_ENTRY(0xfb, bad_trap_handler) /* Software Trap */ -t_badfc:TRAP_ENTRY(0xfc, bad_trap_handler) /* Software Trap */ -t_badfd:TRAP_ENTRY(0xfd, bad_trap_handler) /* Software Trap */ -dbtrap: TRAP_ENTRY(0xfe, bad_trap_handler) /* Debugger/PROM breakpoint #1 */ -dbtrap2:TRAP_ENTRY(0xff, bad_trap_handler) /* Debugger/PROM breakpoint #2 */ +t_tflt: TRAP_ENTRY(0x1, sparc_fault) /* Inst. Access Exception */ +t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ +t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ +t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ +t_wovf: WINDOW_SPILL /* Window Overflow */ +t_wunf: WINDOW_FILL /* Window Underflow */ +t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ +t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ +t_dflt: TRAP_ENTRY(0x9, sparc_fault) /* Data Miss Exception */ +t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ +t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ +t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) +t_irq1: TRAP_ENTRY_SOFTINT(1) /* IRQ Software/SBUS Level 1 */ +t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ +t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ +t_irq4: TRAP_ENTRY_SOFTINT(4) /* IRQ Software Level 4 */ +t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ +t_irq6: TRAP_ENTRY_SOFTINT(6) /* IRQ Software Level 6 */ +t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ +t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ +t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ +t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ +t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ +t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ +t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ +t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ +t_nmi: NMI_TRAP /* Level 15 (NMI) */ +t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ +t_iacce:TRAP_ENTRY(0x21, sparc_fault) /* Instr Access Error */ +t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) +t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ +t_uflsh:TRAP_ENTRY(0x25, do_bad_flush) /* Unimplemented FLUSH inst. */ +t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) +t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ +t_dacce:TRAP_ENTRY(0x29, sparc_fault) /* Data Access Error */ +t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ +t_dserr:TRAP_ENTRY(0x2b, sparc_fault) /* Data Store Error */ +t_daccm:TRAP_ENTRY(0x2c, sparc_fault) /* Data Access MMU-Miss */ +t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) +t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) +t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) +t_iaccm:TRAP_ENTRY(0x3c, sparc_fault) /* Instr Access MMU-Miss */ +t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41) +t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) +t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) +t_bad4c:BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) BAD_TRAP(0x50) +t_bad51:BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) +t_bad56:BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) +t_bad5b:BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) +t_bad60:BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) +t_bad65:BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) +t_bad6a:BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) +t_bad6f:BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) +t_bad74:BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) +t_bad79:BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) +t_bad7e:BAD_TRAP(0x7e) BAD_TRAP(0x7f) +t_sunos:SUNOS_SYSCALL_TRAP /* SunOS System Call */ +t_sbkpt:BAD_TRAP(0x81) /* Software Breakpoint/KGDB */ +t_divz: BAD_TRAP(0x82) /* Divide by zero trap */ +t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ +t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ +t_rchk: BAD_TRAP(0x85) /* Range Check */ +t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ +t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ +t_slowl:SOLARIS_SYSCALL_TRAP /* Slowaris System Call */ +t_netbs:NETBSD_SYSCALL_TRAP /* Net-B.S. System Call */ +t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e) +t_bad8f:BAD_TRAP(0x8f) +t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ +t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) +t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) +t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) +t_getcc:GETCC_TRAP /* Get Condition Codes */ +t_setcc:SETCC_TRAP /* Set Condition Codes */ +t_bada2:BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) +t_bada7:BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) +t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) +t_badb1:BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) +t_badb6:BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) +t_badbb:BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) +t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) +t_badc5:BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) +t_badca:BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) +t_badcf:BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) +t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) +t_badd9:BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) +t_badde:BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) +t_bade3:BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) +t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) +t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) +t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) +t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) +t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd) +dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ +dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ .globl C_LABEL(end_traptable) C_LABEL(end_traptable): @@ -422,8 +185,6 @@ /* This was the only reasonable way I could think of to properly align * these page-table data structures. - * - * XXX swapper_pg_dir is going to have to be 'per-CPU' for SMP support */ .globl C_LABEL(auxio_reg_addr) @@ -435,11 +196,15 @@ .globl C_LABEL(int_reg_addr) C_LABEL(int_reg_addr): .skip (PAGE_SIZE*5) + .globl C_LABEL(bootup_user_stack) + .globl C_LABEL(bootup_kernel_stack) .globl C_LABEL(pg0) .globl C_LABEL(empty_bad_page) .globl C_LABEL(empty_bad_page_table) .globl C_LABEL(empty_zero_page) .globl C_LABEL(swapper_pg_dir) +C_LABEL(bootup_user_stack): .skip 0x1000 +C_LABEL(bootup_kernel_stack): .skip 0x1000 C_LABEL(swapper_pg_dir): .skip 0x1000 C_LABEL(pg0): .skip 0x1000 C_LABEL(empty_bad_page): .skip 0x1000 @@ -449,19 +214,7 @@ /* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in * %g7 and at prom_vector_p. And also quickly check whether we are on - * a v0, v2, or v3 prom. We also get a debug structure of some sort from - * the boot loader (or is it the prom?) in %o1. Finally a call back vector - * is passed in %o2. I think this is how you register yourself with a - * debugger. I do know that it wants my %o7 (return PC - 8) as it's - * first argument. I will poke around and figure out what the debug - * vector is, it could contain useful stuff. - */ - -/* Grrr, in order to be Sparc ABI complient, the kernel has to live in - * an address space above 0xe0000000 ;( Must remain position independant - * until we 'remap' ourselves from low to high addresses. We only map the - * first 3MB of addresses into upper ram as that is how much the PROM - * promises to set up for us. + * a v0, v2, or v3 prom. */ gokernel: /* Ok, it's nice to know, as early as possible, if we @@ -477,31 +230,28 @@ /* XXX Sparc V9 detection goes here XXX */ - or %g0, %o7, %g4 ! Save %o7 + mov %o7, %g4 ! Save %o7 /* Jump to it, and pray... */ current_pc: call 1f - nop + nop 1: - or %g0, %o7, %g3 + mov %o7, %g3 got_pc: - or %g0, %g4, %o7 /* Previous %o7. */ + mov %g4, %o7 /* Previous %o7. */ - or %g0, %o0, %l0 ! stash away romvec - or %g0, %o0, %g7 ! put it here too - or %g0, %o1, %l1 ! stash away debug_vec too - rd %psr, %l2 ! Save psr - rd %wim, %l3 ! wim - rd %tbr, %l4 ! tbr - or %g0, %o2, %l5 ! and the possible magic func + mov %o0, %l0 ! stash away romvec + mov %o0, %g7 ! put it here too + mov %o1, %l1 ! stash away debug_vec too /* Ok, let's check out our run time program counter. */ set current_pc, %g5 cmp %g3, %g5 be already_mapped + nop /* %l6 will hold the offset we have to subtract * from absolute symbols in order to access areas @@ -511,10 +261,10 @@ */ set PAGE_OFFSET, %l6 b copy_prom_lvl14 - nop + nop already_mapped: - or %g0, %g0, %l6 + mov 0, %l6 /* Copy over the Prom's level 14 clock handler. */ copy_prom_lvl14: @@ -544,46 +294,6 @@ ldd [%g2 + 0x18], %g4 std %g4, [%g3 + 0x18] -copy_prom_done: - ld [%o0 + 0x4], %g1 - and %g1, 0x3, %g1 - subcc %g1, 0x0, %g0 - be set_sane_psr ! Not on v0 proms - nop - - subcc %o2, 0x0, %g0 ! check for boot routine pointer - bz set_sane_psr - nop - jmpl %o2, %o7 ! call boot setup func - add %o7, 0x8, %o0 - -set_sane_psr: - /* Traps are on, kadb can be tracing through here. But - * we have no clue what the PIL is. So we set up a sane - * %psr, but preserve CWP or our locals could disappear! - */ - rd %psr, %g2 - and %g2, 0x1f, %g2 ! %g2 has CWP now - set (PSR_S|PSR_PIL), %g1 ! Supervisor + PIL high - or %g1, %g2, %g1 ! mix mix mix - wr %g1, 0x0, %psr ! let PIL set in - wr %g1, PSR_ET, %psr ! now turn on traps - - /* A note about the last two instructions... - * If you are going to increase PIL and turn on - * traps at the same time you are asking for trouble. - * You MUST set a %psr with traps off containing - * your new PIL, then turn on the ET bit with the - * next write. On certain buggy Sparc chips if you - * set both at the same time you can get a Watchdog - * Reset under certain conditions. This is no fun. - * Basically the PIL bits get there before the - * EnableTrap bit does or something like that. - */ - - /* Insane asylum... */ - WRITE_PAUSE - /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT * MMU so we can remap ourselves properly. DONT TOUCH %l0 thru %l5 in these * remapping routines, we need their values afterwards! @@ -593,27 +303,28 @@ /* Now check whether we are already mapped, if we * are we can skip all this garbage coming up. */ - subcc %l6, 0x0, %g0 - bz go_to_highmem ! this will be a nop then - nop +copy_prom_done: + cmp %l6, 0 + be go_to_highmem ! this will be a nop then + nop - sethi %hi(LOAD_ADDR), %g6 - subcc %g7, %g6, %g0 + set LOAD_ADDR, %g6 + cmp %g7, %g6 bne remap_not_a_sun4 ! This is not a Sun4 - nop + nop or %g0, 0x1, %g1 lduba [%g1] ASI_CONTROL, %g1 ! Only safe to try on Sun4. subcc %g1, 0x24, %g0 ! Is this a mutant Sun4/400??? be sun4_mutant_remap ! Ugh, it is... - nop + nop remap_not_a_sun4: lda [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c and %g1, 0x1, %g1 ! Test SRMMU Enable bit ;-) - subcc %g1, 0x0, %g0 - bz sun4c_remap ! A sun4c MMU or normal Sun4 - nop + cmp %g1, 0x0 + be sun4c_remap ! A sun4c MMU or normal Sun4 + nop srmmu_remap: /* First, check for a viking (TI) module. */ set 0x40000000, %g2 @@ -621,7 +332,7 @@ and %g2, %g3, %g3 subcc %g3, 0x0, %g0 bz srmmu_nviking - nop + nop /* Figure out what kind of viking we are on. * We need to know if we have to play with the @@ -636,7 +347,7 @@ and %g2, %g3, %g3 subcc %g3, 0x0, %g0 bnz srmmu_nviking ! is in mbus mode - nop + nop rd %psr, %g3 ! DONT TOUCH %g3 andn %g3, PSR_ET, %g2 @@ -702,7 +413,7 @@ * place to another... Jump to high memory. */ b go_to_highmem - nop + nop /* This works on viking's in Mbus mode and all * other MBUS modules. It is virtually the same as @@ -721,7 +432,7 @@ add %g1, 0x3c0, %g3 ! XXX AWAY WITH IMPERICALS sta %g2, [%g3] ASI_M_BYPASS ! place at KERNBASE entry b go_to_highmem - nop ! wheee.... + nop ! wheee.... /* This remaps the kernel on Sun4/4xx machines * that have the Sun Mutant Three Level MMU. @@ -754,18 +465,16 @@ add %g4, %l6, %g4 ! Move up high memory ptr subcc %g3, %g5, %g0 ! Reached our limit? blu sun4_mutant_loop ! Nope, loop again - add %g3, %l6, %g3 ! delay, Move up low ptr + add %g3, %l6, %g3 ! delay, Move up low ptr b go_to_highmem ! Jump to high memory. - nop + nop /* The following works for normal (ie. non Sun4/400) Sun4 MMU's */ sun4c_remap: - or %g0, %g0, %g3 ! source base - sethi %hi(KERNBASE), %g4 ! destination base - or %g4, %lo(KERNBASE), %g4 - sethi %hi(0x300000), %g5 - or %g5, %lo(0x300000), %g5 ! upper bound 3MB - or %g0, 0x1, %l6 + mov 0, %g3 ! source base + set KERNBASE, %g4 ! destination base + set 0x300000, %g5 ! upper bound 3MB + mov 1, %l6 sll %l6, 18, %l6 ! sun4c mmu segmap size sun4c_remap_loop: lda [%g3] ASI_SEGMAP, %g6 ! load phys_seg @@ -773,20 +482,20 @@ add %g3, %l6, %g3 ! Increment source ptr subcc %g3, %g5, %g0 ! Reached limit? bl sun4c_remap_loop ! Nope, loop again - add %g4, %l6, %g4 ! delay, Increment dest ptr + add %g4, %l6, %g4 ! delay, Increment dest ptr /* Now do a non-relative jump so that PC is in high-memory */ go_to_highmem: set execute_in_high_mem, %g1 - jmp %g1 - nop + jmpl %g1, %g0 + nop /* Acquire boot time privileged register values, this will help debugging. * I figure out and store nwindows and nwindowsm1 later on. */ execute_in_high_mem: - or %g0, %l0, %o0 ! put back romvec - or %g0, %l1, %o1 ! and debug_vec + mov %l0, %o0 ! put back romvec + mov %l1, %o1 ! and debug_vec sethi %hi( C_LABEL(prom_vector_p) ), %g1 st %o0, [%g1 + %lo( C_LABEL(prom_vector_p) )] @@ -797,14 +506,14 @@ ld [%o0 + 0x4], %o3 and %o3, 0x3, %o5 ! get the version - subcc %o3, 0x2, %g0 ! a v2 prom? + cmp %o3, 0x2 ! a v2 prom? be found_version - nop + nop /* paul@sfe.com.au */ - subcc %o3, 0x3, %g0 ! a v3 prom? + cmp %o3, 0x3 ! a v3 prom? be found_version - nop + nop /* Old sun4's pass our load address into %o0 instead of the prom * pointer. On sun4's you have to hard code the romvec pointer into @@ -812,33 +521,21 @@ * trust their own "OpenBoot" specifications. */ - sethi %hi(LOAD_ADDR), %g6 - subcc %o0, %g6, %g0 ! an old sun4? + set LOAD_ADDR, %g6 + cmp %o0, %g6 ! an old sun4? be no_sun4_here - nop + nop found_version: -/* Get the machine type via the mysterious romvec node operations. - * Here we can find out whether we are on a sun4, sun4c, sun4m, - * sun4d, or a sun4e. The "nodes" are set up as a bunch of n-ary trees - * which you can traverse to get information about devices and such. - * The information acquisition happens via the node-ops which are - * defined in the openprom.h header file. Of particular interest - * is the 'nextnode(int node)' function as it does the smart thing when - * presented with a value of '0', it gives you the root node in the - * tree. These node integers probably offset into some internal prom - * pointer table the openboot has. It's completely undocumented, so - * I'm not about to go sifting through the prom address space, but may - * do so if I get suspicious enough. :-) - */ +/* Get the machine type via the mysterious romvec node operations. */ or %g0, %g7, %l1 add %l1, 0x1c, %l1 ld [%l1], %l0 ld [%l0], %l0 call %l0 - or %g0, %g0, %o0 ! next_node(0) = first_node + or %g0, %g0, %o0 ! next_node(0) = first_node or %o0, %g0, %g6 sethi %hi( C_LABEL(cputypvar) ), %o1 ! First node has cpu-arch @@ -848,13 +545,13 @@ ld [%l1], %l0 ! 'compatibility' tells ld [%l0 + 0xc], %l0 ! that we want 'sun4x' where call %l0 ! x is one of '', 'c', 'm', - nop ! 'd' or 'e'. %o2 holds pointer + nop ! 'd' or 'e'. %o2 holds pointer ! to a buf where above string ! will get stored by the prom. subcc %o0, %g0, %g0 bpos got_prop ! Got the property - nop + nop or %g6, %g0, %o0 sethi %hi( C_LABEL(cputypvar_sun4m) ), %o1 @@ -864,55 +561,47 @@ ld [%l1], %l0 ld [%l0 + 0xc], %l0 call %l0 - nop + nop got_prop: - sethi %hi( C_LABEL(cputypval) ), %o2 - or %o2, %lo( C_LABEL(cputypval) ), %o2 - + set C_LABEL(cputypval), %o2 ldub [%o2 + 0x4], %l1 - subcc %l1, 'c', %g0 ! We already know we are not + + cmp %l1, 'c' ! We already know we are not be 1f ! on a plain sun4 because of - nop ! the check for 0x4000 in %o0 - subcc %l1, 'm', %g0 ! at start + nop ! the check for 0x4000 in %o0 + + cmp %l1, 'm' ! at start be 1f - nop + nop - subcc %l1, 'd', %g0 + cmp %l1, 'd' be no_sun4d_here ! God bless the person who - nop ! tried to run this on sun4d. + nop ! tried to run this on sun4d. - subcc %l1, 'e', %g0 + cmp %l1, 'e' be no_sun4e_here ! Could be a sun4e. - nop + nop b no_sun4u_here ! AIEEE, a V9 sun4u... - nop + nop 1: - or %g0, PAGE_SHIFT, %g5 - - sethi %hi( C_LABEL(cputypval) ), %l1 - or %l1, %lo( C_LABEL(cputypval) ), %l1 + set C_LABEL(cputypval), %l1 ldub [%l1 + 0x4], %l1 - subcc %l1, 'm', %g0 ! Test for sun4d, sun4e ? + cmp %l1, 'm' ! Test for sun4d, sun4e ? be sun4m_init - nop + nop - sethi %hi(AC_CONTEXT), %g1 ! kernel context, safe now - ! the only valid context - ! until we call paging_init() + /* Jump into mmu context zero. */ + set AC_CONTEXT, %g1 stba %g0, [%g1] ASI_CONTROL b sun4c_continue_boot - nop + nop sun4m_init: -/* P3: I just do not know what to do here. But I do know that ASI_CONTROL - * will not serve on sun4m. Also I do not want to smash the current MMU - * setup until we call paging_init(). - */ /* Ok, the PROM could have done funny things and apple cider could still * be sitting in the fault status/address registers. Read them all to @@ -920,22 +609,28 @@ */ /* This sucks, aparently this makes Vikings call prom panic, will fix later */ - set (0x40000000), %o1 - rd %psr, %o0 - andcc %o0, %o1, %g0 - bne sun4c_continue_boot ! quick hack - nop + rd %psr, %o1 + srl %o1, 28, %o1 ! Get a type of the CPU + + subcc %o1, 4, %g0 ! TI: Viking or MicroSPARC + be sun4c_continue_boot + nop -clr_srmmu_fregs: set AC_M_SFSR, %o0 lda [%o0] ASI_M_MMUREGS, %g0 set AC_M_SFAR, %o0 lda [%o0] ASI_M_MMUREGS, %g0 + + /* Fujitsu MicroSPARC-II has no asynchronous flavors of FARs */ + subcc %o1, 0, %g0 + be sun4c_continue_boot + nop + set AC_M_AFSR, %o0 lda [%o0] ASI_M_MMUREGS, %g0 set AC_M_AFAR, %o0 lda [%o0] ASI_M_MMUREGS, %g0 - nop + nop sun4c_continue_boot: @@ -948,141 +643,133 @@ sethi %hi( C_LABEL(cputyp) ), %o0 st %g4, [%o0 + %lo( C_LABEL(cputyp) )] - /* Turn on PreviousSupervisor, Supervisor, EnableFloating, - * and all the PIL bits. Also puts us in register window - * zero. + /* Turn on Supervisor, EnableFloating, and all the PIL bits. + * Also puts us in register window zero with traps off. */ - sethi %hi(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 - or %g2, %lo(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 + set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2 wr %g2, 0x0, %psr WRITE_PAUSE - wr %g0, 0x2, %wim ! Make window 1 invalid. - WRITE_PAUSE - - /* Initialize the WIM value for init_task. */ - or %g0, 0x1, %g1 - sethi %hi( C_LABEL(current) + THREAD_WIM), %g2 - st %g1, [%g2 + %lo( C_LABEL(current) + THREAD_WIM)] - -/* I want a kernel stack NOW! */ -/* Grrr, gotta be real careful about alignment here */ - - set ( C_LABEL(init_user_stack) + PAGE_SIZE - 96 - 96 - 80), %g1 - andn %g1, 0x7, %g1 - or %g1, 0x0, %fp - add %fp, (96+80), %sp - - /* Enable traps. */ - rd %psr, %l0 - wr %l0, PSR_ET, %psr - WRITE_PAUSE - -/* - * Maybe the prom zeroes out our BSS section, maybe it doesn't. I certainly - * don't know, do you? - */ + /* I want a kernel stack NOW! */ + set C_LABEL(bootup_user_stack), %g1 + add %g1, (PAGE_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %sp + mov 0, %fp /* And for good luck */ + /* Zero out our BSS section. */ set C_LABEL(edata) , %o0 ! First address of BSS set C_LABEL(end) , %o1 ! Last address of BSS - - /* Argh, ELF gets me again... */ - andn %o0, 0x3, %o0 - andn %o1, 0x3, %o1 - -/* Friggin' bzero() kludge. */ - + add %o0, 0x1, %o0 1: - st %g0, [%o0] - add %o0, 0x4, %o0 + stb %g0, [%o0] subcc %o0, %o1, %g0 bl 1b - nop + add %o0, 0x1, %o0 + + /* Initialize the umask value for init_task just in case. + * But first make current_set[0] point to something useful. + */ + set C_LABEL(init_task), %g4 + set C_LABEL(current_set), %g2 + st %g4, [%g2] + + /* So now this should work. */ + LOAD_CURRENT(g2) + set C_LABEL(bootup_kernel_stack), %g4 + st %g4, [%g2 + TASK_KSTACK_PG] + st %g0, [%g2 + THREAD_UMASK] /* Compute NWINDOWS and stash it away. Now uses %wim trick explained * in the V8 manual. Ok, this method seems to work, Sparc is cool... * No, it doesn't work, have to play the save/readCWP/restore trick. */ - rd %wim, %g1 - rd %psr, %g2 wr %g0, 0x0, %wim ! so we dont get a trap - andn %g2, 0x1f, %g3 - wr %g3, 0x0, %psr WRITE_PAUSE + save + rd %psr, %g3 + restore + and %g3, 0x1f, %g3 add %g3, 0x1, %g3 - wr %g2, 0x0, %psr - wr %g1, 0x0, %wim - cmp %g3, 0x7 - bne,a 2f - sethi %hi( C_LABEL(nwindows) ), %g4 + mov 2, %g1 + wr %g1, 0x0, %wim ! make window 1 invalid + WRITE_PAUSE + cmp %g3, 0x7 + bne 2f + nop - /* Nop out one save and one restore in the save state code - * and system call entry if this is a seven window Sparc. + /* Adjust our window handling routines to + * do things correctly on 7 window Sparcs. */ - sethi %hi(nop7), %g5 - or %g5, %lo(nop7), %g5 - sethi %hi(NOP_INSN), %g6 - or %g6, %lo(NOP_INSN), %g6 - /* patch 1 */ - st %g6, [%g5] - st %g6, [%g5 + 0x4] - sethi %hi(rnop7), %g5 - or %g5, %lo(rnop7), %g5 - /* patch 2 */ - st %g6, [%g5] - st %g6, [%g5 + 0x4] - sethi %hi( C_LABEL(nwindows) ), %g4 +#define PATCH_INSN(src, dest) \ + set src, %g5; \ + set dest, %g6; \ + ld [%g5], %g4; \ + st %g4, [%g6]; + + /* Patch for window spills... */ + PATCH_INSN(spnwin_patch1_7win, spnwin_patch1) + PATCH_INSN(spnwin_patch2_7win, spnwin_patch2) + PATCH_INSN(spnwin_patch3_7win, spnwin_patch3) + + /* Patch for window fills... */ + PATCH_INSN(fnwin_patch1_7win, fnwin_patch1) + PATCH_INSN(fnwin_patch2_7win, fnwin_patch2) + + /* Patch for trap entry setup... */ + PATCH_INSN(tsetup_7win_patch1, tsetup_patch1) + PATCH_INSN(tsetup_7win_patch2, tsetup_patch2) + PATCH_INSN(tsetup_7win_patch3, tsetup_patch3) + PATCH_INSN(tsetup_7win_patch4, tsetup_patch4) + PATCH_INSN(tsetup_7win_patch5, tsetup_patch5) + PATCH_INSN(tsetup_7win_patch6, tsetup_patch6) + + /* Patch for returning from traps... */ + PATCH_INSN(rtrap_7win_patch1, rtrap_patch1) + PATCH_INSN(rtrap_7win_patch2, rtrap_patch2) + PATCH_INSN(rtrap_7win_patch3, rtrap_patch3) + PATCH_INSN(rtrap_7win_patch4, rtrap_patch4) + PATCH_INSN(rtrap_7win_patch5, rtrap_patch5) 2: + sethi %hi( C_LABEL(nwindows) ), %g4 st %g3, [%g4 + %lo( C_LABEL(nwindows) )] ! store final value sub %g3, 0x1, %g3 sethi %hi( C_LABEL(nwindowsm1) ), %g4 st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )] - /* Initialize lnx_winmask. */ - set lnx_winmask, %g4 - or %g0, 0x2, %g5 - or %g0, 0x0, %g6 -msk_loop: - stb %g5, [%g4 + %g6] - add %g6, 0x1, %g6 - cmp %g6, %g3 - bl,a msk_loop - sll %g5, 0x1, %g5 - or %g0, 0x1, %g5 - stb %g5, [%g4 + %g3] - - /* Here we go */ + /* Here we go, start using Linux's trap table... */ set C_LABEL(trapbase), %g3 wr %g3, 0x0, %tbr WRITE_PAUSE + /* Finally, turn on traps so that we can call c-code. */ + rd %psr, %g3 + wr %g3, 0x0, %psr + wr %g3, PSR_ET, %psr + WRITE_PAUSE -/* First we call prom_init() to set up PROMLIB, then off to start_kernel() */ -/* XXX put this in setup_arch() */ + /* First we call prom_init() to set up PROMLIB, then + * off to start_kernel(). + */ sethi %hi( C_LABEL(prom_vector_p) ), %g5 - call C_LABEL(prom_init) ld [%g5 + %lo( C_LABEL(prom_vector_p) )], %o0 - - subcc %o0, 0x1, %g0 - be halt_me ! promlib init failed - nop + call C_LABEL(prom_init) + nop call C_LABEL(start_kernel) - nop + nop /* We should not get here. */ call halt_me - nop + nop /* There, happy now Adrian? */ @@ -1092,39 +779,39 @@ ld [%o1 + %lo(SUN4_PROM_VECTOR+SUN4_PRINTF)], %o1 set sun4_notsup, %o0 call %o1 - nop + nop 1: ba 1b ! Cannot exit into KMON - nop + nop no_sun4d_here: ld [%g7 + 0x68], %o1 set sun4d_notsup, %o0 call %o1 - nop + nop b halt_me - nop + nop no_sun4e_here: ld [%g7 + 0x68], %o1 set sun4e_notsup, %o0 call %o1 - nop + nop b halt_me - nop + nop no_sun4u_here: ld [%g7 + 0x68], %o1 set sun4u_notsup, %o0 call %o1 - nop + nop b halt_me - nop + nop halt_me: ld [%g7 + 0x74], %o0 call %o0 ! Get us out of here... - nop ! Apparently Solaris is better. + nop ! Apparently Solaris is better. .data .align 4 @@ -1135,30 +822,28 @@ * gets initialized in c-code so all routines can use it. */ - .globl C_LABEL(prom_vector_p) -C_LABEL(prom_vector_p): .skip 4 - - .align 4 + .globl C_LABEL(prom_vector_p) +C_LABEL(prom_vector_p): + .word 0 /* We calculate the following at boot time, window fills/spills and trap entry * code uses these to keep track of the register windows. */ - .globl C_LABEL(nwindows) - .globl C_LABEL(nwindowsm1) -C_LABEL(nwindows): .skip 4 -C_LABEL(nwindowsm1): .skip 4 - .align 4 + .globl C_LABEL(nwindows) + .globl C_LABEL(nwindowsm1) +C_LABEL(nwindows): + .word 8 +C_LABEL(nwindowsm1): + .word 7 /* Boot time debugger vector value. We need this later on. */ - .globl C_LABEL(linux_dbvec) -C_LABEL(linux_dbvec): .skip 4 - .align 4 + .globl C_LABEL(linux_dbvec) +C_LABEL(linux_dbvec): + .word 0 + .word 0 -/* Just to get the kernel through the compiler for now */ - .globl C_LABEL(floppy_track_buffer) -C_LABEL(floppy_track_buffer): - .fill 512*2*36,1,0 + .align 4 diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/idprom.c linux/arch/sparc/kernel/idprom.c --- v1.3.43/linux/arch/sparc/kernel/idprom.c Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/idprom.c Sat Nov 25 02:58:06 1995 @@ -1,4 +1,5 @@ -/* idprom.c: Routines to load the idprom into kernel addresses and +/* $Id: idprom.c,v 1.18 1995/11/25 00:58:05 davem Exp $ + * idprom.c: Routines to load the idprom into kernel addresses and * interpret the data contained within. * * Because they use the IDPROM's machine type field, some of the @@ -8,8 +9,8 @@ */ #include +#include -#include #include #include #include /* Fun with Sun released architectures. */ @@ -77,8 +78,8 @@ sparc_display_systype(idprom->id_machtype); printk("Ethernet address: %x:%x:%x:%x:%x:%x\n", - idprom->id_eaddr[0], idprom->id_eaddr[1], idprom->id_eaddr[2], - idprom->id_eaddr[3], idprom->id_eaddr[4], idprom->id_eaddr[5]); + idprom->id_eaddr[0], idprom->id_eaddr[1], idprom->id_eaddr[2], + idprom->id_eaddr[3], idprom->id_eaddr[4], idprom->id_eaddr[5]); return; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v1.3.43/linux/arch/sparc/kernel/ioport.c Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/ioport.c Sat Nov 25 02:58:08 1995 @@ -1,4 +1,5 @@ -/* ioport.c: Simple io mapping allocator. +/* $Id: ioport.c,v 1.12 1995/11/25 00:58:07 davem Exp $ + * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -17,10 +18,13 @@ #include #include #include +#include #include #include #include +#include +#include /* This points to the next to use virtual memory for io mappings */ static long next_free_region = IOBASE_VADDR; @@ -48,25 +52,26 @@ { unsigned long vaddr, base_address; unsigned long addr = (unsigned long) address; - + unsigned long offset = (addr & (~PAGE_MASK)); if (virtual){ vaddr = (unsigned long) virtual; } else { vaddr = next_free_region; } - + + len += offset; if (((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)){ printk ("alloc_io: Mapping ouside IOBASE area\n"); prom_halt (); } - if (check_region (vaddr, len)){ + if (check_region ((vaddr | offset), len)){ printk ("alloc_io: 0x%lx is already in use\n", vaddr); prom_halt (); } /* Tell Linux resource manager about the mapping */ - request_region (vaddr, len, name); + request_region ((vaddr | offset), len, name); base_address = vaddr; /* Do the actual mapping */ @@ -77,10 +82,18 @@ if (!virtual) next_free_region += PAGE_SIZE; } - return (void *) base_address; + return (void *) (base_address | offset); } -/* Does DVMA allocations with PAGE_SIZE granulatity */ +/* Does DVMA allocations with PAGE_SIZE granulatity. How this basically + * works is that the ESP chip can do DVMA transfers at ANY address with + * certain size and boundry restrictions. But other devices that are + * attached to it and would like to do DVMA have to set things up in + * a special way, if the DVMA see's a device attached to it transfer data + * at addresses above DVMA_VADDR it will grab them, this way it does not + * now have to know the peculiarities of where to read the Lance data + * from. (for example) + */ void *sparc_dvma_malloc (int len, char *name) { unsigned long vaddr, base_address; @@ -95,17 +108,15 @@ prom_halt (); } - /* Tell Linux resource manager about the mapping */ - request_region (vaddr, len, name); - + /* Basically these can be mapped just like any old + * IO pages, cacheable bit off, etc. The physical + * pages are pre-mapped in paging_init() + */ base_address = vaddr; - /* Assign the memory area and remove the cache bit */ - /* XXX EWWWWEE!! Sun4c specific, fix now! XXX */ - for (; len > 0; len -= PAGE_SIZE){ - printk ("Len=%d\n", len); - put_pte (vaddr, get_pte (vaddr) | PTE_NC); - vaddr += PAGE_SIZE; - dvma_next_free += PAGE_SIZE; - } + /* Assign the memory area. */ + dvma_next_free = PAGE_ALIGN(dvma_next_free+len); + + request_region(base_address, len, name); + return (void *) base_address; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v1.3.43/linux/arch/sparc/kernel/irq.c Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/irq.c Sat Nov 25 02:58:10 1995 @@ -1,4 +1,5 @@ -/* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the +/* $Id: irq.c,v 1.29 1995/11/25 00:58:08 davem Exp $ + * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device * node trees to find out who's got which IRQ. @@ -8,19 +9,6 @@ * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@jamica.lab.ipmce.su) */ -/* - * IRQ's are in fact implemented a bit like signal handlers for the kernel. - * The same sigaction struct is used, and with similar semantics (ie there - * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there - * are similarities. - * - * sa_handler(int irq_NR) is the default function called (0 if no). - * sa_mask is horribly ugly (I won't even mention it) - * sa_flags contains various info: SA_INTERRUPT etc - * sa_restorer is the unused - */ - -#include #include #include #include @@ -37,38 +25,28 @@ #include #include #include +#include #include #include /* Pointer to the interrupt enable byte */ -/* XXX Ugh, this is so sun4c specific it's driving me nuts. XXX */ unsigned char *interrupt_enable = 0; struct sun4m_intregs *sun4m_interrupts; -/* XXX Needs to handle Sun4m semantics XXX */ void -disable_irq(unsigned int irq_nr) +sun4c_disable_irq(unsigned int irq_nr) { unsigned long flags; unsigned char current_mask, new_mask; - if(sparc_cpu_model != sun4c) return; - - save_flags(flags); - cli(); - + if(sparc_cpu_model != sun4c) + return; + save_flags(flags); cli(); current_mask = *interrupt_enable; - switch(irq_nr) { case 1: new_mask = ((current_mask) & (~(SUN4C_INT_E1))); break; - case 4: - new_mask = ((current_mask) & (~(SUN4C_INT_E4))); - break; - case 6: - new_mask = ((current_mask) & (~(SUN4C_INT_E6))); - break; case 8: new_mask = ((current_mask) & (~(SUN4C_INT_E8))); break; @@ -79,42 +57,49 @@ new_mask = ((current_mask) & (~(SUN4C_INT_E14))); break; default: -#if 0 /* Actually this is safe, as the floppy driver needs this */ - printk("AIEEE, Illegal interrupt disable requested irq=%d\n", - (int) irq_nr); - prom_halt(); -#endif - break; + restore_flags(flags); + return; }; + *interrupt_enable = new_mask; restore_flags(flags); - return; } -/* XXX Needs to handle sun4m semantics XXX */ void -enable_irq(unsigned int irq_nr) +sun4m_disable_irq(unsigned int irq_nr) { - unsigned long flags; - unsigned char current_mask, new_mask; + printk("IRQ routines not yet written for the sun4m\n"); + panic("disable_irq: Unsupported arch."); +} - if(sparc_cpu_model != sun4c) return; +void +disable_irq(unsigned int irq_nr) +{ + switch(sparc_cpu_model) { + case sun4c: + sun4c_disable_irq(irq_nr); + break; + case sun4m: + sun4m_disable_irq(irq_nr); + default: + panic("disable_irq: Unsupported arch."); + } +} - save_flags(flags); - cli(); +void +sun4c_enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + unsigned char current_mask, new_mask; + if(sparc_cpu_model != sun4c) + return; + save_flags(flags); cli(); current_mask = *interrupt_enable; - switch(irq_nr) { case 1: new_mask = ((current_mask) | SUN4C_INT_E1); break; - case 4: - new_mask = ((current_mask) | SUN4C_INT_E4); - break; - case 6: - new_mask = ((current_mask) | SUN4C_INT_E6); - break; case 8: new_mask = ((current_mask) | SUN4C_INT_E8); break; @@ -125,19 +110,34 @@ new_mask = ((current_mask) | SUN4C_INT_E14); break; default: -#if 0 /* Floppy driver does this on sun4c's anyhow */ - printk ("Interrupt does not need to enable IE\n"); - return; -#endif restore_flags(flags); return; }; *interrupt_enable = new_mask; - restore_flags(flags); +} - return; +void +sun4m_enable_irq(unsigned int irq_nr) +{ + printk("IRQ routines not written for the sun4m yet.\n"); + panic("IRQ unsupported arch."); +} + +void +enable_irq(unsigned int irq_nr) +{ + switch(sparc_cpu_model) { + case sun4c: + sun4c_enable_irq(irq_nr); + break; + case sun4m: + sun4m_enable_irq(irq_nr); + break; + default: + panic("IRQ unsupported arch."); + } } /* @@ -193,8 +193,7 @@ printk("Trying to free free IRQ%d\n", irq); return; } - save_flags(flags); - cli(); + save_flags(flags); cli(); disable_irq(irq); action->handler = NULL; action->flags = 0; @@ -210,14 +209,14 @@ printk("IO device interrupt, irq = %d\n", irq); printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, - regs->npc, regs->u_regs[14]); + regs->npc, regs->u_regs[14]); printk("Expecting: "); for (i = 0; i < 16; i++) if (irq_action[i].handler) - printk("[%s:%d:0x%x] ", irq_action[i].name, (int) i, + prom_printf("[%s:%d:0x%x] ", irq_action[i].name, (int) i, (unsigned int) irq_action[i].handler); printk("AIEEE\n"); - prom_halt(); + panic("bogus interrupt received"); } void @@ -225,11 +224,11 @@ { struct irqaction * action = irq_action + irq; - if (!action->handler) { + kstat.interrupts[irq]++; + if (!action->handler) unexpected_irq(irq, regs); - return; - } - action->handler(irq, regs); + else + action->handler(irq, regs); } /* @@ -262,6 +261,40 @@ return; } +int +request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *), + unsigned long irqflags, const char *devname) +{ + struct irqaction *action; + unsigned long flags; + + if(irq > 14) + return -EINVAL; + action = irq + irq_action; + if(action->handler) + return -EBUSY; + if(!handler) + return -EINVAL; + + save_flags(flags); cli(); + + /* Dork with trap table if we get this far. */ + sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one = + SPARC_BRANCH((unsigned long) handler, + (unsigned long) &sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one); + sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_two = SPARC_RD_PSR_L0; + sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_three = SPARC_NOP; + sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_four = SPARC_NOP; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + + restore_flags(flags); + return 0; +} + extern void probe_clock(void); int @@ -271,44 +304,40 @@ struct irqaction *action; unsigned long flags; - if(irq > 14) /* Only levels 1-14 are valid on the Sparc. */ + if(irq > 14) return -EINVAL; - /* i386 keyboard interrupt request, just return */ - if(irq == 1) return 0; - - /* sched_init() requesting the timer IRQ */ - if(irq == 0) { - irq = 10; - } - action = irq + irq_action; - if(action->handler) return -EBUSY; - if(!handler) return -EINVAL; - save_flags(flags); - - cli(); - + save_flags(flags); cli(); action->handler = handler; action->flags = irqflags; action->mask = 0; action->name = devname; - enable_irq(irq); - - /* Init the timer/clocks if necessary. */ - if(irq == 10) probe_clock(); - + if(irq == 10) + probe_clock(); restore_flags(flags); - return 0; } +/* We really don't need these at all on the Sparc. We only have + * stubs here because they are exported to modules. + */ +unsigned long probe_irq_on(void) +{ + return 0; +} + +int probe_irq_off(unsigned long mask) +{ + return 0; +} + void sun4c_init_IRQ(void) { @@ -317,10 +346,8 @@ ie_node = prom_searchsiblings (prom_getchild(prom_root_node), "interrupt-enable"); - if(ie_node == 0) { - printk("Cannot find /interrupt-enable node\n"); - prom_halt(); - } + if(ie_node == 0) + panic("Cannot find /interrupt-enable node"); /* Depending on the "address" property is bad news... */ prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR, @@ -330,16 +357,14 @@ interrupt_enable = (char *) INTREG_VADDR; /* Default value, accept interrupts, but no one is actually active */ - /* We also turn on level14 interrupts so PROM can run the console. */ - *interrupt_enable = (SUN4C_INT_ENABLE | SUN4C_INT_E14); - sti(); /* As of NOW, L1-A works. Turn irq's on full-blast. */ - return; + *interrupt_enable = (SUN4C_INT_ENABLE); + sti(); /* Turn irq's on full-blast. */ } void sun4m_init_IRQ(void) { - int ie_node, i; + int ie_node; struct linux_prom_registers int_regs[PROMREG_MAX]; int num_regs; @@ -349,10 +374,7 @@ if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || (ie_node = prom_getchild (ie_node)) == 0 || (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) - { - printk("Cannot find /obio/interrupt node\n"); - prom_halt(); - } + panic("Cannot find /obio/interrupt node\n"); num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); num_regs = (num_regs/sizeof(struct linux_prom_registers)); @@ -372,27 +394,7 @@ int_regs[num_regs-1].which_io, 0x0); sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR; - -#if 0 - printk("Interrupt register dump...\n"); - - for(i=0; icpu_intregs[i].tbt); - - printk("Master tbt %08x\n", sun4m_interrupts->tbt); - printk("Master irqs %08x\n", sun4m_interrupts->irqs); - printk("Master set %08x\n", sun4m_interrupts->set); - printk("Master clear %08x\n", sun4m_interrupts->clear); - printk("Undirected ints taken by: %08x\n", - sun4m_interrupts->undirected_target); - - prom_halt(); -#endif - sti(); - - return; } void @@ -406,10 +408,7 @@ sun4m_init_IRQ(); break; default: - printk("Cannot initialize IRQ's on this Sun machine...\n"); - halt(); + panic("Cannot initialize IRQ's on this Sun machine..."); break; }; - - return; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/mp.S linux/arch/sparc/kernel/mp.S --- v1.3.43/linux/arch/sparc/kernel/mp.S Tue Jun 27 14:11:31 1995 +++ linux/arch/sparc/kernel/mp.S Sat Nov 25 02:58:12 1995 @@ -1,4 +1,5 @@ -/* mp.S: Multiprocessor low-level routines on the Sparc. +/* $Id: mp.S,v 1.2 1995/11/25 00:58:11 davem Exp $ + * mp.S: Multiprocessor low-level routines on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c --- v1.3.43/linux/arch/sparc/kernel/probe.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/kernel/probe.c Sat Nov 25 02:58:17 1995 @@ -1,4 +1,5 @@ -/* probe.c: Preliminary device tree probing routines... +/* $Id: probe.c,v 1.38 1995/11/25 00:58:14 davem Exp $ + * probe.c: Preliminary device tree probing routines... * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -11,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -24,12 +26,14 @@ /* #define DEBUG_PROBING */ /* XXX Grrr, this stuff should have it's own file, only generic stuff goes - * XXX here. Possibly clock.c and timer.c? + * XXX here. Possibly clock.c and timer.c? This file should get smaller + * XXX and smaller as time goes on... */ enum sparc_clock_type sp_clock_typ; struct mostek48t02 *mstk48t02_regs; struct mostek48t08 *mstk48t08_regs; volatile unsigned int *master_l10_limit = 0; +volatile unsigned int *master_l10_counter = 0; struct sun4m_timer_regs *sun4m_timers; static char node_str[128]; @@ -124,7 +128,7 @@ { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"}, /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */ { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"}, - { 9, 0, "UNKNOWN CPU-VENDOR/TYPE"}, + { 9, 0, "Fujitsu #3"}, { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"}, { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"}, { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"}, @@ -138,16 +142,6 @@ char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" }; char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" }; -/* various Virtual Address Cache parameters we find at boot time... */ - -extern int vac_size, vac_linesize, vac_do_hw_vac_flushes; -extern int vac_entries_per_context, vac_entries_per_segment; -extern int vac_entries_per_page; - -extern int find_vac_size(void); -extern int find_vac_linesize(void); -extern int find_vac_hwflushes(void); - static inline int find_mmu_num_contexts(int cpu) { return prom_getintdefault(cpu, "mmu-nctx", 0x8); @@ -158,99 +152,126 @@ void probe_cpu(void) { - int psr_impl, psr_vers, fpu_vers; - int i, cpuid; + int psr_impl, psr_vers, fpu_vers; + int i, cpuid; + + cpuid = get_cpuid(); - cpuid = get_cpuid(); + psr_impl = ((get_psr()>>28)&0xf); + psr_vers = ((get_psr()>>24)&0xf); - psr_impl = ((get_psr()>>28)&0xf); - psr_vers = ((get_psr()>>24)&0xf); + fpu_vers = ((get_fsr()>>17)&0x7); - fpu_vers = ((get_fsr()>>17)&0x7); - - for(i = 0; i> 12; - for(x=0,y=vac_linesize; ((1<regs; - break; - } - - node = prom_getsibling(node); - if(node == 0) { - printk("Aieee, could not find timer chip type\n"); - return; - } - } - - if(sparc_cpu_model == sun4c) { - - /* Map the Timer chip, this is implemented in hardware inside - * the cache chip on the sun4c. - */ - sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, (void *) TIMER_VADDR, - sizeof (*SUN4C_TIMER_STRUCT), "timer", 0x0, 0x0); - - /* Have the level 10 timer tick at 100HZ. We don't touch the - * level 14 timer limit since we are letting the prom handle - * them until we have a real console driver so L1-A works. - */ - SUN4C_TIMER_STRUCT->timer_limit10 = (((1000000/HZ) + 1) << 10); - master_l10_limit = &(SUN4C_TIMER_STRUCT->timer_limit10); - - } else { - int reg_count; - struct linux_prom_registers cnt_regs[PROMREG_MAX]; - int obio_node, cnt_node; - - cnt_node = 0; - if((obio_node = - prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || - (obio_node = prom_getchild (obio_node)) == 0 || - (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { - printk ("Cannot find /obio/counter node\n"); - prom_halt (); - } - reg_count = prom_getproperty(cnt_node, "reg", - (void *) cnt_regs, sizeof(cnt_regs)); - - reg_count = (reg_count/sizeof(struct linux_prom_registers)); - - /* Apply the obio ranges to the timer registers. */ - prom_apply_obio_ranges(cnt_regs, reg_count); - - /* Map the per-cpu Counter registers. */ - sparc_alloc_io(cnt_regs[0].phys_addr, (void *) TIMER_VADDR, - PAGE_SIZE*NCPUS, "counters_percpu", cnt_regs[0].which_io, 0x0); - - /* Map the system Counter register. */ - sparc_alloc_io(cnt_regs[reg_count-1].phys_addr, - (void *) TIMER_VADDR+(NCPUS*PAGE_SIZE), - cnt_regs[reg_count-1].reg_size, - "counters_system", cnt_regs[reg_count-1].which_io, 0x0); - - - sun4m_timers = (struct sun4m_timer_regs *) TIMER_VADDR; - - foo_limit = (volatile) sun4m_timers->l10_timer_limit; - -/* printk("Timer register dump:\n"); */ -#if 0 - printk("cpu0: l14limit %08x l14curcount %08x\n", - sun4m_timers->cpu_timers[0].l14_timer_limit, - sun4m_timers->cpu_timers[0].l14_cur_count); -#endif -#if 0 - printk("sys: l10limit %08x l10curcount %08x\n", - sun4m_timers->l10_timer_limit, - sun4m_timers->l10_cur_count); -#endif - - /* Must set the master pointer first or we will lose badly. */ - master_l10_limit = - &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit); + /* This will basically traverse the node-tree of the prom to see + * which timer chip is on this machine. + */ - ((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit = - (((1000000/HZ) + 1) << 10); /* 0x9c4000 */ + node = 0; + if(sparc_cpu_model == sun4) { + printk("probe_clock: No SUN4 Clock/Timer support yet...\n"); + return; + } + if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node); + else + if(sparc_cpu_model == sun4m) + node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio")); + type = 0; + sp_clock_typ = MSTK_INVALID; + for(;;) { + prom_getstring(node, "model", node_str, sizeof(node_str)); + if(strcmp(node_str, "mk48t02") == 0) { + sp_clock_typ = MSTK48T02; + if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { + printk("probe_clock: FAILED!\n"); + halt(); + } + prom_apply_obio_ranges(clk_reg, 1); + /* Map the clock register io area read-only */ + mstk48t02_regs = (struct mostek48t02 *) + sparc_alloc_io((void *) clk_reg[0].phys_addr, + (void *) 0, sizeof(*mstk48t02_regs), + "clock", 0x0, 0x1); + mstk48t08_regs = 0; /* To catch weirdness */ + break; + } - /* We should be getting level 10 interrupts now. */ - } + if(strcmp(node_str, "mk48t08") == 0) { + sp_clock_typ = MSTK48T08; + if(prom_getproperty(node, "reg", (char *) clk_reg, + sizeof(clk_reg)) == -1) { + printk("probe_clock: FAILED!\n"); + halt(); + } + prom_apply_obio_ranges(clk_reg, 1); + /* Map the clock register io area read-only */ + mstk48t08_regs = (struct mostek48t08 *) + sparc_alloc_io((void *) clk_reg[0].phys_addr, + (void *) 0, sizeof(*mstk48t08_regs), + "clock", 0x0, 0x1); - return; + mstk48t02_regs = &mstk48t08_regs->regs; + break; + } + + node = prom_getsibling(node); + if(node == 0) { + printk("Aieee, could not find timer chip type\n"); + return; + } + } + + if(sparc_cpu_model == sun4c) { + /* Map the Timer chip, this is implemented in hardware inside + * the cache chip on the sun4c. + */ + sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, (void *) TIMER_VADDR, + sizeof (*SUN4C_TIMER_STRUCT), "timer", 0x0, 0x0); + + /* Have the level 10 timer tick at 100HZ. We don't touch the + * level 14 timer limit since we are letting the prom handle + * them until we have a real console driver so L1-A works. + */ + SUN4C_TIMER_STRUCT->timer_limit10 = (((1000000/HZ) + 1) << 10); + master_l10_limit = &(SUN4C_TIMER_STRUCT->timer_limit10); + master_l10_counter = &(SUN4C_TIMER_STRUCT->cur_count10); + } else { + int reg_count; + struct linux_prom_registers cnt_regs[PROMREG_MAX]; + int obio_node, cnt_node; + + cnt_node = 0; + if((obio_node = + prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || + (obio_node = prom_getchild (obio_node)) == 0 || + (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { + printk ("Cannot find /obio/counter node\n"); + prom_halt (); + } + reg_count = prom_getproperty(cnt_node, "reg", + (void *) cnt_regs, sizeof(cnt_regs)); + reg_count = (reg_count/sizeof(struct linux_prom_registers)); + + /* Apply the obio ranges to the timer registers. */ + prom_apply_obio_ranges(cnt_regs, reg_count); + + /* Map the per-cpu Counter registers. */ + sparc_alloc_io(cnt_regs[0].phys_addr, (void *) TIMER_VADDR, + PAGE_SIZE*NCPUS, "counters_percpu", + cnt_regs[0].which_io, 0x0); + + /* Map the system Counter register. */ + sparc_alloc_io(cnt_regs[reg_count-1].phys_addr, + (void *) TIMER_VADDR+(NCPUS*PAGE_SIZE), + cnt_regs[reg_count-1].reg_size, + "counters_system", cnt_regs[reg_count-1].which_io, 0x0); + sun4m_timers = (struct sun4m_timer_regs *) TIMER_VADDR; + + /* Avoid interrupt bombs... */ + foo_limit = (volatile) sun4m_timers->l10_timer_limit; + + /* Must set the master pointer first or we will lose badly. */ + master_l10_limit = + &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit); + master_l10_counter = + &(((struct sun4m_timer_regs *)TIMER_VADDR)->l10_cur_count); + + ((struct sun4m_timer_regs *)TIMER_VADDR)->l10_timer_limit = + (((1000000/HZ) + 1) << 10); + } } /* Probe and map in the Auxiliaary I/O register */ @@ -455,15 +445,13 @@ sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR, auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0); printk("Mapped AUXIO at paddr %08lx vaddr %08lx\n", - (unsigned long) auxregs[0].phys_addr, - (unsigned long) AUXIO_VADDR); - return; + (unsigned long) auxregs[0].phys_addr, + (unsigned long) AUXIO_VADDR); } extern unsigned long probe_memory(void); extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; unsigned int phys_bytes_of_ram, end_of_phys_memory; -extern unsigned long probe_sbus(int, unsigned long); extern void probe_mbus(void); /* #define DEBUG_PROBE_DEVICES */ @@ -473,54 +461,46 @@ unsigned long probe_devices(unsigned long mem_start) { - int nd, i, prom_node_cpu, thismid; - int cpu_nds[NCPUS]; /* One node for each cpu */ - int cpu_ctr = 0; - - prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); - if(strcmp(node_str, "cpu") == 0) { - cpu_nds[0] = prom_root_node; - cpu_ctr++; - } else { - int scan; - scan = prom_getchild(prom_root_node); - nd = 0; - while((scan = prom_getsibling(scan)) != 0) { - prom_getstring(scan, "device_type", node_str, sizeof(node_str)); - if(strcmp(node_str, "cpu") == 0) { - cpu_nds[cpu_ctr] = scan; - linux_cpus[cpu_ctr].prom_node = scan; - prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); - linux_cpus[cpu_ctr].mid = thismid; - cpu_ctr++; - } - }; - if(cpu_ctr == 0) { - printk("No CPU nodes found, cannot continue.\n"); - /* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */ - halt(); - } - printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); - }; - prom_node_cpu = cpu_nds[0]; - - linux_num_cpus = cpu_ctr; - for(i=0; i #include +#include #include #include #include +#include +#include #include +#include + +int current_user_segment = USER_DS; /* the return value from get_fs */ /* - * The idle loop on a sparc... ;) + * the idle loop on a Sparc... ;) */ asmlinkage int sys_idle(void) { - if (current->pid != 0) return -EPERM; - printk("in sys_idle...\n"); - /* Map out the low memory: it's no longer needed */ - /* Sparc version RSN */ - /* endless idle loop with no priority at all */ current->counter = -100; for (;;) { - printk("calling schedule() aieee!\n"); - schedule(); - printk("schedule() returned, halting...\n"); - halt(); + schedule(); } } void hard_reset_now(void) { - prom_reboot("boot vmlinux"); + prom_halt(); +} + +void show_regwindow(struct reg_window *rw) +{ + printk("l0:%08lx l1:%08lx l2:%08lx l3:%08lx l4:%08lx l5:%08lx l6:%08lx l7:%08lx\n", + rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], + rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); + printk("i0:%08lx i1:%08lx i2:%08lx i3:%08lx i4:%08lx i5:%08lx i6:%08lx i7:%08lx\n", + rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], + rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } void show_regs(struct pt_regs * regs) { - printk("\nFP: %08lx PC: %08lx NPC: %08lx\n", regs->u_regs[14], - regs->pc, regs->npc); + printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs->psr, + regs->pc, regs->npc, regs->y); + printk("%%g0: %08lx %%g1: %08lx %%g2: %08lx %%g3: %08lx\n", + regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], + regs->u_regs[3]); + printk("%%g4: %08lx %%g5: %08lx %%g6: %08lx %%g7: %08lx\n", + regs->u_regs[4], regs->u_regs[5], regs->u_regs[6], + regs->u_regs[7]); + printk("%%o0: %08lx %%o1: %08lx %%o2: %08lx %%o3: %08lx\n", + regs->u_regs[8], regs->u_regs[9], regs->u_regs[10], + regs->u_regs[11]); + printk("%%o4: %08lx %%o5: %08lx %%sp: %08lx %%ret_pc: %08lx\n", + regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], + regs->u_regs[15]); } /* @@ -64,74 +84,92 @@ */ void exit_thread(void) { - halt(); + if(last_task_used_math == current) + last_task_used_math = NULL; + mmu_exit_hook(current); } -void flush_thread(void) +/* + * Free old dead task when we know it can never be on the cpu again. + */ +void release_thread(struct task_struct *dead_task) { - halt(); + mmu_release_hook(dead_task); } -void release_thread(struct task_struct *dead_task) +void flush_thread(void) { - halt(); + /* Make sure old user windows don't get in the way. */ + mmu_flush_hook(current); + flush_user_windows(); + current->signal &= ~(1<<(SIGILL-1)); + current->tss.w_saved = 0; + current->tss.uwinmask = 0; + + current->tss.sig_address = 0; + current->tss.sig_desc = 0; + + /* Signal stack state does not inherit. XXX Really? XXX */ + current->tss.sstk_info.cur_status = 0; + current->tss.sstk_info.the_stack = 0; + + memset(¤t->tss.reg_window[0], 0, + (sizeof(struct reg_window) * NSWINS)); + memset(¤t->tss.rwbuf_stkptrs[0], 0, + (sizeof(unsigned long) * NSWINS)); } -extern void ret_sys_call(void); - /* - * Copy a Sparc thread. The context of a process on the Sparc is - * composed of the following: - * 1) status registers %psr (for condition codes + CWP) and %wim - * 2) current register window (in's and global registers) - * 3) the current live stack frame, it contains the register - * windows the child may 'restore' into, this is important - * 4) kernel stack pointer, user stack pointer (which is %i6) - * 5) The pc and npc the child returns to during a switch + * Copy a Sparc thread. The fork() return value conventions + * under SunOS are nothing short of bletcherous: + * Parent --> %o0 == childs pid, %o1 == 0 + * Child --> %o0 == parents pid, %o1 == 1 + * + * I'm feeling sick... */ +extern void ret_sys_call(void); void copy_thread(int nr, unsigned long clone_flags, unsigned long sp, - struct task_struct * p, struct pt_regs * regs) + struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs; - unsigned char *old_stack; - unsigned char *new_stack; - int i; + struct sparc_stackf *old_stack, *new_stack; + unsigned long stack_offset, kthread_usp = 0; - /* This process has no context yet. */ + mmu_task_cacheflush(current); p->tss.context = -1; - /* Grrr, Sparc stack alignment restrictions make things difficult. */ - childregs = ((struct pt_regs *) - ((p->kernel_stack_page + PAGE_SIZE - 80)&(~7))); - + /* Calculate offset to stack_frame & pt_regs */ + stack_offset = (PAGE_SIZE - TRACEREG_SZ); + childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); *childregs = *regs; - - p->tss.usp = sp; /* both processes have the same user stack */ - /* See entry.S */ - - /* Allocate new processes kernel stack right under pt_regs. - * Hopefully this should align things the right way. + new_stack = (((struct sparc_stackf *) childregs) - 1); + old_stack = (((struct sparc_stackf *) regs) - 1); + *new_stack = *old_stack; + p->tss.ksp = (unsigned long) new_stack; + p->tss.kpc = (((unsigned long) ret_sys_call) - 0x8); + + /* As a special case, if this is a kernel fork we need + * to give the child a new fresh stack for when it returns + * from the syscall. (ie. the "user" stack) This happens + * only once and we count on the page acquisition happening + * successfully. */ - p->tss.ksp = (unsigned long) ((p->kernel_stack_page + PAGE_SIZE - 80 - 96)&(~7)); - new_stack = (unsigned char *) (p->tss.ksp); - old_stack = (unsigned char *) (((unsigned long) regs) - 96); - - /* Copy c-stack. */ - for(i=0; i<96; i++) *new_stack++ = *old_stack++; - - /* These pc values are only used when we switch to the child for - * the first time, it jumps the child to ret_sys_call in entry.S - * so that the child returns from the sys_call just like parent. - */ - p->tss.pc = (((unsigned long) ret_sys_call) - 8); - p->tss.npc = p->tss.pc+4; + if(regs->psr & PSR_PS) { + unsigned long n_stack = get_free_page(GFP_KERNEL); + childregs->u_regs[UREG_FP] = (n_stack | (sp & 0xfff)); + memcpy((char *)n_stack,(char *)(sp & PAGE_MASK),PAGE_SIZE); + kthread_usp = n_stack; + } - /* Set the return values for both the parent and the child */ - regs->u_regs[8] = p->pid; - childregs->u_regs[8] = 0; + /* Set the return value for the child. */ + childregs->u_regs[UREG_I0] = current->pid; + childregs->u_regs[UREG_I1] = 1; - return; + /* Set the return value for the parent. */ + regs->u_regs[UREG_I1] = 0; + + mmu_fork_hook(p, kthread_usp); } /* @@ -139,21 +177,57 @@ */ void dump_thread(struct pt_regs * regs, struct user * dump) { - return; /* solaris does this enough */ } -asmlinkage int sys_fork(struct pt_regs *regs) +/* + * fill in the fpu structure for a core dump. + */ +int dump_fpu (void *fpu_structure) { - return do_fork(SIGCHLD, regs->u_regs[14], regs); + /* Currently we report that we couldn't dump the fpu structure */ + return 0; } /* - * sys_execve() executes a new program. + * sparc_execve() executes a new program after the asm stub has set + * things up for us. This should basically do what I want it to. */ -asmlinkage int sys_execve(struct pt_regs regs) +asmlinkage int sparc_execve(struct pt_regs *regs) { - printk("sys_execve()... halting\n"); - halt(); - return 0; + int error; + char *filename; + + flush_user_windows(); + mmu_task_cacheflush(current); + error = getname((char *) regs->u_regs[UREG_I0], &filename); + if(error) + return error; + error = do_execve(filename, (char **) regs->u_regs[UREG_I1], + (char **) regs->u_regs[UREG_I2], regs); + putname(filename); + return error; } +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +{ + unsigned long saved_psr = (regs->psr & (PSR_CWP)) | PSR_S; + + memset(regs, 0, sizeof(struct pt_regs)); + regs->pc = ((pc & (~3)) - 4); /* whee borken a.out header fields... */ + regs->npc = regs->pc + 4; + regs->psr = saved_psr; + regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */ + + /* XXX More mysterious netbsd garbage... XXX */ + regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc; + + /* Allocate one reg window because the first jump into + * user mode will restore one register window by definition + * of the 'rett' instruction. Also, SunOS crt.o code + * depends upon the arg/envp area being _exactly_ one + * register window above %sp when the process begins + * execution. + */ + sp -= REGWIN_SZ; + regs->u_regs[UREG_FP] = sp; +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/promops.c linux/arch/sparc/kernel/promops.c --- v1.3.43/linux/arch/sparc/kernel/promops.c Sun Feb 26 20:46:20 1995 +++ linux/arch/sparc/kernel/promops.c Thu Jan 1 02:00:00 1970 @@ -1,107 +0,0 @@ -/* promops.c: Prom node tree operations and Prom Vector initialization - * initialization routines. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#include - -#include - -/* #define DEBUG_PROMOPS */ -#define MAX_PR_LEN 64 /* exotic hardware probably overshoots this */ - -int prom_node_root; /* initialized in init_prom */ - -extern struct linux_romvec *romvec; - -/* These two functions return and siblings and direct child descendents - * in the prom device tree respectively. - */ - -int -node_get_sibling(int node) -{ - return (*(romvec->pv_nodeops->no_nextnode))(node); -} - -int -node_get_child(int node) -{ - return (*(romvec->pv_nodeops->no_child))(node); -} - -/* The following routine is used during device probing to determine - * an integer value property about a (perhaps virtual) device. This - * could be anything, like the size of the mmu cache lines, etc. - * the default return value is -1 is the prom has nothing interesting. - */ - -unsigned int prom_int_null; - -unsigned int * -get_int_from_prom(int node, char *nd_prop, unsigned int *value) -{ - unsigned int pr_len; - - *value = &prom_int_null; /* duh, I was returning -1 as an unsigned int, prom_panic() */ - - pr_len = romvec->pv_nodeops->no_proplen(node, nd_prop); - if(pr_len > MAX_PR_LEN) - { -#ifdef DEBUG_PROMOPS - printk("Bad pr_len in promops -- node: %d nd_prop: %s pr_len: %d", - node, nd_prop, (int) pr_len); -#endif - return value; /* XXX */ - } - - romvec->pv_nodeops->no_getprop(node, nd_prop, (char *) value); - - return value; -} - - -/* This routine returns what is termed a property string as opposed - * to a property integer as above. This can be used to extract the - * 'type' of device from the prom. An example could be the clock timer - * chip type. By default you get returned a null string if garbage - * is returned from the prom. - */ - -char * -get_str_from_prom(int node, char *nd_prop, char *value) -{ - unsigned int pr_len; - - *value='\n'; - - pr_len = romvec->pv_nodeops->no_proplen(node, nd_prop); - if(pr_len > MAX_PR_LEN) - { -#ifdef DEBUG_PROMOPS - printk("Bad pr_len in promops -- node: %d nd_prop: %s pr_len: %d", - node, nd_prop, pr_len); -#endif - return value; /* XXX */ - } - - romvec->pv_nodeops->no_getprop(node, nd_prop, value); - value[pr_len] = 0; - - return value; -} - -/* This gets called from head.S upon bootup to initialize the - * prom vector pointer for the rest of the kernel. - */ - -void -init_prom(struct linux_romvec *r_ptr) -{ - romvec = r_ptr; - prom_node_root = romvec->pv_nodeops->no_nextnode(0); - prom_int_null = 0; - - return; -} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v1.3.43/linux/arch/sparc/kernel/rtrap.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/rtrap.S Sat Nov 25 02:58:21 1995 @@ -0,0 +1,332 @@ +/* $Id: rtrap.S,v 1.11 1995/11/25 00:58:19 davem Exp $ + * rtrap.S: Return from Sparc trap low-level code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include + +#define t_psr l0 +#define t_pc l1 +#define t_npc l2 +#define t_wim l3 +#define twin_tmp1 l4 +#define twin_tmp2 l5 +#define twin_tmp3 l6 + + /* 7 WINDOW SPARC PATCH INSTRUCTIONS */ + .globl rtrap_7win_patch1, rtrap_7win_patch2, rtrap_7win_patch3 + .globl rtrap_7win_patch4, rtrap_7win_patch5 +rtrap_7win_patch1: srl %t_wim, 0x6, %twin_tmp2 +rtrap_7win_patch2: and %twin_tmp2, 0x7f, %twin_tmp2 +rtrap_7win_patch3: srl %g1, 7, %g2 +rtrap_7win_patch4: srl %g2, 6, %g2 +rtrap_7win_patch5: and %g1, 0x7f, %g1 + /* END OF PATCH INSTRUCTIONS */ + + /* We need to check for a few things which are: + * 1) The need to call schedule() because this + * processes quantum is up. + * 2) Pending signals for this process, if any + * exist we need to call do_signal() to do + * the needy. + * + * Else we just check if the rett would land us + * in an invalid window, if so we need to grab + * it off the user/kernel stack first. + */ + + .globl ret_trap_entry, rtrap_patch1, rtrap_patch2 + .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 +ret_trap_entry: + ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr + andcc %t_psr, PSR_PS, %g0 + bne ret_trap_kernel + nop + + sethi %hi(C_LABEL(need_resched)), %twin_tmp1 + ld [%twin_tmp1 + %lo(C_LABEL(need_resched))], %twin_tmp2 + LOAD_CURRENT(twin_tmp1) + + cmp %twin_tmp2, 0x0 + be signal_p + nop + + call C_LABEL(schedule) + nop + + /* Try to return again... We are a different process, + * most likely so load and then check if going back + * to user or kernel this time. + */ + b ret_trap_entry + nop + +signal_p: + /* No signals for swapper. */ + sethi %hi(C_LABEL(init_task)), %twin_tmp3 + or %twin_tmp3, %lo(C_LABEL(init_task)), %twin_tmp3 + cmp %twin_tmp3, %twin_tmp1 + be ret_trap_continue + nop + + ld [%twin_tmp1 + TASK_SIGNAL], %twin_tmp2 + ld [%twin_tmp1 + TASK_BLOCKED], %twin_tmp3 + andncc %twin_tmp2, %twin_tmp3, %twin_tmp2 + be ret_trap_continue + nop + + mov %twin_tmp2, %o0 ! oldmask + add %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr + call C_LABEL(do_signal) + nop + + /* Fall through... */ +ret_trap_continue: + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + LOAD_CURRENT(twin_tmp2) + ld [%twin_tmp2 + THREAD_W_SAVED], %twin_tmp1 + orcc %g0, %twin_tmp1, %g0 + be ret_trap_nobufwins + nop + + wr %t_psr, 0x0, %psr + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + mov 1, %o1 + call C_LABEL(do_sparc_winfault) + add %sp, STACKFRAME_SZ, %o0 + + b ret_trap_entry + nop + +ret_trap_nobufwins: + /* Load up the user's out registers so we can pull + * a window from the stack, if necessary. + */ + LOAD_PT_INS(sp) + + /* If there are already live user windows in the + * set we can return from trap safely. + */ + ld [%twin_tmp2 + THREAD_UMASK], %twin_tmp1 + orcc %g0, %twin_tmp1, %g0 + bne ret_trap_userwins_ok + nop + + /* Calculate new %wim, we have to pull a register + * window from the users stack. + */ + rd %wim, %t_wim + sll %t_wim, 0x1, %twin_tmp1 +rtrap_patch1: srl %t_wim, 0x7, %twin_tmp2 + or %twin_tmp2, %twin_tmp1, %twin_tmp2 +rtrap_patch2: and %twin_tmp2, 0xff, %twin_tmp2 + + wr %twin_tmp2, 0x0, %wim + WRITE_PAUSE + + /* Here comes the architecture specific + * branch to the user stack checking routine + * for return from traps. + */ + .globl C_LABEL(rtrap_mmu_patchme) +C_LABEL(rtrap_mmu_patchme): b C_LABEL(sun4c_rett_stackchk) + andcc %fp, 0x7, %g0 + +ret_trap_userwins_ok: + LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) + or %t_pc, %t_npc, %g2 + andcc %g2, 0x3, %g0 + bne ret_trap_unaligned_pc + nop + + LOAD_PT_YREG(sp, g1) + LOAD_PT_GLOBALS(sp) + + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + +ret_trap_unaligned_pc: + add %sp, STACKFRAME_SZ, %o0 + ld [%sp + STACKFRAME_SZ + PT_PC], %o1 + ld [%sp + STACKFRAME_SZ + PT_NPC], %o2 + ld [%sp + STACKFRAME_SZ + PT_PSR], %o3 + + wr %t_psr, 0x0, %psr + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(do_memaccess_unaligned) + nop + + b ret_trap_entry + nop + +ret_trap_kernel: + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + /* Will the rett land us in the invalid window? */ + mov 2, %g1 + sll %g1, %t_psr, %g1 +rtrap_patch3: srl %g1, 8, %g2 + or %g1, %g2, %g1 + rd %wim, %g2 + andcc %g2, %g1, %g0 + be 1f ! Nope, just return from the trap + nop + + /* We have to grab a window before returning. */ + sll %g2, 0x1, %g1 +rtrap_patch4: srl %g2, 7, %g2 + or %g1, %g2, %g1 +rtrap_patch5: and %g1, 0xff, %g1 + + wr %g1, 0x0, %wim + WRITE_PAUSE + + restore %g0, %g0, %g0 + LOAD_WINDOW(sp) + save %g0, %g0, %g0 + + /* Reload the entire frame in case this is from a + * kernel system call or whatever... + */ +1: + LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) + + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + +ret_trap_user_stack_is_bolixed: + wr %t_wim, 0x0, %wim + WRITE_PAUSE + + wr %t_psr, 0x0, %psr + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + mov 0, %o1 + call C_LABEL(do_sparc_winfault) + add %sp, STACKFRAME_SZ, %o0 + + /* Try it all again. */ + b ret_trap_entry + nop + + .globl C_LABEL(sun4c_rett_stackchk) +C_LABEL(sun4c_rett_stackchk): + be 1f + and %fp, 0xfff, %g1 ! delay slot + + b ret_trap_user_stack_is_bolixed + nop + + /* See if we have to check the sanity of one page or two */ +1: + add %g1, 0x38, %g1 + sra %fp, 29, %g2 + add %g2, 0x1, %g2 + andncc %g2, 0x1, %g0 + be 1f + andncc %g1, 0xff8, %g0 + + /* %sp is in vma hole, yuck */ + b ret_trap_user_stack_is_bolixed + nop + +1: + be sun4c_rett_onepage /* Only one page to check */ + lda [%fp] ASI_PTE, %g2 + +sun4c_rett_twopages: + add %fp, 0x38, %g1 + sra %g1, 29, %g2 + add %g2, 0x1, %g2 + andncc %g2, 0x1, %g0 + be 1f + lda [%g1] ASI_PTE, %g2 + + /* Second page is in vma hole */ + b ret_trap_user_stack_is_bolixed + nop + +1: + srl %g2, 29, %g2 + andcc %g2, 0x4, %g0 + bne sun4c_rett_onepage + lda [%fp] ASI_PTE, %g2 + + /* Second page has bad perms */ + b ret_trap_user_stack_is_bolixed + nop + +sun4c_rett_onepage: + srl %g2, 29, %g2 + andcc %g2, 0x4, %g0 + bne 1f + nop + + /* A page had bad page permissions, losing... */ + b ret_trap_user_stack_is_bolixed + nop + + /* Whee, things are ok, load the window and continue. */ +1: + restore %g0, %g0, %g0 + + LOAD_WINDOW(sp) + + save %g0, %g0, %g0 + b ret_trap_userwins_ok + nop + + .globl C_LABEL(sun4c_rett_stackchk) +C_LABEL(srmmu_rett_stackchk): + bne ret_trap_user_stack_is_bolixed + sethi %hi(KERNBASE), %g1 + cmp %g1, %fp + bleu ret_trap_user_stack_is_bolixed + mov AC_M_SFSR, %g1 + lda [%g1] ASI_M_MMUREGS, %g0 + + lda [%g0] ASI_M_MMUREGS, %g1 + or %g1, 0x2, %g1 + sta %g1, [%g0] ASI_M_MMUREGS + + restore %g0, %g0, %g0 + + LOAD_WINDOW(sp) + + save %g0, %g0, %g0 + + andn %g1, 0x2, %g1 + sta %g1, [%g0] ASI_M_MMUREGS + + mov AC_M_SFAR, %g2 + lda [%g2] ASI_M_MMUREGS, %g2 + + mov AC_M_SFSR, %g1 + lda [%g1] ASI_M_MMUREGS, %g1 + andcc %g1, 0x2, %g0 + bne ret_trap_user_stack_is_bolixed + nop + + b ret_trap_userwins_ok + nop diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v1.3.43/linux/arch/sparc/kernel/setup.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/kernel/setup.c Sat Nov 25 02:58:23 1995 @@ -1,13 +1,9 @@ -/* - * linux/arch/alpha/kernel/setup.c +/* $Id: setup.c,v 1.41 1995/11/25 00:58:21 davem Exp $ + * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -/* - * bootup setup stuff.. - */ - #include #include #include @@ -24,27 +20,25 @@ #include #include #include +#include #include -#include /* The PROM is your friend... */ +#include #include #include #include #include #include -extern unsigned long probe_devices(unsigned long); - -/* - * Gcc is hard to keep happy ;-) - */ struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ { 0, 0, }, /* unused */ 0, /* orig-video-page */ 0, /* orig-video-mode */ - 80, /* orig-video-cols */ + 128, /* orig-video-cols */ 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 25 /* orig-video-lines */ + 54, /* orig-video-lines */ + 0, /* orig-video-isVGA */ + 16 /* orig-video-points */ }; char wp_works_ok = 0; @@ -54,43 +48,45 @@ return memory_start; } -/* Lame prom console routines, gets registered below. Thanks for the - * tip Linus. We now use a generic putchar prom routine through the - * linux prom library. - */ - -void sparc_console_print(const char * p) -{ - unsigned char c; - - while ((c = *(p++)) != 0) - { - if (c == '\n') - prom_putchar('\r'); - prom_putchar(c); - } - - return; - -} - /* Typing sync at the prom promptcalls the function pointed to by * romvec->pv_synchook which I set to the following function. * This should sync all filesystems and return, for now it just * prints out pretty messages and returns. */ + +extern unsigned long trapbase; + +/* Pretty sick eh? */ void prom_sync_me(void) { - printk("PROM SYNC COMMAND...\n"); + unsigned long prom_tbr, flags; + + save_flags(flags); cli(); + __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr)); + __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" : : "r" (&trapbase)); + + prom_printf("PROM SYNC COMMAND...\n"); show_free_areas(); - printk("Returning to prom\n"); + prom_printf("Returning to prom\n"); + + __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" : : "r" (prom_tbr)); + restore_flags(flags); + return; } +extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */ + unsigned int boot_flags; #define BOOTME_DEBUG 0x1 #define BOOTME_SINGLE 0x2 -#define BOOTME_KGDB 0x3 +#define BOOTME_KGDB 0x4 /* This routine does no error checking, make sure your string is sane * before calling this! @@ -100,8 +96,8 @@ boot_flags_init(char *commands) { int i; - for(i=0; iteach_debugger))(); - - SP_ENTER_DEBUGGER; - } /* Set sparc_cpu_model */ sparc_cpu_model = sun_unknown; @@ -185,23 +178,10 @@ switch(sparc_cpu_model) { case sun4c: - memset(phys_seg_map, 0x0, sizeof(phys_seg_map[PSEG_ENTRIES])); - put_segmap(IOBASE_VADDR, IOBASE_SUN4C_SEGMAP); - phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV; - node = prom_root_node; - printk("SUN4C\n"); + probe_vac(); break; case sun4m: - node = prom_getchild(prom_root_node); - prom_getproperty(node, "device_type", devtype, sizeof(devtype)); - while(strcmp(devtype, "cpu") != 0) { - node = prom_getsibling(node); - prom_getproperty(node, "device_type", devtype, - sizeof(devtype)); - } - /* Patch trap table. */ - srmmu_patch_fhandlers(); printk("SUN4M\n"); break; case sun4d: @@ -218,51 +198,69 @@ break; }; - /* probe_devices() expects this to be done. */ - get_idprom(); - - /* Probe the mmu constants. */ - probe_mmu(node); + boot_flags_init(*cmdline_p); + if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && + ((*(short *)linux_dbvec) != -1)) { + printk("Booted under KADB. Syncing trap table.\n"); + (*(linux_dbvec->teach_debugger))(); + } + if((boot_flags & BOOTME_KGDB)) { + set_debug_traps(); + breakpoint(); + } - /* Set pointers to memory management routines. */ + get_idprom(); load_mmu(); - - /* Probe for memory. */ total = prom_probe_memory(); *memory_start_p = (((unsigned long) &end)); - printk("Physical Memory: %d bytes (in hex %08lx)\n", (int) total, - (unsigned long) total); + (unsigned long) total); for(i=0; sp_banks[i].num_bytes != 0; i++) { #if 0 printk("Bank %d: base 0x%x bytes %d\n", i, - (unsigned int) sp_banks[i].base_addr, - (int) sp_banks[i].num_bytes); + (unsigned int) sp_banks[i].base_addr, + (int) sp_banks[i].num_bytes); #endif end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes; } - /* Set prom sync hook pointer */ prom_setsync(prom_sync_me); - init_task.mm->start_code = PAGE_OFFSET; - init_task.mm->end_code = PAGE_OFFSET + (unsigned long) &etext; - init_task.mm->end_data = PAGE_OFFSET + (unsigned long) &edata; - init_task.mm->brk = PAGE_OFFSET + (unsigned long) &end; + /* Due to stack alignment restrictions and assumptions... */ init_task.mm->mmap->vm_page_prot = PAGE_SHARED; - /* Grrr, wish I knew why I have to do this ;-( */ - for(counter=1; counter #include #include +#include #include +#include +#include #define _S(nr) (1<<((nr)-1)) #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options); +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs); /* * atomically swap in the new signal mask, and wait for a signal. + * This is really tricky on the Sparc, watch out... */ -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) +asmlinkage inline int _sigpause_common(unsigned int set, struct pt_regs *regs) { unsigned long mask; - struct pt_regs * regs = (struct pt_regs *) &restart; mask = current->blocked; current->blocked = set & _BLOCKABLE; + /* Advance over the syscall instruction for when + * we return. We want setup_frame to save the proper + * state, but then below we set ourselves backwards + * to compensate for what ret_sys_call does. Ick! + */ + regs->pc += 4; + regs->npc += 4; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask,regs)) + if (do_signal(mask, regs)) { + /* If we actually post the signal then we + * will get our PCs advanced in entry.S, to + * compensate we throw the PCs back one insn. + */ + regs->pc -= 4; + regs->npc -= 4; return -EINTR; + } } } -asmlinkage int sys_sigreturn(unsigned long __unused) +asmlinkage int sys_sigpause(unsigned int set) +{ + struct pt_regs *regs; + unsigned long fp; + + __asm__ __volatile__("mov %%fp, %0\n\t" : + "=r" (fp)); + regs = ((struct pt_regs *) (fp + STACKFRAME_SZ)); + return _sigpause_common(set, regs); +} + +asmlinkage int sys_sigsuspend(unsigned int *sigmaskp) +{ + struct pt_regs *regs; + unsigned long fp; + unsigned int set; + + __asm__ __volatile__("mov %%fp, %0\n\t" : + "=r" (fp)); + regs = ((struct pt_regs *) (fp + STACKFRAME_SZ)); + if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int))) + return -EFAULT; + set = *sigmaskp; + return _sigpause_common(set, regs); +} + +extern unsigned long nwindows; + +asmlinkage void do_sigreturn(struct pt_regs *regs) { - halt(); - return 0; + int wsvd; + struct sigcontext_struct *scptr = + (struct sigcontext_struct *) regs->u_regs[UREG_I0]; + + /* Make the stack consistant. */ + flush_user_windows(); + + /* Check sanity of the user arg. */ + if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext_struct)) || + ((((unsigned long) scptr)) & 0x3)) + do_exit(SIGSEGV); + + if((scptr->sigc_pc | scptr->sigc_npc) & 3) + return; /* Nice try. */ + + current->blocked = scptr->sigc_mask & _BLOCKABLE; + current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 0x1); + regs->pc = scptr->sigc_pc; + regs->npc = scptr->sigc_npc; + regs->u_regs[UREG_FP] = scptr->sigc_sp; + regs->u_regs[UREG_I0] = scptr->sigc_o0; + regs->u_regs[UREG_G1] = scptr->sigc_g1; + + /* User can only change condition codes in %psr. */ + regs->psr &= (~PSR_ICC); + regs->psr |= (scptr->sigc_psr & PSR_ICC); +} + +/* I love register windows... + * Basically, this tries to get as many of the current user + * windows on the stack as possible, even if unaligned. Failing + * that the windows end up in the per-task window save buffer + * in the thread struct, these will be copied onto the signal + * stack for possible inspection by the process. + */ +static inline void +do_magic_sparc_stuff(void) +{ + unsigned long sp; + int this_win; + + flush_user_windows(); + this_win = (current->tss.w_saved - 1); + while(this_win >= 0) { + sp = current->tss.rwbuf_stkptrs[this_win]; + if(!(sp & 7) && !verify_area(VERIFY_WRITE, (char *)sp, + sizeof(struct reg_window))) { + memcpy((char *)sp, + (char *)¤t->tss.reg_window[this_win], + sizeof(struct reg_window)); + current->tss.w_saved--; + memcpy((char *)¤t->tss.reg_window[this_win], + (char *)¤t->tss.reg_window[this_win+1], + (sizeof(struct reg_window) * + (current->tss.w_saved-this_win))); + } + this_win -= 1; + } } /* - * Set up a signal frame... Make the stack look the way iBCS2 expects - * it to look. + * Set up a signal frame... Make the stack look the way SunOS + * expects it to look which is basically: + * + * ---------------------------------- <-- %sp at signal time + * Struct sigcontext + * Signal address + * Ptr to sigcontext area above + * Signal code + * The signal number itself + * One register window + * ---------------------------------- <-- New %sp */ -void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip, - struct pt_regs * regs, int signr, unsigned long oldmask) +struct signal_sframe { + struct reg_window sig_window; + int sig_num; + int sig_code; + struct sigcontext_struct *sig_scptr; + int sig_address; + struct sigcontext_struct sig_context; +}; +/* To align the structure properly. */ +#define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7))) + +static inline void +setup_frame(struct sigaction *sa, struct sigcontext_struct **fp, + unsigned long pc, struct pt_regs *regs, int signr, + unsigned long oldmask) { - halt(); + struct signal_sframe *sframep; + struct sigcontext_struct *sc; + int window = 0; + int old_status = current->tss.sstk_info.cur_status; + + sframep = (struct signal_sframe *) *fp; + sframep = (struct signal_sframe *) (((unsigned long) sframep)-SF_ALIGNEDSZ); + sc = &sframep->sig_context; + if(verify_area(VERIFY_WRITE, sframep, sizeof(*sframep)) || + (((unsigned long) sframep) & 7) || + (((unsigned long) sframep) >= KERNBASE)) { + printk("%s [%d]: User has trashed signal stack\n", + current->comm, current->pid); + printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n", + sframep, pc, signr); + show_regs(regs); + /* Don't change signal code and address, so that + * post mortem debuggers can have a look. + */ + current->sig->action[SIGILL-1].sa_handler = SIG_DFL; + current->blocked &= ~(1<<(SIGILL-1)); + send_sig(SIGILL,current,1); + return; + } + *fp = (struct sigcontext_struct *) sframep; + do_magic_sparc_stuff(); + + sc->sigc_onstack = old_status; + sc->sigc_mask = oldmask; + sc->sigc_sp = regs->u_regs[UREG_FP]; + sc->sigc_pc = regs->pc; + sc->sigc_npc = regs->npc; + sc->sigc_psr = regs->psr; + sc->sigc_g1 = regs->u_regs[UREG_G1]; + sc->sigc_o0 = regs->u_regs[UREG_I0]; + sc->sigc_oswins = current->tss.w_saved; + if(current->tss.w_saved) + for(window = 0; window < current->tss.w_saved; window++) { + sc->sigc_spbuf[window] = + (char *)current->tss.rwbuf_stkptrs[window]; + memcpy(&sc->sigc_wbuf[window], + ¤t->tss.reg_window[window], + sizeof(struct reg_window)); + } + else + /* This is so that gdb and friends can trace back + * through the stack properly. An alternative + * is to set the fp in this new window to the + * sp of the frame at the time of the signal and + * I see some problems with that maneuver. + */ + memcpy(sframep, (char *)regs->u_regs[UREG_FP], + sizeof(struct reg_window)); + + current->tss.w_saved = 0; /* So process is allowed to execute. */ + sframep->sig_num = signr; + if(signr == SIGSEGV || + signr == SIGILL || + signr == SIGFPE || + signr == SIGBUS || + signr == SIGEMT) { + sframep->sig_code = current->tss.sig_desc; + sframep->sig_address = current->tss.sig_address; + } else { + sframep->sig_code = 0; + sframep->sig_address = 0; + } + sframep->sig_scptr = sc; } /* @@ -64,8 +255,115 @@ * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ + asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) { - halt(); - return 1; + unsigned long mask = ~current->blocked; + unsigned long handler_signal = 0; + struct sigcontext_struct *frame = NULL; + unsigned long pc = 0; + unsigned long signr; + struct sigaction *sa; + + while ((signr = current->signal & mask) != 0) { + signr = ffz(~signr); + clear_bit(signr, ¤t->signal); + sa = current->sig->action + signr; + signr++; + if((current->flags & PF_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + if(!(signr = current->exit_code)) + continue; + current->exit_code = 0; + if(signr == SIGSTOP) + continue; + if(_S(signr) & current->blocked) { + current->signal |= _S(signr); + continue; + } + sa = current->sig->action + signr - 1; + } + if(sa->sa_handler == SIG_IGN) { + if(signr != SIGCHLD) + continue; + while(sys_waitpid(-1,NULL,WNOHANG) > 0); + continue; + } + if(sa->sa_handler == SIG_DFL) { + if(current->pid == 1) + continue; + switch(signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + if(current->flags & PF_PTRACED) + continue; + current->state = TASK_STOPPED; + current->exit_code = signr; + if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + notify_parent(current); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + if(current->binfmt && current->binfmt->core_dump) { + if(current->binfmt->core_dump(signr, regs)) + signr |= 0x80; + } + /* fall through */ + default: + current->signal |= _S(signr & 0x7f); + do_exit(signr); + } + } + /* OK, we're invoking a handler. */ + handler_signal |= 1 << (signr - 1); + mask &= ~sa->sa_mask; + } + if(!handler_signal) + return 0; + pc = regs->pc; + frame = (struct sigcontext_struct *) regs->u_regs[UREG_FP]; + signr = 1; + sa = current->sig->action; + for(mask = 1; mask; sa++, signr++, mask += mask) { + if(mask > handler_signal) + break; + if(!(mask & handler_signal)) + continue; + setup_frame(sa, &frame, pc, regs, signr, oldmask); + pc = (unsigned long) sa->sa_handler; + if(sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + current->blocked |= sa->sa_mask; + oldmask |= sa->sa_mask; + } + regs->u_regs[UREG_FP] = (unsigned long) frame; + regs->npc = (regs->pc = pc) + 4; + return 1; +} + +asmlinkage int +sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr) +{ + /* First see if old state is wanted. */ + if(ossptr) { + if(verify_area(VERIFY_WRITE, ossptr, sizeof(struct sigstack))) + return -EFAULT; + memcpy(ossptr, ¤t->tss.sstk_info, sizeof(struct sigstack)); + } + + /* Now see if we want to update the new state. */ + if(ssptr) { + if(verify_area(VERIFY_READ, ssptr, sizeof(struct sigstack))) + return -EFAULT; + memcpy(¤t->tss.sstk_info, ssptr, sizeof(struct sigstack)); + } + return 0; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v1.3.43/linux/arch/sparc/kernel/sparc-stub.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sparc-stub.c Sat Nov 25 02:58:28 1995 @@ -0,0 +1,691 @@ +/* $Id: sparc-stub.c,v 1.7 1995/11/25 00:58:26 davem Exp $ + * sparc-stub.c: KGDB support for the Linux kernel. + * + * Modifications to run under Linux + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * This file origionally came from the gdb sources, and the + * copyright notices have been retained below. + */ + +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for SPARC by Stu Grossman, Cygnus Support. + * + * This code has been extensively tested on the Fujitsu SPARClite demo board. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * bBB..BB Set baud rate to BB..BB OK or BNN, then sets + * baud rate + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * + * external low-level support routines + */ + +extern void putDebugChar(char); /* write a single character */ +extern char getDebugChar(void); /* read and return a single char */ + +/* + * BUFMAX defines the maximum number of characters in inbound/outbound buffers + * at least NUMREGBYTES*2 are needed for register packets + */ +#define BUFMAX 2048 + +static int initialized = 0; /* !0 means we've been initialized */ + +static const char hexchars[]="0123456789abcdef"; + +#define NUMREGS 72 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) +enum regnames {G0, G1, G2, G3, G4, G5, G6, G7, + O0, O1, O2, O3, O4, O5, SP, O7, + L0, L1, L2, L3, L4, L5, L6, L7, + I0, I1, I2, I3, I4, I5, FP, I7, + + F0, F1, F2, F3, F4, F5, F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, + F24, F25, F26, F27, F28, F29, F30, F31, + Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR }; + + +extern void trap_low(void); /* In arch/sparc/kernel/entry.S */ + +unsigned long get_sun4cpte(unsigned long addr) +{ + unsigned long entry; + + __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : + "=r" (entry) : + "r" (addr), "i" (ASI_PTE)); + return entry; +} + +unsigned long get_sun4csegmap(unsigned long addr) +{ + unsigned long entry; + + __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : + "=r" (entry) : + "r" (addr), "i" (ASI_SEGMAP)); + return entry; +} + +/* Place where we save old trap entries for restoration */ +struct tt_entry kgdb_savettable[256]; +typedef void (*trapfunc_t)(void); + +/* Helper routine for manipulation of kgdb_savettable */ +static inline void copy_ttentry(struct tt_entry *src, struct tt_entry *dest) +{ + dest->inst_one = src->inst_one; + dest->inst_two = src->inst_two; + dest->inst_three = src->inst_three; + dest->inst_four = src->inst_four; +} + +/* Initialize the kgdb_savettable so that debugging can commence */ +static void eh_init(void) +{ + int i, flags; + + save_flags(flags); cli(); + for(i=0; i < 256; i++) + copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]); + restore_flags(flags); +} + +/* Install an exception handler for kgdb */ +static void exceptionHandler(int tnum, trapfunc_t trap_entry) +{ + unsigned long te_addr = (unsigned long) trap_entry; + int flags; + + /* We are dorking with a live trap table, all irqs off */ + save_flags(flags); cli(); + + /* Make new vector */ + sparc_ttable[tnum].inst_one = + SPARC_BRANCH((unsigned long) te_addr, + (unsigned long) &sparc_ttable[tnum].inst_one); + sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0; + sparc_ttable[tnum].inst_three = SPARC_NOP; + sparc_ttable[tnum].inst_four = SPARC_NOP; + + restore_flags(flags); +} + +/* Convert ch from a hex digit to an int */ +static int +hex(unsigned char ch) +{ + if (ch >= 'a' && ch <= 'f') + return ch-'a'+10; + if (ch >= '0' && ch <= '9') + return ch-'0'; + if (ch >= 'A' && ch <= 'F') + return ch-'A'+10; + return -1; +} + +/* scan for the sequence $# */ +static void +getpacket(char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + unsigned char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = (getDebugChar() & 0x7f)) != '$') ; + + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar() & 0x7f; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + + if (count >= BUFMAX) + continue; + + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar() & 0x7f) << 4; + xmitcsum |= hex(getDebugChar() & 0x7f); + if (checksum != xmitcsum) + putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the ID */ + if (buffer[2] == ':') { + putDebugChar(buffer[0]); + putDebugChar(buffer[1]); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) + buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); +} + +/* send the packet in buffer. */ + +static void +putpacket(unsigned char *buffer) +{ + unsigned char checksum; + int count; + unsigned char ch, recv; + + /* $#. */ + do { + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch = buffer[count])) { + putDebugChar(ch); + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum & 0xf]); + recv = getDebugChar(); + } while ((recv & 0x7f) != '+'); +} + +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +/* Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null), in case of mem fault, + * return 0. + */ + +static unsigned char * +mem2hex(char *mem, char *buf, int count) +{ + unsigned char ch; + + while (count-- > 0) { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + + *buf = 0; + return buf; +} + +/* convert the hex array pointed to by buf into binary to be placed in mem + * return a pointer to the character AFTER the last byte written. +*/ +static char * +hex2mem(char *buf, char *mem, int count) +{ + int i; + unsigned char ch; + + for (i=0; itt && ht->signo; ht++) { + /* Only if it doesn't destroy our fault handlers */ + if((ht->tt != SP_TRAP_TFLT) && + (ht->tt != SP_TRAP_DFLT)) + exceptionHandler(ht->tt, trap_low); + } + + /* In case GDB is started before us, ack any packets (presumably + * "$?#xx") sitting there. + */ + + while((c = getDebugChar()) != '$'); + while((c = getDebugChar()) != '#'); + c = getDebugChar(); /* eat first csum byte */ + c = getDebugChar(); /* eat second csum byte */ + putDebugChar('+'); /* ack it */ + + initialized = 1; /* connect! */ +} + +/* Convert the SPARC hardware trap type code to a unix signal number. */ + +static int +computeSignal(int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +/* + * While we find nice hex chars, build an int. + * Return number of chars processed. + */ + +static int +hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) { + hexValue = hex(**ptr); + if (hexValue < 0) + break; + + *intValue = (*intValue << 4) | hexValue; + numChars ++; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. It + * returns 1 if you should skip the instruction at the trap address, 0 + * otherwise. + */ + +extern void breakinst(void); + +void +handle_exception (unsigned long *registers) +{ + int tt; /* Trap type */ + int sigval; + int addr; + int length; + char *ptr; + unsigned long *sp; + + /* First, we must force all of the windows to be spilled out */ + + asm("save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "save %sp, -64, %sp\n\t" + "restore\n\t" + "restore\n\t" + "restore\n\t" + "restore\n\t" + "restore\n\t" + "restore\n\t" + "restore\n\t" + "restore\n\t"); + + if (registers[PC] == (unsigned long)breakinst) { + /* Skip over breakpoint trap insn */ + registers[PC] = registers[NPC]; + registers[NPC] += 4; + } + + sp = (unsigned long *)registers[SP]; + + tt = (registers[TBR] >> 4) & 0xff; + + /* reply to host that an exception has occurred */ + sigval = computeSignal(tt); + ptr = remcomOutBuffer; + + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[PC], ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[FP >> 4]; + *ptr++ = hexchars[FP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *) (sp + 8 + 6), ptr, 4); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[SP >> 4]; + *ptr++ = hexchars[SP & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)&sp, ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[NPC >> 4]; + *ptr++ = hexchars[NPC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[NPC], ptr, 4); + *ptr++ = ';'; + + *ptr++ = hexchars[O7 >> 4]; + *ptr++ = hexchars[O7 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex((char *)®isters[O7], ptr, 4); + *ptr++ = ';'; + + *ptr++ = 0; + + putpacket(remcomOutBuffer); + + /* XXX We may want to add some features dealing with poking the + * XXX page tables, the real ones on the srmmu, and what is currently + * XXX loaded in the sun4/sun4c tlb at this point in time. But this + * XXX also required hacking to the gdb sources directly... + */ + + while (1) { + remcomOutBuffer[0] = 0; + + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval & 0xf]; + remcomOutBuffer[3] = 0; + break; + + case 'd': + /* toggle debug flag */ + break; + + case 'g': /* return the value of the CPU registers */ + { + ptr = remcomOutBuffer; + /* G & O regs */ + ptr = mem2hex((char *)registers, ptr, 16 * 4); + /* L & I regs */ + ptr = mem2hex((char *) (sp + 0), ptr, 16 * 4); + /* Floating point */ + memset(ptr, '0', 32 * 8); + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + mem2hex((char *)®isters[Y], (ptr + 32 * 4 * 2), (8 * 4)); + } + break; + + case 'G': /* set the value of the CPU registers - return OK */ + { + unsigned long *newsp, psr; + + psr = registers[PSR]; + + ptr = &remcomInBuffer[1]; + /* G & O regs */ + hex2mem(ptr, (char *)registers, 16 * 4); + /* L & I regs */ + hex2mem(ptr + 16 * 4 * 2, (char *) (sp + 0), 16 * 4); + /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */ + hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y], 8 * 4); + + /* See if the stack pointer has moved. If so, + * then copy the saved locals and ins to the + * new location. This keeps the window + * overflow and underflow routines happy. + */ + + newsp = (unsigned long *)registers[SP]; + if (sp != newsp) + sp = memcpy(newsp, sp, 16 * 4); + + /* Don't allow CWP to be modified. */ + + if (psr != registers[PSR]) + registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f); + + strcpy(remcomOutBuffer,"OK"); + } + break; + + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length)) { + if (mem2hex((char *)addr, remcomOutBuffer, length)) + break; + + strcpy (remcomOutBuffer, "E03"); + } else { + strcpy(remcomOutBuffer,"E01"); + } + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* Try to read '%x,%x:'. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length) + && *ptr++ == ':') { + if (hex2mem(ptr, (char *)addr, length)) { + strcpy(remcomOutBuffer, "OK"); + } else { + strcpy(remcomOutBuffer, "E03"); + } + } else { + strcpy(remcomOutBuffer, "E02"); + } + break; + + case 'c': /* cAA..AA Continue at address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) { + registers[PC] = addr; + registers[NPC] = addr + 4; + } + +/* Need to flush the instruction cache here, as we may have deposited a + * breakpoint, and the icache probably has no way of knowing that a data ref to + * some location may have changed something that is in the instruction cache. + */ + + /* Only instruction cache flushing on the sun4c/sun4 + * for now. We assume control flow during the kgdb + * transaction has not left the context in which it + * was entered. + */ + if((sparc_cpu_model==sun4 || sparc_cpu_model==sun4c) && + (sun4c_vacinfo.num_bytes && sun4c_vacinfo.on)) + sun4c_flush_context(); + /* XXX SRMMU and on-chip v8 instruction cache + * XXX flushing goes here! + */ + + return; + + /* kill the program */ + case 'k' : /* do nothing */ + break; + case 'r': /* Reset */ + asm ("call 0\n\t" + "nop\n\t"); + break; + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } /* while(1) */ +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void +breakpoint(void) +{ + if (!initialized) + return; + + /* Again, watch those c-prefixes for solaris/elf kernels */ +#ifndef __svr4__ + asm(" .globl _breakinst + + _breakinst: ta 1 + "); +#else + asm(" .globl breakinst + + breakinst: ta 1 + "); +#endif +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/sunos_asm.S linux/arch/sparc/kernel/sunos_asm.S --- v1.3.43/linux/arch/sparc/kernel/sunos_asm.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sunos_asm.S Sat Nov 25 02:58:30 1995 @@ -0,0 +1,90 @@ +/* $Id: sunos_asm.S,v 1.8 1995/11/25 00:58:29 davem Exp $ + * sunos_asm.S: SunOS system calls which must have a low-level + * entry point to operate correctly. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Based upon preliminary work which is: + * + * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) + */ + +#include +#include + + /* Note that for dual value returning system calls we + * need to store the second one ourselves in the pt_regs + * trap-frame. linux_sparc_syscall does %o0 for us + * however. + */ + + .text + .align 4 + + /* SunOS getpid() returns pid in %o0 and ppid in %o1 */ + .globl C_LABEL(sunos_getpid) +C_LABEL(sunos_getpid): + save %sp, -STACKFRAME_SZ, %sp + call C_LABEL(sys_getpid) + nop + + mov %o0, %i0 + + call C_LABEL(sys_getppid) + nop + + st %o0, [%fp + STACKFRAME_SZ + PT_I1] + + ret + restore + + /* SunOS getuid() returns uid in %o0 and euid in %o1 */ + .globl C_LABEL(sunos_getuid) +C_LABEL(sunos_getuid): + save %sp, -STACKFRAME_SZ, %sp + call C_LABEL(sys_getuid) + nop + + mov %o0, %i0 + + call C_LABEL(sys_geteuid) + nop + + st %o0, [%fp + STACKFRAME_SZ + PT_I1] + + ret + restore + + /* SunOS getgid() returns gid in %o0 and egid in %o1 */ + .globl C_LABEL(sunos_getgid) +C_LABEL(sunos_getgid): + save %sp, -STACKFRAME_SZ, %sp + call C_LABEL(sys_getgid) + nop + + mov %o0, %i0 + + call C_LABEL(sys_getegid) + nop + + st %o0, [%fp + STACKFRAME_SZ + PT_I1] + + ret + restore + + /* SunOS's execv() call only specifies the argv argument, the + * environment settings are the same as the calling processes. + */ + .globl C_LABEL(sunos_execv) +C_LABEL(sunos_execv): + save %sp, -STACKFRAME_SZ, %sp + + st %g0, [%fp + STACKFRAME_SZ + PT_I2] + call C_LABEL(sparc_execve) + add %fp, STACKFRAME_SZ, %o0 + + st %o0, [%fp + STACKFRAME_SZ + PT_I1] + + ret + restore + diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c --- v1.3.43/linux/arch/sparc/kernel/sunos_ioctl.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sunos_ioctl.c Sat Nov 25 02:58:32 1995 @@ -0,0 +1,109 @@ +/* $Id: sunos_ioctl.c,v 1.7 1995/11/25 00:58:30 davem Exp $ + * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. + * + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern asmlinkage int sys_ioctl(unsigned int, unsigned int, unsigned long); + +asmlinkage int sunos_ioctl (int fd, unsigned long cmd, void *arg) +{ + struct file *filp; + + if (fd >= NR_OPEN || !(filp = current->files->fd [fd])) + return -EBADF; + + /* SunOS networking ioctls. */ + switch (cmd) { + case _IOW('r', 10, struct rtentry): + return sys_ioctl(fd, SIOCADDRT, arg); + case _IOW('r', 11, struct rtentry): + return sys_ioctl(fd, SIOCDELRT, arg); + case _IOW('i', 12, struct ifreq): + return sys_ioctl(fd, SIOCSIFADDR, arg); + case _IORW('i', 13, struct ifreq): + return sys_ioctl(fd, SIOCGIFADDR, arg); + case _IOW('i', 14, struct ifreq): + return sys_ioctl(fd, SIOCSIFDSTADDR, arg); + case _IORW('i', 15, struct ifreq): + return sys_ioctl(fd, SIOCGIFDSTADDR, arg); + case _IOW('i', 16, struct ifreq): + return sys_ioctl(fd, SIOCSIFFLAGS, arg); + case _IORW('i', 17, struct ifreq): + return sys_ioctl(fd, SIOCGIFFLAGS, arg); + case _IOW('i', 18, struct ifreq): + return sys_ioctl(fd, SIOCSIFMEM, arg); + case _IORW('i', 19, struct ifreq): + return sys_ioctl(fd, SIOCGIFMEM, arg); + case _IORW('i', 20, struct ifreq): + return sys_ioctl(fd, SIOCGIFCONF, arg); + case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */ + return sys_ioctl(fd, SIOCSIFMTU, arg); + case _IORW('i', 22, struct ifreq): /* SIOCGIFMTU */ + return sys_ioctl(fd, SIOCGIFMTU, arg); + + case _IORW('i', 23, struct ifreq): + return sys_ioctl(fd, SIOCGIFBRDADDR, arg); + case _IOW('i', 24, struct ifreq): + return sys_ioctl(fd, SIOCGIFBRDADDR, arg); + case _IORW('i', 25, struct ifreq): + return sys_ioctl(fd, SIOCGIFNETMASK, arg); + case _IOW('i', 26, struct ifreq): + return sys_ioctl(fd, SIOCSIFNETMASK, arg); + case _IORW('i', 27, struct ifreq): + return sys_ioctl(fd, SIOCGIFMETRIC, arg); + case _IOW('i', 28, struct ifreq): + return sys_ioctl(fd, SIOCSIFMETRIC, arg); + + case _IOW('i', 30, struct arpreq): + return sys_ioctl(fd, SIOCSARP, arg); + case _IOW('i', 31, struct arpreq): + return sys_ioctl(fd, SIOCGARP, arg); + case _IOW('i', 32, struct arpreq): + return sys_ioctl(fd, SIOCGARP, arg); + + case _IOW('i', 40, struct ifreq): /* SIOCUPPER */ + case _IOW('i', 41, struct ifreq): /* SIOCLOWER */ + case _IOW('i', 44, struct ifreq): /* SIOCSETSYNC */ + case _IOW('i', 45, struct ifreq): /* SIOCGETSYNC */ + case _IOW('i', 46, struct ifreq): /* SIOCSSDSTATS */ + case _IOW('i', 47, struct ifreq): /* SIOCSSESTATS */ + case _IOW('i', 48, struct ifreq): /* SIOCSPROMISC */ + return -EINVAL; + + case _IOW('i', 49, struct ifreq): + return sys_ioctl(fd, SIOCADDMULTI, arg); + case _IOW('i', 50, struct ifreq): + return sys_ioctl(fd, SIOCDELMULTI, arg); + + /* FDDI interface ioctls, unsupported. */ + case _IOW('i', 51, struct ifreq): /* SIOCFDRESET */ + case _IOW('i', 52, struct ifreq): /* SIOCFDSLEEP */ + case _IOW('i', 53, struct ifreq): /* SIOCSTRTFMWAR */ + case _IOW('i', 54, struct ifreq): /* SIOCLDNSTRTFW */ + case _IOW('i', 55, struct ifreq): /* SIOCGETFDSTAT */ + case _IOW('i', 56, struct ifreq): /* SIOCFDNMIINT */ + case _IOW('i', 57, struct ifreq): /* SIOCFDEXUSER */ + case _IOW('i', 58, struct ifreq): /* SIOCFDGNETMAP */ + case _IOW('i', 59, struct ifreq): /* SIOCFDGIOCTL */ + return -EINVAL; + } + + return sys_ioctl (fd, cmd, arg); +} + + diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/switch.S linux/arch/sparc/kernel/switch.S --- v1.3.43/linux/arch/sparc/kernel/switch.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/switch.S Sat Nov 25 02:58:34 1995 @@ -0,0 +1,72 @@ +/* $Id: switch.S,v 1.9 1995/11/25 00:58:32 davem Exp $ + * switch.S: Sparc task switch code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include + +#define sw_ntask g1 +#define sw_sp g2 +#define sw_pc g3 +#define sw_psr g4 +#define sw_wim g5 +#define sw_tmp g6 +#define sw_ctx g7 + +/* Context switch code. The new process's task_struct + * ptr is passed as the first parameter. + * + * First successful task switch 05/13/95 21:52:37 + */ + .align 4 + .globl C_LABEL(sparc_switch_to), C_LABEL(mmu_switch_lowlevel) +C_LABEL(sparc_switch_to): + mov %o0, %sw_ntask + + /* Save kernel state. */ + FLUSH_ALL_KERNEL_WINDOWS; + STORE_WINDOW(sp) + rd %psr, %sw_psr + sethi %hi(PSR_EF), %sw_tmp + andn %sw_psr, %sw_tmp, %sw_psr + LOAD_CURRENT(sw_tmp) + rd %wim, %sw_wim + std %sw_psr, [%sw_tmp + THREAD_KPSR] + std %sp, [%sw_tmp + THREAD_KSP] + + /* Load new kernel state. */ + wr %sw_psr, PSR_ET, %psr + sethi %hi(C_LABEL(current_set)), %sw_tmp + st %sw_ntask, [%sw_tmp + %lo(C_LABEL(current_set))] + ldd [%sw_ntask + THREAD_KPSR], %sw_psr + ldd [%sw_ntask + THREAD_KSP], %sw_sp + wr %sw_psr, PSR_ET, %psr + WRITE_PAUSE + wr %sw_wim, 0x0, %wim + WRITE_PAUSE + mov %sw_sp, %sp + LOAD_WINDOW(sp) + mov %sw_pc, %o7 + + /* Jump into the proper context. */ + ld [%sw_ntask + THREAD_CONTEXT], %sw_ctx + tst %sw_ctx + bneg 1f ! this must be swapper + nop + +C_LABEL(mmu_switch_lowlevel): + sethi %hi(AC_CONTEXT), %sw_tmp ! else set new context + stba %sw_ctx, [%sw_tmp] ASI_CONTROL +1: + wr %sw_psr, 0x0, %psr ! traps back on + WRITE_PAUSE + + retl + nop diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v1.3.43/linux/arch/sparc/kernel/sys_sparc.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sys_sparc.c Sat Nov 25 02:58:36 1995 @@ -0,0 +1,135 @@ +/* $Id: sys_sparc.c,v 1.6 1995/11/25 00:58:34 davem Exp $ + * linux/arch/sparc/kernel/sys_sparc.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/sparc + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* XXX Make this per-binary type, this way we can detect the type of + * XXX a binary. Every Sparc executable calls this very early on. + */ +asmlinkage unsigned long sys_getpagesize(void) +{ + return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */ +} + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix tranditionally does this, though. + */ +asmlinkage void sparc_pipe(struct pt_regs *regs) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (error) { + regs->u_regs[UREG_I0] = error; + } else { + regs->u_regs[UREG_I0] = fd[0]; + regs->u_regs[UREG_I1] = fd[1]; + } +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +{ + int version; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + int err; + if (!ptr) + return -EINVAL; + if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) + return err; + fourth.__pad = (void *) get_fs_long(ptr); + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + int err; + if (!ptr) + return -EINVAL; + if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) + return err; + memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp)); + return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + } + case 1: default: + return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + case 0: default: { + ulong raddr; + int err; + if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) + return err; + err = sys_shmat (first, (char *) ptr, second, &raddr); + if (err) + return err; + put_fs_long (raddr, (ulong *) third); + return 0; + } + case 1: /* iBCS2 emulator entry point */ + if (get_fs() != get_ds()) + return -EINVAL; + return sys_shmat (first, (char *) ptr, second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, (struct shmid_ds *) ptr); + default: + return -EINVAL; + } + return -EINVAL; +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v1.3.43/linux/arch/sparc/kernel/sys_sunos.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sys_sunos.c Sat Nov 25 02:58:41 1995 @@ -0,0 +1,801 @@ +/* $Id: sys_sunos.c,v 1.20 1995/11/25 00:58:37 davem Exp $ + * sys_sunos.c: SunOS specific syscall compatability support. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * + * Based upon preliminary work which is: + * + * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* For the nfs mount emulation */ +#include +#include +#include +#include + +/* for sunos_select */ +#include +#include + +static unsigned long get_sparc_unmapped_area(unsigned long len) +{ + unsigned long addr; + struct vm_area_struct * vmm; + + if (len > TASK_SIZE) + return 0; + addr = 0xE8000000UL; /* To make it work on a sun4c. */ + for (vmm = current->mm->mmap; ; vmm = vmm->vm_next) { + if (TASK_SIZE - len < addr) + return 0; + if (!vmm) + return addr; + if (addr > vmm->vm_end) + continue; + if (addr + len > vmm->vm_start) { + addr = vmm->vm_end; + continue; + } + return addr; + } +} + +/* We use the SunOS mmap() semantics. */ +asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off) +{ + struct file * file = NULL; + unsigned long retval, ret_type; + + if(flags & MAP_NORESERVE) { + printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", + current->comm); + flags &= ~MAP_NORESERVE; + } + if(!(flags & MAP_ANONYMOUS)) + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + if(!(flags & MAP_FIXED) && !addr) { + addr = get_sparc_unmapped_area(len); + if(!addr) + return -ENOMEM; + } + /* If this is ld.so or a shared library doing an mmap + * of /dev/zero, transform it into an anonymous mapping. + * SunOS is so stupid some times... hmph! + */ + if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR && + MINOR(file->f_inode->i_rdev) == 5) { + flags |= MAP_ANONYMOUS; + file = 0; + } + ret_type = flags & _MAP_NEW; + flags &= ~_MAP_NEW; + retval = do_mmap(file, addr, len, prot, flags, off); + if(ret_type) + return retval; + else + return ((retval < KERNBASE) ? 0 : retval); +} + +/* Weird SunOS mm control function.. */ +asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, char *arg) +{ + printk("%s: Call to sunos_mctl(addr<%08lx>, len<%08lx>, function<%d>, arg<%p>) " + "is unsupported\n", current->comm, addr, len, function, arg); + return -EAGAIN; +} + +/* XXX This won't be necessary when I sync up to never kernel in 1.3.x series + * XXX which has the sys_msync() system call implemented properly. + */ +asmlinkage int sunos_msync(unsigned long addr, unsigned long len, unsigned long flags) +{ + printk("%s: Call to sunos_msync(addr<%08lx>, len<%08lx>, flags<%08lx>) " + "is unsupported\n", current->comm, addr, len, flags); + return -EINVAL; +} + +/* SunOS is completely broken... it returns 0 on success, otherwise + * ENOMEM. For sys_sbrk() it wants the new brk value as a return + * on success and ENOMEM as before on failure. + */ +asmlinkage int sunos_brk(unsigned long brk) +{ + int freepages; + unsigned long rlim; + unsigned long newbrk, oldbrk; + + if (brk < current->mm->end_code) + return -ENOMEM; + + newbrk = PAGE_ALIGN(brk); + oldbrk = PAGE_ALIGN(current->mm->brk); + if (oldbrk == newbrk) { + current->mm->brk = brk; + return 0; + } + + /* + * Always allow shrinking brk + */ + if (brk <= current->mm->brk) { + current->mm->brk = brk; + do_munmap(newbrk, oldbrk-newbrk); + return 0; + } + /* + * Check against rlimit and stack.. + */ + rlim = current->rlim[RLIMIT_DATA].rlim_cur; + if (rlim >= RLIM_INFINITY) + rlim = ~0; + if (brk - current->mm->end_code > rlim) + return -ENOMEM; + + /* + * Check against existing mmap mappings. + */ + if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE)) + return -ENOMEM; + + /* + * stupid algorithm to decide if we have enough memory: while + * simple, it hopefully works in most obvious cases.. Easy to + * fool it, but this should catch most mistakes. + */ + freepages = buffermem >> 12; + freepages += nr_free_pages; + freepages += nr_swap_pages; + freepages -= MAP_NR(high_memory) >> 4; + freepages -= (newbrk-oldbrk) >> 12; + if (freepages < 0) + return -ENOMEM; + /* + * Ok, we have probably got enough memory - let it rip. + */ + current->mm->brk = brk; + do_mmap(NULL, oldbrk, newbrk-oldbrk, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + return 0; +} + +asmlinkage unsigned long sunos_sbrk(int increment) +{ + int error; + + /* This should do it hopefully... */ + error = sunos_brk(((int) current->mm->brk) + increment); + if(error == 0) + return current->mm->brk; + else + return error; +} + +/* XXX Completely undocumented, and completely magic... + * XXX I belive it is to increase the size of the stack by + * XXX argument 'increment' and return the new end of stack + * XXX area. Wheee... + */ +asmlinkage unsigned long sunos_sstk(int increment) +{ + printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n", + current->comm, increment); + return -1; +} + +/* Give hints to the kernel as to what paging strategy to use... + * Completely bogus, don't remind me. + */ +#define VA_NORMAL 0 /* Normal vm usage expected */ +#define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */ +#define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */ +#define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */ +static char *vstrings[] = { + "VA_NORMAL", + "VA_ABNORMAL", + "VA_SEQUENTIAL", + "VA_INVALIDATE", +}; + +asmlinkage void sunos_vadvise(unsigned long strategy) +{ + /* I wanna see who uses this... */ + printk("%s: Advises us to use %s paging strategy\n", + current->comm, + strategy <= 3 ? vstrings[strategy] : "BOGUS"); + return; /* We don't do diddly... */ +} + +/* Same as vadvise, and just as bogus, but for a range of virtual + * process address space. + */ +#define MADV_NORMAL 0 /* Nothing special... */ +#define MADV_RANDOM 1 /* I am emacs... */ +#define MADV_SEQUENTIAL 2 /* I am researcher code... */ +#define MADV_WILLNEED 3 /* Pages in this range will be needed */ +#define MADV_DONTNEED 4 /* Pages in this range won't be needed */ + +static char *mstrings[] = { + "MADV_NORMAL", + "MADV_RANDOM", + "MADV_SEQUENTIAL", + "MADV_WILLNEED", + "MADV_DONTNEED", +}; + +asmlinkage void sunos_madvise(unsigned long address, unsigned long len, + unsigned long strategy) +{ + /* I wanna see who uses this... */ + printk("%s: Advises us to use %s paging strategy for addr<%08lx> len<%08lx>\n", + current->comm, + strategy <= 4 ? mstrings[strategy] : "BOGUS", + address, len); + return; /* We don't do diddly... */ +} + +/* Places into character array, the status of all the pages in the passed + * range from 'addr' to 'addr + len'. -1 on failure, 0 on success... + * The encoding in each character is: + * low-bit is zero == Page is not in physical ram right now + * low-bit is one == Page is currently residing in core + * All other bits are undefined within the character so there... + * Also, if you try to get stats on an area outside of the user vm area + * *or* the passed base address is not aligned on a page boundry you + * get an error. + */ +asmlinkage int sunos_mincore(unsigned long addr, unsigned long len, char *array) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long limit; + int num_pages, pnum; + + if(addr & (PAGE_SIZE - 1)) + return -EINVAL; + + num_pages = (len / PAGE_SIZE); + if(verify_area(VERIFY_WRITE, array, num_pages)) + return -EFAULT; /* bum array, you lose... */ + if((addr >= KERNBASE) || ((addr + len) > KERNBASE)) + return -ENOMEM; /* I'm sure you're curious about kernel mappings.. */ + + /* Wheee, go through pte's */ + pnum = 0; + for(limit = addr + len; addr < limit; addr += PAGE_SIZE, pnum++) { + pgdp = pgd_offset(current->mm, addr); + if(pgd_none(*pgdp)) + return -ENOMEM; /* As per SunOS manpage */ + pmdp = pmd_offset(pgdp, addr); + if(pmd_none(*pmdp)) + return -ENOMEM; /* As per SunOS manpage */ + ptep = pte_offset(pmdp, addr); + if(pte_none(*ptep)) + return -ENOMEM; /* As per SunOS manpage */ + /* Page in core or Swapped page? */ + array[pnum] = pte_present(*ptep) ? 1 : 0; + } + return 0; /* Success... I think... */ +} + +/* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE + * resource limit and is for backwards compatability with older sunos + * revs. + */ +asmlinkage long sunos_getdtablesize(void) +{ + return NR_OPEN; +} +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask) +{ + unsigned long old = current->blocked; + + current->blocked |= (blk_mask & _BLOCKABLE); + return old; +} + +/* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) */ +/* getdents system call, the format of the structure just has a different */ +/* layout (d_off+d_ino instead of d_ino+d_off) */ +struct sunos_dirent { + long d_off; + unsigned long d_ino; + unsigned short d_reclen; + unsigned short d_namlen; + char d_name[1]; +}; + +struct sunos_dirent_callback { + struct sunos_dirent *curr; + struct sunos_dirent *previous; + int count; + int error; +}; + +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) + +static int sunos_filldir(void * __buf, const char * name, int namlen, + off_t offset, ino_t ino) +{ + struct sunos_dirent * dirent; + struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) + put_user(offset, &dirent->d_off); + dirent = buf->curr; + buf->previous = dirent; + put_user(ino, &dirent->d_ino); + put_user((strlen(name)), &dirent->d_namlen); + put_user(reclen, &dirent->d_reclen); + memcpy_tofs(dirent->d_name, name, namlen); + put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->curr = dirent; + buf->count -= reclen; + return 0; +} + +asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) +{ + struct file * file; + struct sunos_dirent * lastdirent; + struct sunos_dirent_callback buf; + int error; + + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + if (!file->f_op || !file->f_op->readdir) + return -ENOTDIR; + if(verify_area(VERIFY_WRITE, dirent, cnt)) + return -EFAULT; + if(cnt < (sizeof(struct sunos_dirent) + 255)) + return -EINVAL; + + buf.curr = (struct sunos_dirent *) dirent; + buf.previous = NULL; + buf.count = cnt; + buf.error = 0; + error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir); + if (error < 0) + return error; + lastdirent = buf.previous; + if (!lastdirent) + return buf.error; + put_user(file->f_pos, &lastdirent->d_off); + return cnt - buf.count; +} + +asmlinkage int sunos_getdomainname(char *name, int len) +{ + int error; + + if(len > __NEW_UTS_LEN) + return -EFAULT; + error = verify_area(VERIFY_WRITE, name, len); + if(error) + return -EFAULT; + memcpy_tofs(name, system_utsname.domainname, len); + return 0; +} + +struct sunos_utsname { + char sname[9]; + char nname[9]; + char nnext[56]; + char rel[9]; + char ver[9]; + char mach[9]; +}; + +asmlinkage int sunos_uname(struct sunos_utsname *name) +{ + int error; + if(!name) + return -EFAULT; + error = verify_area(VERIFY_WRITE, name, sizeof *name); + if(error) + return error; + memcpy_tofs(&name->sname[0], &system_utsname.sysname[0], + sizeof(name->sname)); + memcpy_tofs(&name->nname[0], &system_utsname.nodename[0], + sizeof(name->nname)); + name->nname[8] = '\0'; + memcpy_tofs(&name->nnext[0], &system_utsname.nodename[9], + sizeof(name->nnext)); + memcpy_tofs(&name->rel[0], &system_utsname.release[0], + sizeof(name->rel)); + memcpy_tofs(&name->ver[0], &system_utsname.version[0], + sizeof(name->ver)); + memcpy_tofs(&name->mach[0], &system_utsname.machine[0], + sizeof(name->mach)); + return 0; +} + +asmlinkage int sunos_nosys(void) +{ + struct pt_regs *regs; + + regs = (struct pt_regs *) (((current->tss.ksp) & PAGE_MASK) + + (PAGE_SIZE - TRACEREG_SZ)); + current->tss.sig_address = regs->pc; + current->tss.sig_desc = regs->u_regs[UREG_G1]; + send_sig(SIGSYS, current, 1); + printk("Process makes ni_syscall number %d, register dump:\n", + (int) regs->u_regs[UREG_G1]); + show_regs(regs); + return -ENOSYS; +} + +/* This is not a real and complete implementation yet, just to keep + * the easy SunOS binaries happy. + */ +asmlinkage int sunos_fpathconf(int fd, int name) +{ + switch(name) { + case _PCONF_LINK: + return LINK_MAX; + case _PCONF_CANON: + return MAX_CANON; + case _PCONF_INPUT: + return MAX_INPUT; + case _PCONF_NAME: + return NAME_MAX; + case _PCONF_PATH: + return PATH_MAX; + case _PCONF_PIPE: + return PIPE_BUF; + case _PCONF_CHRESTRICT: + return 1; /* XXX Investigate XXX */ + case _PCONF_NOTRUNC: + return 0; /* XXX Investigate XXX */ + case _PCONF_VDISABLE: + return 30; /* XXX Investigate XXX */ + default: + return -EINVAL; + } +} + +asmlinkage int sunos_pathconf(char *path, int name) +{ + return sunos_fpathconf(0, name); /* XXX cheese XXX */ +} + +/* SunOS mount system call emulation */ +extern asmlinkage int +sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp); + +asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) +{ + /* SunOS binaries expect that select won't change the tvp contents */ + current->personality |= STICKY_TIMEOUTS; + return sys_select (width, inp, outp, exp, tvp); +} + +asmlinkage void sunos_nop(void) +{ + return; +} + +/* SunOS mount/umount. */ +#define SMNT_RDONLY 1 +#define SMNT_NOSUID 2 +#define SMNT_NEWTYPE 4 +#define SMNT_GRPID 8 +#define SMNT_REMOUNT 16 +#define SMNT_NOSUB 32 +#define SMNT_MULTI 64 +#define SMNT_SYS5 128 + +struct ufs_mntargs { + char *dev_name; +}; + +struct lo_mntargs { + char *dev_name; +}; + +struct ext2_mntargs { + char *dev_name; +}; + +struct iso9660_mntargs { + char *dev_name; +}; + +struct minix_mntargs { + char *dev_name; +}; + +struct ext_mntargs { + char *dev_name; +}; + +struct msdos_mntargs { + char *dev_name; +}; + +struct xiafs_mntargs { + char *dev_name; +}; + +struct sunos_fh_t { + char fh_data [NFS_FHSIZE]; +}; + +struct sunos_nfs_mount_args { + struct sockaddr_in *addr; /* file server address */ + struct nfs_fh *fh; /* File handle to be mounted */ + int flags; /* flags */ + int wsize; /* write size in bytes */ + int rsize; /* read size in bytes */ + int timeo; /* initial timeout in .1 secs */ + int retrans; /* times to retry send */ + char *hostname; /* server's hostname */ + int acregmin; /* attr cache file min secs */ + int acregmax; /* attr cache file max secs */ + int acdirmin; /* attr cache dir min secs */ + int acdirmax; /* attr cache dir max secs */ + char *netname; /* server's netname */ +}; + +extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *); + +extern int do_mount(dev_t, const char *, char *, int, void *); +extern dev_t get_unnamed_dev(void); +extern void put_unnamed_dev(dev_t); + +extern sys_mount (char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void * data); + +extern asmlinkage int +sys_connect(int fd, struct sockaddr *uservaddr, int addrlen); + +extern asmlinkage int +sys_socket(int family, int type, int protocol); + +asmlinkage int +sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); + + +/* Bind the socket on a local reserved port and connect it to the + * remote server. This on Linux/i386 is done by the mount program, + * not by the kernel. + */ +static int +sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr) +{ + struct sockaddr_in local; + struct sockaddr_in server; + int try_port; + int ret; + struct socket *socket; + struct inode *inode; + struct file *file; + + file = current->files->fd [fd]; + inode = file->f_inode; + if (!inode || !inode->i_sock) + return 0; + + socket = &inode->u.socket_i; + local.sin_family = AF_INET; + local.sin_addr.s_addr = INADDR_ANY; + + /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */ + try_port = 1024; + do { + local.sin_port = htons (--try_port); + ret = socket->ops->bind(socket, (struct sockaddr*)&local, + sizeof(local)); + } while (ret && try_port > (1024 / 2)); + + if (ret) + return 0; + + server.sin_family = AF_INET; + server.sin_addr = addr->sin_addr; + server.sin_port = NFS_PORT; + + /* Call sys_connect */ + ret = socket->ops->connect (socket, (struct sockaddr *) &server, + sizeof (server), file->f_flags); + if (ret < 0) + return 0; + return 1; +} + +static int get_default (int value, int def_value) +{ + if (value) + return value; + else + return def_value; +} + +asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) +{ + int ret = -ENODEV, error; + int server_fd; + char *the_name; + struct nfs_mount_data linux_nfs_mount; + struct sunos_nfs_mount_args *sunos_mount = data; + dev_t dev; + struct pt_regs *regs; + + error = verify_area(VERIFY_READ, data, sizeof (struct sunos_nfs_mount_args)); + if (error) + return error; + /* Ok, here comes the fun part: Linux's nfs mount needs a + * socket connection to the server, but SunOS mount does not + * requiere this, so we use the information on the destination + * address to create a socket and bind it to a reserved + * port on this system + */ + server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (server_fd < 0) + return -ENXIO; + + if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){ + sys_close (server_fd); + return -ENXIO; + } + + /* Now, bind it to a locally reserved port */ + linux_nfs_mount.version = NFS_MOUNT_VERSION; + linux_nfs_mount.flags = sunos_mount->flags; + linux_nfs_mount.addr = *sunos_mount->addr; + linux_nfs_mount.root = *sunos_mount->fh; + linux_nfs_mount.fd = server_fd; + + linux_nfs_mount.rsize = get_default (sunos_mount->rsize, 8192); + linux_nfs_mount.wsize = get_default (sunos_mount->wsize, 8192); + linux_nfs_mount.timeo = get_default (sunos_mount->timeo, 10); + linux_nfs_mount.retrans = sunos_mount->retrans; + + linux_nfs_mount.acregmin = sunos_mount->acregmin; + linux_nfs_mount.acregmax = sunos_mount->acregmax; + linux_nfs_mount.acdirmin = sunos_mount->acdirmin; + linux_nfs_mount.acdirmax = sunos_mount->acdirmax; + + if (getname (sunos_mount->hostname, &the_name)) + return -EFAULT; + + strncpy (linux_nfs_mount.hostname, the_name, 254); + linux_nfs_mount.hostname [255] = 0; + putname (the_name); + + dev = get_unnamed_dev (); + + ret = do_mount (dev, dir_name, "nfs", linux_flags, &linux_nfs_mount); + if (ret) + put_unnamed_dev(dev); + +#if 0 + /* Kill the process: the nfs directory is already mounted */ + regs = (struct pt_regs *) (((current->tss.ksp) & PAGE_MASK) + + (PAGE_SIZE - TRACEREG_SZ)); + current->tss.sig_address = regs->pc; + current->tss.sig_desc = regs->u_regs[UREG_G1]; + send_sig(SIGSYS, current, 1); +#endif + return ret; +} + +asmlinkage int +sunos_mount(char *type, char *dir, int flags, void *data) +{ + int linux_flags = MS_MGC_MSK; /* new semantics */ + int error; + char *dev_fname = 0; + + /* We don't handle the integer fs type */ + if ((flags & SMNT_NEWTYPE) == 0) + return -EINVAL; + + /* Do not allow for those flags we don't support */ + if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5)) + return -EINVAL; + + if(flags & SMNT_REMOUNT) + linux_flags |= MS_REMOUNT; + if(flags & SMNT_RDONLY) + linux_flags |= MS_RDONLY; + if(flags & SMNT_NOSUID) + linux_flags |= MS_NOSUID; + error = verify_area(VERIFY_READ, type, 16); + if(error) + return error; + if(strcmp(type, "ext2") == 0) { + dev_fname = (char *) data;; + } else if(strcmp(type, "iso9660") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "minix") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "ext") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "xiafs") == 0) { + dev_fname = (char *) data; + } else if(strcmp(type, "nfs") == 0) { + error = sunos_nfs_mount (dir, flags, data); + return error; + } else if(strcmp(type, "ufs") == 0) { + printk("Warning: UFS filesystem mounts unsupported.\n"); + return -ENODEV; + } else if(strcmp(type, "proc")) { + return -ENODEV; + } + if(error) + return error; + error = sys_mount(dev_fname, dir, type, linux_flags, NULL); + printk("sys_mount(type<%s>, device<%s>) returns %d\n", + type, dev_fname, error); + return error; +} + +extern asmlinkage int sys_setsid(void); +extern asmlinkage int sys_setpgid(pid_t, pid_t); + +asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid) +{ + /* So stupid... */ + if((!pid || pid == current->pid) && + !pgid) { + sys_setsid(); + return 0; + } else { + return sys_setpgid(pid, pgid); + } +} + +/* So stupid... */ +extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *); +asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru) +{ + return sys_wait4((pid ? pid : -1), stat_addr, options, ru); +} + +extern int kill_pg(int, int, int); +asmlinkage int sunos_killpg(int pgrp, int sig) +{ + return kill_pg(pgrp, sig, 0); +} + +extern asmlinkage sunos_audit () +{ + printk ("sys_audit\n"); + return -1; +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v1.3.43/linux/arch/sparc/kernel/systbls.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/systbls.S Sat Nov 25 02:58:45 1995 @@ -0,0 +1,538 @@ +/* $Id: systbls.S,v 1.22 1995/11/25 00:58:42 davem Exp $ + * systbls.S: System call entry point tables for OS compatability. + * The native Linux system call table lives here also. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * Based upon preliminary work which is: + * + * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) + */ + +#include + + .data + .align 4 + + /* First, the Linux native syscall table. */ + + .globl C_LABEL(sys_call_table) +C_LABEL(sys_call_table): + .long C_LABEL(sys_setup) /* 0 */ + .long C_LABEL(sys_exit) + .long C_LABEL(sys_fork) + .long C_LABEL(sys_read) + .long C_LABEL(sys_write) + .long C_LABEL(sys_open) /* 5 */ + .long C_LABEL(sys_close) + .long C_LABEL(sys_wait4) + .long C_LABEL(sys_creat) + .long C_LABEL(sys_link) + .long C_LABEL(sys_unlink) /* 10 */ + .long C_LABEL(sunos_execv) + .long C_LABEL(sys_chdir) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_mknod) + .long C_LABEL(sys_chmod) /* 15 */ + .long C_LABEL(sys_chown) + .long C_LABEL(sys_brk) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_lseek) + .long C_LABEL(sys_getpid) /* 20 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_setuid) + .long C_LABEL(sys_getuid) + .long C_LABEL(sys_ni_syscall) /* 25 */ + .long C_LABEL(sys_ni_syscall) /* this will be sys_ptrace() */ + .long C_LABEL(sys_alarm) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_pause) + .long C_LABEL(sys_utime) /* 30 */ + .long C_LABEL(sys_stty) + .long C_LABEL(sys_gtty) + .long C_LABEL(sys_access) + .long C_LABEL(sys_nice) + .long C_LABEL(sys_ftime) /* 35 */ + .long C_LABEL(sys_sync) + .long C_LABEL(sys_kill) + .long C_LABEL(sys_newstat) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_newlstat) /* 40 */ + .long C_LABEL(sys_dup) + .long C_LABEL(sys_pipe) + .long C_LABEL(sys_times) + .long C_LABEL(sys_profil) + .long C_LABEL(sys_ni_syscall) /* 45 */ + .long C_LABEL(sys_setgid) + .long C_LABEL(sys_getgid) + .long C_LABEL(sys_signal) + .long C_LABEL(sys_geteuid) + .long C_LABEL(sys_getegid) /* 50 */ + .long C_LABEL(sys_acct) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ioctl) + .long C_LABEL(sys_reboot) /* 55 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_symlink) + .long C_LABEL(sys_readlink) + .long C_LABEL(sys_execve) + .long C_LABEL(sys_umask) /* 60 */ + .long C_LABEL(sys_chroot) + .long C_LABEL(sys_newfstat) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_getpagesize) + .long C_LABEL(sys_ni_syscall) /* 65 */ + .long C_LABEL(sys_vfork) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 70 */ + .long C_LABEL(sunos_mmap) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_munmap) + .long C_LABEL(sys_mprotect) + .long C_LABEL(sys_ni_syscall) /* 75 */ + .long C_LABEL(sys_vhangup) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_getgroups) + .long C_LABEL(sys_setgroups) /* 80 */ + .long C_LABEL(sys_getpgrp) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_setitimer) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_swapon) /* 85 */ + .long C_LABEL(sys_getitimer) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_sethostname) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_dup2) /* 90 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_fcntl) + .long C_LABEL(sys_select) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_fsync) /* 95 */ + .long C_LABEL(sys_setpriority) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_getpriority) /* 100 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 105 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 110 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 115 */ + .long C_LABEL(sys_gettimeofday) + .long C_LABEL(sys_getrusage) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 120 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_settimeofday) + .long C_LABEL(sys_fchown) + .long C_LABEL(sys_fchmod) + .long C_LABEL(sys_ni_syscall) /* 125 */ + .long C_LABEL(sys_setreuid) + .long C_LABEL(sys_setregid) + .long C_LABEL(sys_rename) + .long C_LABEL(sys_truncate) + .long C_LABEL(sys_ftruncate) /* 130 */ + .long C_LABEL(sys_flock) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 135 */ + .long C_LABEL(sys_mkdir) + .long C_LABEL(sys_rmdir) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 140 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_getrlimit) + .long C_LABEL(sys_setrlimit) /* 145 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 150 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 155 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_statfs) + .long C_LABEL(sys_fstatfs) + .long C_LABEL(sys_umount) + .long C_LABEL(sys_ni_syscall) /* 160 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_setdomainname) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* sys_quotactl -- 165 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_mount) + .long C_LABEL(sys_ustat) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 170 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_getdents) + .long C_LABEL(sys_setsid) /* 175 */ + .long C_LABEL(sys_fchdir) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 180 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_sigpending) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_setpgid) /* 185 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_uname) + .long C_LABEL(sys_init_module) /* 190 */ + .long C_LABEL(sys_personality) + .long C_LABEL(sys_prof) + .long C_LABEL(sys_break) + .long C_LABEL(sys_lock) + .long C_LABEL(sys_mpx) /* 195 */ + .long C_LABEL(sys_ulimit) + .long C_LABEL(sys_getppid) + .long C_LABEL(sys_sigaction) + .long C_LABEL(sys_sgetmask) + .long C_LABEL(sys_ssetmask) /* 200 */ + .long C_LABEL(sys_sigsuspend) + .long C_LABEL(sys_newlstat) + .long C_LABEL(sys_uselib) + .long C_LABEL(old_readdir) + .long C_LABEL(sys_ni_syscall) /* 205 */ + .long C_LABEL(sys_socketcall) + .long C_LABEL(sys_syslog) + .long C_LABEL(sys_olduname) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_idle) /* 210 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_waitpid) + .long C_LABEL(sys_swapoff) + .long C_LABEL(sys_sysinfo) + .long C_LABEL(sys_ipc) /* 215 */ + .long C_LABEL(sys_sigreturn) + .long C_LABEL(sys_clone) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_adjtimex) + .long C_LABEL(sys_sigprocmask) /* 220 */ + .long C_LABEL(sys_create_module) + .long C_LABEL(sys_delete_module) + .long C_LABEL(sys_get_kernel_syms) + .long C_LABEL(sys_getpgid) + .long C_LABEL(sys_bdflush) /* 225 */ + .long C_LABEL(sys_sysfs) + .long C_LABEL(sys_ni_syscall) /* Andrew Filesystem Syscall */ + .long C_LABEL(sys_setfsuid) + .long C_LABEL(sys_setfsgid) + .long C_LABEL(sys_llseek) /* 230 Should be newselect... */ + .long C_LABEL(sys_time) + .long C_LABEL(sys_ni_syscall) /* Should be oldstat... */ + .long C_LABEL(sys_stime) + .long C_LABEL(sys_ni_syscall) /* Should be oldfstat */ + .long C_LABEL(sys_ni_syscall) /* 235 - sys_phys */ + .long C_LABEL(sys_llseek) + + /* "We are the Knights of the Forest of Ni!!" */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 240 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 245 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 250 */ + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) /* 255 */ + + /* Now the SunOS syscall table. */ + + .align 4 + .globl C_LABEL(sunos_sys_table) +C_LABEL(sunos_sys_table): + .long C_LABEL(sunos_indir) /* so stupid... */ + .long C_LABEL(sys_exit) + .long C_LABEL(sys_fork) + .long C_LABEL(sys_read) + .long C_LABEL(sys_write) + .long C_LABEL(sys_open) /* 5 */ + .long C_LABEL(sys_close) + .long C_LABEL(sunos_wait4) /* broken... */ + .long C_LABEL(sys_creat) + .long C_LABEL(sys_link) + .long C_LABEL(sys_unlink) /* 10 */ + .long C_LABEL(sunos_execv) + .long C_LABEL(sys_chdir) + .long C_LABEL(sunos_nosys) /* Obsolete sys_time(), unused */ + .long C_LABEL(sys_mknod) + .long C_LABEL(sys_chmod) /* 15 */ + .long C_LABEL(sys_chown) + .long C_LABEL(sunos_brk) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_lseek) + .long C_LABEL(sunos_getpid) /* 20 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_getuid) + .long C_LABEL(sunos_nosys) /* 25 */ + .long C_LABEL(sunos_nosys) /* this will be sys_ptrace() */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* Old SunOS fstat, unsupported */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 30 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_access) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 35 */ + .long C_LABEL(sys_sync) + .long C_LABEL(sys_kill) + .long C_LABEL(sys_newstat) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_newlstat) /* 40 */ + .long C_LABEL(sys_dup) + .long C_LABEL(sys_pipe) + .long C_LABEL(sunos_nosys) /* SunOS sys_times() */ + .long C_LABEL(sys_profil) + .long C_LABEL(sunos_nosys) /* 45 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_getgid) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 50 */ + .long C_LABEL(sys_acct) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_mctl) + .long C_LABEL(sunos_ioctl) + .long C_LABEL(sys_reboot) /* 55 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_symlink) + .long C_LABEL(sys_readlink) + .long C_LABEL(sys_execve) + .long C_LABEL(sys_umask) /* 60 */ + .long C_LABEL(sys_chroot) + .long C_LABEL(sys_newfstat) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_getpagesize) + .long C_LABEL(sunos_msync) /* 65 */ + .long C_LABEL(sys_vfork) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_sbrk) + .long C_LABEL(sunos_sstk) /* 70 */ + .long C_LABEL(sunos_mmap) + .long C_LABEL(sunos_vadvise) + .long C_LABEL(sys_munmap) + .long C_LABEL(sys_mprotect) + .long C_LABEL(sunos_madvise) /* 75 */ + .long C_LABEL(sys_vhangup) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_mincore) + .long C_LABEL(sys_getgroups) + .long C_LABEL(sys_setgroups) /* 80 */ + .long C_LABEL(sys_getpgrp) + .long C_LABEL(sunos_setpgrp) + .long C_LABEL(sys_setitimer) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_swapon) /* 85 */ + .long C_LABEL(sys_getitimer) + .long C_LABEL(sys_gethostname) + .long C_LABEL(sys_sethostname) + .long C_LABEL(sunos_getdtablesize) + .long C_LABEL(sys_dup2) /* 90 */ + .long C_LABEL(sunos_nop) /* getdopt() does nothing */ + .long C_LABEL(sys_fcntl) + .long C_LABEL(sys_select) + .long C_LABEL(sunos_nop) /* setdopt() also does nothing */ + .long C_LABEL(sys_fsync) /* 95 */ + .long C_LABEL(sys_setpriority) + .long C_LABEL(sys_socket) + .long C_LABEL(sys_connect) + .long C_LABEL(sys_accept) + .long C_LABEL(sys_getpriority) /* 100 */ + .long C_LABEL(sys_send) + .long C_LABEL(sys_recv) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_bind) + .long C_LABEL(sys_setsockopt) /* 105 */ + .long C_LABEL(sys_listen) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_sigaction) /* sigvec */ + .long C_LABEL(sunos_sigblock) /* sigblock */ + .long C_LABEL(sys_ssetmask) /* sigsetmask -- 110 */ + .long C_LABEL(sys_sigpause) /* sigpause */ + .long C_LABEL(sys_sigstack) /* sigstack */ + .long C_LABEL(sunos_nosys) /* recvmsg */ + .long C_LABEL(sunos_nosys) /* sendmsg */ + .long C_LABEL(sunos_nosys) /* vtrace -- 115 */ + .long C_LABEL(sys_gettimeofday) + .long C_LABEL(sys_getrusage) + .long C_LABEL(sys_getsockopt) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_readv) /* 120 */ + .long C_LABEL(sys_writev) + .long C_LABEL(sys_settimeofday) + .long C_LABEL(sys_fchown) + .long C_LABEL(sys_fchmod) + .long C_LABEL(sys_recvfrom) /* recvfrom -- 125 */ + .long C_LABEL(sys_setreuid) + .long C_LABEL(sys_setregid) + .long C_LABEL(sys_rename) + .long C_LABEL(sys_truncate) + .long C_LABEL(sys_ftruncate) /* 130 */ + .long C_LABEL(sys_flock) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_sendto) /* sendto */ + .long C_LABEL(sys_shutdown) /* shutdown */ + .long C_LABEL(sunos_nosys) /* socketpair -- 135 */ + .long C_LABEL(sys_mkdir) + .long C_LABEL(sys_rmdir) + .long C_LABEL(sys_utimes) /* utimes */ + .long C_LABEL(sys_sigreturn) + .long C_LABEL(sunos_nosys) /* adjtime -- 140 */ + .long C_LABEL(sys_getpeername) /* getpeername */ + .long C_LABEL(sunos_nosys) /* gethostid */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_getrlimit) + .long C_LABEL(sys_setrlimit) /* 145 */ + .long C_LABEL(sunos_killpg) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_getsockname) /* getsockname -- 150 */ + .long C_LABEL(sunos_nosys) /* getmsg */ + .long C_LABEL(sunos_nosys) /* putmsg */ + .long C_LABEL(sunos_nosys) /* poll */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* nfssvc -- 155 */ + .long C_LABEL(sunos_nosys) /* getdirectries */ + .long C_LABEL(sys_statfs) + .long C_LABEL(sys_fstatfs) + .long C_LABEL(sys_umount) + .long C_LABEL(sunos_nosys) /* async_daemon -- 160 */ + .long C_LABEL(sunos_nosys) /* getfh */ + .long C_LABEL(sunos_getdomainname) /* getdomainname */ + .long C_LABEL(sys_setdomainname) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* quotactl -- 165 */ + .long C_LABEL(sunos_nosys) /* exportfs */ + .long C_LABEL(sunos_mount) + .long C_LABEL(sys_ustat) + .long C_LABEL(sunos_nosys) /* semsys */ + .long C_LABEL(sunos_nosys) /* msgsys -- 170 */ + .long C_LABEL(sunos_nosys) /* shmsys */ + .long C_LABEL(sunos_audit) /* auditsys */ + .long C_LABEL(sunos_nosys) /* rfssys */ + .long C_LABEL(sunos_getdents) + .long C_LABEL(sys_setsid) /* 175 */ + .long C_LABEL(sys_fchdir) + .long C_LABEL(sunos_nosys) /* fchroot */ + .long C_LABEL(sunos_nosys) /* vpixsys ???XXX */ + .long C_LABEL(sunos_nosys) /* aioread */ + .long C_LABEL(sunos_nosys) /* aiowrite -- 180 */ + .long C_LABEL(sunos_nosys) /* aiowait */ + .long C_LABEL(sunos_nosys) /* aiocancel */ + .long C_LABEL(sys_sigpending) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sys_setpgid) /* 185 */ + .long C_LABEL(sunos_pathconf) /* pathconf */ + .long C_LABEL(sunos_fpathconf) /* fpathconf */ + .long C_LABEL(sunos_nosys) /* sysconf */ + .long C_LABEL(sunos_uname) + .long C_LABEL(sunos_nosys) /* 190 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 195 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 200 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 205 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 210 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 215 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 220 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 225 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 230 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 235 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 240 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 245 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 250 */ + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) + .long C_LABEL(sunos_nosys) /* 255 */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v1.3.43/linux/arch/sparc/kernel/time.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/time.c Sat Nov 25 02:58:47 1995 @@ -0,0 +1,79 @@ +/* $Id: time.c,v 1.3 1995/11/25 00:58:45 davem Exp $ + * linux/arch/sparc/kernel/time.c + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * This file handles the Sparc specific time handling details. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ + +static int set_rtc_mmss(unsigned long); + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +void timer_interrupt(int irq, struct pt_regs * regs) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update=0; + volatile unsigned int clear_intr; + + /* First, clear the interrupt. */ + clear_intr = *master_l10_limit; + + do_timer(regs); + + /* XXX I don't know if this is right for the Sparc yet. XXX */ + if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec > 500000 - (tick >> 1) && + xtime.tv_usec < 500000 + (tick >> 1)) + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ +} + +void time_init(void) +{ + request_irq(TIMER_IRQ, timer_interrupt, SA_INTERRUPT, "timer"); + return; +} +/* Nothing fancy on the Sparc yet. */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_flags(flags); + cli(); + *tv = xtime; + restore_flags(flags); +} + +void do_settimeofday(struct timeval *tv) +{ + cli(); + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = 0x70000000; + time_esterror = 0x70000000; + sti(); +} + +/* XXX Mostek RTC code needs to be written XXX */ +static int set_rtc_mmss(unsigned long nowtime) +{ + /* Just say we succeeded for now. */ + return 0; +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c --- v1.3.43/linux/arch/sparc/kernel/traps.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/kernel/traps.c Sat Nov 25 02:58:49 1995 @@ -1,4 +1,4 @@ -/* +/* $Id: traps.c,v 1.18 1995/11/25 00:58:47 davem Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -21,6 +21,35 @@ #include void +syscall_trace_entry(struct pt_regs *regs) +{ + printk("%s[%d]: sys[%d](%d, %d, %d, %d) ", + current->comm, current->pid, + regs->u_regs[UREG_G1], regs->u_regs[UREG_I0], + regs->u_regs[UREG_I1], regs->u_regs[UREG_I2], + regs->u_regs[UREG_I3]); + return; +} + +void +syscall_trace_exit(struct pt_regs *regs) +{ + printk("retvals[%d,%d] at pc<%08lx>\n", + regs->u_regs[UREG_I0], regs->u_regs[UREG_I1], + regs->pc, regs->npc); + return; +} + +void +do_cwp_assertion_failure(struct pt_regs *regs, unsigned long psr) +{ + printk("CWP return from trap assertion fails:\n"); + printk("Current psr %08lx, new psr %08lx\n", psr, regs->psr); + show_regs(regs); + panic("bogus CWP"); +} + +void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc) { @@ -37,7 +66,11 @@ { printk("Illegal instruction at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); - halt(); + if(psr & PSR_PS) + panic("Kernel illegal instruction, how are ya!"); + current->tss.sig_address = pc; + current->tss.sig_desc = SUBSIG_ILLINST; + send_sig(SIGILL, current, 1); return; } @@ -47,17 +80,25 @@ { printk("Privileged instruction at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); - halt(); + current->tss.sig_address = pc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGILL, current, 1); return; } +/* XXX User may want to be allowed to do this. XXX */ + void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { printk("Unaligned memory access at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); - halt(); + if(regs->psr & PSR_PS) + panic("Kernel does unaligned memory access, yuck!"); + current->tss.sig_address = pc; + current->tss.sig_desc = SUBSIG_PRIVINST; + send_sig(SIGBUS, current, 1); return; } @@ -65,19 +106,123 @@ do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - printk("Floating Point Disabled trap at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); - return; + /* Sanity check... */ + if(psr & PSR_PS) + panic("FPE disabled trap from kernel, die die die..."); + + put_psr(get_psr() | PSR_EF); /* Allow FPU ops. */ + if(last_task_used_math == current) { + /* No state save necessary */ + regs->psr |= PSR_EF; + return; + } + if(last_task_used_math) { + /* Other processes fpu state, save away */ + __asm__ __volatile__("st %%fsr, [%0]\n\t" : : + "r" (¤t->tss.fsr) : "memory"); + + /* Save away the floating point queue if necessary. */ + if(current->tss.fsr & 0x2000) + __asm__ __volatile__("mov 0x0, %%g2\n\t" + "1: std %%fq, [%2 + %%g2]\n\t" + "st %%fsr, [%0]\n\t" + "ld [%0], %%g3\n\t" + "andcc %%g3, %1, %%g0\n\t" + "bne 1b\n\t" + "add %%g2, 0x8, %%g2\n\t" + "srl %%g2, 0x3, %%g2\n\t" + "st %%g2, [%3]\n\t" : : + "r" (¤t->tss.fsr), "r" (0x2000), + "r" (¤t->tss.fpqueue[0]), + "r" (¤t->tss.fpqdepth) : + "g2", "g3", "memory"); + else + current->tss.fpqdepth = 0; + + __asm__ __volatile__("std %%f0, [%0 + 0x00]\n\t" + "std %%f2, [%0 + 0x08]\n\t" + "std %%f4, [%0 + 0x10]\n\t" + "std %%f6, [%0 + 0x18]\n\t" + "std %%f8, [%0 + 0x20]\n\t" + "std %%f10, [%0 + 0x28]\n\t" + "std %%f12, [%0 + 0x30]\n\t" + "std %%f14, [%0 + 0x38]\n\t" + "std %%f16, [%0 + 0x40]\n\t" + "std %%f18, [%0 + 0x48]\n\t" + "std %%f20, [%0 + 0x50]\n\t" + "std %%f22, [%0 + 0x58]\n\t" + "std %%f24, [%0 + 0x60]\n\t" + "std %%f26, [%0 + 0x68]\n\t" + "std %%f28, [%0 + 0x70]\n\t" + "std %%f30, [%0 + 0x78]\n\t" : : + "r" (¤t->tss.float_regs[0]) : + "memory"); + } + last_task_used_math = current; + if(current->used_math) { + /* Restore the old state. */ + __asm__ __volatile__("ldd [%0 + 0x00], %%f0\n\t" + "ldd [%0 + 0x08], %%f2\n\t" + "ldd [%0 + 0x10], %%f4\n\t" + "ldd [%0 + 0x18], %%f6\n\t" + "ldd [%0 + 0x20], %%f8\n\t" + "ldd [%0 + 0x28], %%f10\n\t" + "ldd [%0 + 0x30], %%f12\n\t" + "ldd [%0 + 0x38], %%f14\n\t" + "ldd [%0 + 0x40], %%f16\n\t" + "ldd [%0 + 0x48], %%f18\n\t" + "ldd [%0 + 0x50], %%f20\n\t" + "ldd [%0 + 0x58], %%f22\n\t" + "ldd [%0 + 0x60], %%f24\n\t" + "ldd [%0 + 0x68], %%f26\n\t" + "ldd [%0 + 0x70], %%f28\n\t" + "ldd [%0 + 0x78], %%f30\n\t" + "ld [%1], %%fsr\n\t" : : + "r" (¤t->tss.float_regs[0]), + "r" (¤t->tss.fsr)); + } else { + /* Set initial sane state. */ + auto unsigned long init_fsr = 0x0UL; + auto unsigned long init_fregs[32] __attribute__ ((aligned (8))) = + { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, + ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, + ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, + ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL }; + __asm__ __volatile__("ldd [%0 + 0x00], %%f0\n\t" + "ldd [%0 + 0x08], %%f2\n\t" + "ldd [%0 + 0x10], %%f4\n\t" + "ldd [%0 + 0x18], %%f6\n\t" + "ldd [%0 + 0x20], %%f8\n\t" + "ldd [%0 + 0x28], %%f10\n\t" + "ldd [%0 + 0x30], %%f12\n\t" + "ldd [%0 + 0x38], %%f14\n\t" + "ldd [%0 + 0x40], %%f16\n\t" + "ldd [%0 + 0x48], %%f18\n\t" + "ldd [%0 + 0x50], %%f20\n\t" + "ldd [%0 + 0x58], %%f22\n\t" + "ldd [%0 + 0x60], %%f24\n\t" + "ldd [%0 + 0x68], %%f26\n\t" + "ldd [%0 + 0x70], %%f28\n\t" + "ldd [%0 + 0x78], %%f30\n\t" + "ld [%1], %%fsr\n\t" : : + "r" (&init_fregs[0]), + "r" (&init_fsr) : "memory"); + current->used_math = 1; + } } void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - printk("Floating Point Exception at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); + if(psr & PSR_PS) + panic("FPE exception trap from kernel, die die die..."); + /* XXX Do something real... XXX */ + regs->psr &= ~PSR_EF; + last_task_used_math = (struct task_struct *) 0; + current->tss.sig_address = pc; + current->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */ + send_sig(SIGFPE, current, 1); return; } @@ -87,7 +232,11 @@ { printk("Tag overflow trap at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); - halt(); + if(psr & PSR_PS) + panic("KERNEL tag overflow trap, wowza!"); + current->tss.sig_address = pc; + current->tss.sig_desc = SUBSIG_TAG; /* as good as any */ + send_sig(SIGEMT, current, 1); return; } @@ -97,7 +246,9 @@ { printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); - halt(); + if(psr & PSR_PS) + panic("Tell me what a watchpoint trap is, and I'll then deal " + "with such a beast..."); return; } @@ -112,16 +263,6 @@ } void -handle_iacc_error(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long psr) -{ - printk("Instruction Access Error at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); - return; -} - -void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { @@ -152,16 +293,6 @@ } void -handle_dacc_error(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long psr) -{ - printk("Data Access Error at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); - return; -} - -void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { @@ -171,33 +302,9 @@ return; } -void -handle_dstore_error(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long psr) +void do_ast(struct pt_regs *regs) { - printk("Data Store Error at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); - return; -} - -void -handle_dacc_mmu_miss(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long psr) -{ - printk("Data Access MMU-Miss Exception at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); - return; -} - -void -handle_iacc_mmu_miss(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long psr) -{ - printk("Instruction Access MMU-Miss Exception at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); - halt(); + panic("Don't know how to handle AST traps yet ;-(\n"); return; } @@ -214,8 +321,6 @@ unsigned int thiscpus_tbr; int thiscpus_mid; -/* #define SMP_TESTING */ - void trap_init(void) { @@ -227,12 +332,12 @@ return; } if(sparc_cpu_model != sun4m) { - printk("trap_init: Multiprocessor on a non-sun4m! Aieee...\n"); - printk("trap_init: Cannot continue, bailing out.\n"); + prom_printf("trap_init: Multiprocessor on a non-sun4m! Aieee...\n"); + prom_printf("trap_init: Cannot continue, bailing out.\n"); prom_halt(); } /* Ok, we are on a sun4m with multiple cpu's */ - printk("trap_init: Multiprocessor detected, initiating CPU-startup. cpus=%d\n", + prom_printf("trap_init: Multiprocessor detected, initiating CPU-startup. cpus=%d\n", linux_num_cpus); linux_smp_still_initting = 1; ctx_reg.which_io = 0x0; /* real ram */ @@ -250,23 +355,14 @@ thiscpus_mid = linux_cpus[i].mid; thiscpus_tbr = (unsigned int) percpu_table[cpuid].trap_table; -#ifdef SMP_TESTING - printk("thiscpus_tbr = %08x\n", thiscpus_tbr); - printk("About to fire up cpu %d mid %d cpuid %d\n", i, - linux_cpus[i].mid, cpuid); -#endif prom_startcpu(linux_cpus[i].prom_node, &ctx_reg, 0x0, (char *) sparc_cpu_startup); - printk("Waiting for cpu %d to start up...\n", i); + prom_printf("Waiting for cpu %d to start up...\n", i); while(percpu_table[cpuid].cpu_is_alive == 0) { static int counter = 0; counter++; - if(counter>200) { -#ifdef SMP_TESTING - printk("UGH, CPU would not start up ;-( \n"); -#endif + if(counter>200) break; - } __delay(200000); } } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S --- v1.3.43/linux/arch/sparc/kernel/wof.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/wof.S Sat Nov 25 02:58:51 1995 @@ -0,0 +1,420 @@ +/* $Id: wof.S,v 1.14 1995/11/25 00:58:49 davem Exp $ + * wof.S: Sparc window overflow handler. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include + +/* WARNING: This routine is hairy and _very_ complicated, but it + * must be as fast as possible as it handles the allocation + * of register windows to the user and kernel. If you touch + * this code be _very_ careful as many other pieces of the + * kernel depend upon how this code behaves. You have been + * duly warned... + */ + +/* We define macro's for registers which have a fixed + * meaning throughout this entire routine. The 'T' in + * the comments mean that the register can only be + * accessed when in the 'trap' window, 'G' means + * accessible in any window. Do not change these registers + * after they have been set, until you are ready to return + * from the trap. + */ +#define t_psr l0 /* %psr at trap time T */ +#define t_pc l1 /* PC for trap return T */ +#define t_npc l2 /* NPC for trap return T */ +#define t_wim l3 /* %wim at trap time T */ +#define saved_g5 l5 /* Global save register T */ +#define saved_g6 l6 /* Global save register T */ +#define curptr g6 /* Gets set to 'current' then stays G */ + +/* Now registers whose values can change within the handler. */ +#define twin_tmp l4 /* Temp reg, only usable in trap window T */ +#define glob_tmp g5 /* Global temporary reg, usable anywhere G */ + + .text + .align 4 + /* BEGINNING OF PATCH INSTRUCTIONS */ + /* On a 7-window Sparc the boot code patches spnwin_* + * instructions with the following ones. + */ + .globl spnwin_patch1_7win, spnwin_patch2_7win, spnwin_patch3_7win +spnwin_patch1_7win: sll %t_wim, 6, %glob_tmp +spnwin_patch2_7win: and %glob_tmp, 0x7f, %glob_tmp +spnwin_patch3_7win: and %twin_tmp, 0x7f, %twin_tmp + /* END OF PATCH INSTRUCTIONS */ + + /* The trap entry point has done the following: + * + * rd %psr, %l0 + * rd %wim, %l3 + * b spill_window_entry + * andcc %l0, PSR_PS, %g0 + */ + + /* Datum current->tss.uwinmask contains at all times a bitmask + * where if any user windows are active, at least one bit will + * be set in to mask. If no user windows are active, the bitmask + * will be all zeroes. + */ + .globl spill_window_entry + .globl spnwin_patch1, spnwin_patch2, spnwin_patch3 +spill_window_entry: + /* LOCATION: Trap Window */ + + mov %g5, %saved_g5 ! save away global temp register + mov %g6, %saved_g6 ! save away 'current' ptr register + + /* Compute what the new %wim will be if we save the + * window properly in this trap handler. + * + * newwim = ((%wim>>1) | (%wim<<(nwindows - 1))); + */ + srl %t_wim, 0x1, %twin_tmp +spnwin_patch1: sll %t_wim, 7, %glob_tmp + or %glob_tmp, %twin_tmp, %glob_tmp +spnwin_patch2: and %glob_tmp, 0xff, %glob_tmp + + /* The trap entry point has set the condition codes + * up for us to see if this is from user or kernel. + * Get the load of 'curptr' out of the way. + */ + LOAD_CURRENT(curptr) + + andcc %t_psr, PSR_PS, %g0 + be spwin_fromuser ! all user wins, branch + nop + + /* See if any user windows are active in the set. */ + ld [%curptr + THREAD_UMASK], %twin_tmp ! grab currents win mask + orcc %g0, %twin_tmp, %g0 ! check for set bits + bne spwin_exist_uwins ! yep, there are some + nop + + /* Save into the window which must be saved and do it. + * Basically if we are here, this means that we trapped + * from kernel mode with only kernel windows in the register + * file. + */ + save %g0, %g0, %g0 ! save into the window to stash away + wr %glob_tmp, 0x0, %wim ! set new %wim, this is safe now + WRITE_PAUSE ! burn cpu cycles due to bad engineering + +spwin_no_userwins_from_kernel: + /* LOCATION: Window to be saved */ + + STORE_WINDOW(sp) ! stash the window + restore %g0, %g0, %g0 ! go back into trap window + + /* LOCATION: Trap window */ + mov %saved_g5, %g5 ! restore %glob_tmp + mov %saved_g6, %g6 ! restore %curptr + wr %t_psr, 0x0, %psr ! restore condition codes in %psr + WRITE_PAUSE ! waste some time + jmp %t_pc ! Return from trap + rett %t_npc ! we are done + +spwin_exist_uwins: + /* LOCATION: Trap window */ + + /* Wow, user windows have to be dealt with, this is dirty + * and messy as all hell. And difficult to follow if you + * are approaching the infamous register window trap handling + * problem for the first time. DONT LOOK! + * + * Note that how the execution path works out, the new %wim + * will be left for us in the global temporary register, + * %glob_tmp. We cannot set the new %wim first because we + * need to save into the appropriate window without inducing + * a trap (traps are off, we'd get a watchdog wheee)... + * But first, store the new user window mask calculated + * above. + */ + andn %twin_tmp, %glob_tmp, %twin_tmp ! compute new umask + st %twin_tmp, [%curptr + THREAD_UMASK] + +spwin_fromuser: + /* LOCATION: Trap window */ + save %g0, %g0, %g0 ! Go to where the saving will occur + + /* LOCATION: Window to be saved */ + wr %glob_tmp, 0x0, %wim ! Now it is safe to set new %wim + WRITE_PAUSE ! burn baby burn + + /* LOCATION: Window to be saved */ + + /* This instruction branches to a routine which will check + * to validity of the users stack pointer by whatever means + * are necessary. This means that this is architecture + * specific and thus this branch instruction will need to + * be patched at boot time once the machine type is known. + * This routine _shall not_ touch %curptr under any + * circumstances whatsoever! It will branch back to the + * label 'spwin_good_ustack' if the stack is ok but still + * needs to be dumped (SRMMU for instance will not need to + * do this) or 'spwin_finish_up' if the stack is ok and the + * registers have already been saved. If the stack is found + * to be bogus for some reason the routine shall branch to + * the label 'spwin_user_stack_is_bolixed' which will take + * care of things at that point. + */ + .globl C_LABEL(spwin_mmu_patchme) +C_LABEL(spwin_mmu_patchme): b C_LABEL(spwin_sun4c_stackchk) + andcc %sp, 0x7, %g0 + +spwin_good_ustack: + /* LOCATION: Window to be saved */ + + /* The users stack is ok and we can safely save it at + * %sp. + */ + STORE_WINDOW(sp) + +spwin_finish_up: + restore %g0, %g0, %g0 /* Back to trap window. */ + + /* LOCATION: Trap window */ + + /* We have spilled successfully, and we have properly stored + * the appropriate window onto the stack. + */ + + /* Restore saved globals */ + mov %saved_g5, %g5 + mov %saved_g6, %g6 + wr %t_psr, 0x0, %psr + WRITE_PAUSE + jmp %t_pc + rett %t_npc + +spwin_user_stack_is_bolixed: + /* LOCATION: Window to be saved */ + + /* Wheee, user has trashed his/her stack. We have to decide + * how to proceed based upon whether we came from kernel mode + * or not. If we came from kernel mode, toss the window into + * a special buffer and proceed, the kernel _needs_ a window + * and we could be in an interrupt handler so timing is crucial. + * If we came from user land we build a full stack frame and call + * c-code to gun down the process. + */ + rd %psr, %glob_tmp + andcc %glob_tmp, PSR_PS, %g0 + bne spwin_bad_ustack_from_kernel + nop + + /* Oh well, throw this one window into the per-task window + * buffer, the first one. + */ + st %sp, [%curptr + THREAD_STACK_PTRS] + STORE_WINDOW(curptr + THREAD_REG_WINDOW) + restore %g0, %g0, %g0 + + /* LOCATION: Trap Window */ + + /* Back in the trap window, update winbuffer save count. */ + mov 1, %glob_tmp + st %glob_tmp, [%curptr + THREAD_W_SAVED] + + /* Compute new user window mask. What we are basically + * doing is taking two windows, the invalid one at trap + * time and the one we attempted to throw onto the users + * stack, and saying that everything else is an ok user + * window. umask = ((~(%t_wim | %wim)) & valid_wim_bits) + */ + rd %wim, %twin_tmp + or %twin_tmp, %t_wim, %twin_tmp + not %twin_tmp +spnwin_patch3: and %twin_tmp, 0xff, %twin_tmp ! patched on 7win Sparcs + st %twin_tmp, [%curptr + THREAD_UMASK] + + /* Jump onto kernel stack for this process... */ + ld [%curptr + TASK_KSTACK_PG], %sp + add %sp, (PAGE_SIZE - TRACEREG_SZ - STACKFRAME_SZ), %sp + + /* Restore the saved globals and build a pt_regs frame. */ + mov %saved_g5, %g5 + mov %saved_g6, %g6 + rd %wim, %twin_tmp + STORE_PT_ALL(sp, t_psr, t_pc, t_npc, twin_tmp, g1) + + /* Turn on traps and call c-code to deal with it. */ + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + mov 1, %o1 + call C_LABEL(do_sparc_winfault) + add %sp, STACKFRAME_SZ, %o0 + + /* Return from trap if C-code actually fixes things, if it + * doesn't then we never get this far as the process will + * be given the look of death from Commander Peanut. + */ + b ret_trap_entry + nop + +spwin_bad_ustack_from_kernel: + /* LOCATION: Window to be saved */ + + /* The kernel provoked a spill window trap, but the window we + * need to save is a user one and the process has trashed its + * stack pointer. We need to be quick, so we throw it into + * a per-process window buffer until we can properly handle + * this later on. + */ + SAVE_BOLIXED_USER_STACK(curptr, glob_tmp) + restore %g0, %g0, %g0 + + /* LOCATION: Trap window */ + + /* Restore globals, condition codes in the %psr and + * return from trap. + */ + mov %saved_g5, %g5 + mov %saved_g6, %g6 + + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + +/* Undefine the register macros which would only cause trouble + * if used below. This helps find 'stupid' coding errors that + * produce 'odd' behavior. The routines below are allowed to + * make usage of glob_tmp and t_psr so we leave them defined. + */ +#undef twin_tmp +#undef curptr +#undef t_pc +#undef t_npc +#undef t_wim +#undef saved_g5 +#undef saved_g6 + +/* Now come the per-architecture window overflow stack checking routines. + * As noted above %curptr cannot be touched by this routine at all. + */ + + .globl C_LABEL(spwin_sun4c_stackchk) +C_LABEL(spwin_sun4c_stackchk): + /* LOCATION: Window to be saved on the stack */ + + /* See if the stack is in the address space hole but first, + * check results of callers andcc %sp, 0x7, %g0 + */ + be 1f + sra %sp, 29, %glob_tmp + + b spwin_user_stack_is_bolixed + nop + +1: + add %glob_tmp, 0x1, %glob_tmp + andncc %glob_tmp, 0x1, %g0 + be 1f + and %sp, 0xfff, %glob_tmp ! delay slot + + b spwin_user_stack_is_bolixed + nop + + /* See if our dump area will be on more than one + * page. + */ +1: + add %glob_tmp, 0x38, %glob_tmp + andncc %glob_tmp, 0xff8, %g0 + be spwin_sun4c_onepage ! only one page to check + lda [%sp] ASI_PTE, %glob_tmp ! have to check first page anyways + +spwin_sun4c_twopages: + /* Is first page ok permission wise? */ + srl %glob_tmp, 29, %glob_tmp + cmp %glob_tmp, 0x6 + be 1f + add %sp, 0x38, %glob_tmp /* Is second page in vma hole? */ + + b spwin_user_stack_is_bolixed + nop + +1: + sra %glob_tmp, 29, %glob_tmp + add %glob_tmp, 0x1, %glob_tmp + andncc %glob_tmp, 0x1, %g0 + be 1f + add %sp, 0x38, %glob_tmp + + b spwin_user_stack_is_bolixed + nop + +1: + lda [%glob_tmp] ASI_PTE, %glob_tmp + +spwin_sun4c_onepage: + srl %glob_tmp, 29, %glob_tmp + cmp %glob_tmp, 0x6 ! can user write to it? + be spwin_good_ustack ! success + nop + + b spwin_user_stack_is_bolixed + nop + + /* This is a generic SRMMU routine. As far as I know this + * works for all current v8/srmmu implementations, we'll + * see... + */ + .globl C_LABEL(spwin_srmmu_stackchk) +C_LABEL(spwin_srmmu_stackchk): + /* LOCATION: Window to be saved on the stack */ + + /* Because of SMP concerns and speed we play a trick. + * We disable fault traps in the MMU control register, + * Execute the stores, then check the fault registers + * to see what happens. I can hear Linus now + * "disgusting... broken hardware...". + * + * But first, check to see if the users stack has ended + * up in kernel vma, then we would succeed for the 'wrong' + * reason... ;( Note that the 'sethi' below assumes the + * kernel is page aligned, which should always be the case. + */ + /* Check results of callers andcc %sp, 0x7, %g0 */ + bne spwin_user_stack_is_bolixed + sethi %hi(KERNBASE), %glob_tmp + cmp %glob_tmp, %sp + bleu spwin_user_stack_is_bolixed + mov AC_M_SFSR, %glob_tmp + + /* Clear the fault status and turn on the no_fault bit. */ + lda [%glob_tmp] ASI_M_MMUREGS, %g0 ! eat SFSR + + lda [%g0] ASI_M_MMUREGS, %glob_tmp ! read MMU control + or %glob_tmp, 0x2, %glob_tmp ! or in no_fault bit + sta %glob_tmp, [%g0] ASI_M_MMUREGS ! set it + + /* Dump the registers and cross fingers. */ + STORE_WINDOW(sp) + + /* Clear the no_fault bit and check the status. */ + andn %glob_tmp, 0x2, %glob_tmp + sta %glob_tmp, [%g0] ASI_M_MMUREGS + + mov AC_M_SFAR, %glob_tmp + lda [%glob_tmp] ASI_M_MMUREGS, %g0 + + mov AC_M_SFSR, %glob_tmp + lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp + andcc %glob_tmp, 0x2, %g0 ! did we fault? + be spwin_finish_up ! cool beans, success + nop + + b spwin_user_stack_is_bolixed ! we faulted, ugh + nop diff -u --recursive --new-file v1.3.43/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S --- v1.3.43/linux/arch/sparc/kernel/wuf.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/wuf.S Sat Nov 25 02:58:53 1995 @@ -0,0 +1,351 @@ +/* $Id: wuf.S,v 1.13 1995/11/25 00:58:51 davem Exp $ + * wuf.S: Window underflow trap handler for the Sparc. + * + * Copyright (C) 1995 David S. Miller + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Just like the overflow handler we define macros for registers + * with fixed meanings in this routine. + */ +#define t_psr l0 +#define t_pc l1 +#define t_npc l2 +#define t_wim l3 +/* Don`t touch the above registers or else you die horribly... */ + +/* Now macros for the available scratch registers in this routine. */ +#define twin_tmp1 l4 +#define twin_tmp2 l5 + + .text + .align 4 + + /* The trap entry point has executed the following: + * + * rd %psr, %l0 + * rd %wim, %l3 + * b fill_window_entry + * andcc %l0, PSR_PS, %g0 + */ + + /* Datum current->tss.uwinmask contains at all times a bitmask + * where if any user windows are active, at least one bit will + * be set in to mask. If no user windows are active, the bitmask + * will be all zeroes. + */ + + /* To get an idea of what has just happened to cause this + * trap take a look at this diagram: + * + * 1 2 3 4 <-- Window number + * ---------- + * T O W I <-- Symbolic name + * + * O == the window that execution was in when + * the restore was attempted + * + * T == the trap itself has save'd us into this + * window + * + * W == this window is the one which is now invalid + * and must be made valid plus loaded from the + * stack + * + * I == this window will be the invalid one when we + * are done and return from trap if successful + */ + + /* BEGINNING OF PATCH INSTRUCTIONS */ + + /* On 7-window Sparc the boot code patches fnwin_patch1 + * with the following instruction. + */ + .globl fnwin_patch1_7win, fnwin_patch2_7win +fnwin_patch1_7win: srl %t_wim, 6, %twin_tmp2 +fnwin_patch2_7win: and %twin_tmp1, 0x7f, %twin_tmp1 + /* END OF PATCH INSTRUCTIONS */ + + .globl fill_window_entry, fnwin_patch1, fnwin_patch2 +fill_window_entry: + /* LOCATION: Window 'T' */ + + /* Compute what the new %wim is going to be if we retrieve + * the proper window off of the stack. + */ + sll %t_wim, 1, %twin_tmp1 +fnwin_patch1: srl %t_wim, 7, %twin_tmp2 + or %twin_tmp1, %twin_tmp2, %twin_tmp1 +fnwin_patch2: and %twin_tmp1, 0xff, %twin_tmp1 + + wr %twin_tmp1, 0x0, %wim /* Make window 'I' invalid */ + WRITE_PAUSE + + andcc %t_psr, PSR_PS, %g0 + be fwin_from_user + restore %g0, %g0, %g0 /* Restore to window 'O' */ + + /* Trapped from kernel, we trust that the kernel does not + * 'over restore' sorta speak and just grab the window + * from the stack and return. Easy enough. + */ +fwin_from_kernel: + /* LOCATION: Window 'O' */ + + restore %g0, %g0, %g0 + + /* LOCATION: Window 'W' */ + + LOAD_WINDOW(sp) /* Load it up */ + + /* Spin the wheel... */ + save %g0, %g0, %g0 + save %g0, %g0, %g0 + /* I'd like to buy a vowel please... */ + + /* LOCATION: Window 'T' */ + + /* Now preserve the condition codes in %psr, pause, and + * return from trap. This is the simplest case of all. + */ + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + +fwin_from_user: + /* LOCATION: Window 'O' */ + + restore %g0, %g0, %g0 /* Restore to window 'W' */ + + /* LOCATION: Window 'W' */ + + /* Branch to the architecture specific stack validation + * routine. They can be found below... + */ + .globl C_LABEL(fwin_mmu_patchme) +C_LABEL(fwin_mmu_patchme): b C_LABEL(sun4c_fwin_stackchk) + andcc %sp, 0x7, %g0 + +fwin_user_stack_is_bolixed: + /* LOCATION: Window 'W' */ + + /* Place a pt_regs frame on the kernel stack, save back + * to the trap window and call c-code to deal with this. + */ + LOAD_CURRENT(l4) + ld [%l4 + TASK_KSTACK_PG], %l5 + add %l5, (PAGE_SIZE - TRACEREG_SZ - STACKFRAME_SZ), %l5 + + /* Store globals into pt_regs frame. */ + STORE_PT_GLOBALS(l5) + STORE_PT_YREG(l5, g3) + + /* Save kernel %sp in global while we change windows */ + mov %l5, %g2 + + save %g0, %g0, %g0 + + /* LOCATION: Window 'O' */ + + rd %psr, %g3 /* Read %psr in live user window */ + + save %g0, %g0, %g0 + + /* LOCATION: Window 'T' */ + + mov %g2, %sp /* Jump onto kernel %sp being held */ + + /* Build rest of pt_regs. */ + STORE_PT_INS(sp) + STORE_PT_PRIV(sp, t_psr, t_pc, t_npc, t_wim) + + /* re-set trap time %wim value */ + wr %t_wim, 0x0, %wim + + /* Fix users window mask and buffer save count. */ + mov 0x1, %g5 + sll %g5, %g3, %g5 + LOAD_CURRENT(twin_tmp1) + st %g5, [%twin_tmp1 + THREAD_UMASK] ! one live user window still + st %g0, [%twin_tmp1 + THREAD_W_SAVED] ! no windows in the buffer + + wr %t_psr, 0x0, %psr + wr %t_psr, PSR_ET, %psr ! enable traps + WRITE_PAUSE + + mov 2, %o1 + call C_LABEL(do_sparc_winfault) ! call c-code + add %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr is arg0 + + /* Return from trap if C-code actually fixes things, if it + * doesn't then we never get this far as the process will + * be given the look of death from Commander Peanut. + */ + b ret_trap_entry + nop + +fwin_user_stack_is_ok: + /* LOCATION: Window 'W' */ + + /* The users stack area is kosher and mapped, load the + * window and fall through to the finish up routine. + */ + LOAD_WINDOW(sp) + + /* Round and round she goes... */ + save %g0, %g0, %g0 /* Save to window 'O' */ + save %g0, %g0, %g0 /* Save to window 'T' */ + /* Where she'll trap nobody knows... */ + + /* LOCATION: Window 'T' */ + +fwin_user_finish_up: + /* LOCATION: Window 'T' */ + + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + + /* Here come the architecture specific checks for stack. + * mappings. Note that unlike the window overflow handler + * we only need to check whether the user can read from + * the appropriate addresses. Also note that we are in + * an invalid window which will be loaded, and this means + * that until we actually load the window up we are free + * to use any of the local registers contained within. + * + * On success these routine branch to fwin_user_stack_is_ok + * if the area at %sp is user readable and the window still + * needs to be loaded, else fwin_user_finish_up if the + * routine has done the loading itself. On failure (bogus + * user stack) the routine shall branch to the label called + * fwin_user_stack_is_bolixed. + * + * Contrary to the arch-specific window overflow stack + * check routines in wof.S, these routines are free to use + * any of the local registers they want to as this window + * does not belong to anyone at this point, however the + * outs and ins are still verbotten as they are part of + * 'someone elses' window possibly. + */ + + .align 4 + .globl C_LABEL(sun4c_fwin_stackchk) +C_LABEL(sun4c_fwin_stackchk): + /* LOCATION: Window 'W' */ + + /* Caller did 'andcc %sp, 0x7, %g0' */ + be 1f + and %sp, 0xfff, %l0 ! delay slot + + b fwin_user_stack_is_bolixed + nop + + /* See if we have to check the sanity of one page or two */ +1: + add %l0, 0x38, %l0 + sra %sp, 29, %l5 + add %l5, 0x1, %l5 + andncc %l5, 0x1, %g0 + be 1f + andncc %l0, 0xff8, %g0 + + b fwin_user_stack_is_bolixed /* %sp is in vma hole, yuck */ + nop + +1: + be sun4c_fwin_onepage /* Only one page to check */ + lda [%sp] ASI_PTE, %l1 +sun4c_fwin_twopages: + add %sp, 0x38, %l0 + sra %l0, 29, %l5 + add %l5, 0x1, %l5 + andncc %l5, 0x1, %g0 + be 1f + lda [%l0] ASI_PTE, %l1 + + b fwin_user_stack_is_bolixed /* Second page in vma hole */ + nop + +1: + srl %l1, 29, %l1 + andcc %l1, 0x4, %g0 + bne sun4c_fwin_onepage + lda [%sp] ASI_PTE, %l1 + + b fwin_user_stack_is_bolixed /* Second page has bad perms */ + nop + +sun4c_fwin_onepage: + srl %l1, 29, %l1 + andcc %l1, 0x4, %g0 + bne fwin_user_stack_is_ok + nop + + /* A page had bad page permissions, losing... */ + b fwin_user_stack_is_bolixed + nop + + .globl C_LABEL(srmmu_fwin_stackchk) +C_LABEL(srmmu_fwin_stackchk): + /* LOCATION: Window 'W' */ + + /* Caller did 'andcc %sp, 0x7, %g0' */ + bne fwin_user_stack_is_bolixed + nop + + /* Check if the users stack is in kernel vma, then our + * trial and error technique below would succeed for + * the 'wrong' reason. + */ + sethi %hi(KERNBASE), %l5 ! delay slot for above + mov AC_M_SFSR, %l4 + cmp %l5, %sp + bleu fwin_user_stack_is_bolixed + lda [%l4] ASI_M_MMUREGS, %g0 ! clear fault status + + /* The technique is, turn off faults on this processor, + * just let the load rip, then check the sfsr to see if + * a fault did occur. Then we turn on fault traps again + * and branch conditionally based upon what happened. + */ + lda [%g0] ASI_M_MMUREGS, %l5 ! read mmu-ctrl reg + or %l5, 0x2, %l5 ! turn on no-fault bit + sta %l5, [%g0] ASI_M_MMUREGS ! store it + + /* Cross fingers and go for it. */ + LOAD_WINDOW(sp) + + /* A penny 'saved'... */ + save %g0, %g0, %g0 + save %g0, %g0, %g0 + /* Is a BADTRAP earned... */ + + /* LOCATION: Window 'T' */ + + lda [%g0] ASI_M_MMUREGS, %twin_tmp1 ! load mmu-ctrl again + andn %twin_tmp1, 0x2, %twin_tmp1 ! clear no-fault bit + sta %twin_tmp1, [%g0] ASI_M_MMUREGS ! store it + + mov AC_M_SFAR, %twin_tmp2 + lda [%twin_tmp2] ASI_M_MMUREGS, %g0 ! read fault address + + mov AC_M_SFSR, %twin_tmp2 + lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2 ! read fault status + andcc %twin_tmp2, 0x2, %g0 ! did fault occur? + be fwin_user_finish_up + nop + + b fwin_user_stack_is_bolixed ! oh well + nop diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile --- v1.3.43/linux/arch/sparc/lib/Makefile Tue Aug 15 20:39:00 1995 +++ linux/arch/sparc/lib/Makefile Sat Nov 25 02:58:59 1995 @@ -1,4 +1,4 @@ -# +# $Id: Makefile,v 1.5 1995/11/25 00:58:56 davem Exp $ # Makefile for Sparc library files.. # diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/ashrdi3.S linux/arch/sparc/lib/ashrdi3.S --- v1.3.43/linux/arch/sparc/lib/ashrdi3.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/ashrdi3.S Sat Nov 25 02:59:00 1995 @@ -1,4 +1,5 @@ -/* ashrdi3.S: The filesystem code creates all kinds of references to +/* $Id: ashrdi3.S,v 1.2 1995/11/25 00:58:59 davem Exp $ + * ashrdi3.S: The filesystem code creates all kinds of references to * this little routine on the sparc with gcc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/mul.S linux/arch/sparc/lib/mul.S --- v1.3.43/linux/arch/sparc/lib/mul.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/mul.S Sat Nov 25 02:59:02 1995 @@ -1,4 +1,5 @@ -/* mul.S: This routine was taken from glibc-1.09 and is covered +/* $Id: mul.S,v 1.2 1995/11/25 00:59:00 davem Exp $ + * mul.S: This routine was taken from glibc-1.09 and is covered * by the GNU Library General Public License Version 2. */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/rem.S linux/arch/sparc/lib/rem.S --- v1.3.43/linux/arch/sparc/lib/rem.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/rem.S Sat Nov 25 02:59:04 1995 @@ -1,4 +1,5 @@ -/* rem.S: This routine was taken from glibc-1.09 and is covered +/* $Id: rem.S,v 1.2 1995/11/25 00:59:02 davem Exp $ + * rem.S: This routine was taken from glibc-1.09 and is covered * by the GNU Library General Public License Version 2. */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/sdiv.S linux/arch/sparc/lib/sdiv.S --- v1.3.43/linux/arch/sparc/lib/sdiv.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/sdiv.S Sat Nov 25 02:59:06 1995 @@ -1,4 +1,5 @@ -/* sdiv.S: This routine was taken from glibc-1.09 and is covered +/* $Id: sdiv.S,v 1.2 1995/11/25 00:59:04 davem Exp $ + * sdiv.S: This routine was taken from glibc-1.09 and is covered * by the GNU Library General Public License Version 2. */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/udiv.S linux/arch/sparc/lib/udiv.S --- v1.3.43/linux/arch/sparc/lib/udiv.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/udiv.S Sat Nov 25 02:59:08 1995 @@ -1,4 +1,5 @@ -/* udiv.S: This routine was taken from glibc-1.09 and is covered +/* $Id: udiv.S,v 1.2 1995/11/25 00:59:06 davem Exp $ + * udiv.S: This routine was taken from glibc-1.09 and is covered * by the GNU Library General Public License Version 2. */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/umul.S linux/arch/sparc/lib/umul.S --- v1.3.43/linux/arch/sparc/lib/umul.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/umul.S Sat Nov 25 02:59:11 1995 @@ -1,4 +1,5 @@ -/* umul.S: This routine was taken from glibc-1.09 and is covered +/* $Id: umul.S,v 1.2 1995/11/25 00:59:08 davem Exp $ + * umul.S: This routine was taken from glibc-1.09 and is covered * by the GNU Library General Public License Version 2. */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/lib/urem.S linux/arch/sparc/lib/urem.S --- v1.3.43/linux/arch/sparc/lib/urem.S Sun Jan 22 23:02:41 1995 +++ linux/arch/sparc/lib/urem.S Sat Nov 25 02:59:13 1995 @@ -1,4 +1,5 @@ -/* urem.S: This routine was taken from glibc-1.09 and is covered +/* $Id: urem.S,v 1.2 1995/11/25 00:59:11 davem Exp $ + * urem.S: This routine was taken from glibc-1.09 and is covered * by the GNU Library General Public License Version 2. */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile --- v1.3.43/linux/arch/sparc/mm/Makefile Tue Aug 15 20:39:00 1995 +++ linux/arch/sparc/mm/Makefile Sat Nov 25 02:59:19 1995 @@ -1,4 +1,4 @@ -# +# $Id: Makefile,v 1.14 1995/11/25 00:59:17 davem Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -7,7 +7,21 @@ # # Note 2! The CFLAGS definition is now in the main makefile... +# Also note that s4ctlb.o _must_ be the last object file + +#.S.s: +# $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s +.S.o: + $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + +all: mm.o O_TARGET := mm.o -O_OBJS := fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o +O_OBJS := fault.o sun4c_vac.o init.o sun4c.o srmmu.o loadmmu.o mbus.o \ + s4cflush.o + +#s4cflush.o: s4cflush.s + +s4cflush.o: s4cflush.S + $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v1.3.43/linux/arch/sparc/mm/fault.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/mm/fault.c Sat Nov 25 02:59:22 1995 @@ -1,4 +1,5 @@ -/* fault.c: Page fault handlers for the Sparc. +/* $Id: fault.c,v 1.42 1995/11/25 00:59:20 davem Exp $ + * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -19,6 +20,7 @@ #include #include #include +#include #include #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0])) @@ -57,40 +59,40 @@ /* Nice, simple, prom library does all the sweating for us. ;) */ int prom_probe_memory (void) { - register struct linux_mlist_v0 *mlist; - register unsigned long bytes, base_paddr, tally; - register int i; - - i = 0; - mlist= *prom_meminfo()->v0_available; - bytes = tally = mlist->num_bytes; - base_paddr = (unsigned long) mlist->start_adr; + register struct linux_mlist_v0 *mlist; + register unsigned long bytes, base_paddr, tally; + register int i; + + i = 0; + mlist= *prom_meminfo()->v0_available; + bytes = tally = mlist->num_bytes; + base_paddr = (unsigned long) mlist->start_adr; - sp_banks[0].base_addr = base_paddr; - sp_banks[0].num_bytes = bytes; + sp_banks[0].base_addr = base_paddr; + sp_banks[0].num_bytes = bytes; - while (mlist->theres_more != (void *) 0){ - i++; - mlist = mlist->theres_more; - bytes = mlist->num_bytes; - tally += bytes; - if (i >= SPARC_PHYS_BANKS-1) { - printk ("The machine has more banks that this kernel can support\n" - "Increase the SPARC_PHYS_BANKS setting (currently %d)\n", - SPARC_PHYS_BANKS); - i = SPARC_PHYS_BANKS-1; - break; - } + while (mlist->theres_more != (void *) 0){ + i++; + mlist = mlist->theres_more; + bytes = mlist->num_bytes; + tally += bytes; + if (i >= SPARC_PHYS_BANKS-1) { + printk ("The machine has more banks that this kernel can support\n" + "Increase the SPARC_PHYS_BANKS setting (currently %d)\n", + SPARC_PHYS_BANKS); + i = SPARC_PHYS_BANKS-1; + break; + } - sp_banks[i].base_addr = (unsigned long) mlist->start_adr; - sp_banks[i].num_bytes = mlist->num_bytes; - } - - i++; - sp_banks[i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; + sp_banks[i].base_addr = (unsigned long) mlist->start_adr; + sp_banks[i].num_bytes = mlist->num_bytes; + } + + i++; + sp_banks[i].base_addr = 0xdeadbeef; + sp_banks[i].num_bytes = 0; - return tally; + return tally; } /* Traverse the memory lists in the prom to see how much physical we @@ -107,450 +109,195 @@ return total; } -asmlinkage void sparc_txtmem_error(int type, unsigned long sync_err_reg, - unsigned long sync_vaddr, - unsigned long async_err_reg, - unsigned long async_vaddr) +/* Whee, a level 15 NMI interrupt memory error. Let's have fun... */ +asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr, + unsigned long svaddr, unsigned long aerr, + unsigned long avaddr) { - printk("Aieee, sparc text page access error, halting\n"); - printk("type = %d sync_err_reg = 0x%x sync_vaddr = 0x%x\n", - type, (unsigned int) sync_err_reg, (unsigned int) sync_vaddr); - printk("async_err_reg = 0x%x async_vaddr = 0x%x\n", - (unsigned int) async_err_reg, (unsigned int) async_vaddr); - halt(); -} - -/* #define DEBUG_SPARC_TEXT_ACCESS_FAULT */ - -asmlinkage void sparc_text_access_fault(int type, unsigned long sync_err_reg, - unsigned long sync_vaddr, - unsigned long pc, unsigned long psr, - struct pt_regs *regs) -{ - struct vm_area_struct *vma; - unsigned long address; - - address = sync_vaddr; -#ifdef DEBUG_SPARC_TEXT_ACCESS_FAULT - printk("Text FAULT: address = %08lx code = %08lx\n", - (unsigned long) address, (unsigned long) sync_err_reg); - printk("PC = %08lx\n", (unsigned long) regs->pc); - SP_ENTER_DEBUGGER; - halt(); -#endif - vma = find_vma(current, address); - if(!vma) { - goto bad_area; - } - if(vma->vm_start <= address) - goto good_area; - goto bad_area; - -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - handle_mm_fault(vma, address, 0); - return; - -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - if((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); - printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n", - (unsigned long) current->tss.pgd_ptr); - halt(); -} - -asmlinkage void sparc_datamem_error(int type, unsigned long sync_err_reg, - unsigned long sync_vaddr, - unsigned long async_err_reg, - unsigned long async_vaddr) -{ - printk("Aieee, sparc data page access error, halting\n"); - printk("type = %d sync_err_reg = 0x%x sync_vaddr = 0x%x\n", - type, (unsigned int) sync_err_reg, (unsigned int) sync_vaddr); - printk("async_err_reg = 0x%x async_vaddr = 0x%x\n", - (unsigned int) async_err_reg, (unsigned int) async_vaddr); - printk("SYNC PAGE has MMU entry %08lx\n", - (unsigned long) get_pte(sync_vaddr)); - halt(); -} - -/* #define DEBUG_SPARC_DATA_ACCESS_FAULT */ - -asmlinkage void sparc_data_access_fault(int type, unsigned long sync_err_reg, - unsigned long sync_vaddr, - unsigned long pc, unsigned long psr, - struct pt_regs *regs) -{ - struct vm_area_struct *vma; - unsigned long address; - int error_code; - - address = sync_vaddr; -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("Data FAULT: address = %08lx code = %08lx\n", - (unsigned long) address, (unsigned long) sync_err_reg); - printk("PC = %08lx\n", (unsigned long) regs->pc); - printk("PTE = %08lx\n", (unsigned long) get_pte(address)); -#endif - vma = find_vma(current, address); - if(!vma) { -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("NULL VMA\n"); -#endif - goto bad_area; - } - if(vma->vm_start <= address) - goto good_area; - - if(!(vma->vm_flags & VM_GROWSDOWN)) { - goto bad_area; - } - if(vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) { - goto bad_area; - } - - vma->vm_offset -= vma->vm_start - (address & PAGE_MASK); - vma->vm_start = (address & PAGE_MASK); - -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("Found good_area\n"); -#endif - if((sync_err_reg & SUN4C_SYNC_BADWRITE) && - (sync_err_reg & SUN4C_SYNC_NPRESENT)) { - if(!(vma->vm_flags & VM_WRITE)) { -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("oops, vma not writable\n"); -#endif - goto bad_area; - } - } else { - if(sync_err_reg & SUN4C_SYNC_PROT) { -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("PROT violation\n"); -#endif - goto bad_area; - } - if(!(vma->vm_flags & (VM_READ | VM_EXEC))) { -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("vma not readable nor executable\n"); -#endif - goto bad_area; - } - } - - if(sync_err_reg & SUN4C_SYNC_BADWRITE) - error_code = 0x2; - else - error_code = 0x0; - -#ifdef DEBUG_SPARC_DATA_ACCESS_FAULT - printk("calling handle_mm_fault vma=%08lx addr=%08lx code=%d\n", - (unsigned long) vma, (unsigned long) address, - (int) error_code); -#endif - handle_mm_fault(vma, address, error_code); - return; - -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - if (wp_works_ok < 0 && address == 0x0) { - wp_works_ok = 1; - pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_SHARED)); - put_pte((unsigned long) 0x0, pg0[0]); - printk("This Sparc honours the WP bit even when in supervisor mode. Good.\n"); - return; - } - - if((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); - printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n", - (unsigned long) current->tss.pgd_ptr); - halt(); -} - -/* Dump the contents of the SRMMU fsr in a human readable format. */ -void -dump_srmmu_fsr(unsigned long fsr) -{ - unsigned long ebe, l, at, ft, fav, ow; - - ebe = (fsr&SRMMU_FSR_EBE_MASK)>>10; - l = (fsr&SRMMU_FSR_L_MASK)>>8; - at = (fsr&SRMMU_FSR_AT_MASK)>>5; - ft = (fsr&SRMMU_FSR_FT_MASK)>>2; - fav = (fsr&SRMMU_FSR_FAV_MASK)>>1; - ow = (fsr&SRMMU_FSR_OW_MASK); - - printk("FSR %08lx: ", fsr); - - /* Ugh, the ebe is arch-dep, have to find out the meanings. */ - printk("EBE<%s> ", (ebe == 0 ? "none" : (ebe == 1 ? "bus err" : - (ebe == 2 ? "bus timeout" : - (ebe == 4 ? "uncorrectable err" : - (ebe == 8 ? "undefined err" : - (ebe == 16 ? "parity err" : - (ebe == 24 ? "tsunami parity err" : - (ebe == 32 ? "store buf err" : - (ebe == 64 ? "control space err" : - "VIKING emergency response team")))))))))); - printk("L<%s> ", (l == 0 ? "context table" : (l == 1 ? "level1" : - (l == 2 ? "level2" : - "level3")))); - printk("AT<%s> ", (at == 0 ? "user load" : - (at == 1 ? "priv load" : - (at == 2 ? "user rd/exec" : - (at == 3 ? "priv rd/exec" : - (at == 4 ? "user store data" : - (at == 5 ? "priv store data" : - (at == 6 ? "user store inst" : - "priv store inst")))))))); - - printk("FT<%s> ", (ft == 0 ? "none" : - (ft == 1 ? "invalid address" : - (ft == 2 ? "prot violation" : - (ft == 3 ? "priv violation" : - (ft == 4 ? "translation error" : - (ft == 5 ? "bus acc error" : - (ft == 6 ? "internal error" : - "reserved")))))))); - - printk("FAV<%s> ", (fav == 0 ? "faddr invalid" : "faddr valid")); - printk("OW<%s>\n", (ow == 0 ? "fsr not overwritten" : "fsr overwritten")); - - return; -} - -/* #define DEBUG_SRMMU_TEXT_ACCESS_FAULT */ - -void -really_bad_srmmu_fault(int type, unsigned long fstatus, unsigned long faddr) -{ - /* Learn how to handle these later... */ - printk("REALLY BAD SRMMU FAULT DETECTED\n"); - printk("Bailing out...\n"); - dump_srmmu_fsr(fstatus); + printk("FAULT: NMI received\n"); + printk("SREGS: Synchronous Error %08lx\n", serr); + printk(" Synchronous Vaddr %08lx\n", svaddr); + printk(" Asynchronous Error %08lx\n", aerr); + printk(" Asynchronous Vaddr %08lx\n", avaddr); + printk("REGISTER DUMP:\n"); + show_regs(regs); prom_halt(); - return; } -asmlinkage void srmmu_text_access_fault(int type, unsigned long fstatus, - unsigned long faddr, - unsigned long pc, unsigned long psr, - struct pt_regs *regs) +/* Whee, looks like an i386 to me ;-) */ +asmlinkage void do_sparc_fault(struct pt_regs *regs, unsigned long tbr) { - struct vm_area_struct *vma; - unsigned long address; - - /* Check for external bus errors and uncorrectable errors */ - if(fstatus&SRMMU_FSR_EBE_MASK) - printk("External Bus Error detected during a text fault.\n"); - - /* Check for multiple faults... */ - if(fstatus&SRMMU_FSR_OW_MASK && (fstatus&SRMMU_FSR_FT_TRANS)) { - printk("Multiple faults detected in text fault handler\n"); - printk("Fault number one: Text fault at addr %08lx", faddr); - printk("Fault number two: Translation Error\n"); - printk("Giving up...\n"); - prom_halt(); - } - - if(fstatus&(SRMMU_FSR_EBE_BERR | SRMMU_FSR_EBE_BTIMEO | SRMMU_FSR_EBE_UNCOR)) - really_bad_srmmu_fault(type, fstatus, faddr); - - /* Ok, we should be able to handle it at this point. */ - - address = faddr; -#ifdef DEBUG_SRMMU_TEXT_ACCESS_FAULT - printk("Text FAULT: address = %08lx code = %08lx\n", - (unsigned long) address, (unsigned long) fstatus); - printk("PC = %08lx\n", (unsigned long) regs->pc); - dump_srmmu_fsr(fstatus); - halt(); -#endif - - /* Ugh, how often does this happen? ;-( */ - if(!(fstatus&SRMMU_FSR_FAV_MASK)) { - printk("Fault address register is INVALID! Since this is a text\n"); - printk("fault I'll use the value of the trapped PC instead...\n"); - address = regs->pc; - } - - /* Ugh, I don't wanna know... */ - - vma = find_vma(current, address); - if(!vma) { - goto bad_area; - } - if(vma->vm_start <= address) - goto good_area; - goto bad_area; - -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ + struct vm_area_struct *vma; + unsigned long address, error_code, trap_type; + unsigned long from_user; + + from_user = (((regs->psr & PSR_PS) >> 4) ^ FAULT_CODE_USER); + if(get_fault_info(&address, &error_code, from_user)) + goto bad_area; + trap_type = ((tbr>>4)&0xff); + if(trap_type == SP_TRAP_TFLT) { + /* We play it 'safe'... */ + address = regs->pc; + error_code = (from_user); /* no page, read */ + } else if(trap_type != SP_TRAP_DFLT) + panic("Bad sparc trap, trap_type not data or text fault..."); + + /* Now actually handle the fault. Do kernel faults special, + * because on the sun4c we could have faulted trying to read + * the vma area of the task and without the following code + * we'd fault recursively until all our stack is gone. ;-( + * + * XXX I think there are races with this maneuver. XXX + */ + if(!from_user && address >= KERNBASE) { + update_mmu_cache(0, address, __pte(0)); + return; + } + + vma = find_vma(current, address); + if(!vma) + goto bad_area; + if(vma->vm_start <= address) + goto good_area; + if(!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if(expand_stack(vma, address)) + goto bad_area; + /* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ good_area: - do_no_page(vma, address, 0); - return; - -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ + if(error_code & FAULT_CODE_WRITE) { + if(!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + /* Allow reads even for write-only mappings */ + if(!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + handle_mm_fault(vma, address, error_code & FAULT_CODE_WRITE); + return; + /* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ bad_area: - if((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); - printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n", - (unsigned long) current->tss.pgd_ptr); - halt(); + if(error_code & FAULT_CODE_USER) { + current->tss.sig_address = address; + current->tss.sig_desc = SUBSIG_NOMAPPING; + send_sig(SIGSEGV, current, 1); + return; + } + /* Uh oh, a kernel fault. Check for bootup wp_test... */ + if (wp_works_ok < 0 && address == 0x0) { + wp_works_ok = 1; + printk("This Sparc honours the WP bit even when in supervisor mode. " + "Good.\n"); + /* Advance program counter over the store. */ + regs->pc = regs->npc; + regs->npc += 4; + return; + } + if((unsigned long) address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + } else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk("At PC %08lx nPC %08lx\n", (unsigned long) regs->pc, + (unsigned long) regs->npc); + printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n", + (unsigned long) current->tss.pgd_ptr); + show_regs(regs); + panic("KERNAL FAULT"); } -/* #define DEBUG_SRMMU_DATA_ACCESS_FAULT */ - -asmlinkage void srmmu_data_access_fault(int type, unsigned long fstatus, - unsigned long faddr, - unsigned long afstatus, - unsigned long afaddr, - struct pt_regs *regs) -{ - struct vm_area_struct *vma; - unsigned long address, pc, psr; - int error_code; - - pc = regs->pc; - psr= regs->psr; - address = faddr; -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("Data FAULT: address = %08lx code = %08lx\n", - (unsigned long) address, (unsigned long) fstatus); - printk("PC = %08lx\n", (unsigned long) pc); - printk("afsr = %08lx afaddr = %08lx\n", afstatus, afaddr); - dump_srmmu_fsr(fstatus); -#endif - - /* I figure if I make the panic's look like they came from SunOS or Solaris - * my life will be a lot easier ;-) - */ - if(!(fstatus&SRMMU_FSR_FAV_MASK)) { - dump_srmmu_fsr(fstatus); - panic("hat_pteload: Fault address is invalid on a data fault, I'm confused...\n"); - } - -#if 0 /* I see this all the time on supersparcs ;-( */ - if(fstatus&SRMMU_FSR_OW_MASK) { - dump_srmmu_fsr(fstatus); - panic("hat_pteload: Multiple faults at once, giving up...\n"); - } -#endif - - vma = find_vma(current, address); - if(!vma) { -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("NULL VMA\n"); -#endif - goto bad_area; - } - if(vma->vm_start <= address) - goto good_area; - - if(!(vma->vm_flags & VM_GROWSDOWN)) { - goto bad_area; - } - if(vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) { - goto bad_area; - } - - vma->vm_offset -= vma->vm_start - (address & PAGE_MASK); - vma->vm_start = (address & PAGE_MASK); - -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. +/* When the user does not have a mapped stack and we either + * need to read the users register window from that stack or + * we need to save a window to that stack, control flow + * ends up here to investigate the situation. This is a + * very odd situation where a 'user fault' happens from + * kernel space. */ -good_area: -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("Found good_area\n"); -#endif - if((fstatus & SUN4C_SYNC_BADWRITE) && - (fstatus & SUN4C_SYNC_NPRESENT)) { - if(!(vma->vm_flags & VM_WRITE)) { -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("oops, vma not writable\n"); -#endif - goto bad_area; - } - } else { - if(fstatus & SUN4C_SYNC_PROT) { -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("PROT violation\n"); -#endif - goto bad_area; - } - if(!(vma->vm_flags & (VM_READ | VM_EXEC))) { -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("vma not readable nor executable\n"); -#endif - goto bad_area; - } - } - - if(fstatus & SUN4C_SYNC_BADWRITE) - error_code = 0x2; - else - error_code = 0x0; - -#ifdef DEBUG_SRMMU_DATA_ACCESS_FAULT - printk("calling do_no_page vma=%08lx addr=%08lx code=%d\n", - (unsigned long) vma, (unsigned long) address, - (int) error_code); -#endif - do_no_page(vma, address, error_code); - return; -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - if (wp_works_ok < 0 && address == 0x0) { - wp_works_ok = 1; - /* Advance the PC and NPC over the test store. */ - regs->pc = regs->npc; - regs->npc += 4; - printk("This Sparc honours the WP bit even when in supervisor mode. Good.\n"); - return; - } - - if((unsigned long) address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - } else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); - printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n", - (unsigned long) current->tss.pgd_ptr); - halt(); +/* #define DEBUG_WINFAULT */ +extern void show_regwindow(struct reg_window *); +asmlinkage void do_sparc_winfault(struct pt_regs *regs, int push) +{ + int wincount = 0; + int signal = 0; + struct thread_struct *tsp = ¤t->tss; + + flush_user_windows(); +#ifdef DEBUG_WINFAULT + { + int i; + printk("%s[%d]wfault<%d>: WINDOW DUMP --> ", current->comm, + current->pid, push); + if(push==1) + for(i = 0; i < tsp->w_saved; i++) + printk("w[%d]sp<%08lx>, ", + i, tsp->rwbuf_stkptrs[i]); + else + printk("w[0]sp<%08lx>", regs->u_regs[UREG_FP]); + if(push!=2) + printk("\n"); + } +#endif + if(push==1) { + /* We failed to push a window to users stack. */ + while(wincount < tsp->w_saved) { + if ((tsp->rwbuf_stkptrs[wincount] & 7) || + (tsp->rwbuf_stkptrs[wincount] > KERNBASE) || + verify_area(VERIFY_WRITE, + (char *) tsp->rwbuf_stkptrs[wincount], + sizeof(struct reg_window))) { + signal = SIGILL; + break; + } + /* Do it! */ + memcpy((char *) tsp->rwbuf_stkptrs[wincount], + (char *)&tsp->reg_window[wincount], + sizeof(struct reg_window)); + wincount++; + } + } else { + /* We failed to pull a window from users stack. + * For a window underflow from userland we need + * to verify two stacks, for a return from trap + * we need only inspect the one at UREG_FP. + */ + if((regs->u_regs[UREG_FP] & 7) || + (regs->u_regs[UREG_FP] > KERNBASE) || + verify_area(VERIFY_READ, + (char *) regs->u_regs[UREG_FP], + sizeof(struct reg_window))) + signal = SIGILL; + else + memcpy((char *)&tsp->reg_window[0], + (char *) regs->u_regs[UREG_FP], + sizeof(struct reg_window)); + if(push==2 && !signal) { + unsigned long sp = tsp->reg_window[0].ins[6]; +#ifdef DEBUG_WINFAULT + printk(", w[1]sp<%08lx>\n", sp); + show_regwindow(&tsp->reg_window[0]); +#endif + if((sp & 7) || (sp > KERNBASE) || + verify_area(VERIFY_READ, (char *) sp, + sizeof(struct reg_window))) + signal = SIGILL; + else + memcpy((char *)&tsp->reg_window[1], + (char *) sp, sizeof(struct reg_window)); + } + } + if(signal) { + printk("%s[%d]: User has trashed stack pointer pc<%08lx>sp<%08lx>\n", + current->comm, current->pid, regs->pc, regs->u_regs[UREG_FP]); + tsp->sig_address = regs->pc; + tsp->sig_desc = SUBSIG_STACK; + send_sig(signal, current, 1); + } else + tsp->w_saved = 0; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v1.3.43/linux/arch/sparc/mm/init.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/mm/init.c Sat Nov 25 02:59:24 1995 @@ -1,4 +1,4 @@ -/* +/* $Id: init.c,v 1.26 1995/11/25 00:59:22 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -23,29 +23,10 @@ #include #include -extern void scsi_mem_init(unsigned long); -extern void sound_mem_init(void); -extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; -/* The following number keeps track of which page table is to - * next be allocated in a page. This is necessary since there - * are 16 page tables per page on the space. - */ -unsigned long ptr_in_current_pgd; - -/* This keeps track of which physical segments are in use right now. */ -unsigned int phys_seg_map[PSEG_ENTRIES]; -unsigned int phys_seg_life[PSEG_ENTRIES]; - -/* Context allocation. */ -struct task_struct *ctx_tasks[MAX_CTXS]; -int ctx_tasks_last_frd; - -extern int invalid_segment, num_segmaps, num_contexts; - /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -82,18 +63,18 @@ int i,free = 0,total = 0,reserved = 0; int shared = 0; - printk("Mem-info:\n"); + printk("\nMem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = high_memory >> PAGE_SHIFT; + i = MAP_NR(high_memory); while (i-- > 0) { total++; - if (mem_map[i] & MAP_PAGE_RESERVED) + if (mem_map[i].reserved) reserved++; - else if (!mem_map[i]) + else if (!mem_map[i].count) free++; else - shared += mem_map[i]-1; + shared += mem_map[i].count-1; } printk("%d pages of RAM\n",total); printk("%d free pages\n",free); @@ -105,7 +86,6 @@ #endif } -extern unsigned long free_area_init(unsigned long, unsigned long); extern pgprot_t protection_map[16]; /* @@ -119,57 +99,51 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) { - int i; - switch(sparc_cpu_model) { case sun4c: + case sun4e: start_mem = sun4c_paging_init(start_mem, end_mem); break; case sun4m: case sun4d: - case sun4e: start_mem = srmmu_paging_init(start_mem, end_mem); break; default: printk("paging_init: Cannot init paging on this Sparc\n"); printk("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model); printk("paging_init: Halting...\n"); - halt(); + panic("paging_init"); }; - /* Initialize context map. */ - for(i=0; i= base) && (phys_addr < limit) && + ((phys_addr + PAGE_SIZE) < limit)) + mem_map[MAP_NR(addr)].reserved = 0; + } + } for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { - if(mem_map[MAP_NR(addr)]) { + if(mem_map[MAP_NR(addr)].reserved) { if (addr < (unsigned long) &etext) codepages++; else if(addr < start_mem) datapages++; - else - reservedpages++; continue; } - mem_map[MAP_NR(addr)] = 1; + mem_map[MAP_NR(addr)].count = 1; free_page(addr); } tmp2 = nr_free_pages << PAGE_SHIFT; - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n", + printk("Memory: %luk available (%dk kernel code, %dk data)\n", tmp2 >> 10, - (high_memory - PAGE_OFFSET) >> 10, codepages << (PAGE_SHIFT-10), - reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10)); -/* Heh, test write protection just like the i386, this is bogus but it is - * fun to do ;) - */ switch(sparc_cpu_model) { case sun4c: - start_mem = sun4c_test_wp(start_mem); + case sun4e: + sun4c_lock_entire_kernel(start_mem); + sun4c_test_wp(); break; case sun4m: case sun4d: - case sun4e: srmmu_test_wp(); break; default: printk("mem_init: Could not test WP bit on this machine.\n"); printk("mem_init: sparc_cpu_model = %d\n", sparc_cpu_model); printk("mem_init: Halting...\n"); - halt(); + panic("mem_init()"); }; - -#ifdef DEBUG_MEMINIT - printk("Breaker breaker...Roger roger.... Over and out...\n"); -#endif - invalidate(); - - return; } void si_meminfo(struct sysinfo *val) { int i; - i = high_memory >> PAGE_SHIFT; + i = MAP_NR(high_memory); val->totalram = 0; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = buffermem; while (i-- > 0) { - if (mem_map[i] & MAP_PAGE_RESERVED) + if (mem_map[i].reserved) continue; val->totalram++; - if (!mem_map[i]) + if (!mem_map[i].count) continue; - val->sharedram += mem_map[i]-1; + val->sharedram += mem_map[i].count-1; } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; - return; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c --- v1.3.43/linux/arch/sparc/mm/loadmmu.c Sun Sep 3 12:26:49 1995 +++ linux/arch/sparc/mm/loadmmu.c Sat Nov 25 02:59:26 1995 @@ -1,16 +1,38 @@ -/* loadmmu.c: This code loads up all the mm function pointers once the +/* $Id: loadmmu.c,v 1.13 1995/11/25 00:59:24 davem Exp $ + * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include + #include #include #include +struct ctx_list *ctx_list_pool; +struct ctx_list ctx_free; +struct ctx_list ctx_used; + +void (*mmu_exit_hook)(void *); +void (*mmu_fork_hook)(void *, unsigned long); +void (*mmu_release_hook)(void *); +void (*mmu_flush_hook)(void *); +void (*mmu_task_cacheflush)(void *); + +char *(*mmu_lockarea)(char *, unsigned long); +void (*mmu_unlockarea)(char *, unsigned long); +char *(*mmu_get_scsi_buffer)(char *, unsigned long); +void (*mmu_release_scsi_buffer)(char *, unsigned long); + + +int (*get_fault_info)(unsigned long *, unsigned long *, unsigned long); +void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte); + void (*invalidate)(void); -void (*set_pte)(pte_t *ptep, pte_t entry); +void (*set_pte)(pte_t *pteptr, pte_t pteval); unsigned int pmd_shift, pmd_size, pmd_mask; unsigned int (*pmd_align)(unsigned int); @@ -21,14 +43,13 @@ pgprot_t page_none, page_shared, page_copy, page_readonly, page_kernel; pgprot_t page_invalid; -/* Grrr... function pointers galore... */ unsigned long (*pte_page)(pte_t); unsigned long (*pmd_page)(pmd_t); unsigned long (*pgd_page)(pgd_t); void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir); unsigned long (*(vmalloc_start))(void); -void (*switch_to_context)(int); +void (*switch_to_context)(void *vtask); int (*pte_none)(pte_t); int (*pte_present)(pte_t); @@ -51,9 +72,9 @@ void (*pgd_reuse)(pgd_t *); pte_t (*mk_pte)(unsigned long, pgprot_t); -void (*pgd_set)(pgd_t *, pte_t *); +void (*pgd_set)(pgd_t *, pmd_t *); pte_t (*pte_modify)(pte_t, pgprot_t); -pgd_t * (*pgd_offset)(struct task_struct *, unsigned long); +pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long); pmd_t * (*pmd_offset)(pgd_t *, unsigned long); pte_t * (*pte_offset)(pmd_t *, unsigned long); void (*pte_free_kernel)(pte_t *); @@ -70,10 +91,6 @@ pgd_t * (*pgd_alloc)(void); -/* - * The following only work if pte_present() is true. - * Undefined behaviour if not.. - */ int (*pte_read)(pte_t); int (*pte_write)(pte_t); int (*pte_exec)(pte_t); @@ -94,6 +111,9 @@ pte_t (*pte_mkyoung)(pte_t); pte_t (*pte_mkcow)(pte_t); +unsigned long (*sparc_virt_to_phys)(unsigned long); +unsigned long (*sparc_phys_to_virt)(unsigned long); + extern void ld_mmu_sun4c(void); extern void ld_mmu_srmmu(void); @@ -110,10 +130,9 @@ ld_mmu_srmmu(); break; default: - printk("load_mmu: MMU support not available for this architecture\n"); - printk("load_mmu: sparc_cpu_model = %d\n", (int) sparc_cpu_model); - printk("load_mmu: Halting...\n"); - halt(); + printk("load_mmu:MMU support not available for this architecture\n"); + printk("load_mmu:sparc_cpu_model = %d\n", (int) sparc_cpu_model); + printk("load_mmu:Halting...\n"); + panic("load_mmu()"); }; - return; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/mbus.c linux/arch/sparc/mm/mbus.c --- v1.3.43/linux/arch/sparc/mm/mbus.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/mm/mbus.c Sat Nov 25 02:59:27 1995 @@ -0,0 +1,186 @@ +/* $Id: mbus.c,v 1.9 1995/11/25 00:59:26 davem Exp $ + * mbus.c: MBUS probing routines, called from kernel/probe.c + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG_MBUS */ + +unsigned int viking_rev, swift_rev, cypress_rev; +enum mbus_module srmmu_modtype; +unsigned int hwbug_bitmask; + +void +probe_mbus(void) +{ + register unsigned int mreg, vaddr; + register int impl, vers, syscntrl, pso, resv, nofault, enable; + register int mod_typ, mod_rev; + + srmmu_modtype = SRMMU_INVAL_MOD; + hwbug_bitmask = 0; + vaddr = 0; + + mreg = srmmu_get_mmureg(); + impl = (mreg & SRMMU_CTREG_IMPL_MASK) >> SRMMU_CTREG_IMPL_SHIFT; + vers = (mreg & SRMMU_CTREG_VERS_MASK) >> SRMMU_CTREG_VERS_SHIFT; + syscntrl = (mreg & SRMMU_CTREG_SYSCNTRL_MASK) >> SRMMU_CTREG_SYSCNTRL_SHIFT; + pso = (mreg & SRMMU_CTREG_PSO_MASK) >> SRMMU_CTREG_PSO_SHIFT; + resv = (mreg & SRMMU_CTREG_RESV_MASK) >> SRMMU_CTREG_RESV_SHIFT; + nofault = (mreg & SRMMU_CTREG_NOFAULT_MASK) >> SRMMU_CTREG_NOFAULT_SHIFT; + enable = (mreg & SRMMU_CTREG_ENABLE_MASK) >> SRMMU_CTREG_ENABLE_SHIFT; + +#ifdef DEBUG_MBUS + printk("MMU REGISTER\n"); + printk("IMPL<%01x> VERS<%01x> SYSCNTRL<%04x> PSO<%d> RESV<%02x> NOFAULT<%d> ENABLE<%d>\n", + impl, vers, syscntrl, (int) pso, resv, (int) nofault, (int) enable); +#endif + + mod_typ = impl; mod_rev = vers; + printk("MBUS: "); + + if(mod_typ == 0x1) /* Ross HyperSparc or Cypress */ + if (mod_rev == 0x7) { + srmmu_modtype = HyperSparc; + hwbug_bitmask |= HWBUG_VACFLUSH_BITROT; + /* Turn off Cache Wrapping and copyback caching, I don't + * understand them completely yet... */ + printk("Enabling HyperSparc features...\n"); + /* FUCK IT, I wanna see this baby chug! */ + /* First, flush the cache */ +#if 0 + for(vaddr = 0; vaddr != vac_size; vaddr+=vac_linesize) + flush_ei_ctx(vaddr); +#endif + mreg &= (~HYPERSPARC_CWENABLE); + mreg &= (~HYPERSPARC_CMODE); + mreg &= (~HYPERSPARC_WBENABLE); + mreg |= (HYPERSPARC_CENABLE); + srmmu_set_mmureg(mreg); + /* Clear all the cache tags */ +#if 0 + for(vaddr = 0; vaddr != vac_size; vaddr+=vac_linesize) + __asm__ __volatile__("sta %%g0, [%0] %1" : : + "r" (vaddr), "i" (0xe)); +#endif + /* Flush the ICACHE */ + flush_whole_icache(); + + } else { + cypress_rev = mod_rev; + if(mod_rev == 0xe) { + srmmu_modtype = Cypress_vE; + hwbug_bitmask |= HWBUG_COPYBACK_BROKEN; + } else + if(mod_rev == 0xd) { + srmmu_modtype = Cypress_vD; + hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN; + } else + srmmu_modtype = Cypress; + + /* It is a Cypress module */ + printk("ROSS Cypress Module %s\n", + (srmmu_modtype == Cypress_vE ? "Rev. E" : + (srmmu_modtype == Cypress_vD ? "Rev. D" : + ""))); + /* Enable Cypress features */ + printk("Enabling Cypress features...\n"); + mreg &= (~CYPRESS_CMODE); + mreg |= (CYPRESS_CENABLE); + srmmu_set_mmureg(mreg); + /* Maybe play with Cypress 604/605 cache stuff here? */ + } + + + if(((get_psr()>>0x18)&0xff)==0x04) { + __asm__ __volatile__("lda [%1] %2, %0\n\t" + "srl %0, 0x18, %0\n\t" : + "=r" (swift_rev) : + "r" (0x10003000), "i" (0x20)); + printk("Fujitsu MB86904 or higher Swift module\n"); /* MB86905 etc. */ + switch(swift_rev) { + case 0x11: + case 0x20: + case 0x23: + case 0x30: + srmmu_modtype = Swift_lots_o_bugs; + hwbug_bitmask |= HWBUG_KERN_ACCBROKEN; + hwbug_bitmask |= HWBUG_KERN_CBITBROKEN; + printk("Detected Swift with Lots 'o' Bugs\n"); + break; + case 0x25: + case 0x31: + srmmu_modtype = Swift_bad_c; + hwbug_bitmask |= HWBUG_KERN_CBITBROKEN; + printk("Detected Swift with kernel pte C bit bug\n"); + break; + default: + srmmu_modtype = Swift_ok; + printk("Detected Swift with no bugs...\n"); + break; + } + /* Enable Fujitsu Swift specific features here... */ + printk("Enabling Swift features...\n"); + mreg |= 0; + srmmu_set_mmureg(mreg); + } + + if((((get_psr()>>0x18)&0xff)==0x40 || + (((get_psr()>>0x18)&0xff)==0x41 && mod_typ==0 && mod_rev==0))) { + if(((get_psr()>>0x18)&0xf)==0 && mod_rev==0) { + srmmu_modtype = Viking_12; + hwbug_bitmask |= HWBUG_MODIFIED_BITROT; + hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; + } else { + if(((get_psr()>>0x18)&0xf)!=0) { + srmmu_modtype = Viking_2x; + hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; + } else + if(mod_rev==1) { + srmmu_modtype = Viking_30; + hwbug_bitmask |= HWBUG_PACINIT_BITROT; + } else { + if (mod_rev<8) + srmmu_modtype = Viking_35; + else + srmmu_modtype = Viking_new; + } + } + + /* SPARCclassic's STP1010 may be produced under other name */ + printk("VIKING Module\n"); + printk("Enabling Viking features...\n"); + mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE | + VIKING_TCENABLE | VIKING_DPENABLE); + srmmu_set_mmureg(mreg); + } + + if((((get_psr()>>0x18)&0xff)==0x41) && (mod_typ || mod_rev)) { + srmmu_modtype = Tsunami; + printk("Tsunami module\n"); + /* Enable Tsunami features */ + } + + if(srmmu_modtype == SRMMU_INVAL_MOD) { + printk("Unknown SRMMU module type!\n"); + printk("MMU_CREG: impl=%x vers=%x\n", mod_typ, mod_rev); + printk("PSR: impl=%x vers=%x\n", ((get_psr()>>28)&0xf), + ((get_psr()>>24)&0xf)); + panic("probe_mbus()"); + } + + /* AIEEE, should get this from the prom... */ + printk("Boot processor ID %d Module ID %d (%s MBUS)\n", + get_cpuid(), get_modid(), (get_modid() == 0x8 ? "Level 1" : "Level 2")); +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/s4cflush.S linux/arch/sparc/mm/s4cflush.S --- v1.3.43/linux/arch/sparc/mm/s4cflush.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/mm/s4cflush.S Sat Nov 25 02:59:32 1995 @@ -0,0 +1,575 @@ +/* $Id: s4cflush.S,v 1.8 1995/11/25 00:59:29 davem Exp $ + * s4cflush.S: Inline management of the sun4c cache. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include + +/* We need to be able to call a routine which will in low-level + * assembly flush an entire segment from the virtual cache using + * a base virtual address and that will use as few registers as + * possible. The address of that function is stored here. + * The register usage for this routine is defined as + * %l2 -- Address of Segment to flush + * %l4 -- Return address + * %l6 -- scratch + * %l7 -- scratch + */ + .align 4 + .globl C_LABEL(sun4c_ctxflush), C_LABEL(sun4c_segflush) + .globl C_LABEL(sun4c_pgflush) +C_LABEL(sun4c_ctxflush): .word C_LABEL(sun4c_ctxflush_sw64KB16B) +C_LABEL(sun4c_segflush): .word C_LABEL(sun4c_segflush_sw64KB16B) +C_LABEL(sun4c_pgflush): .word C_LABEL(sun4c_pgflush_sw64KB16B) + + .text + + /* Here are the assembly in-line virtual cache flushing + * routines on the sun4c. + */ + + .align 4 + .globl C_LABEL(sun4c_ctxflush_hw64KB16B) + + /* Flush an entire context using hardware assisted flushes + * for a cache of size 64KB with 16B lines. + */ +C_LABEL(sun4c_ctxflush_hw64KB16B): + sethi %hi(PAGE_SIZE), %l6 + /* Now flush 16 pages starting at virtual address zero */ + or %g0, %g0, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* One */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Two */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Three */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Four */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Five */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Six */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Seven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Eight */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Nine */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Ten */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Eleven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Twelve */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Thirteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Fourteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Fifteen */ + add %l7, %l6, %l7 + + /* Return to caller and flush the last page */ + jmpl %l4 + 0x8, %g0 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Sixteen */ + + + .globl C_LABEL(sun4c_ctxflush_sw64KB16B) + + /* Flush an entire context using software flushes + * for a cache of size 64KB with 16B lines. + */ +C_LABEL(sun4c_ctxflush_sw64KB16B): + /* Starting at virtual address zero, software flush + * 4096 lines at 16 byte intervals. + */ +#define SWFLUSHCTX16_2LINES \ + sta %g0, [%l7] ASI_FLUSHCTX; \ + add %l7, 0x10, %l7; \ + sta %g0, [%l7] ASI_FLUSHCTX; \ + add %l7, 0x10, %l7; \ + +#define SWFLUSHCTX16_4LINES \ + SWFLUSHCTX16_2LINES \ + SWFLUSHCTX16_2LINES \ + +#define SWFLUSHCTX16_8LINES \ + SWFLUSHCTX16_4LINES \ + SWFLUSHCTX16_4LINES \ + +#define SWFLUSHCTX16_16LINES \ + SWFLUSHCTX16_8LINES \ + SWFLUSHCTX16_8LINES \ + +#define SWFLUSHCTX16_32LINES \ + SWFLUSHCTX16_16LINES \ + SWFLUSHCTX16_16LINES \ + +#define SWFLUSHCTX16_64LINES \ + SWFLUSHCTX16_32LINES \ + SWFLUSHCTX16_32LINES \ + +#define SWFLUSHCTX16_128LINES \ + SWFLUSHCTX16_64LINES \ + SWFLUSHCTX16_64LINES \ + +#define SWFLUSHCTX16_256LINES \ + SWFLUSHCTX16_128LINES \ + SWFLUSHCTX16_128LINES \ + + /* WHEE! */ + or %g0, %g0, %l7 /* Base register */ + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + + /* Done, return to caller */ + jmpl %l4 + 0x8, %g0 + nop + + .globl C_LABEL(sun4c_ctxflush_hw64KB32B) + /* Flush an entire context using hardware assisted flushes + * for a cache of size 64KB with 32B lines. + */ +C_LABEL(sun4c_ctxflush_hw64KB32B): + sethi %hi(PAGE_SIZE), %l6 + /* Now flush 16 pages starting at virtual address zero */ + or %g0, %g0, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* One */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Two */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Three */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Four */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Five */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Six */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Seven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Eight */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Nine */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Ten */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Eleven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Twelve */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Thirteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Fourteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Fifteen */ + add %l7, %l6, %l7 + + /* Return to caller and flush the last page */ + jmpl %l4 + 0x8, %g0 + sta %g0, [%l7] ASI_HWFLUSHCONTEXT /* Sixteen */ + + .globl C_LABEL(sun4c_ctxflush_sw64KB32B) + + /* Flush an entire context using software flushes + * for a cache of size 64KB with 32B lines. + */ +C_LABEL(sun4c_ctxflush_sw64KB32B): + /* Starting at virtual address zero, software flush + * 2048 lines at 32 byte intervals. + */ +#define SWFLUSHCTX32_2LINES \ + sta %g0, [%l7] ASI_FLUSHCTX; \ + add %l7, 0x20, %l7; \ + sta %g0, [%l7] ASI_FLUSHCTX; \ + add %l7, 0x20, %l7; \ + +#define SWFLUSHCTX32_4LINES \ + SWFLUSHCTX32_2LINES \ + SWFLUSHCTX32_2LINES \ + +#define SWFLUSHCTX32_8LINES \ + SWFLUSHCTX32_4LINES \ + SWFLUSHCTX32_4LINES \ + +#define SWFLUSHCTX32_16LINES \ + SWFLUSHCTX32_8LINES \ + SWFLUSHCTX32_8LINES \ + +#define SWFLUSHCTX32_32LINES \ + SWFLUSHCTX32_16LINES \ + SWFLUSHCTX32_16LINES \ + +#define SWFLUSHCTX32_64LINES \ + SWFLUSHCTX32_32LINES \ + SWFLUSHCTX32_32LINES \ + +#define SWFLUSHCTX32_128LINES \ + SWFLUSHCTX32_64LINES \ + SWFLUSHCTX32_64LINES \ + + /* WHEE! */ + or %g0, %g0, %l7 /* Base register */ + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX32_128LINES + SWFLUSHCTX16_256LINES + SWFLUSHCTX16_256LINES + + jmpl %l4 + 0x8, %g0 + nop + + .align 4 + .globl C_LABEL(sun4c_segflush_hw64KB16B) + + /* Flush an entire segment using hardware assisted flushes + * for a cache of size 64KB with 16B lines. + */ +C_LABEL(sun4c_segflush_hw64KB16B): + sethi %hi(PAGE_SIZE), %l6 /* Increment */ + sethi %hi(0xfffc0000), %l7 + and %l2, %l7, %l7 /* Base address */ + + /* Now flush 16 pages starting at beginning of vseg */ + sta %g0, [%l7] ASI_HWFLUSHSEG /* One */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Two */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Three */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Four */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Five */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Six */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Seven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Eight */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Nine */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Ten */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Eleven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Twelve */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Thirteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Fourteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Fifteen */ + add %l7, %l6, %l7 + + /* Return to caller and flush the last page */ + jmpl %l4 + 0x8, %g0 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Sixteen */ + + .globl C_LABEL(sun4c_segflush_sw64KB16B) + + /* Flush an entire segment using software flushes + * for a cache of size 64KB with 16B lines. + */ +C_LABEL(sun4c_segflush_sw64KB16B): + /* Starting at virtual address in %l2, software flush + * 4096 lines at 16 byte intervals. + */ +#define SWFLUSHSEG16_2LINES \ + sta %g0, [%l7] ASI_FLUSHSEG; \ + add %l7, 0x10, %l7; \ + sta %g0, [%l7] ASI_FLUSHSEG; \ + add %l7, 0x10, %l7; \ + +#define SWFLUSHSEG16_4LINES \ + SWFLUSHSEG16_2LINES \ + SWFLUSHSEG16_2LINES \ + +#define SWFLUSHSEG16_8LINES \ + SWFLUSHSEG16_4LINES \ + SWFLUSHSEG16_4LINES \ + +#define SWFLUSHSEG16_16LINES \ + SWFLUSHSEG16_8LINES \ + SWFLUSHSEG16_8LINES \ + +#define SWFLUSHSEG16_32LINES \ + SWFLUSHSEG16_16LINES \ + SWFLUSHSEG16_16LINES \ + +#define SWFLUSHSEG16_64LINES \ + SWFLUSHSEG16_32LINES \ + SWFLUSHSEG16_32LINES \ + +#define SWFLUSHSEG16_128LINES \ + SWFLUSHSEG16_64LINES \ + SWFLUSHSEG16_64LINES \ + +#define SWFLUSHSEG16_256LINES \ + SWFLUSHSEG16_128LINES \ + SWFLUSHSEG16_128LINES \ + + sethi %hi(0xfffc0000), %l7 + and %l2, %l7, %l7 /* Base register */ + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + SWFLUSHSEG16_256LINES + + /* Done, return to caller */ + jmpl %l4 + 0x8, %g0 + nop + + .globl C_LABEL(sun4c_segflush_hw64KB32B) + + /* Flush an entire segment using hardware assisted flushes + * for a cache of size 64KB with 32B lines. + */ +C_LABEL(sun4c_segflush_hw64KB32B): + sethi %hi(PAGE_SIZE), %l6 /* Increment */ + sethi %hi(0xfffc0000), %l7 + and %l2, %l7, %l7 /* Base register */ + + /* Now flush 16 pages starting at virtual address in %l7 */ + sta %g0, [%l7] ASI_HWFLUSHSEG /* One */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Two */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Three */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Four */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Five */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Six */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Seven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Eight */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Nine */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Ten */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Eleven */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Twelve */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Thirteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Fourteen */ + add %l7, %l6, %l7 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Fifteen */ + add %l7, %l6, %l7 + + /* Return to caller and flush the last page */ + jmpl %l4 + 0x8, %g0 + sta %g0, [%l7] ASI_HWFLUSHSEG /* Sixteen */ + + .globl C_LABEL(sun4c_segflush_sw64KB32B) + + /* Flush an entire segment using software flushes + * for a cache of size 64KB with 32B lines. + */ +C_LABEL(sun4c_segflush_sw64KB32B): + /* Starting at virtual address passed in %l2, software + * flush 2048 lines at 32 byte intervals. + */ +#define SWFLUSHSEG32_2LINES \ + sta %g0, [%l7] ASI_FLUSHSEG; \ + add %l7, 0x20, %l7; \ + sta %g0, [%l7] ASI_FLUSHSEG; \ + add %l7, 0x20, %l7; \ + +#define SWFLUSHSEG32_4LINES \ + SWFLUSHSEG32_2LINES \ + SWFLUSHSEG32_2LINES \ + +#define SWFLUSHSEG32_8LINES \ + SWFLUSHSEG32_4LINES \ + SWFLUSHSEG32_4LINES \ + +#define SWFLUSHSEG32_16LINES \ + SWFLUSHSEG32_8LINES \ + SWFLUSHSEG32_8LINES \ + +#define SWFLUSHSEG32_32LINES \ + SWFLUSHSEG32_16LINES \ + SWFLUSHSEG32_16LINES \ + +#define SWFLUSHSEG32_64LINES \ + SWFLUSHSEG32_32LINES \ + SWFLUSHSEG32_32LINES \ + +#define SWFLUSHSEG32_128LINES \ + SWFLUSHSEG32_64LINES \ + SWFLUSHSEG32_64LINES \ + + /* WHEE! */ + sethi %hi(0xfffc0000), %l7 + and %l2, %l7, %l7 /* Base register */ + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + SWFLUSHSEG32_128LINES + + jmpl %l4 + 0x8, %g0 + nop + + .align 4 + .globl C_LABEL(sun4c_pgflush_hw64KB16B) + .globl C_LABEL(sun4c_pgflush_hw64KB32B) + + /* Flush a page using hardware assisted flushes + * for a cache of size 64KB with 16B or 32B lines. + */ +C_LABEL(sun4c_pgflush_hw64KB16B): +C_LABEL(sun4c_pgflush_hw64KB32B): + /* Easiest flush possible on sun4c */ + jmpl %l4 + 0x8, %g0 + sta %g0, [%l2] ASI_HWFLUSHPAGE + + .globl C_LABEL(sun4c_pgflush_sw64KB16B) + /* Flush a page using software flushes for a cache + * of size 64KB with 16B lines. + */ +C_LABEL(sun4c_pgflush_sw64KB16B): + /* Flush every line within the page */ +#define SWFLUSHPG16_2LINES \ + sta %g0, [%l7] ASI_FLUSHPG; \ + add %l7, 0x10, %l7; \ + sta %g0, [%l7] ASI_FLUSHPG; \ + add %l7, 0x10, %l7; \ + +#define SWFLUSHPG16_4LINES \ + SWFLUSHPG16_2LINES \ + SWFLUSHPG16_2LINES \ + +#define SWFLUSHPG16_8LINES \ + SWFLUSHPG16_4LINES \ + SWFLUSHPG16_4LINES \ + +#define SWFLUSHPG16_16LINES \ + SWFLUSHPG16_8LINES \ + SWFLUSHPG16_8LINES \ + +#define SWFLUSHPG16_32LINES \ + SWFLUSHPG16_16LINES \ + SWFLUSHPG16_16LINES \ + +#define SWFLUSHPG16_64LINES \ + SWFLUSHPG16_32LINES \ + SWFLUSHPG16_32LINES \ + +#define SWFLUSHPG16_128LINES \ + SWFLUSHPG16_64LINES \ + SWFLUSHPG16_64LINES \ + +#define SWFLUSHPG16_256LINES \ + SWFLUSHPG16_128LINES \ + SWFLUSHPG16_128LINES \ + + or %l2, %g0, %l7 /* Base address of page */ + SWFLUSHPG16_256LINES + + /* Return to caller and flush last line */ + jmpl %l4 + 0x8, %g0 + nop + + .globl C_LABEL(sun4c_pgflush_sw64KB32B) + /* Flush a page using software flushes for a cache + * of size 64KB with 32B lines. + */ +C_LABEL(sun4c_pgflush_sw64KB32B): + /* Flush every line within the page */ +#define SWFLUSHPG32_2LINES \ + sta %g0, [%l7] ASI_FLUSHPG; \ + add %l7, 0x20, %l7; \ + sta %g0, [%l7] ASI_FLUSHPG; \ + add %l7, 0x20, %l7; \ + +#define SWFLUSHPG32_4LINES \ + SWFLUSHPG32_2LINES \ + SWFLUSHPG32_2LINES \ + +#define SWFLUSHPG32_8LINES \ + SWFLUSHPG32_4LINES \ + SWFLUSHPG32_4LINES \ + +#define SWFLUSHPG32_16LINES \ + SWFLUSHPG32_8LINES \ + SWFLUSHPG32_8LINES \ + +#define SWFLUSHPG32_32LINES \ + SWFLUSHPG32_16LINES \ + SWFLUSHPG32_16LINES \ + +#define SWFLUSHPG32_64LINES \ + SWFLUSHPG32_32LINES \ + SWFLUSHPG32_32LINES \ + +#define SWFLUSHPG32_128LINES \ + SWFLUSHPG32_64LINES \ + SWFLUSHPG32_64LINES \ + + or %l2, %g0, %l7 /* Base address of page */ + SWFLUSHPG32_128LINES + + /* Return to caller and flush last line */ + jmpl %l4 + 0x8, %g0 + nop + +/* All that crap just to flush a fucking virtual cache, sheesh... */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v1.3.43/linux/arch/sparc/mm/srmmu.c Sun Sep 3 12:26:49 1995 +++ linux/arch/sparc/mm/srmmu.c Sat Nov 25 02:59:35 1995 @@ -1,4 +1,5 @@ -/* srmmu.c: SRMMU specific routines for memory management. +/* $Id: srmmu.c,v 1.22 1995/11/25 00:59:33 davem Exp $ + * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@lab.ipmce.su) @@ -20,53 +21,6 @@ unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); } unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); } -/* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job. - * Many of the page table/directory functions on the SRMMU use this - * routine. - * - * Having a complete physical ram structure walk happen for each - * invocation is quite costly. However, this does do some nice - * sanity checking and we'll see when our maps don't match. Eventually - * when I trust my code I will just do a direct mmu probe in mk_pte(). - */ -static inline unsigned int -srmmu_virt_to_phys(unsigned int vaddr) -{ - unsigned int paddr = 0; - unsigned int voff = (vaddr - PAGE_OFFSET); - int i; - - for(i=0; sp_banks[i].num_bytes != 0; i++) { - if(voff < paddr + sp_banks[i].num_bytes) { - /* This matches. */ - return sp_banks[i].base_addr + voff - paddr; - } else - paddr += sp_banks[i].num_bytes; - } - /* Shit, gotta consult the MMU, this shouldn't happen... */ - printk("srmmu_virt_to_phys: SRMMU virt to phys translation failed, halting\n"); - halt(); -} - -static inline unsigned long -srmmu_phys_to_virt(unsigned long paddr) -{ - int i; - unsigned long offset = PAGE_OFFSET; - - for (i=0; sp_banks[i].num_bytes != 0; i++) - { - if (paddr >= sp_banks[i].base_addr && - paddr < (sp_banks[i].base_addr - + sp_banks[i].num_bytes)) { - return (paddr - sp_banks[i].base_addr) + offset; - } else - offset += sp_banks[i].num_bytes; - } - printk("srmmu_phys_to_virt: Could not make translation, halting...\n"); - halt(); -} - unsigned long srmmu_vmalloc_start(void) { @@ -79,7 +33,7 @@ unsigned long page; page = (pmd_val(pmd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT; - return srmmu_phys_to_virt(page); + return (page + PAGE_OFFSET); } unsigned long @@ -88,7 +42,7 @@ unsigned long page; page = (pgd_val(pgd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT; - return srmmu_phys_to_virt(page); + return (page + PAGE_OFFSET); } unsigned long @@ -97,18 +51,17 @@ unsigned long page; page = (pte_val(pte) & (SRMMU_PTE_PPN_MASK)) << SRMMU_PTE_PPN_PADDR_SHIFT; - printk("srmmu_pte_page: page = %08lx\n", page); - return srmmu_phys_to_virt(page); + return (page + PAGE_OFFSET); } int srmmu_pte_none(pte_t pte) { return !pte_val(pte); } int srmmu_pte_present(pte_t pte) { return pte_val(pte) & SRMMU_ET_PTE; } -int srmmu_pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] != 1; } +int srmmu_pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; } void srmmu_pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } void srmmu_pte_reuse(pte_t *ptep) { - if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED)) - mem_map[MAP_NR(ptep)]++; + if(!mem_map[MAP_NR(ptep)].reserved) + mem_map[MAP_NR(ptep)].count++; } int srmmu_pmd_none(pmd_t pmd) { return !pmd_val(pmd); } @@ -119,12 +72,12 @@ } int srmmu_pmd_present(pmd_t pmd) { return pmd_val(pmd) & SRMMU_ET_PTD; } -int srmmu_pmd_inuse(pmd_t *pmdp) { return mem_map[MAP_NR(pmdp)] != 1; } +int srmmu_pmd_inuse(pmd_t *pmdp) { return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; } void srmmu_pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } void srmmu_pmd_reuse(pmd_t * pmdp) { - if (!(mem_map[MAP_NR(pmdp)] & MAP_PAGE_RESERVED)) - mem_map[MAP_NR(pmdp)]++; + if (!mem_map[MAP_NR(pmdp)].reserved) + mem_map[MAP_NR(pmdp)].count++; } int srmmu_pgd_none(pgd_t pgd) { return !pgd_val(pgd); } @@ -134,12 +87,12 @@ (srmmu_pgd_page(pgd) > high_memory); } int srmmu_pgd_present(pgd_t pgd) { return pgd_val(pgd) & SRMMU_ET_PTD; } -int srmmu_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)] != 1; } +int srmmu_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; } void srmmu_pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; } void srmmu_pgd_reuse(pgd_t *pgdp) { - if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED)) - mem_map[MAP_NR(pgdp)]++; + if (!mem_map[MAP_NR(pgdp)].reserved) + mem_map[MAP_NR(pgdp)].count++; } /* @@ -179,7 +132,7 @@ pte_t pte; if(page & (~PAGE_MASK)) panic("srmmu_mk_pte() called with unaligned page"); - page = (srmmu_virt_to_phys(page) >> SRMMU_PTE_PPN_PADDR_SHIFT); + page = ((page - PAGE_OFFSET) >> SRMMU_PTE_PPN_PADDR_SHIFT); pte_val(pte) = (page & SRMMU_PTE_PPN_MASK); pte_val(pte) |= pgprot_val(pgprot); return pte; @@ -190,7 +143,7 @@ { unsigned long page = (unsigned long) pmdp; - page = (srmmu_virt_to_phys(page) >> SRMMU_PTD_PTP_PADDR_SHIFT); + page = ((page - PAGE_OFFSET) >> SRMMU_PTD_PTP_PADDR_SHIFT); pgd_val(*pgdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD); } @@ -200,7 +153,7 @@ { unsigned long page = (unsigned long) ptep; - page = (srmmu_virt_to_phys(page) >> SRMMU_PTD_PTP_PADDR_SHIFT); + page = ((page - PAGE_OFFSET) >> SRMMU_PTD_PTP_PADDR_SHIFT); pmd_val(*pmdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD); } @@ -214,10 +167,9 @@ /* to find an entry in a top-level page table... */ pgd_t * -srmmu_pgd_offset(struct task_struct * tsk, unsigned long address) +srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) { - return ((pgd_t *) tsk->tss.pgd_ptr) + - ((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)); + return mm->pgd + ((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1)); } /* Find an entry in the second-level page table.. */ @@ -243,7 +195,7 @@ /* See if this process has a context entry already, like after execve() */ if(tsk->tss.context != -1) { pgd_t *ctable_ptr = 0; - ctable_ptr = (pgd_t *) srmmu_phys_to_virt(srmmu_get_ctable_ptr()); + ctable_ptr = (pgd_t *) (srmmu_get_ctable_ptr() + PAGE_OFFSET); ctable_ptr += tsk->tss.context; srmmu_pgd_set(ctable_ptr, (pmd_t *) pgdir); /* Should flush caches here too... */ @@ -263,7 +215,7 @@ void srmmu_pte_free_kernel(pte_t *pte) { - mem_map[MAP_NR(pte)] = 1; + mem_map[MAP_NR(pte)].reserved = 0; free_page((unsigned long) pte); } @@ -278,7 +230,7 @@ if (srmmu_pmd_none(*pmd)) { if (page) { srmmu_pmd_set(pmd, page); - mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED; + mem_map[MAP_NR(page)].reserved = 1; return page + address; } srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD); @@ -298,7 +250,7 @@ void srmmu_pmd_free_kernel(pmd_t *pmd) { - mem_map[MAP_NR(pmd)] = 1; + mem_map[MAP_NR(pmd)].reserved = 0; free_page((unsigned long) pmd); } @@ -313,7 +265,7 @@ if (srmmu_pgd_none(*pgd)) { if (page) { srmmu_pgd_set(pgd, page); - mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED; + mem_map[MAP_NR(page)].reserved = 1; return page + address; } srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD); @@ -346,7 +298,6 @@ if (srmmu_pmd_none(*pmd)) { if (page) { srmmu_pmd_set(pmd, page); - mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED; return page + address; } srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD); @@ -383,7 +334,6 @@ if (srmmu_pgd_none(*pgd)) { if (page) { srmmu_pgd_set(pgd, page); - mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED; return page + address; } srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD); @@ -427,18 +377,19 @@ return; } -void -srmmu_set_pte(pte_t *ptep, pte_t entry) +/* XXX Needs to be written */ +void srmmu_set_pte(pte_t *ptep, pte_t pteval) { - /* for now... */ - *ptep = entry; + /* More than this is needed. */ + *ptep = pteval; } /* XXX Needs to be written */ void -srmmu_switch_to_context(int context) +srmmu_switch_to_context(void *vtask) { - printk("switching to context %d\n", context); + struct task_struct *tsk = vtask; + printk("switching to context %d\n", tsk->tss.context); return; } @@ -460,7 +411,7 @@ pmd_t *pmdp; pte_t *ptep; - pgdp = srmmu_pgd_offset(&init_task, virt_addr); + pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); pmdp = srmmu_pmd_offset(pgdp, virt_addr); ptep = srmmu_pte_offset(pmdp, virt_addr); pte_val(*ptep) = (physaddr >> SRMMU_PTE_PPN_PADDR_SHIFT) & SRMMU_PTE_PPN_MASK; @@ -478,6 +429,25 @@ return; } +char *srmmu_lockarea(char *vaddr, unsigned long len) +{ + return vaddr; +} + +void srmmu_unlockarea(char *vaddr, unsigned long len) +{ +} + +char *srmmu_get_scsi_buffer(char *vaddr, unsigned long len) +{ + panic("sun4m: get_scsi_buffer() not implemented yet."); +} + +void srmmu_release_scsi_buffer(char *vaddr, unsigned long len) +{ + panic("sun4m: release_scsi_buffer() not implemented yet."); +} + /* Perfom a some soft of MMU tablewalk. * Long contiguous mappings are not supported (yet ?). * @@ -590,28 +560,13 @@ return (void*) ret; } -extern unsigned long srmmu_data_fault, srmmu_text_fault; - -/* Patch in the SRMMU fault handlers for the trap table. */ -void -srmmu_patch_fhandlers(void) +/* Get fault information on an SRMMU. */ +int +srmmu_get_fault_info(unsigned long *address, unsigned long *error_code, + unsigned long from_user) { - /* Say the following ten times fast... */ - sparc_ttable[SP_TRAP_TFLT].inst_one = SPARC_MOV_CONST_L3(0x1); - sparc_ttable[SP_TRAP_TFLT].inst_two = - SPARC_BRANCH((unsigned long) &srmmu_text_fault, - (unsigned long) &sparc_ttable[SP_TRAP_TFLT].inst_two); - sparc_ttable[SP_TRAP_TFLT].inst_three = SPARC_RD_PSR_L0; - sparc_ttable[SP_TRAP_TFLT].inst_four = SPARC_NOP; - - sparc_ttable[SP_TRAP_DFLT].inst_one = SPARC_MOV_CONST_L3(0x9); - sparc_ttable[SP_TRAP_DFLT].inst_two = - SPARC_BRANCH((unsigned long) &srmmu_data_fault, - (unsigned long) &sparc_ttable[SP_TRAP_DFLT].inst_two); - sparc_ttable[SP_TRAP_DFLT].inst_three = SPARC_RD_PSR_L0; - sparc_ttable[SP_TRAP_DFLT].inst_four = SPARC_NOP; - - return; + /* XXX Foo, write this... XXX */ + return 0; } /* Paging initialization on the Sparc Reference MMU. */ @@ -653,7 +608,7 @@ /* Make Linux physical page tables. */ for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) { - pgdp = srmmu_pgd_offset(&init_task, vaddr); + pgdp = srmmu_pgd_offset(init_task.mm, vaddr); if(srmmu_pgd_none(*pgdp)) { pmdp = srmmu_init_alloc(&mempool, SRMMU_PTRS_PER_PMD*sizeof(pmd_t)); @@ -674,7 +629,7 @@ /* Map IO areas. */ for(vaddr = IOBASE_VADDR; vaddr < (IOBASE_VADDR+IOBASE_LEN); vaddr += SRMMU_PMD_SIZE) { - pgdp = srmmu_pgd_offset(&init_task, vaddr); + pgdp = srmmu_pgd_offset(init_task.mm, vaddr); if(srmmu_pgd_none(*pgdp)) { pmdp = srmmu_init_alloc(&mempool, SRMMU_PTRS_PER_PMD*sizeof(pmd_t)); @@ -688,12 +643,37 @@ } } + /* Map DVMA areas. */ + for(vaddr = (DVMA_VADDR); vaddr < (DVMA_VADDR + DVMA_LEN); + vaddr += PAGE_SIZE) { + pgdp = srmmu_pgd_offset(init_task.mm, vaddr); + if(srmmu_pgd_none(*pgdp)) { + pmdp = srmmu_init_alloc(&mempool, + SRMMU_PTRS_PER_PMD*sizeof(pmd_t)); + srmmu_pgd_set(pgdp, pmdp); + } + pmdp = srmmu_pmd_offset(pgdp, vaddr); + if(srmmu_pmd_none(*pmdp)) { + ptep = srmmu_init_alloc(&mempool, + SRMMU_PTRS_PER_PTE*sizeof(pte_t)); + srmmu_pmd_set(pmdp, ptep); + } + + ptep = srmmu_pte_offset(pmdp, vaddr); + *ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE), SRMMU_PAGE_KERNEL); + pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK); + } + srmmu_flush_whole_tlb(); + flush_ei_ctx(0x0); + /* Map in the PERCPU areas in virtual address space. */ - printk("PERCPU_VADDR + PERCPU_LEN = %08lx\n", - (PERCPU_VADDR + PERCPU_LEN)); +#if 0 + prom_printf("PERCPU_VADDR + PERCPU_LEN = %08lx\n", + (PERCPU_VADDR + PERCPU_LEN)); +#endif for(vaddr = PERCPU_VADDR; vaddr < (PERCPU_VADDR + PERCPU_LEN); vaddr += PERCPU_ENTSIZE) { - pgdp = srmmu_pgd_offset(&init_task, vaddr); + pgdp = srmmu_pgd_offset(init_task.mm, vaddr); if(srmmu_pgd_none(*pgdp)) { pmdp = srmmu_init_alloc(&mempool, SRMMU_PTRS_PER_PMD*sizeof(pmd_t)); @@ -724,6 +704,10 @@ * you will lose with video cards when we take over the ctx table. * Also, must take into consideration that prom might be using level * two or one PTE's. TODO + * + * XXX This still isn't right, the cg* graphics cards get their + * XXX mapped screens all fucked up when I jump onto Linux's + * XXX page tables. Must investigate... */ for(vaddr = KADB_DEBUGGER_BEGVM; vaddr != 0x0;) { unsigned int prom_pte; @@ -731,7 +715,7 @@ prom_pte = srmmu_init_twalk(vaddr, 0); if(prom_pte) { - pgdp = srmmu_pgd_offset(&init_task, vaddr); + pgdp = srmmu_pgd_offset(init_task.mm, vaddr); if((prom_pte&0x3) == 0x0) { prom_pte &= ~0x3; prom_pte |= SRMMU_ET_PTE; @@ -772,9 +756,9 @@ /* We probably do, and should do it just to be safe... -Davem */ /* Take the MMU over from the PROM */ - printk("Taking over MMU from PROM.\n"); + prom_printf("Taking over MMU from PROM.\n"); - srmmu_set_ctable_ptr(srmmu_virt_to_phys((unsigned)lnx_root)); + srmmu_set_ctable_ptr(((unsigned)lnx_root) - PAGE_OFFSET); srmmu_flush_whole_tlb(); @@ -784,14 +768,14 @@ start_mem = PAGE_ALIGN(start_mem); #if 0 - printk("Testing context switches...\n"); + prom_printf("Testing context switches...\n"); for(i=0; i /* for printk */ +#include #include -#include /* for wp_works_ok */ +#include #include #include #include #include #include +#include #include +#include +#include +#include +#include #include -unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); } -unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); } - -extern int num_segmaps, num_contexts; - -/* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job. - * The only function that actually uses this is sun4c_mk_pte() and - * to have a complete physical ram structure walk happen for each - * invocation is quite costly. However, this does do some nice - * sanity checking and we'll see when our maps don't match. Eventually - * when I trust my code I will just do a direct mmu probe in mk_pte(). - */ -static inline unsigned int sun4c_virt_to_phys(unsigned int vaddr) -{ - unsigned int paddr = 0; - unsigned int voff = (vaddr - PAGE_OFFSET); - int i; +/* Pseg allocation structures. */ +static struct pseg_list s4cpseg_pool[256]; - for(i=0; sp_banks[i].num_bytes != 0; i++) { - if(voff < paddr + sp_banks[i].num_bytes) { - /* This matches. */ - return sp_banks[i].base_addr + voff - paddr; - } else - paddr += sp_banks[i].num_bytes; - } - /* Shit, gotta consult the MMU, this shouldn't happen... */ - printk("sun4c_virt_to_phys: Could not make translation for vaddr %08lx\n", (unsigned long) vaddr); - SP_ENTER_DEBUGGER; -} +struct pseg_list s4cpseg_free; +struct pseg_list s4cpseg_used; +static struct pseg_list s4cpseg_locked; +static struct pseg_list s4cpseg_per_context[16]; -static inline unsigned long -sun4c_phys_to_virt(unsigned long paddr) -{ - int i; - unsigned long offset = PAGE_OFFSET; +static unsigned char pseg_count_per_context[16]; - for (i=0; sp_banks[i].num_bytes != 0; i++) - { - if (paddr >= sp_banks[i].base_addr && - paddr < (sp_banks[i].base_addr - + sp_banks[i].num_bytes)) { - return (paddr - sp_banks[i].base_addr) + offset; - } else - offset += sp_banks[i].num_bytes; - } - printk("sun4c_phys_to_virt: Could not make translation for paddr %08lx\n", (unsigned long) paddr); - SP_ENTER_DEBUGGER; -} +unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); } +unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); } -unsigned long -sun4c_vmalloc_start(void) -{ - return ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1)); -} +extern int num_segmaps, num_contexts; -/* Note that I have 16 page tables per page, thus four less - * bits of shifting than normal. +/* First the functions which the mid-level code uses to directly + * manipulate the software page tables. Some defines since we are + * emulating the i386 page directory layout. */ +#define PGD_PRESENT 0x001 +#define PGD_RW 0x002 +#define PGD_USER 0x004 +#define PGD_ACCESSED 0x020 +#define PGD_DIRTY 0x040 +#define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY) -unsigned long -sun4c_pte_page(pte_t pte) -{ - unsigned long page; - - page = ((pte_val(pte) & _SUN4C_PFN_MASK) << (PAGE_SHIFT)); - return sun4c_phys_to_virt(page); -} - -unsigned long -sun4c_pmd_page(pmd_t pmd) +unsigned long sun4c_vmalloc_start(void) { - return ((pmd_val(pmd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT)); -} - -unsigned long -sun4c_pgd_page(pgd_t pgd) -{ - return ((pgd_val(pgd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT)); + return SUN4C_VMALLOC_START; } /* Update the root mmu directory on the sun4c mmu. */ -void -sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) +void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) { (tsk)->tss.pgd_ptr = (unsigned long) (pgdir); - - /* May have to do some flushing here. */ - - return; } int sun4c_pte_none(pte_t pte) { return !pte_val(pte); } int sun4c_pte_present(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_VALID; } -int sun4c_pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] != 1; } +int sun4c_pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; } void sun4c_pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } void sun4c_pte_reuse(pte_t *ptep) { - if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED)) - mem_map[MAP_NR(ptep)]++; + if(!mem_map[MAP_NR(ptep)].reserved) + mem_map[MAP_NR(ptep)].count++; } int sun4c_pmd_none(pmd_t pmd) { return !pmd_val(pmd); } int sun4c_pmd_bad(pmd_t pmd) { - return ((pmd_val(pmd) & _SUN4C_PGD_MMU_MASK) != _SUN4C_PAGE_TABLE); + return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory; } -int sun4c_pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SUN4C_PAGE_VALID; } +int sun4c_pmd_present(pmd_t pmd) { return pmd_val(pmd) & PGD_PRESENT; } int sun4c_pmd_inuse(pmd_t *pmdp) { return 0; } void sun4c_pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } void sun4c_pmd_reuse(pmd_t * pmdp) { } @@ -138,21 +87,16 @@ int sun4c_pgd_none(pgd_t pgd) { return 0; } int sun4c_pgd_bad(pgd_t pgd) { return 0; } int sun4c_pgd_present(pgd_t pgd) { return 1; } -int sun4c_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)] != 1; } +int sun4c_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; } void sun4c_pgd_clear(pgd_t * pgdp) { } -void sun4c_pgd_reuse(pgd_t *pgdp) -{ - if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED)) - mem_map[MAP_NR(pgdp)]++; -} /* * The following only work if pte_present() is true. * Undefined behaviour if not.. */ -int sun4c_pte_read(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_VALID; } +int sun4c_pte_read(pte_t pte) { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); } int sun4c_pte_write(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_WRITE; } -int sun4c_pte_exec(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_VALID; } +int sun4c_pte_exec(pte_t pte) { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); } int sun4c_pte_dirty(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_DIRTY; } int sun4c_pte_young(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_REF; } int sun4c_pte_cow(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_COW; } @@ -174,103 +118,287 @@ * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ -pte_t -sun4c_mk_pte(unsigned long page, pgprot_t pgprot) +pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot) { - pte_t pte; + return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); +} - if(page & (~PAGE_MASK)) panic("sun4c_mk_pte() called with unaligned page"); - page = sun4c_virt_to_phys(page); - pte_val(pte) = ((page>>PAGE_SHIFT)&_SUN4C_PFN_MASK); - pte_val(pte) |= (pgprot_val(pgprot) & _SUN4C_MMU_MASK); - return pte; +pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot) +{ + return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot)); } -void -sun4c_pgd_set(pgd_t * pgdp, pte_t * ptep) +unsigned long sun4c_pte_page(pte_t pte) { - pgd_val(*pgdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK); - pgd_val(*pgdp) |= (((((unsigned long) ptep)) >> - (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK); + return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT))); } -pte_t -sun4c_pte_modify(pte_t pte, pgprot_t newprot) +unsigned long sun4c_pmd_page(pmd_t pmd) { - pte_val(pte) = (pte_val(pte) & _SUN4C_PAGE_CHG_MASK); - pte_val(pte) |= pgprot_val(newprot); - return pte; + return (pmd_val(pmd) & PAGE_MASK); } /* to find an entry in a page-table-directory */ -pgd_t * -sun4c_pgd_offset(struct task_struct * tsk, unsigned long address) +pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) { - return ((pgd_t *) (tsk->tss.pgd_ptr)) + - (address >> SUN4C_PGDIR_SHIFT); + return mm->pgd + (address >> SUN4C_PGDIR_SHIFT); } /* Find an entry in the second-level page table.. */ -pmd_t * -sun4c_pmd_offset(pgd_t * dir, unsigned long address) +pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address) { return (pmd_t *) dir; } /* Find an entry in the third-level page table.. */ -pte_t * -sun4c_pte_offset(pmd_t * dir, unsigned long address) +pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address) { return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)); } -/* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any, and marks the page tables reserved. +/* Here comes the sun4c mmu-tlb management engine. It is here because + * some of the mid-level mm support needs to be able to lock down + * critical areas of kernel memory into the tlb. */ -void -sun4c_pte_free_kernel(pte_t *pte) +static inline void add_pseg_list(struct pseg_list *head, struct pseg_list *entry) { - mem_map[MAP_NR(pte)] = 1; - free_page((unsigned long) pte); + entry->next = head; + (entry->prev = head->prev)->next = entry; + head->prev = entry; +} +#define add_to_used_pseg_list(entry) add_pseg_list(&s4cpseg_used, entry) +#define add_to_free_pseg_list(entry) add_pseg_list(&s4cpseg_free, entry) +#define add_to_locked_pseg_list(entry) add_pseg_list(&s4cpseg_locked, entry) + +static inline void remove_pseg_list(struct pseg_list *entry) +{ + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +static inline void add_pseg_ctxlist(struct pseg_list *entry, int ctx) +{ + struct pseg_list *head = &s4cpseg_per_context[ctx]; + + entry->ctx_next = head; + (entry->ctx_prev = head->ctx_prev)->ctx_next = entry; + head->ctx_prev = entry; + pseg_count_per_context[ctx]++; } -static inline void -sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep) +static inline void remove_pseg_ctxlist(struct pseg_list *entry, int ctx) { - pmd_val(*pmdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK); - pmd_val(*pmdp) |= ((((unsigned long) ptep) >> (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK); + entry->ctx_next->ctx_prev = entry->ctx_prev; + entry->ctx_prev->ctx_next = entry->ctx_next; + pseg_count_per_context[ctx]--; } +static inline void sun4c_init_pseg_lists(void) +{ + int i; + + s4cpseg_free.prev = s4cpseg_free.next = &s4cpseg_free; + s4cpseg_used.prev = s4cpseg_used.next = &s4cpseg_used; + s4cpseg_locked.prev = s4cpseg_locked.next = &s4cpseg_locked; + for(i = 0; i < num_contexts; i++) { + s4cpseg_per_context[i].ctx_prev = s4cpseg_per_context[i].ctx_next = + &s4cpseg_per_context[i]; + } + for(i = 0; i <= invalid_segment; i++) { + s4cpseg_pool[i].vaddr = 0; + s4cpseg_pool[i].context = 0; + s4cpseg_pool[i].ref_cnt = 0; + s4cpseg_pool[i].hardlock = 0; + s4cpseg_pool[i].pseg = i; + } + s4cpseg_pool[invalid_segment].hardlock = 1; +} + +static inline void sun4c_distribute_kernel_mapping(unsigned long address, + unsigned char pseg) +{ + unsigned int flags; + int ctx, save_ctx; + + save_flags(flags); cli(); + save_ctx = get_context(); + flush_user_windows(); + for(ctx = 0; ctx < num_contexts; ctx++) { + set_context(ctx); + put_segmap(address, pseg); + } + set_context(save_ctx); + restore_flags(flags); +} -pte_t * -sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address) +static inline void sun4c_delete_kernel_mapping(unsigned long address) { - pte_t *page; + unsigned int flags; + int ctx, save_ctx; + save_flags(flags); cli(); + save_ctx = get_context(); + flush_user_windows(); + /* Flush only needed in one context for kernel mappings. */ + sun4c_flush_segment(address); + for(ctx = 0; ctx < num_contexts; ctx++) { + set_context(ctx); + put_segmap(address, invalid_segment); + } + set_context(save_ctx); + restore_flags(flags); +} + +/* NOTE: You can only lock kernel tlb entries, attempts to lock + * pages in user vm will bolix the entire system. + */ +static inline void sun4c_lock_tlb_entry(unsigned long address) +{ + unsigned long flags; + unsigned char pseg; + + save_flags(flags); cli(); + /* Fault it in. */ + __asm__ __volatile__("ldub [%0], %%g0\n\t" : : "r" (address)); + address &= SUN4C_REAL_PGDIR_MASK; + pseg = get_segmap(address); + if(address < KERNBASE) + panic("locking user address space into tlb!"); + if(pseg == invalid_segment) + panic("cannot lock kernel tlb entry..."); + if(!s4cpseg_pool[pseg].ref_cnt++ && !s4cpseg_pool[pseg].hardlock) { + /* Move from used to locked list. */ + remove_pseg_list(&s4cpseg_pool[pseg]); + add_to_locked_pseg_list(&s4cpseg_pool[pseg]); + } + restore_flags(flags); +} + +static inline void sun4c_unlock_tlb_entry(unsigned long address) +{ + unsigned long flags; + struct pseg_list *psegp; + unsigned char pseg; + + save_flags(flags); cli(); + address &= SUN4C_REAL_PGDIR_MASK; + pseg = get_segmap(address); + if(address < KERNBASE) + panic("unlocking user tlb entry!"); + if(pseg == invalid_segment) + panic("unlocking non-locked kernel tlb entry..."); + psegp = &s4cpseg_pool[pseg]; + if(!--psegp->ref_cnt && !psegp->hardlock) { + /* Move from locked list to used list. */ + remove_pseg_list(psegp); + add_to_used_pseg_list(psegp); + } + restore_flags(flags); +} + +/* Anyone who calls this must turn _all_ interrupts off and flush + * any necessary user windows beforehand. + */ +static inline void sun4c_unload_context_from_tlb(unsigned char ctx) +{ + struct pseg_list *psegp, *pnextp; + + if(pseg_count_per_context[ctx]) { + sun4c_flush_context(); /* Most efficient */ + psegp = s4cpseg_per_context[ctx].ctx_next; + while(psegp != &s4cpseg_per_context[ctx]) { + pnextp = psegp->ctx_next; + if(psegp->vaddr >= KERNBASE) + panic("Unloading kernel from tlb, not good."); + put_segmap(psegp->vaddr, invalid_segment); + remove_pseg_ctxlist(psegp, ctx); + remove_pseg_list(psegp); + add_to_free_pseg_list(psegp); + psegp = pnextp; + } + if(pseg_count_per_context[ctx]) + panic("pseg_count_per_context inconsistant after " + "invalidate."); + } +} + +/* This page must be a page in user vma... again all IRQ's gotta be off. */ +static inline void sun4c_unload_page_from_tlb(unsigned long addr, + struct task_struct *tsk) +{ + unsigned char save_ctx; + + if(tsk->tss.context != -1) { + save_ctx = get_context(); + flush_user_windows(); + set_context(tsk->tss.context); + sun4c_flush_page(addr); + put_pte(addr, 0); + set_context(save_ctx); + } +} + +/* NOTE: When we have finer grained invalidate()'s (RSN) this + * whole scheme will be much more efficient and need to + * be re-written. Also note that this routine only + * unloads user page translations, this may need to + * be changed at some point. + */ +void sun4c_invalidate(void) +{ + int orig_ctx, cur_ctx, flags; + + save_flags(flags); cli(); + flush_user_windows(); + orig_ctx = get_context(); + for(cur_ctx = 0; cur_ctx < num_contexts; cur_ctx++) { + set_context(cur_ctx); + sun4c_unload_context_from_tlb(cur_ctx); + } + set_context(orig_ctx); + restore_flags(flags); +} + +/* We're only updating software tables on the sun4c. */ +void sun4c_set_pte(pte_t *ptep, pte_t pteval) +{ + *ptep = pteval; +} + +/* Now back to the mid-level interface code: + * + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any, and marks the page tables reserved. + */ +void sun4c_pte_free_kernel(pte_t *pte) +{ + mem_map[MAP_NR(pte)].reserved = 0; + free_page((unsigned long) pte); +} + +pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address) +{ address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1); if (sun4c_pmd_none(*pmd)) { - /* New scheme, use a whole page */ - page = (pte_t *) get_free_page(GFP_KERNEL); + pte_t *page = (pte_t *) get_free_page(GFP_KERNEL); if (sun4c_pmd_none(*pmd)) { if (page) { - sun4c_pmd_set(pmd, page); - mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED; + pmd_val(*pmd) = PGD_TABLE | (unsigned long) page; + mem_map[MAP_NR(page)].reserved = 1; return page + address; } - sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE; return NULL; } free_page((unsigned long) page); } if (sun4c_pmd_bad(*pmd)) { printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); - sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE; return NULL; } - return (pte_t *) sun4c_pmd_page(*pmd) + address; } @@ -278,49 +406,41 @@ * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -void -sun4c_pmd_free_kernel(pmd_t *pmd) +void sun4c_pmd_free_kernel(pmd_t *pmd) { - return; + pmd_val(*pmd) = 0; } -pmd_t * -sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address) +pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address) { return (pmd_t *) pgd; } -void -sun4c_pte_free(pte_t *pte) +void sun4c_pte_free(pte_t *pte) { free_page((unsigned long) pte); } -pte_t * -sun4c_pte_alloc(pmd_t * pmd, unsigned long address) +pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address) { - pte_t *page; - address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1); if (sun4c_pmd_none(*pmd)) { - page = (pte_t *) get_free_page(GFP_KERNEL); + pte_t *page = (pte_t *) get_free_page(GFP_KERNEL); if (sun4c_pmd_none(*pmd)) { if (page) { - sun4c_pmd_set(pmd, page); + pmd_val(*pmd) = PGD_TABLE | (unsigned long) page; return page + address; } - sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE; return NULL; } free_page((unsigned long) page); } if (sun4c_pmd_bad(*pmd)) { printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); - halt(); + pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE; return NULL; } - return (pte_t *) sun4c_pmd_page(*pmd) + address; } @@ -328,291 +448,610 @@ * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -void -sun4c_pmd_free(pmd_t * pmd) +void sun4c_pmd_free(pmd_t * pmd) { - return; + pmd_val(*pmd) = 0; } -pmd_t * -sun4c_pmd_alloc(pgd_t * pgd, unsigned long address) +pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address) { return (pmd_t *) pgd; } -/* This now works, as both our pgd's and pte's have 1024 entries. */ -void -sun4c_pgd_free(pgd_t *pgd) +void sun4c_pgd_free(pgd_t *pgd) { free_page((unsigned long) pgd); + sun4c_unlock_tlb_entry((unsigned long) pgd); } -/* A page directory on the sun4c needs 64k, thus we request an order of - * four. We must also clear it by hand, very inefficient. - */ - -pgd_t * -sun4c_pgd_alloc(void) +pgd_t *sun4c_pgd_alloc(void) { - return (pgd_t *) get_free_page(GFP_KERNEL); + unsigned long new_pgd = get_free_page(GFP_KERNEL); + sun4c_lock_tlb_entry(new_pgd); + return (pgd_t *) new_pgd; } -void -sun4c_invalidate(void) +/* Jumping to and fro different contexts, the modifying of the pseg lists + * must be atomic during the switch, or else... + */ +void sun4c_switch_to_context(void *new_task) { - flush_vac_context(); + struct task_struct *tsk = (struct task_struct *) new_task; + struct task_struct *old_tsk; + struct ctx_list *ctxp; + unsigned long flags; + int ctx = tsk->tss.context; + + /* Swapper can execute in any context, or this task + * has already been allocated a piece of the mmu real- + * estate. + */ + if(tsk->pid == 0 || ctx != -1) + return; + ctxp = ctx_free.next; + if(ctxp != &ctx_free) { + save_flags(flags); cli(); + ctx = ctxp->ctx_number; + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + tsk->tss.context = ctx; + ctxp->ctx_task = tsk; + restore_flags(flags); + return; + } + save_flags(flags); cli(); + ctxp = ctx_used.prev; + /* Don't steal from current, thank you. */ + if(ctxp->ctx_task == current) + ctxp = ctxp->prev; + if(ctxp == &ctx_used) + panic("out of contexts"); + remove_from_ctx_list(ctxp); + old_tsk = ctxp->ctx_task; + old_tsk->tss.context = -1; + ctxp->ctx_task = tsk; + tsk->tss.context = ctxp->ctx_number; + add_to_used_ctxlist(ctxp); + /* User windows flushed already by switch_to(p) macro. */ + set_context(ctxp->ctx_number); + sun4c_unload_context_from_tlb(ctxp->ctx_number); + restore_flags(flags); } -void -sun4c_set_pte(pte_t *ptep, pte_t entry) +/* Low level IO area allocation on the Sun4c MMU. This function is called + * for each page of IO area you need. Kernel code should not call this + * routine directly, use sparc_alloc_io() instead. + */ +void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, + int bus_type, int rdonly) { - /* for now... */ - *ptep = entry; + unsigned long page_entry; + + page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff); + page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | + _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO); + if(rdonly) + page_entry &= (~_SUN4C_PAGE_WRITE); + sun4c_flush_page(virt_addr); + put_pte(virt_addr, page_entry); } -void -sun4c_switch_to_context(int context) +/* These routines are used to lock down and unlock data transfer + * areas in the sun4c tlb. If the pages need to be uncached the + * caller must do that himself. + */ +inline char *sun4c_lockarea(char *vaddr, unsigned long size) { - __asm__ __volatile__("stba %0, [%1] %2" : : - "r" (context), - "r" (AC_CONTEXT), "i" (ASI_CONTROL)); + unsigned long flags; + unsigned long orig_addr = (unsigned long) vaddr; + unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK); + unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK); + + save_flags(flags); cli(); + for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE) + sun4c_lock_tlb_entry(first_seg); - return; + restore_flags(flags); + return vaddr; } -int -sun4c_get_context(void) +/* Note that when calling unlockarea you pass as 'vaddr' the address that + * was returned to you by lockarea for this pool above. + */ +inline void sun4c_unlockarea(char *vaddr, unsigned long size) { - register int ctx; + unsigned long flags; + unsigned long orig_addr = (unsigned long) vaddr; + unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK); + unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK); - __asm__ __volatile__("lduba [%1] %2, %0" : - "=r" (ctx) : - "r" (AC_CONTEXT), "i" (ASI_CONTROL)); + save_flags(flags); cli(); + for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE) + sun4c_unlock_tlb_entry(first_seg); - return ctx; + restore_flags(flags); } -/* Low level IO area allocation on the Sun4c MMU. This function is called - * for each page of IO area you need. Kernel code should not call this - * routine directly, use sparc_alloc_io() instead. - */ -void -sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, - int bus_type, int rdonly) +/* Getting and Releasing scsi dvma buffers. */ +char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len) { - unsigned long page_entry; + unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK; + unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK; - page_entry = ((physaddr >> PAGE_SHIFT) & _SUN4C_PFN_MASK); + /* First lock down the area. */ + bufptr = sun4c_lockarea(bufptr, len); - if(!rdonly) - page_entry |= (PTE_V | PTE_ACC | PTE_NC | PTE_IO); /* kernel io addr */ - else - page_entry |= (PTE_V | PTE_P | PTE_NC | PTE_IO); /* readonly io addr */ + /* Uncache and flush all the pages. */ + for(; first_page <= last_page; first_page += PAGE_SIZE) { + sun4c_flush_page(first_page); + put_pte(first_page, get_pte(first_page) | PTE_NC); + } + return bufptr; +} - page_entry &= (~PTE_RESV); +void sun4c_release_scsi_buffer(char *bufptr, unsigned long len) +{ + unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK; + unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK; - /* Maybe have to do something with the bus_type on sun4c's? */ + /* Recache all the pages. */ + for(; first_page <= last_page; first_page += PAGE_SIZE) + put_pte(first_page, get_pte(first_page) & ~PTE_NC); - put_pte(virt_addr, page_entry); - return; + sun4c_unlockarea(bufptr, len); } -/* Paging initialization on the Sun4c. */ -extern unsigned long free_area_init(unsigned long, unsigned long); -extern unsigned long eintstack, intstack; - -/* This code was soooo krufty, I have to rewrite this now! XXX - * Ok, things are cleaning up. I have now decided that it makes - * a lot of sense to put the free page pool in upper ram right - * after the kernel. We map these free pages to be virtually - * contiguous, that way we don't get so many reserved pages - * during mem_init(). I think this will work out nicely. - */ -extern unsigned long start; +/* Code to fill the sun4c tlb during a fault. Plus fault helper routine. */ +int sun4c_get_fault_info(unsigned long *address, unsigned long *error_code, + unsigned long from_user) +{ + unsigned long faddr, fstatus, new_code; -static unsigned long mempool; /* This allows us to work with elf bootloaders */ + faddr = sun4c_get_synchronous_address(); + *address = faddr; + if(faddr >= 0x20000000 && faddr < 0xe0000000) { + printk("SUN4C: Fault in vm hole at %08lx\n", faddr); + *error_code = from_user; + return 1; + } + fstatus = sun4c_get_synchronous_error(); + if(fstatus & SUN4C_SYNC_BOLIXED) + panic("SUN4C: Unrecoverable fault type."); + new_code = 0; + if(fstatus & SUN4C_SYNC_PROT) + new_code |= FAULT_CODE_PROT; + if(fstatus & SUN4C_SYNC_BADWRITE) + new_code |= FAULT_CODE_WRITE; + *error_code = (new_code | from_user); + return 0; +} + +static inline void sun4c_alloc_pseg(unsigned long address) +{ + struct pseg_list *psegp; + unsigned char cur_ctx = get_context(); + int kernel_address = (address >= KERNBASE); + int user_address = !kernel_address; + + psegp = s4cpseg_free.next; + if(psegp != &s4cpseg_free) { + remove_pseg_list(psegp); + add_to_used_pseg_list(psegp); + if(user_address) + add_pseg_ctxlist(psegp, cur_ctx); + psegp->vaddr = address; + psegp->context = cur_ctx; + /* No cache flush needed */ + if(kernel_address) + sun4c_distribute_kernel_mapping(address, psegp->pseg); + else + put_segmap(address, psegp->pseg); + return; + } + psegp = s4cpseg_used.prev; /* Take last used list entry. */ + if(psegp == &s4cpseg_used) + panic("Sun4c psegs have disappeared..."); + if(psegp->vaddr >= KERNBASE) { + sun4c_delete_kernel_mapping(psegp->vaddr); + } else { + flush_user_windows(); + set_context(psegp->context); + sun4c_flush_segment(psegp->vaddr); + put_segmap(psegp->vaddr, invalid_segment); + set_context(cur_ctx); + } + remove_pseg_list(psegp); + if(psegp->vaddr < KERNBASE) + remove_pseg_ctxlist(psegp, psegp->context); + psegp->vaddr = address; + psegp->context = cur_ctx; + if(kernel_address) + sun4c_distribute_kernel_mapping(address, psegp->pseg); + else + put_segmap(address, psegp->pseg); + add_to_used_pseg_list(psegp); + if(user_address) + add_pseg_ctxlist(psegp, cur_ctx); +} -unsigned long -sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) +/* + * handle_mm_fault() gets here so that we can update our 'view' + * of a new address translation. A lot of the time, mappings + * don't change and we are just 'working the tlb cache'. + */ +void sun4c_update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) { - unsigned long addr, vaddr, kern_begin, kern_end; - unsigned long prom_begin, prom_end; - int phys_seg, i, min_prom_segmap; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; + unsigned long flags, segmap, segaddr, clean; - mempool = start_mem; + save_flags(flags); cli(); + address &= PAGE_MASK; + segaddr = address & SUN4C_REAL_PGDIR_MASK; + segmap = get_segmap(segaddr); + if(segmap == invalid_segment) { + sun4c_alloc_pseg(segaddr); + /* XXX make segmap freeing routines do this. XXX */ + for(clean = segaddr; clean < (segaddr + SUN4C_REAL_PGDIR_SIZE); + clean += PAGE_SIZE) + put_pte(clean, 0); + } - /* 127 on most sun4c's, 255 on SS2 and IPX. */ - invalid_segment = (num_segmaps - 1); + /* If this is a user fault, only load the one pte so that + * the kernel's ref/mod bits accurately reflect what is + * in the tlb. handle_pte_fault() causes this to work. + */ + if(address < TASK_SIZE) + put_pte(address, pte_val(pte)); + else { + /* We have a kernel fault here, load entire segment. */ + pgd_t *pgdp; + pte_t *ptable; + int pnum = 64; + + pgdp = sun4c_pgd_offset(&init_mm, segaddr); + ptable = sun4c_pte_offset((pmd_t *)pgdp, segaddr); + while(pnum--) { + put_pte(segaddr, pte_val(*ptable++)); + segaddr += PAGE_SIZE; + }; + } + restore_flags(flags); +} - memset(swapper_pg_dir, 0, PAGE_SIZE); - memset(pg0, 0, PAGE_SIZE); - /* Delete low mapping of the kernel and sanitize invalid segmap. */ - for(vaddr=0; vaddr<(4*1024*1024); vaddr+=SUN4C_REAL_PGDIR_SIZE) - put_segmap(vaddr, invalid_segment); - for(vaddr=0; vaddr<(256*1024); vaddr+=PAGE_SIZE) put_pte(vaddr, 0); - - /* Initialize phys_seg_map[] */ - for(i=0; ipseg); + for(i=0; i<64; i++) + put_pte((i * PAGE_SIZE), 0x0); + plp = plp->next; + } + put_segmap(0x0, invalid_segment); +} - /* Set up swapper_pg_dir based upon three things: - * 1) Where the kernel lives (KERNBASE) - * 2) Where the PROM lives (PROM_BEGVM -> PROM_ENDVM) - * This is cheese, should do it dynamically XXX - * 3) Where the valid physical pages are (sp_banks[]) - * This is done first. - * - * I'm trying to concentrate this into one big loop and localize - * the logic because it is so messy to do it in seperate loop - * stages. If anyone else has better ideas, let me know. - */ +static inline struct pseg_list *sun4c_alloc_pseg_from_free_list(void) +{ + struct pseg_list *psegp; - if(sp_banks[0].base_addr != 0) - panic("sun4c_paging_init: First physical address in first bank is not zero!\n"); - /* First, linearly map all physical RAM to the equivalent virtual pages. - * Then, we invalidate everything the kernel uses by either invalidating - * the entire segmep (if the whole segment is used by the kernel) or - * just invalidating the relevant pte's. - */ + psegp = s4cpseg_free.next; + if(psegp != &s4cpseg_free) { + remove_pseg_list(psegp); + return psegp; + } + return 0; +} - for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) { - pgdp = sun4c_pgd_offset(current, vaddr); - pmdp = sun4c_pmd_offset(pgdp, vaddr); - if(sun4c_pmd_none(*pmdp)) { - pgd_set(pgdp, (pte_t *) mempool); - mempool += PAGE_SIZE; +static inline void sun4c_init_lock_area(unsigned long start_addr, + unsigned long end_addr) +{ + struct pseg_list *psegp; + unsigned long a; + int ctx; + + for(a = start_addr; a < end_addr; a += SUN4C_REAL_PGDIR_SIZE) { + psegp = sun4c_alloc_pseg_from_free_list(); + if(!psegp) { + prom_printf("whoops..."); + prom_halt(); } - ptep = sun4c_pte_offset(pmdp, vaddr); - *ptep = sun4c_mk_pte(vaddr, SUN4C_PAGE_KERNEL); + for(ctx=0;ctxpseg); + add_to_locked_pseg_list(psegp); + psegp->hardlock = 1; } +} - /* Now map the kernel, and mark the segmaps as PSEG_KERN. +static inline void sun4c_check_for_ss2_cache_bug(void) +{ + extern unsigned long start; + + /* Well we've now got a problem, on the SS2 a cache bug + * causes line entries to get severely corrupted if the + * trap table is able to be cached. A sane and simple + * workaround, at least for now, is to mark the trap + * table page as uncacheable. * - * NOTE: The first address of the upper kernel mapping must be - * segment aligned. + * XXX Investigate other possible workarounds and see + * XXX if they help performance enough to warrant using + * XXX them. -- 8/6/95 davem */ - if(kern_begin & (~SUN4C_REAL_PGDIR_MASK)) { - panic("paging_init() Kernel not segmap aligned, halting..."); + if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) { + /* Whee.. */ + printk("SS2 cache bug detected, uncaching trap table page\n"); + sun4c_flush_page((unsigned int) &start); + put_pte(((unsigned long) &start), + (get_pte((unsigned long) &start) | PTE_NC)); } +} - /* Mark the segmaps so that our phys_seg allocator doesn't try to - * use them for TLB misses. - */ - for(addr=kern_begin; addr < kern_end; addr += SUN4C_REAL_PGDIR_SIZE) { - if(get_segmap(addr) == invalid_segment) { - panic("paging_init() AIEEE, Kernel has invalid mapping, halting..."); +extern unsigned long free_area_init(unsigned long, unsigned long); + +/* Whee, this is now *ultra* clean and more managable */ +extern unsigned long end; +extern void probe_mmu(void); + +unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) +{ + unsigned long addr, vaddr, kern_begin, kern_end; + unsigned long prom_begin, prom_end, kadb_begin; + pgd_t *pgdp; + pte_t *pg_table; + int phys_seg, i, ctx; + + start_mem = PAGE_ALIGN(start_mem); + + probe_mmu(); + invalid_segment = (num_segmaps - 1); + sun4c_init_pseg_lists(); + for(kern_begin = KERNBASE; + kern_begin < (unsigned long) &end; + kern_begin += SUN4C_REAL_PGDIR_SIZE) { + unsigned char pseg = get_segmap(kern_begin); + + s4cpseg_pool[pseg].hardlock=1; + for(ctx=0; ctxpv_setctxt)(i, (char *) addr, phys_seg); - } - - for(addr=((unsigned long) (&empty_zero_page)) + PAGE_SIZE; - addr < ((unsigned long) (&etext)); addr += PAGE_SIZE) - put_pte(addr, (get_pte(addr) & (~(PTE_W | PTE_NC)))); - - /* Finally map the prom's address space. Any segments that - * are not the invalid segment are marked as PSEG_RESV so - * they are never re-allocated. This guarentees the PROM - * a sane state if we have to return execution over to it. - * Our kernel static tables make it look like nothing is - * mapped in these segments, if we get a page fault for - * a prom address either the user is gonna die or the kernel - * is doing something *really* bad. + } + /* Clean the MMU of excess garbage... */ + for(ctx=0; ctx>SUN4C_PGDIR_SHIFT]) = + PGD_TABLE | (unsigned long) pg0; + + /* Initialize swapper_pg_dir to map the kernel + * addresses in high memory. Note that as soon as we get past + * the 4MB lower mapping and start using dynamic memory from + * start_mem we can start faulting and this is ok since our + * pseg free list and the lower 4MB of the kernel is mapped + * properly in the software page tables. */ - if(prom_begin & (~SUN4C_REAL_PGDIR_MASK)) { - panic("paging_init() Boot PROM not segmap aligned, halting..."); - halt(); - } - - min_prom_segmap = 254; - for(addr=KADB_DEBUGGER_BEGVM; addr < prom_end; addr += SUN4C_REAL_PGDIR_SIZE) { - if(get_segmap(addr) == invalid_segment) - continue; - phys_seg = get_segmap(addr); - if(phys_seg < min_prom_segmap) min_prom_segmap = phys_seg; - phys_seg_map[phys_seg] = PSEG_RSV; - /* Make the prom pages unaccessible from userland. However, we - * don't touch debugger segmaps/ptes. - */ - if((addr>=LINUX_OPPROM_BEGVM) && (addrpv_setctxt)(i, (char *) addr, phys_seg); - } - - /* Finally, unmap kernel page zero. */ - put_pte(0x0, 0x0); - - /* Hard pin down the IO area segmaps */ - phys_seg = (min_prom_segmap - 1); - for(addr = (IOBASE_VADDR + SUN4C_REAL_PGDIR_SIZE); addr < (IOBASE_VADDR + IOBASE_LEN); - addr += SUN4C_REAL_PGDIR_SIZE) { - if(addr & (~SUN4C_REAL_PGDIR_MASK)) { - panic("paging_init() IO segment not aligned, halting..."); + pgdp = swapper_pg_dir; + kern_end = PAGE_ALIGN(end_mem); + kern_begin = KERNBASE; + while(kern_begin < kern_end) { + unsigned long pte, tmp; + + /* We only need _one_ mapping, the high address one. */ + pg_table = (pte_t *) (PAGE_MASK & pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT])); + if(!pg_table) { + pg_table = (pte_t *) start_mem; + start_mem += PAGE_SIZE; + } + pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]) = + PGD_TABLE | (unsigned long) pg_table; + pgdp++; + for(tmp = 0; tmp < SUN4C_PTRS_PER_PTE; tmp++, pg_table++) { + if(kern_begin < kern_end) + sun4c_set_pte(pg_table, + mk_pte(kern_begin, + SUN4C_PAGE_SHARED)); + else + sun4c_pte_clear(pg_table); + pte = get_pte(kern_begin); + if(pte & _SUN4C_PAGE_VALID) { + pte &= ~(_SUN4C_PAGE_NOCACHE); + pte |= (_SUN4C_PAGE_PRIV | _SUN4C_PAGE_WRITE | + _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY); + put_pte(kern_begin, pte); + } + kern_begin += PAGE_SIZE; } - phys_seg_map[phys_seg] = PSEG_RSV; /* Don't touch */ - put_segmap(addr, phys_seg--); } - phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV; + sun4c_check_for_ss2_cache_bug(); + /* Fix kadb/prom permissions. */ + kadb_begin = KADB_DEBUGGER_BEGVM; + prom_end = LINUX_OPPROM_ENDVM; + for(; kadb_begin < prom_end; kadb_begin += PAGE_SIZE) { + unsigned long pte = get_pte(kadb_begin); + if(pte & _SUN4C_PAGE_VALID) + put_pte(kadb_begin, (pte | _SUN4C_PAGE_PRIV)); + } + /* Allocate the DVMA pages */ + addr = DVMA_VADDR; + start_mem = PAGE_ALIGN(start_mem); + while(addr < DVMA_END) { + unsigned long dvmapte = start_mem - PAGE_OFFSET; - start_mem = PAGE_ALIGN(mempool); + start_mem += PAGE_SIZE; + dvmapte = ((dvmapte>>PAGE_SHIFT) & 0xffff); + dvmapte |= (_SUN4C_PAGE_VALID | + _SUN4C_PAGE_WRITE | + _SUN4C_PAGE_NOCACHE); + put_pte(addr, dvmapte); + addr += PAGE_SIZE; + } + /* Tell the user our allocations */ + for(phys_seg=0, i=0; i<=invalid_segment; i++) + if(s4cpseg_pool[i].hardlock) + phys_seg++; + printk("SUN4C: Hard locked %d boot-up psegs\n", phys_seg); + /* Init the context pool and lists */ + ctx_list_pool = (struct ctx_list *) start_mem; + start_mem += (num_contexts * sizeof(struct ctx_list)); + for(ctx = 0; ctx < num_contexts; ctx++) { + struct ctx_list *clist; + + clist = (ctx_list_pool + ctx); + clist->ctx_number = ctx; + clist->ctx_task = 0; + } + ctx_free.next = ctx_free.prev = &ctx_free; + ctx_used.next = ctx_used.prev = &ctx_used; + for(ctx = 0; ctx < num_contexts; ctx++) + add_to_free_ctxlist(ctx_list_pool + ctx); + start_mem = PAGE_ALIGN(start_mem); start_mem = free_area_init(start_mem, end_mem); start_mem = PAGE_ALIGN(start_mem); - - /* That should be it. */ - invalidate(); - return start_mem; } /* Test the WP bit on the sun4c. */ -unsigned long -sun4c_test_wp(unsigned long start_mem) +void sun4c_test_wp(void) { - unsigned long addr, segmap; - unsigned long page_entry; - wp_works_ok = -1; - page_entry = pte_val(sun4c_mk_pte(PAGE_OFFSET, SUN4C_PAGE_READONLY)); - put_pte((unsigned long) 0x0, page_entry); /* Let it rip... */ + put_pte((unsigned long) 0x0, (PTE_V | PTE_P)); __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory"); put_pte((unsigned long) 0x0, 0x0); if (wp_works_ok < 0) wp_works_ok = 0; +} - /* Make all kernet static segmaps PSEG_KERNEL. */ - for(addr=PAGE_OFFSET; addrkernel_stack_page); + if(kthread_usp) + sun4c_lock_tlb_entry(kthread_usp); +} + +static void sun4c_release_hook(void *vtask) +{ + struct task_struct *old_task = vtask; + struct ctx_list *ctx_old; + struct pt_regs *regs; + unsigned char this_ctx = get_context(); + unsigned long flags; + + save_flags(flags); cli(); + if(old_task == &init_task) + panic("AIEEE releasing swapper"); + if(old_task->tss.context != -1) { + + /* Clear from the mmu, all notions of this dead task. */ + flush_user_windows(); + set_context(old_task->tss.context); + sun4c_unload_context_from_tlb(old_task->tss.context); + set_context(this_ctx); + + ctx_old = ctx_list_pool + old_task->tss.context; + remove_from_ctx_list(ctx_old); + add_to_free_ctxlist(ctx_old); + old_task->tss.context = -1; + } + regs = (struct pt_regs *) + (((old_task->tss.ksp & ~0xfff)) + (0x1000 - TRACEREG_SZ)); + if(regs->u_regs[UREG_FP] > KERNBASE) + sun4c_unlock_tlb_entry(regs->u_regs[UREG_FP] & PAGE_MASK); + sun4c_unlock_tlb_entry(old_task->kernel_stack_page); + sun4c_unlock_tlb_entry((unsigned long) old_task); + restore_flags(flags); + /* bye bye... */ } -/* Real work gets done here. */ +static void sun4c_flush_hook(void *vtask) +{ + struct task_struct *dead_task = vtask; + + if(dead_task->tss.context != -1) + sun4c_flush_context(); +} + +static void sun4c_task_cacheflush(void *vtask) +{ + struct task_struct *flush_task = vtask; + + if(flush_task->tss.context != -1) + sun4c_flush_context(); +} + +static void sun4c_exit_hook(void *vtask) +{ +} /* Load up routines and constants for sun4c mmu */ -void -ld_mmu_sun4c(void) +void ld_mmu_sun4c(void) { printk("Loading sun4c MMU routines\n"); @@ -645,7 +1084,6 @@ pte_page = sun4c_pte_page; pmd_page = sun4c_pmd_page; - pgd_page = sun4c_pgd_page; sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir; @@ -667,10 +1105,8 @@ pgd_present = sun4c_pgd_present; pgd_inuse = sun4c_pgd_inuse; pgd_clear = sun4c_pgd_clear; - pgd_reuse = sun4c_pgd_reuse; mk_pte = sun4c_mk_pte; - pgd_set = sun4c_pgd_set; pte_modify = sun4c_pte_modify; pgd_offset = sun4c_pgd_offset; pmd_offset = sun4c_pmd_offset; @@ -704,6 +1140,20 @@ pte_mkdirty = sun4c_pte_mkdirty; pte_mkyoung = sun4c_pte_mkyoung; pte_mkcow = sun4c_pte_mkcow; - - return; + get_fault_info = sun4c_get_fault_info; + update_mmu_cache = sun4c_update_mmu_cache; + mmu_exit_hook = sun4c_exit_hook; + mmu_fork_hook = sun4c_fork_hook; + mmu_release_hook = sun4c_release_hook; + mmu_flush_hook = sun4c_flush_hook; + mmu_task_cacheflush = sun4c_task_cacheflush; + mmu_lockarea = sun4c_lockarea; + mmu_unlockarea = sun4c_unlockarea; + mmu_get_scsi_buffer = sun4c_get_scsi_buffer; + mmu_release_scsi_buffer = sun4c_release_scsi_buffer; + + /* These should _never_ get called with two level tables. */ + pgd_set = 0; + pgd_reuse = 0; + pgd_page = 0; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/sun4c_vac.c linux/arch/sparc/mm/sun4c_vac.c --- v1.3.43/linux/arch/sparc/mm/sun4c_vac.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/mm/sun4c_vac.c Sat Nov 25 02:59:45 1995 @@ -0,0 +1,37 @@ +/* $Id: sun4c_vac.c,v 1.5 1995/11/25 00:59:43 davem Exp $ + * vac.c: Routines for flushing various amount of the Sparc VAC + * (virtual address cache) on the sun4c. + * + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + */ + +#include + +#include +#include +#include +#include + +struct sun4c_vac_props sun4c_vacinfo; + +/* Invalidate the entire sun4c VAC, it must be off at this point */ +void +sun4c_flush_all(void) +{ + unsigned long begin, end; + + if(sun4c_vacinfo.on) + panic("SUN4C: AIEEE, trying to invalidate vac while" + " it is on."); + + /* Clear 'valid' bit in all cache line tags */ + begin = AC_CACHETAGS; + end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes); + while(begin < end) { + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (begin), "i" (ASI_CONTROL)); + begin += sun4c_vacinfo.linesize; + } + return; +} + diff -u --recursive --new-file v1.3.43/linux/arch/sparc/mm/vac-flush.c linux/arch/sparc/mm/vac-flush.c --- v1.3.43/linux/arch/sparc/mm/vac-flush.c Thu Feb 2 08:45:28 1995 +++ linux/arch/sparc/mm/vac-flush.c Thu Jan 1 02:00:00 1970 @@ -1,94 +0,0 @@ -/* vac.c: Routines for flushing various amount of the Sparc VAC - (virtual address cache). - - Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) -*/ - -#include -#include - -/* Flush all VAC entries for the current context */ - -extern int vac_do_hw_vac_flushes, vac_size, vac_linesize; -extern int vac_entries_per_context, vac_entries_per_segment; -extern int vac_entries_per_page; - -void -flush_vac_context() -{ - register int entries_left, offset; - register char* address; - - entries_left = vac_entries_per_context; - address = (char *) 0; - - if(vac_do_hw_vac_flushes) - { - while(entries_left-- >=0) - { - hw_flush_vac_context_entry(address); - address += PAGE_SIZE; - } - } - else - { - offset = vac_linesize; - while(entries_left-- >=0) - { - sw_flush_vac_context_entry(address); - address += offset; - } - } -} - -void -flush_vac_segment(register unsigned int segment) -{ - register int entries_left, offset; - register char* address = (char *) 0; - - entries_left = vac_entries_per_segment; - __asm__ __volatile__("sll %0, 18, %1\n\t" - "sra %1, 0x2, %1\n\t" - : "=r" (segment) : "0" (address)); - - if(vac_do_hw_vac_flushes) - { - while(entries_left-- >=0) - { - hw_flush_vac_segment_entry(address); - address += PAGE_SIZE; - } - } - else - { - offset = vac_linesize; - while(entries_left-- >=0) - { - sw_flush_vac_segment_entry(address); - address += offset; - } - } -} - -void -flush_vac_page(register unsigned int addr) -{ - register int entries_left, offset; - - if(vac_do_hw_vac_flushes) - { - hw_flush_vac_page_entry((unsigned long *) addr); - } - else - { - entries_left = vac_entries_per_page; - offset = vac_linesize; - while(entries_left-- >=0) - { - sw_flush_vac_page_entry((unsigned long *) addr); - addr += offset; - } - } -} - diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/Makefile linux/arch/sparc/prom/Makefile --- v1.3.43/linux/arch/sparc/prom/Makefile Tue Aug 15 20:39:00 1995 +++ linux/arch/sparc/prom/Makefile Sat Nov 25 02:59:51 1995 @@ -1,4 +1,4 @@ -# +# $Id: Makefile,v 1.5 1995/11/25 00:59:48 davem Exp $ # Makefile for the Sun Boot PROM interface library under # Linux. # diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c --- v1.3.43/linux/arch/sparc/prom/bootstr.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/bootstr.c Sat Nov 25 02:59:54 1995 @@ -1,4 +1,5 @@ -/* bootstr.c: Boot string/argument acquisition from the PROM. +/* $Id: bootstr.c,v 1.3 1995/11/25 00:59:51 davem Exp $ + * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v1.3.43/linux/arch/sparc/prom/console.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/console.c Sat Nov 25 02:59:56 1995 @@ -1,4 +1,5 @@ -/* console.c: Routines that deal with sending and receiving IO +/* $Id: console.c,v 1.5 1995/11/25 00:59:54 davem Exp $ + * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -6,6 +7,7 @@ #include #include +#include /* Non blocking get character from console input device, returns -1 * if no input was taken. This can be used for polling. @@ -71,3 +73,53 @@ return; } +/* Query for input device type */ +enum prom_input_device +prom_query_input_device() +{ + switch(*romvec->pv_stdin) { + case PROMDEV_KBD: return PROMDEV_IKBD; + case PROMDEV_TTYA: return PROMDEV_ITTYA; + case PROMDEV_TTYB: return PROMDEV_ITTYB; + default: + return PROMDEV_I_UNK; + }; +} + +/* Query for output device type */ + +enum prom_output_device +prom_query_output_device() +{ + int st_p; + char propb[ sizeof("display") ]; + int propl; + + switch(prom_vers) { + case PROM_V0: + switch(*romvec->pv_stdin) { + case PROMDEV_SCREEN: return PROMDEV_OSCREEN; + case PROMDEV_TTYA: return PROMDEV_OTTYA; + case PROMDEV_TTYB: return PROMDEV_OTTYB; + }; + break; + case PROM_V2: + case PROM_V3: + case PROM_P1275: + st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); + propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); + if (propl >= 0 && propl == sizeof("display") && + strncmp("display", propb, sizeof("display")) == 0) + { + return PROMDEV_OSCREEN; + } + /* This works on SS-2 (an early OpenFirmware) still. */ + /* XXX fix for serial cases at SS-5. */ + switch(*romvec->pv_stdin) { + case PROMDEV_TTYA: return PROMDEV_OTTYA; + case PROMDEV_TTYB: return PROMDEV_OTTYB; + }; + break; + }; + return PROMDEV_O_UNK; +} diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/devmap.c linux/arch/sparc/prom/devmap.c --- v1.3.43/linux/arch/sparc/prom/devmap.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/devmap.c Sat Nov 25 02:59:58 1995 @@ -1,4 +1,5 @@ -/* promdevmap.c: Map device/IO areas to virtual addresses. +/* $Id: devmap.c,v 1.2 1995/11/25 00:59:56 davem Exp $ + * promdevmap.c: Map device/IO areas to virtual addresses. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c --- v1.3.43/linux/arch/sparc/prom/devops.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/devops.c Sat Nov 25 03:00:00 1995 @@ -1,4 +1,5 @@ -/* devops.c: Device operations using the PROM. +/* $Id: devops.c,v 1.3 1995/11/25 00:59:59 davem Exp $ + * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/init.c linux/arch/sparc/prom/init.c --- v1.3.43/linux/arch/sparc/prom/init.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/init.c Sat Nov 25 03:00:02 1995 @@ -1,9 +1,12 @@ -/* init.c: Initialize internal variables used by the PROM +/* $Id: init.c,v 1.6 1995/11/25 01:00:01 davem Exp $ + * init.c: Initialize internal variables used by the PROM * library functions. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include + #include #include @@ -25,15 +28,11 @@ extern void prom_meminit(void); extern void prom_ranges_init(void); -int +void prom_init(struct linux_romvec *rp) { - if(!rp) return 1; romvec = rp; - if(romvec->pv_magic_cookie != LINUX_OPPROM_MAGIC) - return 1; - /* Ok, we seem to have a sane romvec here. */ switch(romvec->pv_romvers) { case 0: prom_vers = PROM_V0; @@ -47,12 +46,12 @@ case 4: prom_vers = PROM_P1275; prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n"); - return 1; + prom_halt(); break; default: prom_printf("PROMLIB: Bad PROM version %d\n", romvec->pv_romvers); - return 1; + prom_halt(); break; }; @@ -62,18 +61,19 @@ prom_root_node = prom_getsibling(0); if((prom_root_node == 0) || (prom_root_node == -1)) - return 1; + prom_halt(); if((((unsigned long) prom_nodeops) == 0) || (((unsigned long) prom_nodeops) == -1)) - return 1; + prom_halt(); prom_meminit(); + prom_ranges_init(); - prom_printf("PROMLIB: Sun Boot Prom Version %d Revision %d\n", - romvec->pv_romvers, prom_rev); + printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n", + romvec->pv_romvers, prom_rev); /* Initialization successful. */ - return 0; + return; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c --- v1.3.43/linux/arch/sparc/prom/memory.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/memory.c Sat Nov 25 03:00:04 1995 @@ -1,4 +1,5 @@ -/* memory.c: Prom routine for acquiring various bits of information +/* $Id: memory.c,v 1.4 1995/11/25 01:00:02 davem Exp $ + * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c --- v1.3.43/linux/arch/sparc/prom/misc.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/misc.c Sat Nov 25 03:00:06 1995 @@ -1,4 +1,5 @@ -/* misc.c: Miscellaneous prom functions that don't belong +/* $Id: misc.c,v 1.3 1995/11/25 01:00:04 davem Exp $ + * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c --- v1.3.43/linux/arch/sparc/prom/mp.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/mp.c Sat Nov 25 03:00:08 1995 @@ -1,4 +1,5 @@ -/* mp.c: OpenBoot Prom Multiprocessor support routines. Don't call +/* $Id: mp.c,v 1.4 1995/11/25 01:00:06 davem Exp $ + * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call * these on a UP or else you will halt and catch fire. ;) * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/palloc.c linux/arch/sparc/prom/palloc.c --- v1.3.43/linux/arch/sparc/prom/palloc.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/palloc.c Sat Nov 25 03:00:10 1995 @@ -1,4 +1,5 @@ -/* palloc.c: Memory allocation from the Sun PROM. +/* $Id: palloc.c,v 1.3 1995/11/25 01:00:08 davem Exp $ + * palloc.c: Memory allocation from the Sun PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/printf.c linux/arch/sparc/prom/printf.c --- v1.3.43/linux/arch/sparc/prom/printf.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/printf.c Sat Nov 25 03:00:12 1995 @@ -1,4 +1,5 @@ -/* printf.c: Internal prom library printf facility. +/* $Id: printf.c,v 1.4 1995/11/25 01:00:10 davem Exp $ + * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -7,102 +8,32 @@ * about or use it! It's simple and smelly anyway.... */ -#include +#include #include #include -char hexstring[] = "0123456789abcdef"; +static char ppbuf[1024]; void prom_printf(char *fmt, ...) { va_list args; - unsigned int ui_val; - int i_val, n_ctr; - char c_val; - char nstr_buf[32]; - char *s_val; - + char ch, *bptr; + int i; + va_start(args, fmt); - while(*fmt) { - if(*fmt != '%') { - if(*fmt == '\n') - prom_putchar('\r'); - prom_putchar(*fmt++); - continue; - } - - fmt++; - if(!*fmt) break; - n_ctr = 0; - switch(*fmt) { - case 'c': - c_val = va_arg(args, char); - if(c_val == '\n') - prom_putchar('\r'); - prom_putchar(c_val); - fmt++; - break; - case 's': - s_val = va_arg(args, char *); - while(*s_val != 0) { - prom_putchar(*s_val); - s_val++; - } - fmt++; - break; - case 'd': - /* Base 10 */ - i_val = va_arg(args, int); - if(i_val==0x0) - prom_putchar('0'); - else - while(i_val != 0x0) { - nstr_buf[n_ctr] = hexstring[i_val%0xa]; - i_val = ((unsigned long)i_val) / (unsigned) 0xa; - n_ctr++; - }; - while(--n_ctr >= 0) - prom_putchar(nstr_buf[n_ctr]); - fmt++; - break; - case 'x': - /* Base 16 */ - ui_val = va_arg(args, unsigned int); - if(ui_val==0x0) - prom_putchar('0'); - else - while(ui_val != 0x0) { - nstr_buf[n_ctr] = hexstring[ui_val%0x10]; - ui_val = ((unsigned long) ui_val) / (unsigned) 0x10; - n_ctr++; - }; - while(--n_ctr >= 0) - prom_putchar(nstr_buf[n_ctr]); - fmt++; - break; - case 'o': - /* Base 8 */ - ui_val = va_arg(args, unsigned int); - if(ui_val==0x0) - prom_putchar('0'); - else - while(ui_val != 0x0) { - nstr_buf[n_ctr] = hexstring[ui_val%0x8]; - ui_val = ((unsigned long) ui_val) / (unsigned) 0x8; - }; - while(--n_ctr >= 0) - prom_putchar(nstr_buf[n_ctr]); - fmt++; - break; - default: - /* Uh oh, something we can't handle... skip it */ - fmt++; - break; - }; + i = vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while((ch = *(bptr++)) != 0) { + if(ch == '\n') + prom_putchar('\r'); + + prom_putchar(ch); } - /* We are done... */ + va_end(args); return; } diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c --- v1.3.43/linux/arch/sparc/prom/ranges.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/ranges.c Sat Nov 25 03:00:14 1995 @@ -1,4 +1,5 @@ -/* ranges.c: Handle ranges in newer proms for obio. +/* $Id: ranges.c,v 1.4 1995/11/25 01:00:12 davem Exp $ + * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/segment.c linux/arch/sparc/prom/segment.c --- v1.3.43/linux/arch/sparc/prom/segment.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/segment.c Sat Nov 25 03:00:16 1995 @@ -1,4 +1,5 @@ -/* segment.c: Prom routine to map segments in other contexts before +/* $Id: segment.c,v 1.2 1995/11/25 01:00:14 davem Exp $ + * segment.c: Prom routine to map segments in other contexts before * a standalone is completely mapped. This is for sun4 and * sun4c architectures only. * diff -u --recursive --new-file v1.3.43/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v1.3.43/linux/arch/sparc/prom/tree.c Tue Jun 27 14:11:32 1995 +++ linux/arch/sparc/prom/tree.c Sat Nov 25 03:00:18 1995 @@ -1,4 +1,5 @@ -/* tree.c: Basic device tree traversal/scanning for the Linux +/* $Id: tree.c,v 1.6 1995/11/25 01:00:16 davem Exp $ + * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.3.43/linux/drivers/block/README.ide Tue Nov 21 13:22:06 1995 +++ linux/drivers/block/README.ide Sat Nov 25 11:46:06 1995 @@ -34,8 +34,6 @@ - PCI support is automatic - for VLB, use kernel command line option: ide0=cmd640_vlb - this support also enables the secondary i/f on most cards - - experimental interface timing parameter support -NEW! - experimental support for UMC 8672 interfaces NEW! - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f - use kernel command line option: ide1=ht6560 NEW! - experimental "fast" speed support for QD6580 interfaces @@ -47,10 +45,7 @@ NEW! - transparent support for DiskManager 6.0x and "Dynamic Disk Overlay" - works with Linux fdisk, LILO, loadlin, bootln, etc.. NEW! - mostly transparent support for EZ-Drive -NEW! - to use LILO with EZ, install LILO on the linux partition - rather than on the master boot record, and then mark the - linux partition as "bootable" or "active" using fdisk. - (courtesy of Juha Laiho ). + - LILO is incompatible (also harmless) with EZ-Drive NEW! - ide-cd.c now compiles separate from ide.c NEW! - Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces - for details, see comments at top of triton.c @@ -471,62 +466,24 @@ ================================================================================ - 1995 Nov 16 at 08:25 EST - from: 'dwhysong@dolphin.physics.ucsb.edu' (BNR400) + from: 'delman@mipg.upenn.edu' + subject: rz1000 -[I'm cc'ing this to Mark Lord: FYI, I've got at DTC2278S VLB EIDE -controller with a Connor CFA850A as /dev/hda and a Maxtor 7213A as -/dev/hdb using Linux 1.2.13 w/patches for assembly strcpy and the kswap -patches. I'm getting strange behavior and an unstable system when I try to -use 32 bit VLB data transfer to the interface card. However, hdparm -reports that the Connor is extremely fast when I can get the 32 bit mode -enabled using hdparm -c1 /dev/hd(a|b). However, if I don't do hdparm -c1 -on both /dev/hda and /dev/hdb, then when I run "hdparm -t /dev/hda" the -disk subsystem locks up... the disk LED comes on and stays on, and no -other programs are able to get disk access (I can switch VC's, but I can't -get past the username prompt). I thought you should know about this. I'm -not sure if it's a problem with the support for the DTC cards, or a -peculiarity with my hardware configuration. I doubt that my hardware -itself is flaky, though that's always a possibility.] - -On Wed, 15 Nov 1995, Michael Faurot wrote: - -> > The trick is setting BOTH drives to use the 32 bit interface. -> -> Congrats on getting it going. Those are some great transfer -> rates. I noticed you did switch on the unmasking. Noticed any -> problems with things under extreme load or with serial transfers? - -I've never had any problems which I could trace to interrupt unmasking. -Of course, my system usually doesn't have a really heavy load, either. -These numbers seem way too high for a disk with something like 3500 (?) -RPM. - -Sleepy# hdparm -t /dev/hda - -/dev/hda: - Timing buffer-cache reads: 32 MB in 2.24 seconds =14.29 MB/sec - Timing buffered disk reads: 16 MB in 3.63 seconds = 4.41 MB/sec - Estimating raw driver speed: 16 MB in 2.51 seconds = 6.37 MB/sec - -> Not sure I was much help to you, but I'm glad to hear you got it -> working--and pretty impressivly at that. :-) - -Mmm, well, about that... I've found that my Connor drive (/dev/hda) is -pretty fast when I have my system configured like this. I'm still not -sure I trust the "hdparm -t" results, though. However, when I try -"hdparm -t /dev/hdb" (/dev/hdb is an older Maxtor 7213A) I have the same -problem I had before with my disk subsystem locking up. - -I've tried just about every possible combination of flags in ide.c and -hdparm, and I can't get decent performance out of this drive/controller -combination without some kind of instability creeping in. I'm living with -the situation now only because /dev/hdb is a DOS-only drive, and I don't -need it under Linux. However, I don't really like the situation. +Hi Mark! Looks like you managed to get the info from Intel to disable +the read-ahead feature of the RZ1000. My encounter with +Zeos (subsidiary of Micron which owns PCTech) has not been as +successful --- one guy needs to ask his supervisors about NDA, another +guy thinks that there is too much of a performance hit with read-ahead +disabled. + +Did the following benchmark to see how true the claim is. +With Linux 1.2.13, average of 10 "hdparm -t" in MB/s: + + hdparm -c0 hdparm -c1 +read-ahead enabled 4.28 4.25 +read-ahead disabled 3.58 4.30 --Dave -dwhysong@physics.ucsb.edu - -(Why can't this stuff be simple? Plug the card in, and it works? Every -hardware manufacturer has to have their own way of doing things...) +Maybe -c1 should be the default for the RZ1000, or as a suggestion in +the README for people with the RZ1000. +Cheers, Delman. diff -u --recursive --new-file v1.3.43/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v1.3.43/linux/drivers/block/cmd640.c Tue Nov 21 13:22:06 1995 +++ linux/drivers/block/cmd640.c Thu Jan 1 02:00:00 1970 @@ -1,444 +0,0 @@ -/* - * linux/drivers/block/cmd640.c Version 0.01 Nov 16, 1995 - * - * Copyright (C) 1995 Linus Torvalds & author (see below) - */ - -/* - * Principal Author/Maintainer: abramov@cecmow.enet.dec.com (Igor) - * - * This file provides support for the advanced features and bugs - * of IDE interfaces using the CMD Technologies 0640 IDE interface chip. - * - * Version 0.01 Initial version, hacked out of ide.c, - * and #include'd rather than compiled separately. - * This will get cleaned up in a subsequent release. - */ - -/* Interface to access cmd640x registers */ -static void (*put_cmd640_reg)(int key, int reg_no, int val); -static byte (*get_cmd640_reg)(int key, int reg_no); - -enum { none, vlb, pci1, pci2 }; -static int bus_type = none; -static int cmd640_chip_version; -static int cmd640_key; -static byte is_cmd640[MAX_HWIFS]; - -/* - * For some unknown reasons pcibios functions which read and write registers - * do not work with cmd640. We use direct io instead. - */ - -/* PCI method 1 access */ - -static void put_cmd640_reg_pci1(int key, int reg_no, int val) -{ - unsigned long flags; - - save_flags(flags); - cli(); - outl_p((reg_no & 0xfc) | key, 0xcf8); - outb_p(val, (reg_no & 3) + 0xcfc); - restore_flags(flags); -} - -static byte get_cmd640_reg_pci1(int key, int reg_no) -{ - byte b; - unsigned long flags; - - save_flags(flags); - cli(); - outl_p((reg_no & 0xfc) | key, 0xcf8); - b = inb(0xcfc + (reg_no & 3)); - restore_flags(flags); - return b; -} - -/* PCI method 2 access (from CMD datasheet) */ - -static void put_cmd640_reg_pci2(int key, int reg_no, int val) -{ - unsigned long flags; - - save_flags(flags); - cli(); - outb_p(0x10, 0xcf8); - outb_p(val, key + reg_no); - outb_p(0, 0xcf8); - restore_flags(flags); -} - -static byte get_cmd640_reg_pci2(int key, int reg_no) -{ - byte b; - unsigned long flags; - - save_flags(flags); - cli(); - outb_p(0x10, 0xcf8); - b = inb(key + reg_no); - outb_p(0, 0xcf8); - restore_flags(flags); - return b; -} - -/* VLB access */ - -static void put_cmd640_reg_vlb(int key, int reg_no, int val) -{ - unsigned long flags; - - save_flags(flags); - cli(); - outb(reg_no, key + 8); - outb(val, key + 0xc); - restore_flags(flags); -} - -static byte get_cmd640_reg_vlb(int key, int reg_no) -{ - byte b; - unsigned long flags; - - save_flags(flags); - cli(); - outb(reg_no, key + 8); - b = inb(key + 0xc); - restore_flags(flags); - return b; -} - -/* - * Probe for CMD640x -- pci method 1 - */ - -static int probe_for_cmd640_pci1(void) -{ - long id; - int k; - - for (k = 0x80000000; k <= 0x8000f800; k += 0x800) { - outl(k, 0xcf8); - id = inl(0xcfc); - if (id != 0x06401095) - continue; - put_cmd640_reg = put_cmd640_reg_pci1; - get_cmd640_reg = get_cmd640_reg_pci1; - cmd640_key = k; - return 1; - } - return 0; -} - -/* - * Probe for CMD640x -- pci method 2 - */ - -static int probe_for_cmd640_pci2(void) -{ - int i; - int v_id; - int d_id; - - for (i = 0xc000; i <= 0xcf00; i += 0x100) { - outb(0x10, 0xcf8); - v_id = inw(i); - d_id = inw(i + 2); - outb(0, 0xcf8); - if (v_id != 0x1095 || d_id != 0x640) - continue; - put_cmd640_reg = put_cmd640_reg_pci2; - get_cmd640_reg = get_cmd640_reg_pci2; - cmd640_key = i; - return 1; - } - return 0; -} - -/* - * Probe for CMD640x -- vlb - */ - -static int probe_for_cmd640_vlb(void) { - byte b; - - outb(0x50, 0x178); - b = inb(0x17c); - if (b == 0xff || b == 0 || (b & 0x20)) { - outb(0x50, 0xc78); - b = inb(0x7c); - if (b == 0xff || b == 0 || !(b & 0x20)) - return 0; - cmd640_key = 0x70; - } else { - cmd640_key = 0x170; - } - put_cmd640_reg = put_cmd640_reg_vlb; - get_cmd640_reg = get_cmd640_reg_vlb; - return 1; -} - -/* - * Probe for Cmd640x and initialize it if found - */ - -int ide_probe_for_cmd640x(void) -{ - int i; - - for (i = 0; i < MAX_HWIFS; i++) - is_cmd640[i] = 0; - - if (probe_for_cmd640_pci1()) { - bus_type = pci1; - } else if (probe_for_cmd640_pci2()) { - bus_type = pci2; - } else if (cmd640_vlb && probe_for_cmd640_vlb()) { - /* May be remove cmd640_vlb at all, and probe in any case */ - bus_type = vlb; - } else { - return 0; - } - - /* - * Undocumented magic. (There is no 0x5b port in specs) - */ - - put_cmd640_reg(cmd640_key, 0x5b, 0xbd); - if (get_cmd640_reg(cmd640_key, 0x5b) != 0xbd) { - printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n"); - return 0; - } - put_cmd640_reg(cmd640_key, 0x5b, 0); - - /* - * Documented magic. - */ - - cmd640_chip_version = get_cmd640_reg(cmd640_key, 0x50) & 3; - if (cmd640_chip_version == 0) { - printk ("ide: wrong CMD640 version -- 0\n"); - return 0; - } - - put_cmd640_reg(cmd640_key, 0x51, get_cmd640_reg(cmd640_key, 0x51) | 0xc8); - put_cmd640_reg(cmd640_key, 0x57, 0); - put_cmd640_reg(cmd640_key, 0x57, get_cmd640_reg(cmd640_key, 0x57) | 0x0c); - - serialized = 1; - - printk("ide: buggy CMD640 interface at "); - switch (bus_type) { - case vlb : - printk("local bus, port 0x%x", cmd640_key); - break; - case pci1: - printk("pci, (0x%x)", cmd640_key); - break; - case pci2: - printk("pci,(access method 2) (0x%x)", cmd640_key); - break; - } - - is_cmd640[0] = is_cmd640[1] = 1; - - /* - * Reset interface timings - */ - - put_cmd640_reg(cmd640_key, 0x58, 0); - put_cmd640_reg(cmd640_key, 0x52, 0); - - printk("\n ... serialized, disabled read-ahead, secondary interface enabled\n"); - - return 1; -} - -static int as_clocks(int a) { - switch (a & 0xf0) { - case 0 : return 4; - case 0x40 : return 2; - case 0x80 : return 3; - case 0xc0 : return 5; - default : return -1; - } -} - -/* - * Tuning of drive parameters - */ - -static void cmd640_set_timing(int if_num, int dr_num, int r1, int r2) { - int b_reg; - byte b; - int r52; - - b_reg = if_num ? 0x57 : dr_num ? 0x55 : 0x53; - - if (if_num == 0) { - put_cmd640_reg(cmd640_key, b_reg, r1); - put_cmd640_reg(cmd640_key, b_reg + 1, r2); - } else { - b = get_cmd640_reg(cmd640_key, b_reg); - if ((b&1) == 0) { - put_cmd640_reg(cmd640_key, b_reg, r1); - } else { - if (as_clocks(b) < as_clocks(r1)) - put_cmd640_reg(cmd640_key, b_reg, r1); - } - b = get_cmd640_reg(cmd640_key, b_reg + 1); - if (b == 0) { - put_cmd640_reg(cmd640_key, b_reg + 1, r2); - } else { - r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf); - r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0); - put_cmd640_reg(cmd640_key, b_reg+1, r52); - } - } - - b = get_cmd640_reg(cmd640_key, 0x52); - if (b == 0) { - put_cmd640_reg(cmd640_key, 0x52, r2); - } else { - r52 = (b&0xf) < (r2&0xf) ? (r2&0xf) : (b&0xf); - r52 |= (b&0xf0) < (r2&0xf0) ? (r2&0xf0) : (b&0xf0); - put_cmd640_reg(cmd640_key, 0x52, r52); - } -} - -static int bus_speed = 33; /* MHz */ - -struct pio_timing { - int mc_time; /* Minimal cycle time (ns) */ - int av_time; /* Address valid to DIOR-/DIOW- setup (ns) */ - int ds_time; /* DIOR data setup (ns) */ -} pio_timings[6] = { - { 70, 165, 600 }, /* PIO Mode 0 */ - { 50, 125, 383 }, /* PIO Mode 1 */ - { 30, 100, 240 }, /* PIO Mode 2 */ - { 30, 80, 180 }, /* PIO Mode 3 */ - { 25, 70, 125 }, /* PIO Mode 4 */ - { 20, 50, 100 } /* PIO Mode ? */ -}; - -struct drive_pio_info { - const char *name; - int pio; -} drive_pios[] = { - { "Maxtor 7131 AT", 1 }, - { "Maxtor 7171 AT", 1 }, - { "Maxtor 7213 AT", 1 }, - { "Maxtor 7245 AT", 1 }, - { "SAMSUNG SHD-3122A", 1 }, - { "QUANTUM ELS127A", 0 }, - { "QUANTUM LPS240A", 0 }, - { "QUANTUM LPS270A", 3 }, - { "QUANTUM LPS540A", 3 }, - { NULL, 0 } -}; - -static int known_drive_pio(char* name) { - struct drive_pio_info* pi; - - for (pi = drive_pios; pi->name != NULL; pi++) { - if (strcmp(pi->name, name) == 0) - return pi->pio; - } - return -1; -} - -static void cmd640_timings_to_regvals(int mc_time, int av_time, int ds_time, - int clock_time, - int* r1, int* r2) -{ - int a, b; - - a = (mc_time + clock_time - 1)/clock_time; - if (a <= 2) *r1 = 0x40; - else if (a == 3) *r1 = 0x80; - else if (a == 4) *r1 = 0; - else *r1 = 0xc0; - - a = (av_time + clock_time - 1)/clock_time; - if (a < 2) - a = 2; - b = (ds_time + clock_time - 1)/clock_time - a; - if (b < 2) - b = 2; - if (b > 0x11) { - a += b - 0x11; - b = 0x11; - } - if (a > 0xf) - a = 0; - if (cmd640_chip_version > 1) - b -= 1; - if (b > 0xf) - b = 0; - *r2 = (a << 4) | b; -} - -static void set_pio_mode(int if_num, int drv_num, int mode_num) { - int p_base; - int i; - - p_base = if_num ? 0x170 : 0x1f0; - outb(3, p_base + 1); - outb(mode_num | 8, p_base + 2); - outb((drv_num | 0xa) << 4, p_base + 6); - outb(0xef, p_base + 7); - for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++) - delay_10ms(); -} - -void cmd640_tune_drive(ide_drive_t* drive) { - int interface_number; - int drive_number; - int clock_time; /* ns */ - int max_pio; - int mc_time, av_time, ds_time; - struct hd_driveid* id; - int r1, r2; - - /* - * Determine if drive is under cmd640 control - */ - interface_number = HWIF(drive) - ide_hwifs; - if (!is_cmd640[interface_number]) - return; - - drive_number = drive - HWIF(drive)->drives; - clock_time = 1000/bus_speed; - id = drive->id; - if ((max_pio = known_drive_pio(id->model)) != -1) { - mc_time = pio_timings[max_pio].mc_time; - av_time = pio_timings[max_pio].av_time; - ds_time = pio_timings[max_pio].ds_time; - } else { - max_pio = id->tPIO; - mc_time = pio_timings[max_pio].mc_time; - av_time = pio_timings[max_pio].av_time; - ds_time = pio_timings[max_pio].ds_time; - if (id->field_valid & 2) { - if ((id->capability & 8) && (id->eide_pio_modes & 7)) { - if (id->eide_pio_modes & 4) max_pio = 5; - else if (id->eide_pio_modes & 2) max_pio = 4; - else max_pio = 3; - ds_time = id->eide_pio_iordy; - mc_time = pio_timings[max_pio].mc_time; - av_time = pio_timings[max_pio].av_time; - } else { - ds_time = id->eide_pio; - } - if (ds_time == 0) - ds_time = pio_timings[max_pio].ds_time; - } - } - cmd640_timings_to_regvals(mc_time, av_time, ds_time, clock_time, - &r1, &r2); - set_pio_mode(interface_number, drive_number, max_pio); - cmd640_set_timing(interface_number, drive_number, r1, r2); - printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2); -} diff -u --recursive --new-file v1.3.43/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v1.3.43/linux/drivers/block/ide-cd.c Wed Nov 8 07:11:30 1995 +++ linux/drivers/block/ide-cd.c Wed Nov 22 13:42:41 1995 @@ -69,12 +69,12 @@ * Fix handling of errors occuring before the * packet command is transferred. * Fix transfers with odd bytelengths. + * 3.03 Oct 27, 1995 -- Some Creative drives have an id of just `CD'. + * `DCI-2S10' drives are broken too. + * 3.04 Nov 20, 1995 -- So are Vertros drives. * - * NOTE: I've tried to implement support for direct audio reads - * in this version, but i haven't been able to fully test it - * due to a lack of the proper hardware. I'd be interested in hearing - * if you get anything other than a `Parameter not supported' - * (asc=0x26, ascq=1) error when trying to do a direct audio read. + * NOTE: Direct audio reads will only work on some types of drive. + * So far, i've received reports of success for Sony and Toshiba drives. * * ATAPI cd-rom driver. To be used with ide.c. * @@ -2603,13 +2603,19 @@ ((drive->id->config & 0x0060) == 0x20); /* Accommodate some broken drives... */ - if (strcmp (drive->id->model, "CD220E") == 0) /* Creative Labs */ + if (strcmp (drive->id->model, "CD220E") == 0 || + strcmp (drive->id->model, "CD") == 0) /* Creative Labs */ CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; else if (strcmp (drive->id->model, "TO-ICSLYAL") == 0 || /* Acer CD525E */ strcmp (drive->id->model, "OTI-SCYLLA") == 0) CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; + /* I don't know who makes this. + Francesco Messineo says this one's broken too. */ + else if (strcmp (drive->id->model, "DCI-2S10") == 0) + CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; + else if (strcmp (drive->id->model, "CDA26803I SE") == 0) /* Aztech */ { CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; @@ -2618,6 +2624,12 @@ CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1; } + else if (strcmp (drive->id->model, "V003S0DS") == 0 || /* Vertros */ + strcmp (drive->id->model, "0V300SSD") == 0 || + strcmp (drive->id->model, "V004E0DT") == 0 || + strcmp (drive->id->model, "0V400ETD") == 0) + CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1; + drive->cdrom_info.toc = NULL; drive->cdrom_info.sector_buffer = NULL; drive->cdrom_info.sector_buffered = 0; @@ -2635,4 +2647,6 @@ * duplicated functionality between read and ioctl paths? * Establish interfaces for an IDE port driver, and break out the cdrom * code into a loadable module. + * Support changers. + * Write some real documentation. */ diff -u --recursive --new-file v1.3.43/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.3.43/linux/drivers/block/ide.c Tue Nov 21 13:22:07 1995 +++ linux/drivers/block/ide.c Sat Nov 25 11:46:06 1995 @@ -1,11 +1,11 @@ /* - * linux/drivers/block/ide.c Version 5.18 Nov 16, 1995 + * linux/drivers/block/ide.c Version 5.17 Nov 3, 1995 * * Copyright (C) 1994, 1995 Linus Torvalds & authors (see below) */ /* - * This is the multiple IDE interface driver, as evolved from hd.c. + * This is the multiple IDE interface driver, as evolved from hd.c. * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15). * There can be up to two drives per interface, as per the ATA-2 spec. * @@ -13,17 +13,17 @@ * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64 * Tertiary i/f: ide2: major=33; (hde) minor=0; (hdf) minor=64 * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64 - * + * * It is easy to extend ide.c to handle more than four interfaces: * * Change the MAX_HWIFS constant in ide.h. - * + * * Define some new major numbers (in major.h), and insert them into * the ide_hwif_to_major table in ide.c. - * + * * Fill in the extra values for the new interfaces into the two tables * inside ide.c: default_io_base[] and default_irqs[]. - * + * * Create the new request handlers by cloning "do_ide3_request()" * for each new interface, and add them to the switch statement * in the ide_init() function in ide.c. @@ -56,7 +56,7 @@ * Maintained by Mark Lord (mlord@bnr.ca): ide.c, ide.h, triton.c, hd.c, .. * * This was a rewrite of just about everything from hd.c, though some original - * code is still sprinkled about. Think of it as a major evolution, with + * code is still sprinkled about. Think of it as a major evolution, with * inspiration from lots of linux users, esp. hamish@zot.apana.org.au * * Version 1.0 ALPHA initial code, primary i/f working okay @@ -167,18 +167,15 @@ * remove "Huh?" from cmd640 code * added qd6580 interface speed select from Colten Edwards * Version 5.17 kludge around bug in BIOS32 on Intel triton motherboards - * Version 5.18 new CMD640 code, moved to cmd640.c, #include'd for now - * new UMC8672 code, moved to umc8672.c, #include'd for now - * disallow turning on DMA when h/w not capable of DMA * * Driver compile-time options are in ide.h * * To do, in likely order of completion: - * - make cmd640.c and umc8672.c compile separately from ide.c * - add ALI M1443/1445 chipset support from derekn@vw.ece.cmu.edu - * - add ioctls to get/set interface timings on various interfaces * - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk + * - add ioctls to get/set interface timings on various interfaces * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f + * - improved CMD support: handed this off to someone else * - find someone to work on IDE *tape drive* support */ @@ -212,14 +209,9 @@ #include "ide.h" -#ifdef SUPPORT_CMD640 -void cmd640_tune_drive(ide_drive_t *); -static int cmd640_vlb = 0; -#endif - ide_hwif_t ide_hwifs[MAX_HWIFS]; /* hwif info */ static ide_hwgroup_t *irq_to_hwgroup [16]; -static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; +static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168}; static const byte default_irqs[MAX_HWIFS] = {14, 15, 11, 10}; @@ -1007,7 +999,7 @@ /* * multwrite() transfers a block of one or more sectors of data to a drive - * as part of a disk multwrite operation. + * as part of a disk multwrite operation. */ static void multwrite (ide_drive_t *drive) { @@ -1240,7 +1232,7 @@ if (drive->select.b.lba) { #ifdef DEBUG printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n", - drive->name, (rq->cmd==READ)?"read":"writ", + drive->name, (rq->cmd==READ)?"read":"writ", block, rq->nr_sectors, (unsigned long) rq->buffer); #endif OUT_BYTE(block,io_base+IDE_SECTOR_OFFSET); @@ -1503,7 +1495,7 @@ printk("%s: marginal timeout\n", drive->name); } else { /* drive not responding */ hwgroup->handler = NULL; - if (hwgroup->hwif->dmaproc) + if (hwgroup->hwif->dmaproc) (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive); if (!ide_error(drive, "irq timeout", GET_STAT())) do_hwgroup_request (hwgroup); @@ -1530,7 +1522,7 @@ * In reality, this is a non-issue. The new command is not sent unless the * drive is ready to accept one, in which case we know the drive is not * trying to interrupt us. And ide_set_handler() is always invoked before - * completing the issuance of any new drive command, so we will not be + * completing the issuance of any new drive command, so we will not be * accidently invoked as a result of any valid command completion interrupt. * */ @@ -1814,24 +1806,24 @@ case BLKRAGET: return write_fs_long(arg, read_ahead[MAJOR(inode->i_rdev)]); - case BLKGETSIZE: /* Return device size */ + case BLKGETSIZE: /* Return device size */ return write_fs_long(arg, drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects); case BLKRRPART: /* Re-read partition tables */ return revalidate_disk(inode->i_rdev); - case HDIO_GET_KEEPSETTINGS: + case HDIO_GET_KEEPSETTINGS: return write_fs_long(arg, drive->keep_settings); - case HDIO_GET_UNMASKINTR: + case HDIO_GET_UNMASKINTR: return write_fs_long(arg, drive->unmask); - case HDIO_GET_DMA: + case HDIO_GET_DMA: return write_fs_long(arg, drive->using_dma); - case HDIO_GET_CHIPSET: + case HDIO_GET_CHIPSET: return write_fs_long(arg, drive->chipset); - case HDIO_GET_MULTCOUNT: + case HDIO_GET_MULTCOUNT: return write_fs_long(arg, drive->mult_count); case HDIO_GET_IDENTITY: @@ -1866,10 +1858,6 @@ cli(); switch (cmd) { case HDIO_SET_DMA: - if (!(HWIF(drive)->dmaproc)) { - restore_flags(flags); - return -EPERM; - } drive->using_dma = arg; break; case HDIO_SET_KEEPSETTINGS: @@ -2058,7 +2046,7 @@ drive->present = 1; drive->cyl = drive->bios_cyl = id->cyls; drive->head = drive->bios_head = id->heads; - drive->sect = drive->bios_sect = id->sectors; + drive->sect = drive->bios_sect = id->sectors; } /* Handle logical geometry translation by the drive */ if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads @@ -2067,7 +2055,7 @@ /* * Extract the physical drive geometry for our use. * Note that we purposely do *not* update the bios info. - * This way, programs that use it (like fdisk) will + * This way, programs that use it (like fdisk) will * still have the same logical view as the BIOS does, * which keeps the partition table from being screwed. * @@ -2091,7 +2079,7 @@ if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) { drive->cyl = id->cyls; drive->head = id->heads; - drive->sect = id->sectors; + drive->sect = id->sectors; } /* Correct the number of cyls if the bios value is too small */ if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) { @@ -2119,9 +2107,6 @@ printk(", DMA"); } printk("\n"); -#ifdef SUPPORT_CMD640 - cmd640_tune_drive(drive); /* but can we tune a fish? */ -#endif } /* @@ -2351,8 +2336,8 @@ * The code enables the secondary IDE controller and the PIO4 (3?) timings on * the primary (EIDE). You may probably have to enable the 32-bit support to * get the full speed. You better get the disk interrupts disabled ( hdparm -u0 - * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my - * filesystem corrupted with -u1, but under heavy disk load only :-) + * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my + * filesystem corrupted with -u1, but under heavy disk load only :-) * * From: mlord@bnr.ca -- this chipset is now forced to use the "serialize" feature, * which hopefully will make it more reliable to use.. maybe it has the same bugs @@ -2432,13 +2417,59 @@ } #endif /* SUPPORT_QD6580 */ -#ifdef SUPPORT_UMC8672 -#include "umc8672.c" /* until we tidy up the interface some more */ -#endif +#if SUPPORT_CMD640 +/* + * ??? fixme: + */ +byte read_cmd640_vlb (byte port, byte reg) +{ + byte val; + + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, port); + val = inb(port+4); + restore_flags(flags); + return val; +} + +void write_cmd640_vlb (byte port, byte reg, byte val) +{ + unsigned long flags; + save_flags(flags); + cli(); + outw(reg, port); + outw(val, port+4); + restore_flags(flags); +} + +void init_cmd640_vlb (void) +{ + byte reg; + unsigned short port = 0x178; -#ifdef SUPPORT_CMD640 -#include "cmd640.c" /* until we tidy up the interface some more */ + serialized = 1; + printk("ide: buggy CMD640 interface: serialized, "); + reg = read_cmd640_vlb(port, 0x50); + if (reg == 0xff || (reg & 0x90) != 0x90) { +#if TRY_CMD640_VLB_AT_0x78 + port = 0x78; + reg = read_cmd640_vlb(port, 0x50); + if (reg == 0xff || (reg & 0x90) != 0x90) #endif + { + disallow_unmask = 1; + printk("(probe failed) disabled unmasking\n"); + return; + } + } + write_cmd640_vlb(port, 0x51, read_cmd640_vlb(port, 0x51)|0xc8); + write_cmd640_vlb(port, 0x57, read_cmd640_vlb(port, 0x57)|0x0c); + printk("disabled read-ahead, enabled secondary\n"); + +} +#endif /* SUPPORT_CMD640 */ /* * stridx() returns the offset of c within s, @@ -2457,7 +2488,7 @@ * 2. if the remainder matches one of the supplied keywords, * the index (1 based) of the keyword is negated and returned. * 3. if the remainder is a series of no more than max_vals numbers - * separated by commas, the numbers are saved in vals[] and a + * separated by commas, the numbers are saved in vals[] and a * count of how many were saved is returned. Base10 is assumed, * and base16 is allowed when prefixed with "0x". * 4. otherwise, zero is returned. @@ -2480,7 +2511,7 @@ /* * Look for a series of no more than "max_vals" * numeric values separated by commas, in base10, - * or base16 when prefixed with "0x". + * or base16 when prefixed with "0x". * Return a count of how many were found. */ for (n = 0; (i = stridx(decimal, *s)) >= 0;) { @@ -2590,18 +2621,11 @@ * Look for interface options: "idex=" */ if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) { - const char *ide_words[] = {"noprobe", "serialize", "dtc2278", "ht6560b", - "cmd640_vlb", "qd6580", "umc8672", NULL}; + const char *ide_words[] = {"noprobe", "serialize", "dtc2278", "ht6560b", "cmd640_vlb", "qd6580", NULL}; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; switch (match_parm(&s[4], ide_words, vals, 3)) { -#if SUPPORT_UMC8672 - case -7: /* "umc8672" */ - if (hw != 0) goto bad_hwif; - init_umc8672(); - goto done; -#endif /* SUPPORT_UMC8672 */ #if SUPPORT_QD6580 case -6: /* "qd6580" */ if (hw != 0) goto bad_hwif; @@ -2611,7 +2635,8 @@ #if SUPPORT_CMD640 case -5: /* "cmd640_vlb" */ if (hw > 1) goto bad_hwif; - cmd640_vlb = 1; + init_cmd640_vlb(); + goto do_serialize; /* not necessary once we implement the above */ break; #endif /* SUPPORT_CMD640 */ #if SUPPORT_HT6560B @@ -2684,7 +2709,7 @@ drive->cyl = drive->bios_cyl = drive->id->cyls; drive->head = drive->bios_head = drive->id->heads; - drive->sect = drive->bios_sect = drive->id->sectors; + drive->sect = drive->bios_sect = drive->id->sectors; drive->special.b.set_geometry = 1; tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63; @@ -2720,7 +2745,7 @@ * drives in the system -- the ones reflected as drive 1 or 2. The first * drive is stored in the high nibble of CMOS byte 0x12, the second in the low * nibble. This will be either a 4 bit drive type or 0xf indicating use byte - * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value + * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value * means we have an AT controller hard disk for that drive. * * Of course, there is no guarantee that either drive is actually on the @@ -2880,6 +2905,45 @@ } #endif /* SUPPORT_RZ1000 */ +#if SUPPORT_CMD640 +void init_cmd640 (byte bus, byte fn) +{ + int rc; + unsigned char reg; + + serialized = 1; + printk("ide: buggy CMD640 interface: "); + +#if 0 /* funny.. the cmd640b I tried this on claimed to not be enabled.. */ + unsigned short sreg; + if ((rc = pcibios_read_config_word (bus, fn, PCI_COMMAND, &sreg))) { + ide_pci_access_error (rc); + } else if (!(sreg & 1)) { + printk("not enabled\n"); + } else { + + /* + * The first part is undocumented magic from the DOS driver. + * According to the datasheet, there is no port 0x5b on the cmd640. + */ + (void) pcibios_write_config_byte(bus, fn, 0x5b, 0xbd); + if (pcibios_write_config_byte(bus, fn, 0x5b, 0xbd) != 0xbd) + printk("init_cmd640: huh? 0x5b read back wrong\n"); + (void) pcibios_write_config_byte(bus, fn, 0x5b, 0); +#endif /* 0 */ + /* + * The rest is from the cmd640b datasheet. + */ + if ((rc = pcibios_read_config_byte(bus, fn, 0x51, ®)) + || (rc = pcibios_write_config_byte(bus, fn, 0x51, reg | 0xc0)) /* 0xc8 to enable 2nd i/f */ + || (rc = pcibios_read_config_byte(bus, fn, 0x57, ®)) + || (rc = pcibios_write_config_byte(bus, fn, 0x57, reg | 0x0c))) + buggy_interface_fallback (rc); + else + printk("serialized, disabled read-ahead\n"); +} +#endif /* SUPPORT_CMD640 */ + typedef void (ide_pci_init_proc_t)(byte, byte); /* @@ -2902,7 +2966,7 @@ /* * ide_init_pci() finds/initializes "known" PCI IDE interfaces - * + * * This routine should ideally be using pcibios_find_class() to find * all IDE interfaces, but that function causes some systems to "go weird". */ @@ -2911,6 +2975,9 @@ #if SUPPORT_RZ1000 ide_probe_pci (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, &init_rz1000, 0); #endif +#if SUPPORT_CMD640 + ide_probe_pci (PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, &init_cmd640, 0); +#endif #ifdef CONFIG_BLK_DEV_TRITON /* * Apparently the BIOS32 services on Intel motherboards are buggy, @@ -2941,9 +3008,6 @@ if (pcibios_present()) ide_init_pci (); #endif /* CONFIG_PCI */ -#ifdef SUPPORT_CMD640 - ide_probe_for_cmd640x(); -#endif /* * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports diff -u --recursive --new-file v1.3.43/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v1.3.43/linux/drivers/block/ide.h Tue Nov 21 13:22:07 1995 +++ linux/drivers/block/ide.h Sat Nov 25 12:10:07 1995 @@ -40,9 +40,6 @@ #ifndef SUPPORT_CMD640 /* 1 to support CMD640 chipset */ #define SUPPORT_CMD640 1 /* 0 to reduce kernel size */ #endif -#ifndef SUPPORT_UMC8672 /* 1 to support UMC8672 chipset */ -#define SUPPORT_UMC8672 1 /* 0 to reduce kernel size */ -#endif #ifndef SUPPORT_HT6560B /* 1 to support HT6560B chipset */ #define SUPPORT_HT6560B 1 /* 0 to reduce kernel size */ #endif diff -u --recursive --new-file v1.3.43/linux/drivers/block/triton.c linux/drivers/block/triton.c --- v1.3.43/linux/drivers/block/triton.c Tue Nov 21 13:22:08 1995 +++ linux/drivers/block/triton.c Sat Nov 25 11:46:06 1995 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/triton.c Version 1.03 Nov 16, 1995 + * linux/drivers/block/triton.c Version 1.02 Oct 13, 1995 * * Copyright (c) 1995 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -64,12 +64,8 @@ * the observation that WRITEs work most of the time, depending on * cache-buffer occupancy, but multi-sector reads seldom work. * - * Testing was done with a Gigabyte GA-586 ATE system and the following drive: - * (Uwe Bonnes - bon@elektron.ikp.physik.th-darmstadt.de) - * - * Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4. - * - much better than its 1Gig cousin, this drive is reported to work - * very well with DMA (7.3MB/sec). + * Drives like the AC31000H could likely be made to work if all DMA were done + * one sector at a time, but that would likely negate any advantage over PIO. * * If you have any drive models to add, email your results to: mlord@bnr.ca * Keep an eye on /var/adm/messages for "DMA disabled" messages. diff -u --recursive --new-file v1.3.43/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c --- v1.3.43/linux/drivers/block/umc8672.c Tue Nov 21 13:22:08 1995 +++ linux/drivers/block/umc8672.c Thu Jan 1 02:00:00 1970 @@ -1,108 +0,0 @@ -/* - * linux/drivers/block/umc8672.c Version 0.01 Nov 16, 1995 - * - * Copyright (C) 1995 Linus Torvalds & author (see below) - */ - -/* - * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien) - * - * This file provides support for the advanced features - * of the UMC 8672 IDE interface. - * - * Version 0.01 Initial version, hacked out of ide.c, - * and #include'd rather than compiled separately. - * This will get cleaned up in a subsequent release. - */ - -/* - * VLB Controller Support from - * Wolfram Podien - * Rohoefe 3 - * D28832 Achim - * Germany - * - * To enable UMC8672 support there must a lilo line like - * append="hd=umc8672"... - * To set the speed according to the abilities of the hardware there must be a - * line like - * #define UMC_DRIVE0 11 - * in the beginning of the driver, which sets the speed of drive 0 to 11 (there - * are some lines present). 0 - 11 are allowed speed values. These values are - * the results from the DOS speed test programm supplied from UMC. 11 is the - * highest speed (about PIO mode 3) - */ - -/* - * The speeds will eventually become selectable using hdparm via ioctl's, - * but for now they are coded here: - */ -#define UMC_DRIVE0 11 /* DOS messured drive Speeds */ -#define UMC_DRIVE1 11 /* 0 - 11 allowed */ -#define UMC_DRIVE2 11 /* 11 = Highest Speed */ -#define UMC_DRIVE3 11 /* In case of crash reduce speed */ - -void out_umc (char port,char wert) -{ - outb_p (port,0x108); - outb_p (wert,0x109); -} - -byte in_umc (char port) -{ - outb_p (port,0x108); - return inb_p (0x109); -} - -void init_umc8672(void) -{ - int i,tmp; - int speed [4]; -/* 0 1 2 3 4 5 6 7 8 9 10 11 */ - char speedtab [3][12] = { - {0xf ,0xb ,0x2 ,0x2 ,0x2 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 }, - {0x3 ,0x2 ,0x2 ,0x2 ,0x2 ,0x2 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 ,0x1 }, - {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}}; - - cli (); - outb_p (0x5A,0x108); /* enable umc */ - if (in_umc (0xd5) != 0xa0) - { - sti (); - printk ("UMC8672 not found\n"); - return; - } - speed[0] = UMC_DRIVE0; - speed[1] = UMC_DRIVE1; - speed[2] = UMC_DRIVE2; - speed[3] = UMC_DRIVE3; - for (i = 0;i < 4;i++) - { - if ((speed[i] < 0) || (speed[i] > 11)) - { - sti (); - printk ("UMC 8672 drive speed out of range. Drive %d Speed %d\n", - i, speed[i]); - printk ("UMC support aborted\n"); - return; - } - } - out_umc (0xd7,(speedtab[0][speed[2]] | (speedtab[0][speed[3]]<<4))); - out_umc (0xd6,(speedtab[0][speed[0]] | (speedtab[0][speed[1]]<<4))); - tmp = 0; - for (i = 3; i >= 0; i--) - { - tmp = (tmp << 2) | speedtab[1][speed[i]]; - } - out_umc (0xdc,tmp); - for (i = 0;i < 4; i++) - { - out_umc (0xd0+i,speedtab[2][speed[i]]); - out_umc (0xd8+i,speedtab[2][speed[i]]); - } - outb_p (0xa5,0x108); /* disable umc */ - sti (); - printk ("Speeds for UMC8672 \n"); - for (i = 0;i < 4;i++) - printk ("Drive %d speed %d\n",i,speed[i]); -} diff -u --recursive --new-file v1.3.43/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c --- v1.3.43/linux/drivers/cdrom/aztcd.c Thu Nov 9 11:23:47 1995 +++ linux/drivers/cdrom/aztcd.c Sat Nov 25 17:28:41 1995 @@ -1,5 +1,5 @@ -#define AZT_VERSION "1.90" -/* $Id: aztcd.c,v 1.90 1995/10/21 17:51:59 root Exp root $ +#define AZT_VERSION "2.0" +/* $Id: aztcd.c,v 2.0 1995/11/10 19:33:41 root Exp root $ linux/drivers/block/aztcd.c - AztechCD268 CDROM driver Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de) @@ -128,14 +128,19 @@ Werner Zimmermann, August 8, 1995 V1.70 Multisession support now is completed, but there is still not enough testing done. If you can test it, please contact me. For - details please read README.aztcd. + details please read /usr/src/linux/Documentation/cdrom/aztcd Werner Zimmermann, August 19, 1995 V1.80 Modification to suit the new kernel boot procedure introduced with kernel 1.3.33. Will definitely not work with older kernels. Programming done by Linus himself. Werner Zimmermann, October 11, 1995 - V1.90 Support for Conrad TXC drives, thank's to Jochen and Olaf. + V1.90 Support for Conrad TXC drives, thank's to Jochen Koch and Olaf Koluza. Werner Zimmermann, October 21, 1995 + V2.00 Changed #include "blk.h" to as the directory + structure was changed. README.aztcd is now /usr/src/docu- + mentation/cdrom/aztcd + Werner Zimmermann, November 10, 95 + NOTE: Points marked with ??? are questionable ! */ @@ -1526,7 +1531,7 @@ } printk("aztcd: Aztech,Orchid,Okano,Wearnes,TXC CD-ROM Driver (C) 1994,1995 W.Zimmermann\n"); printk("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n",AZT_VERSION,azt_port); - printk("aztcd: If you have problems, read /usr/src/linux/drivers/block/README.aztcd\n"); + printk("aztcd: If you have problems, read /usr/src/linux/Documentation/cdrom/aztcd\n"); if (check_region(azt_port, 4)) { printk("aztcd: conflict, I/O port (%X) already used\n", diff -u --recursive --new-file v1.3.43/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.3.43/linux/drivers/net/3c501.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/3c501.c Fri Nov 24 16:39:53 1995 @@ -120,7 +120,7 @@ static void el_reset(struct device *dev); static int el1_close(struct device *dev); static struct enet_statistics *el1_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); #define EL1_IO_EXTENT 16 @@ -647,29 +647,32 @@ return &lp->stats; } -/* Set or clear the multicast filter for this adaptor. - num_addrs == -2 All multicast hosts - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. +/* + * Set or clear the multicast filter for this adaptor. + * best-effort filtering. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void set_multicast_list(struct device *dev) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; - if (num_addrs > 0 || num_addrs==-2) { - outb(RX_MULT, RX_CMD); /* Multicast or all multicast is the same */ - inb(RX_STATUS); /* Clear status. */ - } else if (num_addrs < 0) { - outb(RX_PROM, RX_CMD); - inb(RX_STATUS); - } else { - outb(RX_NORM, RX_CMD); - inb(RX_STATUS); - } + if(dev->flags&IFF_PROMISC) + { + outb(RX_PROM, RX_CMD); + inb(RX_STATUS); + } + else if (dev->mc_list || dev->flags&IFF_ALLMULTI) + { + outb(RX_MULT, RX_CMD); /* Multicast or all multicast is the same */ + inb(RX_STATUS); /* Clear status. */ + } + else + { + outb(RX_NORM, RX_CMD); + inb(RX_STATUS); + } } + #ifdef MODULE static char devicename[9] = { 0, }; static struct device dev_3c501 = { diff -u --recursive --new-file v1.3.43/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v1.3.43/linux/drivers/net/3c505.c Mon Nov 13 12:36:44 1995 +++ linux/drivers/net/3c505.c Fri Nov 24 16:39:53 1995 @@ -1173,21 +1173,26 @@ ************************************************************/ static void -elp_set_mc_list (struct device *dev, int num_addrs, void *addrs) +elp_set_mc_list (struct device *dev) { elp_device *adapter = (elp_device *) dev->priv; + struct dev_mc_list *dmi=dev->mc_list; int i; if (elp_debug >= 3) printk("%s: request to set multicast list\n", dev->name); - if (num_addrs != -1) { + if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) + { /* send a "load multicast list" command to the board, max 10 addrs/cmd */ /* if num_addrs==0 the list will be cleared */ adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST; - adapter->tx_pcb.length = 6*num_addrs; - for (i=0;itx_pcb.data.multicast[i], addrs+6*i,6); + adapter->tx_pcb.length = 6*dev->mc_count; + for (i=0;imc_count;i++) + { + memcpy(adapter->tx_pcb.data.multicast[i], dmi->dmi_addr,6); + dmi=dmi->next; + } adapter->got[CMD_LOAD_MULTICAST_LIST] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) printk("%s: couldn't send set_multicast command\n", dev->name); @@ -1199,11 +1204,12 @@ TIMEOUT_MSG(__LINE__); } } - if (num_addrs) + if (dev->mc_count) adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI; else /* num_addrs == 0 */ adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; - } else /* num_addrs == -1 */ + } + else adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC; /* * configure adapter to receive messages (as specified above) diff -u --recursive --new-file v1.3.43/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.3.43/linux/drivers/net/3c509.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/3c509.c Fri Nov 24 16:39:53 1995 @@ -107,9 +107,7 @@ static struct enet_statistics *el3_get_stats(struct device *dev); static int el3_rx(struct device *dev); static int el3_close(struct device *dev); -#ifdef HAVE_MULTICAST -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif +static void set_multicast_list(struct device *dev); @@ -259,9 +257,7 @@ dev->hard_start_xmit = &el3_start_xmit; dev->stop = &el3_close; dev->get_stats = &el3_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif /* Fill in the generic fields of the device structure. */ ether_setup(dev); @@ -630,33 +626,32 @@ return 0; } -#ifdef HAVE_MULTICAST -/* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. +/* + * Set or clear the multicast filter for this adaptor. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void set_multicast_list(struct device *dev) { short ioaddr = dev->base_addr; if (el3_debug > 1) { static int old = 0; - if (old != num_addrs) { - old = num_addrs; - printk("%s: Setting Rx mode to %d addresses.\n", dev->name, num_addrs); + if (old != dev->mc_count) { + old = dev->mc_count; + printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count); } } - if (num_addrs > 0 || num_addrs == -2) { + if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) + { outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - } else if (num_addrs < 0) { + } + else if (dev->flags&IFF_PROMISC) + { outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); - } else + } + else outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); } -#endif static int el3_close(struct device *dev) diff -u --recursive --new-file v1.3.43/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v1.3.43/linux/drivers/net/8390.c Fri Nov 17 08:42:25 1995 +++ linux/drivers/net/8390.c Fri Nov 24 16:39:53 1995 @@ -32,6 +32,8 @@ Much of this code should have been cleaned up, but every attempt has broken some clone part. + Doesn't currently work on all shared memory cards. + Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. */ @@ -105,9 +107,7 @@ /* Routines generic to NS8390-based boards. */ static void NS8390_trigger_send(struct device *dev, unsigned int length, int start_page); -#ifdef HAVE_MULTICAST -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif +static void set_multicast_list(struct device *dev); /* Open/initialize the board. This routine goes all-out, setting everything @@ -572,27 +572,27 @@ return &ei_local->stat; } -#ifdef HAVE_MULTICAST -/* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - . best-effort filtering. - */ +/* + * Set or clear the multicast filter for this adaptor. + */ + static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) { - short ioaddr = dev->base_addr; + short ioaddr = dev->base_addr; - if (num_addrs > 0 || num_addrs == -2) { + if(dev->flags&IFF_PROMISC) + { + outb_p(E8390_RXCONFIG | 0x18, ioaddr + EN0_RXCR); + } + else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) + { /* The multicast-accept list is initialized to accept-all, and we rely on higher-level filtering for now. */ outb_p(E8390_RXCONFIG | 0x08, ioaddr + EN0_RXCR); - } else if (num_addrs < 0) - outb_p(E8390_RXCONFIG | 0x18, ioaddr + EN0_RXCR); - else + } + else outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR); } -#endif /* Initialize the rest of the 8390 device structure. */ int ethdev_init(struct device *dev) @@ -680,6 +680,8 @@ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */ /* 3c503 TechMan says rxconfig only after the NIC is started. */ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ + dev->set_multicast_list(dev); /* Get the multicast status right if this + was a reset. */ } return; } diff -u --recursive --new-file v1.3.43/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v1.3.43/linux/drivers/net/Config.in Fri Nov 17 08:42:25 1995 +++ linux/drivers/net/Config.in Tue Nov 21 16:35:07 1995 @@ -43,6 +43,7 @@ bool 'NI5210 support' CONFIG_NI52 bool 'NI6510 support' CONFIG_NI65 tristate 'WaveLAN support' CONFIG_WAVELAN + tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I fi tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN @@ -60,7 +61,6 @@ fi tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT tristate 'DE425, DE434, DE435, DE500 support' CONFIG_DE4X5 - tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16 # tristate 'DEC 21040 PCI support' CONFIG_DEC_ELCP # bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 # bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 diff -u --recursive --new-file v1.3.43/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.43/linux/drivers/net/Makefile Fri Nov 17 08:42:25 1995 +++ linux/drivers/net/Makefile Tue Nov 21 16:35:07 1995 @@ -332,10 +332,10 @@ endif endif -ifeq ($(CONFIG_ETH16),y) +ifeq ($(CONFIG_ETH16I),y) L_OBJS += eth16i.o else - ifeq ($(CONFIG_ETH16),m) + ifeq ($(CONFIG_ETH16I),m) M_OBJS += eth16i.o endif endif diff -u --recursive --new-file v1.3.43/linux/drivers/net/README.multicast linux/drivers/net/README.multicast --- v1.3.43/linux/drivers/net/README.multicast Fri Oct 13 14:44:33 1995 +++ linux/drivers/net/README.multicast Fri Nov 24 16:39:53 1995 @@ -22,14 +22,14 @@ ac3200 YES YES YES Software(#) apricot YES PROMISC YES Hardware arcnet NO NO NO N/A -at1700 **** PROMISC YES Software -atp **** PROMISC YES Software +at1700 PROMISC PROMISC YES Software +atp PROMISC PROMISC YES Software de4x5 YES NO YES Hardware de600 NO NO NO N/A -de620 **** PROMISC YES Software +de620 PROMISC PROMISC YES Software depca YES PROMISC YES Hardware e2100 YES YES YES Software(#) -eepro YES(*) PROMISC YES Hardware +eepro YES PROMISC YES Hardware eexpress NO NO NO N/A ewrk3 YES PROMISC YES Hardware hp-plus YES YES YES Software(#) @@ -49,10 +49,8 @@ znet YES YES YES Software -**** = This driver would take down your entire network if you use it in a - multicast kernel with IP forwarding enabled (patches sent to Linus) -YES(*) = As above but only if >64 addresses are activated. -PROMISC = All multicasts mode is in fact promiscuous mode. +PROMISC = This multicasts mode is in fact promiscuous mode. Avoid using +cards who go PROMISC on any multicast in a multicast kernel. (#) = Hardware multicast support is not used yet. diff -u --recursive --new-file v1.3.43/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.3.43/linux/drivers/net/Space.c Fri Nov 17 08:42:25 1995 +++ linux/drivers/net/Space.c Tue Nov 21 16:35:07 1995 @@ -51,6 +51,7 @@ extern int el3_probe(struct device *); extern int at1500_probe(struct device *); extern int at1700_probe(struct device *); +extern int eth16i_probe(struct device *); extern int depca_probe(struct device *); extern int apricot_probe(struct device *); extern int ewrk3_probe(struct device *); @@ -117,6 +118,9 @@ #endif #ifdef CONFIG_AT1700 && at1700_probe(dev) +#endif +#ifdef CONFIG_ETH16I + && eth16i_probe(dev) /* ICL EtherTeam 16i/32 */ #endif #ifdef CONFIG_EL3 /* 3c509 */ && el3_probe(dev) diff -u --recursive --new-file v1.3.43/linux/drivers/net/apricot.c linux/drivers/net/apricot.c --- v1.3.43/linux/drivers/net/apricot.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/apricot.c Fri Nov 24 16:39:53 1995 @@ -188,9 +188,7 @@ static struct enet_statistics *i596_get_stats(struct device *dev); static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd); static void print_eth(char *); -#ifdef HAVE_MULTICAST -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif +static void set_multicast_list(struct device *dev); static inline int @@ -729,9 +727,7 @@ dev->stop = &i596_close; dev->hard_start_xmit = &i596_start_xmit; dev->get_stats = &i596_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif dev->mem_start = (int)kmalloc(sizeof(struct i596_private)+ 0x0f, GFP_KERNEL); /* align for scp */ @@ -954,49 +950,55 @@ return &lp->stats; } -#ifdef HAVE_MULTICAST -/* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. +/* + * Set or clear the multicast filter for this adaptor. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void set_multicast_list(struct device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; - struct i596_cmd *cmd; + struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_cmd *cmd; - if (i596_debug > 1) - printk ("%s: set multicast list %d\n", dev->name, num_addrs); + if (i596_debug > 1) + printk ("%s: set multicast list %d\n", dev->name, num_addrs); - if (num_addrs > 0) { - cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd)+2+num_addrs*6, GFP_ATOMIC); - if (cmd == NULL) - { - printk ("%s: set_multicast Memory squeeze.\n", dev->name); - return; - } - - cmd->command = CmdMulticastList; - *((unsigned short *) (cmd + 1)) = num_addrs * 6; - memcpy (((char *)(cmd + 1))+2, addrs, num_addrs * 6); - print_eth (((char *)(cmd + 1)) + 2); - - i596_add_cmd(dev, cmd); - } else - { - if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL) return; - if (num_addrs == 0) - lp->i596_config[8] &= ~0x01; + if (dev->mc_count > 0) + { + struct dev_mc_list *dmi; + char *cp; + cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC); + if (cmd == NULL) + { + printk ("%s: set_multicast Memory squeeze.\n", dev->name); + return; + } + cmd->command = CmdMulticastList; + *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; + cp=((char *)(cmd + 1))+2 + for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) + { + memcpy(cp, addr,6); + cp+=6; + } + print_eth (((char *)(cmd + 1)) + 2); + i596_add_cmd(dev, cmd); + } else - lp->i596_config[8] |= 0x01; - - i596_add_cmd(dev, &lp->set_conf); - } + { + if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL) + return; + if (dev->mc_count == 0 && !(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) + { + if(dev->flags&IFF_ALLMULTI) + dev->flags|=IFF_PROMISC; + lp->i596_config[8] &= ~0x01; + } + else + lp->i596_config[8] |= 0x01; + i596_add_cmd(dev, &lp->set_conf); + } } -#endif #ifdef HAVE_DEVLIST static unsigned int apricot_portlist[] = {0x300, 0}; diff -u --recursive --new-file v1.3.43/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v1.3.43/linux/drivers/net/at1700.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/at1700.c Fri Nov 24 16:39:53 1995 @@ -121,7 +121,7 @@ static void net_rx(struct device *dev); static int net_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); /* Check for a network adaptor of this type, and return '0' iff one exists. @@ -611,10 +611,10 @@ best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { short ioaddr = dev->base_addr; - if (num_addrs) + if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) { /* * We must make the kernel realise we had to move diff -u --recursive --new-file v1.3.43/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v1.3.43/linux/drivers/net/atp.c Tue Oct 10 18:46:35 1995 +++ linux/drivers/net/atp.c Fri Nov 24 16:39:53 1995 @@ -140,7 +140,7 @@ static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode); static int net_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); /* Check for a network adapter of this type, and return '0' iff one exists. @@ -754,17 +754,18 @@ return &lp->stats; } -/* Set or clear the multicast filter for this adapter. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. +/* + * Set or clear the multicast filter for this adapter. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void set_multicast_list(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; + int num_addrs=dev->mc_list; + + if(dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + num_addrs=1; /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on diff -u --recursive --new-file v1.3.43/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v1.3.43/linux/drivers/net/de4x5.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/de4x5.c Fri Nov 24 16:39:53 1995 @@ -399,7 +399,7 @@ static void de4x5_interrupt(int irq, struct pt_regs *regs); static int de4x5_close(struct device *dev); static struct enet_statistics *de4x5_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd); /* @@ -1384,35 +1384,42 @@ ** Set all multicast bits (pass all multicasts). */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - u_long iobase = dev->base_addr; + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + u_long iobase = dev->base_addr; - /* First, double check that the adapter is open */ - if (irq2dev_map[dev->irq] != NULL) { - if (num_addrs >= 0) { - SetMulticastFilter(dev, num_addrs, (char *)addrs); - if (lp->setup_f == HASH_PERF) { - load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | + /* First, double check that the adapter is open */ + if (irq2dev_map[dev->irq] != NULL) + { + if (num_addrs >= 0) + { + SetMulticastFilter(dev); + if (lp->setup_f == HASH_PERF) + { + load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | SETUP_FRAME_LEN, NULL); - } else { - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + } + else + { + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, NULL); - } - - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ - dev->trans_start = jiffies; - } else { /* set promiscuous mode */ - u32 omr; - omr = inl(DE4X5_OMR); - omr |= OMR_PR; - outl(omr, DE4X5_OMR); - } - } + } - return; + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ + dev->trans_start = jiffies; + } + else + { + /* set promiscuous mode */ + u32 omr; + omr = inl(DE4X5_OMR); + omr |= OMR_PR; + outl(omr, DE4X5_OMR); + } + } + return; } /* @@ -1420,64 +1427,88 @@ ** from a list of ethernet multicast addresses. ** Little endian crc one liner from Matt Thomas, DEC. */ -static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs) +static void SetMulticastFilter(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct dev_mc_list *dmi=dev->mc_list; u_long iobase = dev->base_addr; int i, j, bit, byte; u16 hashcode; u32 omr, crc, poly = CRC_POLYNOMIAL_LE; char *pa; + unsigned char *addrs; omr = inl(DE4X5_OMR); pa = build_setup_frame(dev, ALL); /* Build the basic frame */ - if (lp->setup_f == HASH_PERF) { - if (num_addrs == HASH_TABLE_LEN) { /* Pass all multicasts */ - omr |= OMR_PM; - } else { - omr &= ~OMR_PM; + if (lp->setup_f == HASH_PERF) + { + if (num_addrs >= HASH_TABLE_LEN || (dev->flags&IFF_ALLMULTI)) + { + /* Pass all multicasts */ + omr |= OMR_PM; + } + else + { + omr &= ~OMR_PM; /* Now update the MCA table */ - for (i=0;i>=1) { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } - } - hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ - - byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ - bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ - - byte <<= 1; /* calc offset into setup frame */ - if (byte & 0x02) { - byte -= 1; - } - lp->setup_frame[byte] |= bit; + for (i=0;idmi_addr; + dmi=dmi->next; + if ((*addrs & 0x01) == 1) + { + /* multicast address? */ + crc = 0xffffffff; /* init CRC for each address */ + for (byte=0;byte>=1) + { + crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); + } + } + hashcode = crc & HASH_BITS; /* hashcode is 9 LSb of CRC */ + + byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + + byte <<= 1; /* calc offset into setup frame */ + if (byte & 0x02) + { + byte -= 1; + } + lp->setup_frame[byte] |= bit; - } else { /* skip this address */ - addrs += ETH_ALEN; + } + else + { /* skip this address */ + addrs += ETH_ALEN; + } + } + } + else + { /* Perfect filtering */ + omr &= ~OMR_PM; + for (j=0; jmc_count; j++) + { + addrs=dmi->dmi_addr; + dmi=dmi->next; + for (i=0; imc_count == 0) + omr &= ~OMR_PR; + outl(omr, DE4X5_OMR); - return; + return; } /* diff -u --recursive --new-file v1.3.43/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v1.3.43/linux/drivers/net/de620.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/de620.c Fri Nov 24 16:39:53 1995 @@ -206,7 +206,7 @@ static int de620_open(struct device *); static int de620_close(struct device *); static struct netstats *get_stats(struct device *); -static void de620_set_multicast_list(struct device *, int, void *); +static void de620_set_multicast_list(struct device *); static int de620_start_xmit(struct sk_buff *, struct device *); /* Dispatch from interrupts. */ @@ -481,15 +481,11 @@ * Set or clear the multicast filter for this adaptor. * (no real multicast implemented for the DE-620, but she can be promiscuous...) * - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, and do - * best-effort filtering. */ -static void -de620_set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void de620_set_multicast_list(struct device *dev) { - if (num_addrs) + if (dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) { /* Enable promiscuous mode */ /* * We must make the kernel realise we had to move @@ -500,7 +496,8 @@ de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL); } - else { /* Disable promiscuous mode, use normal mode */ + else + { /* Disable promiscuous mode, use normal mode */ de620_set_register(dev, W_TCR, TCR_DEF); } } diff -u --recursive --new-file v1.3.43/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v1.3.43/linux/drivers/net/depca.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/depca.c Fri Nov 24 16:39:53 1995 @@ -363,7 +363,7 @@ static int depca_close(struct device *dev); static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd); static struct enet_statistics *depca_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev,int num_addrs,void *addrs); +static void set_multicast_list(struct device *dev); /* ** Private functions @@ -379,7 +379,7 @@ static int DevicePresent(u_long ioaddr); static int get_hw_addr(struct device *dev); static int EISA_signature(char *name, s32 eisa_id); -static void SetMulticastFilter(struct device *dev,int num_addrs,char *addrs); +static void SetMulticastFilter(struct device *dev); static void isa_probe(struct device *dev, u_long iobase); static void eisa_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); @@ -788,7 +788,7 @@ lp->init_block.rx_ring = ((u32)((u_long)lp->rx_ring)&LA_MASK) | lp->rx_rlen; lp->init_block.tx_ring = ((u32)((u_long)lp->tx_ring)&LA_MASK) | lp->tx_rlen; - SetMulticastFilter(dev, 0, NULL); + SetMulticastFilter(dev); for (i = 0; i < ETH_ALEN; i++) { lp->init_block.phys_addr[i] = dev->dev_addr[i]; @@ -1151,13 +1151,9 @@ /* ** Set or clear the multicast filter for this adaptor. -** num_addrs == -1 Promiscuous mode, receive all packets -** num_addrs == 0 Normal mode, clear multicast list -** num_addrs > 0 Multicast mode, receive normal and MC packets, and do -** best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; @@ -1170,13 +1166,15 @@ STOP_DEPCA; /* Temporarily stop the depca. */ depca_init_ring(dev); /* Initialize the descriptor rings */ - if (num_addrs >= 0) { - SetMulticastFilter(dev, num_addrs, (char *)addrs); - lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ - } else { - lp->init_block.mode |= PROM; /* Set promiscuous mode */ + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + { + lp->init_block.mode |= PROM; /* Set promiscuous mode */ + } + else + { + SetMulticastFilter(dev); + lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ } - LoadCSRs(dev); /* Reload CSR3 */ InitRestartDepca(dev); /* Resume normal operation. */ dev->tbusy = 0; /* Unlock the TX ring */ @@ -1189,25 +1187,31 @@ ** Big endian crc one liner is mine, all mine, ha ha ha ha! ** LANCE calculates its hash codes big endian. */ -static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs) +static void SetMulticastFilter(struct device *dev) { struct depca_private *lp = (struct depca_private *)dev->priv; int i, j, bit, byte; u16 hashcode; s32 crc, poly = CRC_POLYNOMIAL_BE; + struct dev_mc_list *dmi=dev->mc_list; - if (num_addrs == HASH_TABLE_LEN) { /* Set all multicast bits */ - for (i=0; i<(HASH_TABLE_LEN>>3); i++) { - lp->init_block.mcast_table[i] = (char)0xff; - } - } else { + if (dev->mc_count >= HASH_TABLE_LEN) + { /* Set all multicast bits */ + for (i=0; i<(HASH_TABLE_LEN>>3); i++) + { + lp->init_block.mcast_table[i] = (char)0xff; + } + } + else { /* Clear the multicast table first */ for (i=0; i<(HASH_TABLE_LEN>>3); i++){ lp->init_block.mcast_table[i]=0; } /* Add multicast addresses */ - for (i=0;imc_count;i++) { /* for each address in the list */ + unsigned char *addrs=dmi->dmi_addr; + dmi=dmi->next; if ((*addrs & 0x01) == 1) { /* multicast address? */ crc = 0xffffffff; /* init CRC for each address */ for (byte=0;bytelen != HASH_TABLE_LEN) { /* MCA changes */ @@ -1772,6 +1777,7 @@ } break; +#endif case DEPCA_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); diff -u --recursive --new-file v1.3.43/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v1.3.43/linux/drivers/net/eepro.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/eepro.c Fri Nov 24 16:39:53 1995 @@ -140,7 +140,7 @@ static void eepro_transmit_interrupt(struct device *dev); static int eepro_close(struct device *dev); static struct enet_statistics *eepro_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); static int read_eeprom(int ioaddr, int location); static void hardware_send_packet(struct device *dev, void *buf, short length); @@ -351,7 +351,7 @@ printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); } - outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */ + outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ id = inb(ioaddr + REG3); if (id & TPE_BIT) dev->if_port = TPE; @@ -441,13 +441,13 @@ int irqlist[] = { 5, 9, 10, 11, 4, 3, 0}; int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr; - outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */ + outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ /* Enable the interrupt line. */ temp_reg = inb(ioaddr + REG1); outb(temp_reg | INT_ENABLE, ioaddr + REG1); - outb(BANK0_SELECT, ioaddr); /* be CAREFULL, BANK 0 now */ + outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */ /* clear all interrupts */ outb(ALL_MASK, ioaddr + STATUS_REG); @@ -455,7 +455,7 @@ outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG); do { - outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */ + outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ temp_reg = inb(ioaddr + INT_NO_REG); outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG); @@ -522,7 +522,7 @@ /* Initialize the 82595. */ - outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */ + outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ temp_reg = inb(ioaddr + EEPROM_REG); if (temp_reg & 0x10) /* Check the TurnOff Enable bit */ outb(temp_reg & 0xef, ioaddr + EEPROM_REG); @@ -540,7 +540,7 @@ outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */ /* Set the receiving mode */ - outb(BANK1_SELECT, ioaddr); /* be CAREFULL, BANK 1 now */ + outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */ temp_reg = inb(ioaddr + INT_NO_REG); outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); @@ -769,19 +769,17 @@ } /* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; unsigned short mode; + struct dev_mc_list *dmi=dev->mc_list; - if (num_addrs <= -1 || num_addrs > 63) { + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) + { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on @@ -790,7 +788,7 @@ */ dev->flags|=IFF_PROMISC; - outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */ + outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode | PRMSC_Mode, ioaddr + REG2); mode = inb(ioaddr + REG3); @@ -798,16 +796,18 @@ outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ printk("%s: promiscuous mode enabled.\n", dev->name); } - else if (num_addrs == 0) { - outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */ + else if (dev->mc_count==0 ) + { + outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */ mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */ } - else { - unsigned short status, *eaddrs = addrs; + else + { + unsigned short status, *eaddrs; int i, boguscount = 0; /* Disable RX and TX interrupts. Neccessary to avoid @@ -815,7 +815,7 @@ service routines. */ outb(ALL_MASK, ioaddr + INT_MASK_REG); - outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */ + outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode | Multi_IA, ioaddr + REG2); mode = inb(ioaddr + REG3); @@ -825,8 +825,11 @@ outw(MC_SETUP, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); - outw(6*(num_addrs + 1), ioaddr + IO_PORT); - for (i = 0; i < num_addrs; i++) { + outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); + for (i = 0; i < dev->mc_count; i++) + { + eaddrs=(unsigned short *)dmi->dmi_addr; + dmi=dmi->next; outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); @@ -839,8 +842,9 @@ outb(MC_SETUP, ioaddr); /* Update the transmit queue */ - i = lp->tx_end + XMT_HEADER + 6*(num_addrs + 1); - if (lp->tx_start != lp->tx_end) { + i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); + if (lp->tx_start != lp->tx_end) + { /* update the next address and the chain bit in the last packet */ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); @@ -849,13 +853,15 @@ status = inw(ioaddr + IO_PORT); outw(status | CHAIN_BIT, ioaddr + IO_PORT); lp->tx_end = i ; - } else lp->tx_start = lp->tx_end = i ; + } + else lp->tx_start = lp->tx_end = i ; /* Acknowledge that the MC setup is done */ do { /* We should be doing this in the eepro_interrupt()! */ SLOW_DOWN_IO; SLOW_DOWN_IO; - if (inb(ioaddr + STATUS_REG) & 0x08) { + if (inb(ioaddr + STATUS_REG) & 0x08) + { i = inb(ioaddr); outb(0x08, ioaddr + STATUS_REG); if (i & 0x20) { /* command ABORTed */ @@ -864,7 +870,7 @@ break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ printk("%s: set Rx mode to %d addresses.\n", - dev->name, num_addrs); + dev->name, dev->mc_count); break; } } diff -u --recursive --new-file v1.3.43/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v1.3.43/linux/drivers/net/eexpress.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/eexpress.c Fri Nov 24 16:39:53 1995 @@ -290,7 +290,7 @@ static void eexp_rx(struct device *dev); static int eexp_close(struct device *dev); static struct enet_statistics *eexp_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); static int read_eeprom(int ioaddr, int location); static void hardware_send_packet(struct device *dev, void *buf, short length); @@ -671,13 +671,9 @@ } /* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { /* This doesn't work yet */ #if 0 diff -u --recursive --new-file v1.3.43/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v1.3.43/linux/drivers/net/eth16i.c Mon Nov 13 12:36:44 1995 +++ linux/drivers/net/eth16i.c Fri Nov 24 16:39:53 1995 @@ -1,4 +1,4 @@ -/* eth16i.c An ICL EtherTeam 16i/32 ethernet driver for Linux +/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux Written 1994-95 by Mika Kuoppala @@ -8,11 +8,15 @@ This software may be used and distributed according to the terms of the GNU Public Licence, incorporated herein by reference. - The author may be reached as miku@pupu.elt.icl.fi + The author may be reached as miku@elt.icl.fi + + This driver supports following cards : + - ICL EtherTeam 16i + - ICL EtherTeam 32 EISA Sources: - skeleton.c a sample network driver core for linux, - written by Donald Becker + written by Donald Becker - at1700.c a driver for Allied Telesis AT1700, written by Donald Becker. - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i @@ -68,7 +72,7 @@ */ static char *version = - "eth16i.c: v0.21 17-10-95 Mika Kuoppala (miku@pupu.elt.icl.fi)\n"; + "eth16i.c: v0.21 17-10-95 Mika Kuoppala (miku@elt.icl.fi)\n"; #include @@ -1147,7 +1151,9 @@ { short ioaddr = dev->base_addr; - if(num_addrs) { + if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + { + dev->flags|=IFF_PROMISC; /* Must do this */ outb(3, ioaddr + RECEIVE_MODE_REG); } else { outb(2, ioaddr + RECEIVE_MODE_REG); @@ -1197,16 +1203,10 @@ void cleanup_module(void) { - if (MOD_IN_USE) - printk("eth16i: Device busy, remove delayed\n"); - else - { - unregister_netdev( &dev_eth16i ); - - free_irq( dev_eth16i.irq ); - irq2dev_map[ dev_eth16i.irq ] = NULL; - release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT ); - } + unregister_netdev( &dev_eth16i ); + free_irq( dev_eth16i.irq ); + irq2dev_map[ dev_eth16i.irq ] = NULL; + release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT ); } #endif /* MODULE */ diff -u --recursive --new-file v1.3.43/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v1.3.43/linux/drivers/net/ewrk3.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/ewrk3.c Fri Nov 24 16:39:53 1995 @@ -290,7 +290,7 @@ static void ewrk3_interrupt(int irq, struct pt_regs *regs); static int ewrk3_close(struct device *dev); static struct enet_statistics *ewrk3_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); static int ewrk3_ioctl(struct device *dev, struct ifreq *rq, int cmd); /* @@ -303,7 +303,7 @@ static void EthwrkSignature(char * name, char *eeprom_image); static int DevicePresent(short iobase); -static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table); +static void SetMulticastFilter(struct device *dev, int num_addr, char *multicast_table); static int Read_EEPROM(short iobase, unsigned char eaddr); static int Write_EEPROM(short data, short iobase, unsigned char eaddr); @@ -723,11 +723,15 @@ struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; char csr, page; short iobase = dev->base_addr; + int flags=dev->flags; /* ** Enable all multicasts */ - set_multicast_list(dev, HASH_TABLE_LEN, NULL); + + dev->flags|=IFF_ALLMULTI; + set_multicast_list(dev); + dev->flags=flags; /* ** Clean out any remaining entries in all the queues here @@ -1207,7 +1211,7 @@ ** best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; int iobase = dev->base_addr; @@ -1216,21 +1220,24 @@ csr = inb(EWRK3_CSR); - if (lp->shmem_length == IO_ONLY) { + if (lp->shmem_length == IO_ONLY) + { multicast_table = (char *) PAGE0_HTE; } else { multicast_table = (char *)(lp->shmem_base + PAGE0_HTE); } - if (num_addrs >= 0) { - SetMulticastFilter(dev, num_addrs, (char *)addrs, multicast_table); - csr &= ~PME; - csr |= MCE; - outb(csr, EWRK3_CSR); - } else { /* set promiscuous mode */ + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + { csr |= PME; csr &= ~MCE; outb(csr, EWRK3_CSR); + dev->flags|=IFF_PROMISC; + } else { /* set promiscuous mode */ + SetMulticastFilter(dev, dev->mc_count, multicast_table); + csr &= ~PME; + csr |= MCE; + outb(csr, EWRK3_CSR); } } @@ -1242,83 +1249,110 @@ ** Note that when clearing the table, the broadcast bit must remain asserted ** to receive broadcast messages. */ -static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table) +static void SetMulticastFilter(struct device *dev, int num_addrs, char *multicast_table) { - struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; - int i, iobase = dev->base_addr; - char j, bit, byte; - short *p = (short *) multicast_table; - u_short hashcode; - u_long crc, poly = CRC_POLYNOMIAL_LE; - - while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ - - if (lp->shmem_length == IO_ONLY) { - outb(0, EWRK3_IOPR); - outw((short)((long)multicast_table), EWRK3_PIR1); - } else { - outb(0, EWRK3_MPR); - } + struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv; + char *addrs; + struct dev_mc_list *dmi=dev->mc_list; + int i, iobase = dev->base_addr; + char j, bit, byte; + short *p = (short *) multicast_table; + u_short hashcode; + u_long crc, poly = CRC_POLYNOMIAL_LE; - if (num_addrs == HASH_TABLE_LEN) { - for (i=0; i<(HASH_TABLE_LEN >> 3); i++) { - if (lp->shmem_length == IO_ONLY) { - outb(0xff, EWRK3_DATA); - } else { /* memset didn't work here */ - *p++ = 0xffff; - i++; - } - } - } else { - /* Clear table except for broadcast bit */ - if (lp->shmem_length == IO_ONLY) { - for (i=0; i<(HASH_TABLE_LEN >> 4) - 1; i++) { - outb(0x00, EWRK3_DATA); - } - outb(0x80, EWRK3_DATA); i++; /* insert the broadcast bit */ - for (; i<(HASH_TABLE_LEN >> 3); i++) { - outb(0x00, EWRK3_DATA); - } - } else { - memset(multicast_table, 0, (HASH_TABLE_LEN >> 3)); - *(multicast_table + (HASH_TABLE_LEN >> 4) - 1) = 0x80; - } + while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */ - /* Update table */ - for (i=0;i>=1) { - crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); - } + if (lp->shmem_length == IO_ONLY) + { + outb(0, EWRK3_IOPR); + outw((short)((long)multicast_table), EWRK3_PIR1); + } + else + { + outb(0, EWRK3_MPR); } - hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */ - byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ - bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + if (num_addrs >= HASH_TABLE_LEN) + { + for (i=0; i<(HASH_TABLE_LEN >> 3); i++) + { + if (lp->shmem_length == IO_ONLY) + { + outb(0xff, EWRK3_DATA); + } + else + { /* memset didn't work here */ + *p++ = 0xffff; + i++; + } + } + } + else + { + /* Clear table except for broadcast bit */ + if (lp->shmem_length == IO_ONLY) + { + for (i=0; i<(HASH_TABLE_LEN >> 4) - 1; i++) + { + outb(0x00, EWRK3_DATA); + } + outb(0x80, EWRK3_DATA); i++; /* insert the broadcast bit */ + for (; i<(HASH_TABLE_LEN >> 3); i++) + { + outb(0x00, EWRK3_DATA); + } + } + else + { + memset(multicast_table, 0, (HASH_TABLE_LEN >> 3)); + *(multicast_table + (HASH_TABLE_LEN >> 4) - 1) = 0x80; + } - if (lp->shmem_length == IO_ONLY) { - unsigned char tmp; + /* Update table */ - outw((short)((long)multicast_table) + byte, EWRK3_PIR1); - tmp = inb(EWRK3_DATA); - tmp |= bit; - outw((short)((long)multicast_table) + byte, EWRK3_PIR1); - outb(tmp, EWRK3_DATA); - } else { - multicast_table[byte] |= bit; + for (i=0;imc_count;i++) + { + /* for each address in the list */ + addrs=dmi->dmi_addr; + dmi=dmi->next; + + if ((*addrs & 0x01) == 1) + { /* multicast address? */ + crc = 0xffffffff; /* init CRC for each address */ + for (byte=0;byte>=1) + { + crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0); + } + } + hashcode = crc & ((1 << 9) - 1); /* hashcode is 9 LSb of CRC */ + + byte = hashcode >> 3; /* bit[3-8] -> byte in filter */ + bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */ + + if (lp->shmem_length == IO_ONLY) + { + unsigned char tmp; + + outw((short)((long)multicast_table) + byte, EWRK3_PIR1); + tmp = inb(EWRK3_DATA); + tmp |= bit; + outw((short)((long)multicast_table) + byte, EWRK3_PIR1); + outb(tmp, EWRK3_DATA); + } + else + { + multicast_table[byte] |= bit; + } + } + } } - } else { /* skip this address */ - addrs += ETH_ALEN; - } - } - } - lp->lock = 0; /* Unlock the page register */ + lp->lock = 0; /* Unlock the page register */ - return; + return; } #ifndef MODULE @@ -1669,7 +1703,8 @@ break; case EWRK3_SAY_BOO: /* Say "Boo!" to the kernel log file */ - printk("%s: Boo!\n", dev->name); + if(suser()) + printk("%s: Boo!\n", dev->name); break; case EWRK3_GET_MCA: /* Get the multicast address table */ @@ -1692,6 +1727,8 @@ lp->lock = 0; /* Unlock the page register */ break; + +#if 0 case EWRK3_SET_MCA: /* Set a multicast address */ if (suser()) { err = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len); @@ -1725,6 +1762,7 @@ } break; +#endif case EWRK3_GET_STATS: /* Get the driver statistics */ err = verify_area(VERIFY_WRITE, (void *)ioc->data, sizeof(lp->pktStats)); if (err) return err; diff -u --recursive --new-file v1.3.43/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v1.3.43/linux/drivers/net/hp100.c Thu Nov 9 11:23:49 1995 +++ linux/drivers/net/hp100.c Fri Nov 24 16:39:53 1995 @@ -195,9 +195,7 @@ static struct enet_statistics *hp100_get_stats( struct device *dev ); static void hp100_update_stats( struct device *dev ); static void hp100_clear_stats( int ioaddr ); -#ifdef HAVE_MULTICAST -static void hp100_set_multicast_list( struct device *dev, int num_addrs, void *addrs ); -#endif +static void hp100_set_multicast_list( struct device *dev); static void hp100_interrupt( int irq, struct pt_regs *regs ); static void hp100_start_interface( struct device *dev ); @@ -430,9 +428,7 @@ dev -> stop = hp100_close; dev -> hard_start_xmit = hp100_start_xmit; dev -> get_stats = hp100_get_stats; -#ifdef HAVE_MULTICAST dev -> set_multicast_list = &hp100_set_multicast_list; -#endif request_region( dev -> base_addr, HP100_REGION_SIZE, eid -> name ); @@ -846,37 +842,30 @@ * multicast setup */ -#ifdef HAVE_MULTICAST - /* * Set or clear the multicast filter for this adapter. - * - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * best-effort filtering. */ -static void hp100_set_multicast_list( struct device *dev, int num_addrs, void *addrs ) +static void hp100_set_multicast_list( struct device *dev) { int ioaddr = dev -> base_addr; struct hp100_private *lp = (struct hp100_private *)dev -> priv; #ifdef HP100_DEBUG_MULTI - printk( "hp100_set_multicast_list: num_addrs = %d\n", num_addrs ); + printk( "hp100_set_multicast_list: num_addrs = %d\n", dev->mc_count); #endif cli(); hp100_ints_off(); hp100_page( MAC_CTRL ); hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ - if ( num_addrs == -1 ) + if ( dev->flags&IFF_PROMISC) { lp -> mac2_mode = HP100_MAC2MODE6; /* promiscuous mode, all good */ lp -> mac1_mode = HP100_MAC1MODE6; /* packets on the net */ } else - if ( num_addrs != 0 ) + if ( dev->mc_count || dev->flags&IFF_ALLMULTI ) { lp -> mac2_mode = HP100_MAC2MODE5; /* multicast mode, packets for me */ lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */ @@ -896,8 +885,6 @@ hp100_ints_on(); sti(); } - -#endif /* HAVE_MULTICAST */ /* * hardware interrupt handling diff -u --recursive --new-file v1.3.43/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.3.43/linux/drivers/net/lance.c Mon Oct 16 18:38:23 1995 +++ linux/drivers/net/lance.c Fri Nov 24 16:39:53 1995 @@ -257,9 +257,7 @@ static void lance_interrupt(int irq, struct pt_regs *regs); static int lance_close(struct device *dev); static struct enet_statistics *lance_get_stats(struct device *dev); -#ifdef HAVE_MULTICAST -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif +static void set_multicast_list(struct device *dev); @@ -1076,24 +1074,27 @@ } /* Set or clear the multicast filter for this adaptor. - num_addrs == -2 All multicasts - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) { short ioaddr = dev->base_addr; outw(0, ioaddr+LANCE_ADDR); outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */ - if (num_addrs >= 0 || num_addrs==-2) { + if (dev->flags&IFF_PROMISC) { + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + outw(15, ioaddr+LANCE_ADDR); + outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */ + } else { short multicast_table[4]; int i; - /* We don't use the multicast table, but rely on upper-layer filtering. */ + int num_addrs=dev->mc_count; + if(dev->flags&IFF_ALLMULTI) + num_addrs=1; + /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */ memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table)); for (i = 0; i < 4; i++) { outw(8 + i, ioaddr+LANCE_ADDR); @@ -1101,11 +1102,6 @@ } outw(15, ioaddr+LANCE_ADDR); outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */ - } else { - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - outw(15, ioaddr+LANCE_ADDR); - outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */ } lance_restart(dev, 0x0142, 0); /* Resume normal operation */ diff -u --recursive --new-file v1.3.43/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v1.3.43/linux/drivers/net/ni52.c Sat Sep 9 15:26:52 1995 +++ linux/drivers/net/ni52.c Fri Nov 24 16:39:53 1995 @@ -51,6 +51,8 @@ */ /* + * 18.Nov.95: Mcast changes (AC). + * * 19.Jan.95: verified (MH) * * 19.Sep.94: Added Multicast support (not tested yet) (MH) @@ -163,10 +165,10 @@ static int ni52_close(struct device *dev); static int ni52_send_packet(struct sk_buff *,struct device *); static struct enet_statistics *ni52_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); /* helper-functions */ -static int init586(struct device *dev,int num_addrs,void *addrs); +static int init586(struct device *dev); static int check586(struct device *dev,char *where,unsigned size); static void alloc586(struct device *dev); static void startrecv586(struct device *dev); @@ -221,7 +223,7 @@ static int ni52_open(struct device *dev) { alloc586(dev); - init586(dev,0,NULL); + init586(dev); startrecv586(dev); if(request_irq(dev->irq, &ni52_interrupt,0,"ni52")) @@ -446,7 +448,7 @@ * needs a correct 'allocated' memory */ -static int init586(struct device *dev,int num_addrs,void *addrs) +static int init586(struct device *dev) { void *ptr; unsigned long s; @@ -456,6 +458,8 @@ volatile struct iasetup_cmd_struct *ias_cmd; volatile struct tdr_cmd_struct *tdr_cmd; volatile struct mcsetup_cmd_struct *mc_cmd; + struct dev_mc_list *dmi=dev->mc_list; + int num_addrs=dev->mc_count; ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); @@ -472,7 +476,12 @@ cfg_cmd->ifs = 0x60; cfg_cmd->time_low = 0x00; cfg_cmd->time_high = 0xf2; - cfg_cmd->promisc = (num_addrs < 0) ? 1 : 0; /* promisc on/off */ + cfg_cmd->promisc = 0; + if(dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) + { + cfg_cmd->promisc=1; + dev->flags|=IFF_PROMISC; + } cfg_cmd->carr_coll = 0x00; p->scb->cbl_offset = make16(cfg_cmd); @@ -598,7 +607,7 @@ * Multicast setup */ - if(num_addrs > 0) + if(dev->mc_count) { /* I don't understand this: do we really need memory after the init? */ int len = ((char *) p->iscp - (char *) ptr - 8) / 6; if(len <= 0) @@ -609,6 +618,7 @@ { if(len < num_addrs) { + /* BUG - should go ALLMULTI in this case */ num_addrs = len; printk("%s: Sorry, can only apply %d MC-Address(es).\n",dev->name,num_addrs); } @@ -618,7 +628,10 @@ mc_cmd->cmd_link = 0xffff; mc_cmd->mc_cnt = num_addrs * 6; for(i=0;imc_list[i],((char (*)[6]) addrs)[i],6); + { + memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6); + dmi=dmi->next; + } p->scb->cbl_offset = make16(mc_cmd); p->scb->cmd = CUC_START; ni_attn586(); @@ -1077,9 +1090,9 @@ * Set MC list .. */ -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +static void set_multicast_list(struct device *dev) { - if(!dev->start && !num_addrs) + if(!dev->start) { printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name); return; @@ -1087,7 +1100,7 @@ dev->start = 0; alloc586(dev); - init586(dev,num_addrs,addrs); + init586(dev); startrecv586(dev); dev->start = 1; } diff -u --recursive --new-file v1.3.43/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v1.3.43/linux/drivers/net/ni65.c Tue Oct 10 18:46:36 1995 +++ linux/drivers/net/ni65.c Fri Nov 24 16:39:53 1995 @@ -21,6 +21,8 @@ */ /* + * Nov.18: multicast tweaked (AC). + * * Aug.22: changes in xmit_intr (ack more than one xmitted-packet), ni65_send_packet (p->lock) (MH) * * July.16: fixed bugs in recv_skb and skb-alloc stuff (MH) @@ -121,7 +123,7 @@ static int ni65_close(struct device *dev); static struct enet_statistics *ni65_get_stats(struct device *); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); struct priv { @@ -636,7 +638,7 @@ return &((struct priv *) dev->priv)->stats; } -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +static void set_multicast_list(struct device *dev) { } diff -u --recursive --new-file v1.3.43/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v1.3.43/linux/drivers/net/seeq8005.c Wed Nov 8 07:11:33 1995 +++ linux/drivers/net/seeq8005.c Fri Nov 24 16:39:53 1995 @@ -85,7 +85,7 @@ static void seeq8005_rx(struct device *dev); static int seeq8005_close(struct device *dev); static struct enet_statistics *seeq8005_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); /* Example routines you must write ;->. */ #define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON) @@ -608,7 +608,7 @@ best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { /* * I _could_ do upto 6 addresses here, but wont (yet?) @@ -623,6 +623,7 @@ if (num_addrs) { /* Enable promiscuous mode */ outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1); + dev->flags|=IFF_PROMISC; } else { /* Disable promiscuous mode, use normal mode */ outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1); } diff -u --recursive --new-file v1.3.43/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v1.3.43/linux/drivers/net/sk_g16.c Tue Oct 10 18:46:37 1995 +++ linux/drivers/net/sk_g16.c Fri Nov 24 16:39:53 1995 @@ -496,9 +496,7 @@ unsigned int SK_rom_addr(void); -#ifdef HAVE_MULTICAST -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -#endif +static void set_multicast_list(struct device *dev); /* * LANCE Functions @@ -798,10 +796,7 @@ dev->stop = &SK_close; dev->hard_start_xmit = &SK_send_packet; dev->get_stats = &SK_get_stats; - -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif /* Set the generic fields of the device structure */ @@ -1706,7 +1701,6 @@ } /* End of SK_get_stats() */ -#ifdef HAVE_MULTICAST /*- * Function : set_multicast_list @@ -1724,32 +1718,27 @@ * that all information on the net is not encrypted. * * Parameters : I : struct device *dev - SK_G16 device Structure - * I : int num_addrs - explanation further down - * I : void *addrs - * Return Value : None * Errors : None * Globals : None * Update History : * YY/MM/DD uid Description + * 95/10/18 ACox Noew multicast calling scheme -*/ /* Set or clear the multicast filter for SK_G16. - * - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets */ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) { - if (num_addrs == -1) + if (dev->flags&IFF_PROMISC) { /* Reinitialize LANCE with MODE_PROM set */ SK_lance_init(dev, MODE_PROM); } - else if (num_addrs == 0) + else if (dev->mc_count==0 && !(dev->flags&IFF_ALLMULTI)) { /* Reinitialize LANCE without MODE_PROM */ SK_lance_init(dev, MODE_NORMAL); @@ -1757,6 +1746,8 @@ else { /* Multicast with logical address filter on */ + /* Reinitialize LANCE without MODE_PROM */ + SK_lance_init(dev, MODE_NORMAL); /* Not implemented yet. */ } diff -u --recursive --new-file v1.3.43/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v1.3.43/linux/drivers/net/skeleton.c Thu Nov 9 11:23:50 1995 +++ linux/drivers/net/skeleton.c Fri Nov 24 16:39:53 1995 @@ -102,7 +102,7 @@ static void net_rx(struct device *dev); static int net_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); /* Example routines you must write ;->. */ #define tx_done(dev) 1 @@ -514,13 +514,24 @@ best-effort filtering. */ static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) +set_multicast_list(struct device *dev) { short ioaddr = dev->base_addr; - if (num_addrs) { - outw(69, ioaddr); /* Enable promiscuous mode */ - } else - outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */ + if (dev->flags&IFF_PROMISC) { + outw(MULTICAST|PROMISC, ioaddr); /* Enable promiscuous mode */ + } + else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) + { + hardware_set_filter(NULL); + outw(MULTICAST, ioaddr); /* Disable promiscuous mode, use normal mode */ + } + else if(dev->mc_count) + { + hardware_set_filter(dev->mc_list); /* Walk the address list and load the filter */ + outw(MULTICAST, ioaddr); + } + else + outw(0, ioaddr); } #ifdef MODULE diff -u --recursive --new-file v1.3.43/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.3.43/linux/drivers/net/slip.c Thu Nov 9 11:23:50 1995 +++ linux/drivers/net/slip.c Fri Nov 24 16:39:53 1995 @@ -998,7 +998,8 @@ static int sl_set_dev_mac_address(struct device *dev, void *addr) { - memcpy(dev->dev_addr, addr, AX25_ADDR_LEN); + struct sockaddr *sa=addr; + memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); return 0; } #endif /* CONFIG_AX25 */ diff -u --recursive --new-file v1.3.43/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v1.3.43/linux/drivers/net/sunlance.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sunlance.c Fri Nov 24 17:17:31 1995 @@ -0,0 +1,799 @@ +/* lance.c: Linux/Sparc/Lance driver */ +/* + Written 1995 by Miguel de Icaza + Sources: + The Linux depca driver + The Linux lance driver. + The Linux skeleton driver. + The NetBSD Sparc/Lance driver. + Theo Deraadt (deraadt@theos.com) + NCR92C990 Lan Controller manual +*/ + +static char *version = + "lance.c:v1.2 29/Oct/95 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Used by the checksum routines */ + +/* Used for the temporal inet entries and routing */ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define MASK_INTERRUPTS 1 +#define UNMASK_INTERRUPTS 0 + +/* Define: 2^2 Tx buffers and 2^4 Rx buffers */ +#ifndef LANCE_LOG_TX_BUFFERS +#define LANCE_LOG_TX_BUFFERS 2 +#define LANCE_LOG_RX_BUFFERS 4 +#endif + +#define LE_CSR0 0 +#define LE_CSR1 1 +#define LE_CSR2 2 +#define LE_CSR3 3 + +#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ + +#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ +#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ +#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ +#define LE_C0_MISS 0x1000 /* MISS: Missed a packaed */ +#define LE_C0_MERR 0x0800 /* ME: Memory error */ +#define LE_C0_RINT 0x0400 /* Received interrupt */ +#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ +#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ +#define LE_C0_INTR 0x0080 /* Interrupt or error */ +#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 /* Transmiter demand */ +#define LE_C0_STOP 0x0004 /* Stop the card */ +#define LE_C0_STRT 0x0002 /* Start the card */ +#define LE_C0_INIT 0x0001 /* Init the card */ + +#define LE_C3_BSWP 0x4 /* SWAP */ +#define LE_C3_ACON 0x2 /* ALE Control */ +#define LE_C3_BCON 0x1 /* Byte control */ + +/* Receive message descriptor 1 */ +#define LE_R1_OWN 0x80 /* Who owns the entry */ +#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ +#define LE_R1_FRA 0x20 /* FRA: Frame error */ +#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUF 0x04 /* BUF: Buffer error */ +#define LE_R1_SOP 0x02 /* Start of packet */ +#define LE_R1_EOP 0x01 /* End of packet */ +#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ + +#define LE_T1_OWN 0x80 /* Lance owns the packet */ +#define LE_T1_ERR 0x40 /* Error summary */ +#define LE_T1_EONE 0x08 /* Error: one retry needed */ +#define LE_T1_EDEF 0x04 /* Error: defered */ +#define LE_T1_SOP 0x02 /* Start of packet */ +#define LE_T1_EOP 0x01 /* End of packet */ + +#define LE_T3_BUF 0x8000 /* Buffer error */ +#define LE_T3_UFL 0x4000 /* Error undeflow */ +#define LE_T3_LCOL 0x1000 /* Error late collision */ +#define LE_T3_CLOS 0x0800 /* Error carrier loss */ +#define LE_T3_RTY 0x0400 /* Error retry */ +#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ + +#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) +#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) + +#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) +#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) + +#define PKT_BUF_SZ 1544 +#define RX_BUFF_SIZE 1536 +#define TX_BUFF_SIZE 1536 + +struct lance_rx_desc { + unsigned short rmd0; /* low address of packet */ + unsigned char rmd1_bits; /* descriptor bits */ + unsigned char rmd1_hadr; /* high address of packet */ + short length; /* This length is 2s complement (negative)! Buffer length */ + unsigned short mblength; /* This is the actual number of bytes received */ +}; + +struct lance_tx_desc { + unsigned short tmd0; /* low address of packet */ + unsigned char tmd1_bits; /* descriptor bits */ + unsigned char tmd1_hadr; /* high address of packet */ + short length; /* Length is 2s complement (negative)! */ + unsigned short misc; +}; + +/* The LANCE initialization block, described in databook. */ +/* On the Sparc, this block should be on a DMA region */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode (reg. 15) */ + unsigned char phys_addr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter. */ + + /* Receive and transmit ring base, along with extra bits. */ + unsigned short rx_ptr; /* receive descriptor addr */ + unsigned short rx_len; /* receive len and high addr */ + unsigned short tx_ptr; /* transmit descriptor addr */ + unsigned short tx_len; /* transmit len and high addr */ + + /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ + struct lance_rx_desc brx_ring[RX_RING_SIZE]; + struct lance_tx_desc btx_ring[TX_RING_SIZE]; + + char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; + char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; +}; + +struct lance_private { + char *name; + volatile struct lance_regs *ll; + volatile struct lance_init_block *init_block; + + int rx_new, tx_new; + int rx_old, tx_old; + + struct enet_statistics stats; +}; + +#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ + lp->tx_old+TX_RING_MOD_MASK-lp->tx_new:\ + lp->tx_old - lp->tx_new-1) + +/* On the sparc, the lance control ports are memory mapped */ +struct lance_regs { + unsigned short rdp; /* register data port */ + unsigned short rap; /* register address port */ +}; + +int sparc_lance_debug = 2; + +/* The Lance uses 24 bit addresses */ +/* The DVMA will provide the remaining bytes for us */ +#define LANCE_ADDR(x) ((int)(x) & ~0xff000000) + +/* Load the CSR registers */ +static void load_csrs (struct lance_private *lp) +{ + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_init_block *ib = lp->init_block; + int leptr; + + leptr = LANCE_ADDR (ib); + ll->rap = LE_CSR1; + ll->rdp = (leptr & 0xFFFF); + ll->rap = LE_CSR2; + ll->rdp = leptr >> 16; + ll->rap = LE_CSR3; + ll->rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; + + /* Point back to csr0 */ + ll->rap = LE_CSR0; +} + +#define ZERO 0 + +/* Setup the Lance Rx and Tx rings */ +/* Sets dev->tbusy */ +static void +lance_init_ring (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + int leptr; + int i; + + /* Lock out other processes while setting up harware */ + dev->tbusy = 1; + lp->rx_new = lp->tx_new = 0; + lp->rx_old = lp->tx_old = 0; + + ib->mode = 0; + + /* Copy the ethernet address to the lance init block + * Note that on the sparc you need to swap the ethernet address. + */ + ib->phys_addr [0] = dev->dev_addr [1]; + ib->phys_addr [1] = dev->dev_addr [0]; + ib->phys_addr [2] = dev->dev_addr [3]; + ib->phys_addr [3] = dev->dev_addr [2]; + ib->phys_addr [4] = dev->dev_addr [5]; + ib->phys_addr [5] = dev->dev_addr [4]; + + if (ZERO) + printk ("TX rings:\n"); + + /* Setup the Tx ring entries */ + for (i = 0; i <= TX_RING_SIZE; i++){ + leptr = LANCE_ADDR(&ib->tx_buf[i][0]); + ib->btx_ring [i].tmd0 = leptr; + ib->btx_ring [i].tmd1_hadr = leptr >> 16; + ib->btx_ring [i].tmd1_bits = 0; + ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */ + ib->btx_ring [i].misc = 0; + if (i < 3) + if (ZERO) printk ("%d: 0x%8.8x\n", i, leptr); + } + + /* Setup the Rx ring entries */ + if (ZERO) printk ("RX rings:\n"); + for (i = 0; i < RX_RING_SIZE; i++){ + leptr = LANCE_ADDR(&ib->rx_buf[i][0]); + + ib->brx_ring [i].rmd0 = leptr; + ib->brx_ring [i].rmd1_hadr = leptr >> 16; + ib->brx_ring [i].rmd1_bits = LE_R1_OWN; + ib->brx_ring [i].length = -RX_BUFF_SIZE | 0xf000; + ib->brx_ring [i].mblength = 0; + if (i < 3) + if (ZERO) printk ("%d: 0x%8.8x\n", i, leptr); + } + + /* Setup the initialization block */ + + /* Setup rx descriptor pointer */ + leptr = LANCE_ADDR(&ib->brx_ring); + ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16); + ib->rx_ptr = leptr; + if (ZERO) printk ("RX ptr: %8.8x\n", leptr); + + /* Setup tx descriptor pointer */ + leptr = LANCE_ADDR(&ib->btx_ring); + ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16); + ib->tx_ptr = leptr; + if (ZERO) printk ("TX ptr: %8.8x\n", leptr); + + /* Clear the multicast filter */ + ib->filter [0] = 0; + ib->filter [1] = 0; +} + +static int init_restart_lance (struct lance_private *lp) +{ + volatile struct lance_regs *ll = lp->ll; + int i; + + ll->rap = LE_CSR0; + ll->rdp = LE_C0_INIT; + + /* Wait for the lance to complete initialization */ + for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++) + ; + if ((i == 100) || (ll->rdp & LE_C0_ERR)){ + printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); + return -1; + } + + /* Clear IDON by writing a "1", enable interrupts and start lance */ + ll->rdp = LE_C0_IDON; + ll->rdp = LE_C0_INEA | LE_C0_STRT; + printk ("LANCE opened after %d ticks, csr0=%4.4x\n", i, ll->rdp); + return 0; +} + +static int +lance_rx (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_rx_desc *rd; + int i; + int entry; + unsigned char bits; + +#ifdef TEST_HITS + printk ("["); + for (i = 0; i < RX_RING_SIZE; i++){ + if (i == lp->rx_new) + printk ("%s", ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X"); + else + printk ("%s", ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1"); + } + printk ("]"); +#endif + +#ifdef OLD_METHOD + ll->rdp = LE_C0_RINT|LE_C0_INEA; + /* FIXME: Add slot prediction */ + for (rd = &ib->brx_ring [i = 0]; i < RX_RING_SIZE; i++, rd++){ + int bits; + + bits = rd->rmd1_bits; + + /* Check if we own the packet */ + if (bits & LE_R1_OWN) + continue; + + /* We got an incomplete frame? */ + if ((bits & LE_R1_POK) != LE_R1_POK){ + /* Count only the end frame as a tx error, not the beginning */ + if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; + if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; + } else { + int pkt_len = rd->mblength; + struct sk_buff *skb; + char *buf; + + skb = dev_alloc_skb (pkt_len+2); + if (skb == NULL){ + printk ("%s: Memory squeeze, deferring packet.\n", dev->name); + lp->stats.rx_dropped++; + rd->rmd1_bits = LE_R1_OWN; + return 0; + } + + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align */ + buf = skb_put (skb, pkt_len); /* make room */ + memcpy (buf, &(ib->rx_buf [i][0]), pkt_len); + skb->protocol = eth_type_trans (skb,dev); + netif_rx (skb); + lp->stats.rx_packets++; + } + + /* Return the packet to the pool */ + rd->rmd1_bits = LE_R1_OWN; + } +#else + ll->rdp = LE_C0_RINT|LE_C0_INEA; + for (rd = &ib->brx_ring [lp->rx_new]; + !((bits = rd->rmd1_bits) & LE_R1_OWN); + rd = &ib->brx_ring [lp->rx_new]){ + + /* We got an incomplete frame? */ + if ((bits & LE_R1_POK) != LE_R1_POK){ + printk ("Incomplete frame\n"); + /* Count only the end frame as a tx error, not the beginning */ + if (bits & LE_R1_EOP) lp->stats.rx_errors++; + if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; + if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; + } else { + int pkt_len = rd->mblength; + struct sk_buff *skb; + char *buf; + + skb = dev_alloc_skb (pkt_len+2); + if (skb == NULL){ + printk ("%s: Memory squeeze, deferring packet.\n", dev->name); + lp->stats.rx_dropped++; + rd->rmd1_bits = LE_R1_OWN; + lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + return 0; + } + + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align */ + buf = skb_put (skb, pkt_len); /* make room */ + memcpy (buf, (char *) &(ib->rx_buf [lp->rx_new][0]), pkt_len); + skb->protocol = eth_type_trans (skb,dev); + netif_rx (skb); + lp->stats.rx_packets++; + } + + /* Return the packet to the pool */ + rd->rmd1_bits = LE_R1_OWN; + lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + } +#endif + return 0; +} + +static int +lance_tx (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_tx_desc *td; + int i, j; + int status; + + /* csr0 is 2f3 */ + ll->rdp = LE_C0_TINT | LE_C0_INEA; + /* csr0 is 73 */ + j = lp->tx_old; + for (i = 0; i < TX_RING_SIZE; i++){ + td = &ib->btx_ring [j]; + + if (td->tmd1_bits & LE_T1_ERR){ + status = td->misc; + + if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; + if (status & LE_T3_CLOS) lp->stats.tx_carrier_errors++; + if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + + /* buffer errors and underflows turn off the transmiter */ + /* Restart the adapter */ + if (status & (LE_T3_BUF|LE_T3_UFL)){ + lp->stats.tx_fifo_errors++; + + printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); + /* Stop the lance */ + ll->rdp = LE_CSR0; + ll->rap = LE_C0_STOP; + init_restart_lance (lp); + } + } + + j = (j + 1) & TX_RING_MOD_MASK; + } + lp->tx_old = (lp->tx_old+1) & TX_RING_MOD_MASK; + + ll->rdp = LE_C0_TINT | LE_C0_INEA; + return 0; +} + +static void +lance_interrupt (int irq, struct pt_regs *regs) +{ + struct device *dev = (struct device *) (irq2dev_map [irq]); + struct lance_private *lp; + volatile struct lance_regs *ll; + int csr0; + + lp = (struct lance_private *) dev->priv; + ll = lp->ll; + + if (dev->interrupt) + printk ("%s: again", dev->name); + + dev->interrupt = 1; + + csr0 = ll->rdp; + + /* Acknowledge all the interrupt sources ASAP */ + ll->rdp = csr0 & 0x004f; + + if ((csr0 & LE_C0_ERR)){ + /* Clear the error condition */ + ll->rdp = LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA; + } + + if (csr0 & LE_C0_RINT){ + lance_rx (dev); + } + + if (csr0 & LE_C0_TINT){ + lance_tx (dev); + } + + if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy){ + dev->tbusy = 0; + mark_bh (NET_BH); + } + ll->rap = 0; + ll->rdp = 0x7940; + + dev->interrupt = 0; +} + +struct device *last_dev = 0; + +static int +lance_open (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + volatile struct lance_regs *ll = lp->ll; + int status = 0; + + last_dev = dev; + + /* Stop the Lance */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + + if (request_irq (dev->irq, &lance_interrupt, 0, "LANCE")){ + printk ("Lance: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + irq2dev_map [dev->irq] = dev; + + lance_init_ring (dev); + load_csrs (lp); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + status = init_restart_lance (lp); + + /* To make life easier to us while Sparc Linux becomes self hosting: */ + { + struct rtentry server_route; + struct sockaddr_in *sin; + + sin=(struct sockaddr_in *)&server_route.rt_dst; + *sin=server; + sin=(struct sockaddr_in *)&server_route.rt_genmask; + sin->sin_family=AF_INET; + sin->sin_addr.s_addr= ip_get_mask (dev->pa_addr); + server_route.rt_dev[0]=dev; + server_route. + server_route.rt_flags=RTF_HOST|RTF_UP; + + if(ip_rt_new(&server_route)==-1) + printk("Unable to add NFS server route.\n"); + } + ip_rt_add (RTF_UP, + dev->pa_addr & ip_get_mask (dev->pa_addr), + ip_get_mask (dev->pa_addr), + 0, dev, dev->mtu, 0, 0); + return status; +} + +static int +lance_close (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + + dev->start = 0; + dev->tbusy = 1; + + /* Stop the card */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + + free_irq (dev->irq); + irq2dev_map [dev->irq] = NULL; + + return 0; +} + +inline static int lance_reset (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + volatile struct lance_regs *ll = lp->ll; + int status; + + /* Stop the lance */ + ll->rdp = LE_CSR0; + ll->rap = LE_C0_STOP; +#ifdef DEBUG_DRIVER + printk ("Lance stopped: csr0=%4.4x\n", ll->rdp); +#endif + lance_init_ring (dev); + load_csrs (lp); + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; + dev->tbusy = 0; + status = init_restart_lance (lp); +#ifdef DEBUG_DRIVER + printk ("Lance restart=%d\n", status); +#endif +} + +static int lance_start_xmit (struct sk_buff *skb, struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_init_block *ib = lp->init_block; + int entry, skblen, len; + int status = 0; + static int outs; + + /* Transmitter timeout, serious problems */ + if (dev->tbusy){ + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 100) + status = -1; + else { + printk ("%s: trasmit timed out, status %04x, resetting\n", + dev->name, ll->rdp); + lance_reset (dev); + } + return status; + } + + if (skb == NULL){ + dev_tint (dev); + printk ("skb is NULL\n"); + return 0; + } + + if (skb->len <= 0){ + printk ("skb len is %ld\n", skb->len); + return 0; + } + /* Block a timer-based transmit from overlapping. */ +#ifdef OLD_METHOD + dev->tbusy = 1; +#else + if (set_bit (0, (void *) &dev->tbusy) != 0){ + printk ("Transmitter access conflict.\n"); + return -1; + } +#endif + skblen = skb->len; + + if (!TX_BUFFS_AVAIL){ + return -1; + } + +#ifdef DEBUG_DRIVER + /* dump the packet */ + for (i = 0; i < 64; i++){ + if ((i % 16) == 0) printk ("\n"); + printk ("%2.2x ", skb->data [i]); + } +#endif + len = (skblen < ETH_ZLEN) ? ETH_ZLEN : skblen; + entry = lp->tx_new & TX_RING_MOD_MASK; + ib->btx_ring [entry].length = (-len) | 0xf000; + ib->btx_ring [entry].misc = 0; + + memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); + + /* Clear the slack of the packet, do I need this? */ + if (len != skblen){ + memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); + } + + + /* Now, give the packet to the lance */ + ib->btx_ring [entry].tmd1_bits = (LE_T1_SOP|LE_T1_EOP|LE_T1_OWN); + lp->tx_new = (lp->tx_new+1) & TX_RING_MOD_MASK; + + outs++; + /* Kick the lance: transmit now */ + ll->rdp = LE_C0_INEA | LE_C0_TDMD; + dev->trans_start = jiffies; + dev_kfree_skb (skb, FREE_WRITE); + + if (TX_BUFFS_AVAIL) + dev->tbusy = 0; + + return status; +} + +static struct enet_statistics * +lance_get_stats (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + + return &lp->stats; +} + +static void +lance_set_multicast (struct device *dev) +{ +#ifdef NOT_YET + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + volatile struct lance_regs *ll = lp->ll; + + ll->rdp = LE_CSR0; + ll->rap = LE_C0_STOP; + lance_init_ring (dev); + if (num_addrs >= 0){ + printk ("Ignoring set_multicast\n"); + } else { + ib->mode |= LE_MO_PROM; + } + lance_init_ring (dev); + load_csrs (lp); + init_restart_lance (lp); + dev->tbusy = 0; +#endif +} + +int sparc_lance_probe (struct device *dev) +{ + static unsigned version_printed = 0; + int i; + int found = 0; + struct linux_sbus *bus; + struct linux_sbus_device *sdev = 0; + struct lance_private *lp; + volatile struct lance_regs *ll; + +#ifdef DEBUG_DRIVER + printk ("Lance probe...0x%p\n", SBus_chain); +#endif + for_each_sbus (bus){ + for_each_sbusdev (sdev, bus){ + if (strcmp (sdev->prom_name, "le") == 0){ + found = 1; + break; + } + } + } + if (!found) + return ENODEV; + + if (dev == NULL){ + printk ("LANCE buffer @0x0. You don't really want this\n"); + dev = init_etherdev (0, sizeof (struct lance_private)); + } else { + dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL); + } + if (sparc_lance_debug && version_printed++ == 0) + printk (version); + + printk ("%s: LANCE ", dev->name); + /* Fill the dev fields */ + dev->base_addr = (long) sdev; + + /* Copy the IDPROM ethernet address to the device structure, later we + * will copy the address in the device structure to the lance initialization + * block + */ + for (i = 0; i < 6; i++){ + printk ("%2.2x%c", dev->dev_addr [i] = idprom->id_eaddr [i], i == 5 ? ' ': ':'); + } + /* Get the IO region */ + ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, + sizeof (struct lance_regs), "Lance driver", 0x0, 0x0); + + /* Make certain the data structures used by the LANCE are aligned. */ + dev->priv = (void *)(((int)dev->priv + 7) & ~7); + lp = (struct lance_private *) dev->priv; + + lp->init_block = (void *) + sparc_dvma_malloc (sizeof (struct lance_init_block), "LANCE"); + + lp->ll = ll; + lp->name = "LANCE"; + + /* This should never happen. */ + if ((int)(lp->init_block->brx_ring) & 0x07) { + printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n"); + return ENODEV; + } + + dev->open = &lance_open; + dev->stop = &lance_close; + dev->hard_start_xmit = &lance_start_xmit; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &lance_set_multicast; + + dev->irq = (unsigned char) sdev->irqs [0].pri; + dev->dma = 0; + ether_setup (dev); + + return 0; +} +/* + * Local variables: + * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I../../..//net/tcp -c lance.c" + * version-control: t + * kept-new-versions: 5 + * End: + */ diff -u --recursive --new-file v1.3.43/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v1.3.43/linux/drivers/net/tulip.c Thu Nov 9 11:23:50 1995 +++ linux/drivers/net/tulip.c Fri Nov 24 16:39:54 1995 @@ -158,7 +158,7 @@ static void tulip_interrupt(int irq, struct pt_regs *regs); static int tulip_close(struct device *dev); static struct enet_statistics *tulip_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); static int set_mac_address(struct device *dev, void *addr); @@ -254,12 +254,8 @@ dev->hard_start_xmit = &tulip_start_xmit; dev->stop = &tulip_close; dev->get_stats = &tulip_get_stats; -#ifdef HAVE_MULTICAST dev->set_multicast_list = &set_multicast_list; -#endif -#ifdef HAVE_SET_MAC_ADDR dev->set_mac_address = &set_mac_address; -#endif return; } @@ -673,36 +669,44 @@ return &tp->stats; } -/* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. +/* + * Set or clear the multicast filter for this adaptor. */ -static void -set_multicast_list(struct device *dev, int num_addrs, void *addrs) + +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) { short ioaddr = dev->base_addr; int csr6 = inl(ioaddr + CSR6) & ~0x00D5; - if (num_addrs > 15 || num_addrs == -2) { - /* Too many to filter perfectly -- accept all multicasts. */ - outl(csr6 | 0x0080, ioaddr + CSR6); - } else if (num_addrs < 0) { /* Set promiscuous. */ + if (dev->flags&IFF_PROMISC) + { /* Set promiscuous. */ outl(csr6 | 0x00C0, ioaddr + CSR6); /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); - } else { + } + else if (dev->mc_count > 15 || (dev->mc_flags&IFF_ALLMULTI)) + { + /* Too many to filter perfectly -- accept all multicasts. */ + outl(csr6 | 0x0080, ioaddr + CSR6); + } + else + { struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct dev_mc_list *dmi=dev->mc_list; int *setup_frm = tp->setup_frame; - unsigned short *eaddrs = addrs; + unsigned short *eaddrs; int i; /* We have <= 15 addresses that we can use the wonderful 16 address perfect filtering of the Tulip. Note that only the low shortword of setup_frame[] is valid. */ outl(csr6 | 0x0000, ioaddr + CSR6); - for(i = 0; i < num_addrs; i++) { + i=0; + while(dmi) + { + eaddrs=(unsigned short *)dmi->dmi_addr; + dmi=dmi->next; + i++; *setup_frm++ = *eaddrs++; *setup_frm++ = *eaddrs++; *setup_frm++ = *eaddrs++; diff -u --recursive --new-file v1.3.43/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v1.3.43/linux/drivers/net/wavelan.c Thu Nov 9 11:23:50 1995 +++ linux/drivers/net/wavelan.c Fri Nov 24 16:39:54 1995 @@ -80,7 +80,7 @@ static void wavelan_interrupt(int, struct pt_regs *); static int wavelan_close(device *); static en_stats *wavelan_get_stats(device *); -static void wavelan_set_multicast_list(device *, int, void *); +static void wavelan_set_multicast_list(device *); static int wavelan_get_info(char*, char**, off_t, int, int); /* @@ -1051,6 +1051,8 @@ */ ether_setup(dev); + dev->flags &= ~IFF_MULTICAST; /* Not yet supported */ + dev->mtu = WAVELAN_MTU; if (wavelan_debug > 0) @@ -2015,19 +2017,18 @@ static void -wavelan_set_multicast_list(device *dev, int num_addrs, void *addrs) +wavelan_set_multicast_list(device *dev) { net_local *lp; unsigned long x; if (wavelan_debug > 0) - printk("%s: ->wavelan_set_multicast_list(dev=0x%x, num_addrs=%d, addrs=0x%x)\n", dev->name, (unsigned int)dev, num_addrs, (unsigned int)addrs); + printk("%s: ->wavelan_set_multicast_list(dev=0x%x)", dev->name, dev); lp = (net_local *)dev->priv; - switch (num_addrs) + if(dev->flags&IFF_PROMISC) { - case -1: /* * Promiscuous mode: receive all packets. */ @@ -2035,9 +2036,16 @@ x = wavelan_splhi(); (void)wavelan_hardware_reset(dev); wavelan_splx(x); - break; - - case 0: + } +#if MULTICAST_IS_ADDED + else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) + { + + + } +#endif + else + { /* * Normal mode: disable promiscuous mode, * clear multicast list. @@ -2046,14 +2054,6 @@ x = wavelan_splhi(); (void)wavelan_hardware_reset(dev); wavelan_splx(x); - break; - - default: - /* - * Multicast mode: receive normal and - * multicast packets and do best-effort filtering. - */ - break; } if (wavelan_debug > 0) diff -u --recursive --new-file v1.3.43/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v1.3.43/linux/drivers/net/znet.c Tue Oct 10 18:46:37 1995 +++ linux/drivers/net/znet.c Fri Nov 24 16:39:54 1995 @@ -186,7 +186,7 @@ static void znet_rx(struct device *dev); static int znet_close(struct device *dev); static struct enet_statistics *net_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void set_multicast_list(struct device *dev); static void hardware_init(struct device *dev); static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); @@ -625,10 +625,6 @@ #ifdef HAVE_MULTICAST /* Set or clear the multicast filter for this adaptor. - num_addrs == -1 Promiscuous mode, receive all packets - num_addrs == 0 Normal mode, clear multicast list - num_addrs > 0 Multicast mode, receive normal and MC packets, and do - best-effort filtering. As a side effect this routine must also initialize the device parameters. This is taken advantage of in open(). @@ -636,15 +632,15 @@ mode change persistent, but must be changed if this code is moved to a multiple adaptor environment. */ -static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +static void set_multicast_list(struct device *dev) { short ioaddr = dev->base_addr; - if (num_addrs == -1) { + if (dev->flags&IFF_PROMISC) { /* Enable promiscuous mode */ i593_init[7] &= ~3; i593_init[7] |= 1; i593_init[13] &= ~8; i593_init[13] |= 8; - } else if (num_addrs != 0) { + } else if (dev->mc_list || (dev->flags&IFF_ALLMULTI)) { /* Enable accept-all-multicast mode */ i593_init[7] &= ~3; i593_init[7] |= 0; i593_init[13] &= ~8; i593_init[13] |= 8; diff -u --recursive --new-file v1.3.43/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v1.3.43/linux/drivers/pci/pci.c Fri Nov 17 08:42:26 1995 +++ linux/drivers/pci/pci.c Tue Nov 21 16:27:33 1995 @@ -41,6 +41,7 @@ * it is sequential by both vendor and device id. */ struct pci_dev_info dev_info[] = { + DEVICE( COMPAQ, COMPAQ_1280, "QVision 1280/p"), DEVICE( NCR, NCR_53C810, "53c810"), DEVICE( NCR, NCR_53C820, "53c820"), DEVICE( NCR, NCR_53C825, "53c825"), @@ -88,12 +89,7 @@ DEVICE( SI, SI_5511, "85C5511"), DEVICE( SI, SI_5513, "85C5513"), DEVICE( HP, HP_J2585A, "J2585A"), -#if 0 - DEVICE( SMC, SMC_37C665, "FDC 37C665"), /* 1042 ? */ - DEVICE( SMC, SMC_37C922, "FDC 37C922"), -#else - DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"), /* 1042 */ -#endif + DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"), DEVICE( DPT, DPT, "SmartCache/Raid"), DEVICE( OPTI, OPTI_82C557, "82C557"), DEVICE( OPTI, OPTI_82C558, "82C558"), @@ -101,6 +97,7 @@ DEVICE( OPTI, OPTI_82C822, "82C822"), DEVICE( BUSLOGIC, BUSLOGIC_946C_2,"946C"), DEVICE( BUSLOGIC, BUSLOGIC_946C, "946C"), + DEVICE( BUSLOGIC, BUSLOGIC_930, "BT-930"), DEVICE( PROMISE, PROMISE_5300, "DC5030"), DEVICE( N9, N9_I128, "Imagine 128"), DEVICE( UMC, UMC_UM8673F, "UM8673F"), @@ -118,6 +115,7 @@ DEVICE( CMD, CMD_646, "646"), DEVICE( VISION, VISION_QD8500, "QD-8500"), DEVICE( VISION, VISION_QD8580, "QD-8580"), + DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"), DEVICE( WINBOND, WINBOND_83769, "W83769F"), DEVICE( 3COM, 3COM_3C590, "3C590 10bT"), DEVICE( 3COM, 3COM_3C595TX, "3C595 100bTX"), @@ -128,18 +126,22 @@ DEVICE( AL, AL_M1451, "M1451"), DEVICE( AL, AL_M1461, "M1461"), DEVICE( AL, AL_M4803, "M4803"), + DEVICE( ASP, ASP_ABP940, "ABP940"), DEVICE( IMS, IMS_8849, "8849"), + DEVICE( TEKRAM2, TEKRAM2_690c, "DC690c"), DEVICE( REALTEK, REALTEK_8029, "8029"), DEVICE( VIA, VIA_82C505, "VT 82C505"), DEVICE( VIA, VIA_82C561, "VT 82C561"), DEVICE( VIA, VIA_82C576, "VT 82C576 3V"), DEVICE( VORTEX, VORTEX_GDT, "GDT 6000b"), - DEVICE( EF, EF_ATM, "155P-MF1"), + DEVICE( EF, EF_ATM_FPGA, "155P-MF1 (FPGA)"), + DEVICE( EF, EF_ATM_ASIC, "155P-MF1 (ASIC)"), DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"), DEVICE( PLX, PLX_9060, "PCI9060 i960 bridge"), DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), - DEVICE( ZEINET, ZEINET_1221, "1221"), + DEVICE( ZEITNET, ZEITNET_1221, "1221"), + DEVICE( HAL, HAL_RIO, "RIO host"), DEVICE( CYCLADES, CYCLADES_Y, "Cyclome-Y"), DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), @@ -160,14 +162,16 @@ DEVICE( INTEL, INTEL_7116, "SAA7116"), DEVICE( INTEL, INTEL_82596, "82596"), DEVICE( INTEL, INTEL_82865, "82865"), + DEVICE( INTEL, INTEL_82557, "82557"), DEVICE( INTEL, INTEL_82437, "82437"), DEVICE( INTEL, INTEL_82371_0, "82371 Triton PIIX"), DEVICE( INTEL, INTEL_82371_1, "82371 Triton PIIX"), - DEVICE( INTEL, INTEL_P6, "Experimental P6 bridge"), + DEVICE( INTEL, INTEL_P6, "Orion P6"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"), DEVICE( ADAPTEC, ADAPTEC_7871, "AIC-7871"), DEVICE( ADAPTEC, ADAPTEC_7872, "AIC-7872"), + DEVICE( ADAPTEC, ADAPTEC_7873, "AIC-7873"), DEVICE( ADAPTEC, ADAPTEC_7880, "AIC-7880U"), DEVICE( ADAPTEC, ADAPTEC_7881, "AIC-7881U"), DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"), @@ -368,61 +372,66 @@ const char *pci_strvendor(unsigned int vendor) { switch (vendor) { + case PCI_VENDOR_ID_COMPAQ: return "Compaq"; case PCI_VENDOR_ID_NCR: return "NCR"; - case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; - case PCI_VENDOR_ID_DPT: return "DPT"; - case PCI_VENDOR_ID_S3: return "S3 Inc."; - case PCI_VENDOR_ID_OPTI: return "OPTI"; - case PCI_VENDOR_ID_UMC: return "UMC"; - case PCI_VENDOR_ID_DEC: return "DEC"; - case PCI_VENDOR_ID_MATROX: return "Matrox"; - case PCI_VENDOR_ID_INTEL: return "Intel"; -#if 0 - case PCI_VENDOR_ID_SMC: return "SMC"; -#else - case PCI_VENDOR_ID_PCTECH: return "PCTECH"; -#endif case PCI_VENDOR_ID_ATI: return "ATI"; + case PCI_VENDOR_ID_VLSI: return "VLSI"; + case PCI_VENDOR_ID_ADL: return "Advance Logic"; + case PCI_VENDOR_ID_NS: return "NS"; + case PCI_VENDOR_ID_TSENG: return "Tseng'Lab"; case PCI_VENDOR_ID_WEITEK: return "Weitek"; + case PCI_VENDOR_ID_DEC: return "DEC"; case PCI_VENDOR_ID_CIRRUS: return "Cirrus Logic"; - case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic"; - case PCI_VENDOR_ID_N9: return "Number Nine"; - case PCI_VENDOR_ID_AI: return "Acer Incorporated"; - case PCI_VENDOR_ID_AL: return "Acer Labs"; - case PCI_VENDOR_ID_TSENG: return "Tseng'Lab"; - case PCI_VENDOR_ID_CMD: return "CMD"; - case PCI_VENDOR_ID_VISION: return "Vision"; + case PCI_VENDOR_ID_IBM: return "IBM"; case PCI_VENDOR_ID_AMD: return "AMD"; - case PCI_VENDOR_ID_VLSI: return "VLSI"; - case PCI_VENDOR_ID_ADL: return "Advance Logic"; - case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; case PCI_VENDOR_ID_TRIDENT: return "Trident"; - case PCI_VENDOR_ID_CONTAQ: return "Contaq"; - case PCI_VENDOR_ID_NS: return "NS"; - case PCI_VENDOR_ID_VIA: return "VIA Technologies"; - case PCI_VENDOR_ID_SI: return "Silicon Integrated Systems"; - case PCI_VENDOR_ID_LEADTEK: return "Leadtek Research"; - case PCI_VENDOR_ID_IMS: return "IMS"; - case PCI_VENDOR_ID_ZEINET: return "ZeiNet"; - case PCI_VENDOR_ID_EF: return "Efficient Networks"; - case PCI_VENDOR_ID_HER: return "Hercules"; - case PCI_VENDOR_ID_ATRONICS: return "Atronics"; + case PCI_VENDOR_ID_AI: return "Acer Incorporated"; + case PCI_VENDOR_ID_MATROX: return "Matrox"; case PCI_VENDOR_ID_CT: return "Chips & Technologies"; case PCI_VENDOR_ID_FD: return "Future Domain"; - case PCI_VENDOR_ID_WINBOND: return "Winbond"; - case PCI_VENDOR_ID_3COM: return "3Com"; + case PCI_VENDOR_ID_SI: return "Silicon Integrated Systems"; + case PCI_VENDOR_ID_HP: return "Hewlett Packard"; + case PCI_VENDOR_ID_PCTECH: return "PCTECH"; + case PCI_VENDOR_ID_DPT: return "DPT"; + case PCI_VENDOR_ID_OPTI: return "OPTI"; + case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic"; case PCI_VENDOR_ID_PROMISE: return "Promise Technology"; - case PCI_VENDOR_ID_QLOGIC: return "Q Logic"; + case PCI_VENDOR_ID_N9: return "Number Nine"; + case PCI_VENDOR_ID_UMC: return "UMC"; case PCI_VENDOR_ID_X: return "X TECHNOLOGY"; + case PCI_VENDOR_ID_QLOGIC: return "Q Logic"; + case PCI_VENDOR_ID_LEADTEK: return "Leadtek Research"; + case PCI_VENDOR_ID_CONTAQ: return "Contaq"; + case PCI_VENDOR_ID_OLICOM: return "Olicom"; + case PCI_VENDOR_ID_CMD: return "CMD"; + case PCI_VENDOR_ID_VISION: return "Vision"; + case PCI_VENDOR_ID_SIERRA: return "Sierra"; case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS"; + case PCI_VENDOR_ID_WINBOND: return "Winbond"; + case PCI_VENDOR_ID_3COM: return "3Com"; + case PCI_VENDOR_ID_AL: return "Acer Labs"; + case PCI_VENDOR_ID_ASP: return "Advanced System Products"; + case PCI_VENDOR_ID_IMS: return "IMS"; + case PCI_VENDOR_ID_TEKRAM2: return "Tekram"; + case PCI_VENDOR_ID_REALTEK: return "Realtek"; + case PCI_VENDOR_ID_VIA: return "VIA Technologies"; case PCI_VENDOR_ID_VORTEX: return "VORTEX"; - case PCI_VENDOR_ID_HP: return "Hewlett Packard"; + case PCI_VENDOR_ID_EF: return "Efficient Networks"; case PCI_VENDOR_ID_IMAGINGTECH: return "Imaging Technology"; + case PCI_VENDOR_ID_PLX: return "PLX"; + case PCI_VENDOR_ID_ALLIANCE: return "Alliance"; + case PCI_VENDOR_ID_MUTECH: return "Mutech"; + case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; + case PCI_VENDOR_ID_HAL: return "HAL"; case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; - case PCI_VENDOR_ID_OLICOM: return "Olicom"; - case PCI_VENDOR_ID_IBM: return "IBM"; + case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; + case PCI_VENDOR_ID_TEKRAM: return "Tekram"; case PCI_VENDOR_ID_AVANCE: return "Avance"; - case PCI_VENDOR_ID_ALLIANCE: return "Alliance"; + case PCI_VENDOR_ID_S3: return "S3 Inc."; + case PCI_VENDOR_ID_INTEL: return "Intel"; + case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; + case PCI_VENDOR_ID_ATRONICS: return "Atronics"; + case PCI_VENDOR_ID_HER: return "Hercules"; default: return "Unknown vendor"; } } diff -u --recursive --new-file v1.3.43/linux/fs/fcntl.c linux/fs/fcntl.c --- v1.3.43/linux/fs/fcntl.c Fri Nov 17 08:42:27 1995 +++ linux/fs/fcntl.c Fri Nov 24 07:17:31 1995 @@ -41,19 +41,9 @@ return -EBADF; if (newfd == oldfd) return newfd; - /* - * errno's for dup2() are slightly different than for fcntl(F_DUPFD) - * for historical reasons. - */ - if (newfd > NR_OPEN) /* historical botch - should have been >= */ - return -EBADF; /* dupfd() would return -EINVAL */ -#if 1 - if (newfd == NR_OPEN) - return -EBADF; /* dupfd() does return -EINVAL and that may - * even be the standard! But that is too - * weird for now. - */ -#endif + if (newfd >= NR_OPEN) + return -EBADF; /* following POSIX.1 6.2.1 */ + sys_close(newfd); return dupfd(oldfd,newfd); } diff -u --recursive --new-file v1.3.43/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.3.43/linux/fs/isofs/inode.c Thu Nov 9 11:23:51 1995 +++ linux/fs/isofs/inode.c Sat Nov 25 18:03:12 1995 @@ -339,13 +339,13 @@ brelse(bh); - printk("Max size:%ld Log zone size:%ld\n", + printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n", s->u.isofs_sb.s_max_size, 1UL << s->u.isofs_sb.s_log_zone_size); - printk("First datazone:%ld Root inode number %d\n", + printk(KERN_DEBUG "First datazone:%ld Root inode number %d\n", s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size, isonum_733 (rootp->extent) << s -> u.isofs_sb.s_log_zone_size); - if(high_sierra) printk("Disc in High Sierra format.\n"); + if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n"); unlock_super(s); /* set up enough so that it can read an inode */ diff -u --recursive --new-file v1.3.43/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v1.3.43/linux/fs/nfs/nfsroot.c Tue Nov 21 13:22:12 1995 +++ linux/fs/nfs/nfsroot.c Fri Nov 24 16:42:09 1995 @@ -7,6 +7,14 @@ * is to first determine the local IP address via RARP. Then handle * the RPC negotiation with the system which replied to the RARP. The * actual mounting is done later, when init() is running. + * + * Changes: + * + * Alan Cox : Removed get_address name clash with FPU. + * Alan Cox : Reformatted a bit. + * + * TODO: + * Support bootp and dhcp as well as rarp. */ @@ -42,7 +50,6 @@ #include #include #include -/* #include */ #define IPPORT_RESERVED 1024 @@ -99,41 +106,51 @@ * For receiving rarp packets a packet type has to be registered. Also * initialize all devices for usage by RARP. */ + static int root_rarp_open(void) { - struct open_dev *openp; - struct device *dev; - unsigned short old_flags; - int num; - - /* Register the packet type */ - rarp_packet_type.type=htons(ETH_P_RARP); - dev_add_pack(&rarp_packet_type); - - /* Open all devices which allow RARP */ - for (dev = dev_base, num = 0; dev != NULL; dev = dev->next) { - if (dev->type < ARPHRD_SLIP && - dev->family == AF_INET && - !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOARP))) { - /* First up the interface */ - old_flags = dev->flags; - dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; - if (!(old_flags & IFF_UP) && dev_open(dev)) { - dev->flags = old_flags; - continue; - } - openp = (struct open_dev *) kmalloc(sizeof(struct open_dev), + struct open_dev *openp; + struct device *dev; + unsigned short old_flags; + int num; + + /* + * Register the packet type + */ + + rarp_packet_type.type=htons(ETH_P_RARP); + dev_add_pack(&rarp_packet_type); + + /* + * Open all devices which allow RARP + */ + + for (dev = dev_base, num = 0; dev != NULL; dev = dev->next) + { + if (dev->type < ARPHRD_SLIP && + dev->family == AF_INET && + !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOARP))) + { + /* First up the interface */ + old_flags = dev->flags; + dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; + if (!(old_flags & IFF_UP) && dev_open(dev)) + { + dev->flags = old_flags; + continue; + } + openp = (struct open_dev *) kmalloc(sizeof(struct open_dev), GFP_ATOMIC); - if (openp == NULL) - continue; - openp->dev = dev; - openp->old_flags = old_flags; - openp->next = open_base; - open_base = openp; - num++; + if (openp == NULL) + continue; + openp->dev = dev; + openp->old_flags = old_flags; + openp->next = open_base; + open_base = openp; + num++; + } } - } - return num; + return num; } @@ -142,159 +159,204 @@ * and restore the state of the device. However, keep the root device * open for the upcoming mount. */ + static void root_rarp_close(void) { - struct open_dev *openp; - struct open_dev *nextp; - - /* Deregister the packet type */ - rarp_packet_type.type=htons(ETH_P_RARP); - dev_remove_pack(&rarp_packet_type); + struct open_dev *openp; + struct open_dev *nextp; - /* Deactivate all previously opened devices except that one which is - * able to connect to a suitable server - */ - openp = open_base; - while (openp != NULL) { - nextp = openp->next; - openp->next = NULL; - if (openp->dev != root_dev) { - if (!(openp->old_flags & IFF_UP)) - dev_close(openp->dev); - openp->dev->flags = openp->old_flags; + /* + * Deregister the packet type + */ + + rarp_packet_type.type=htons(ETH_P_RARP); + dev_remove_pack(&rarp_packet_type); + + /* + * Deactivate all previously opened devices except that one which is + * able to connect to a suitable server + */ + + openp = open_base; + while (openp != NULL) + { + nextp = openp->next; + openp->next = NULL; + if (openp->dev != root_dev) + { + if (!(openp->old_flags & IFF_UP)) + dev_close(openp->dev); + openp->dev->flags = openp->old_flags; + } + kfree_s(openp, sizeof(struct open_dev)); + openp = nextp; } - kfree_s(openp, sizeof(struct open_dev)); - openp = nextp; - } } /* - * Receive RARP packets. + * Receive RARP packets. */ + static int root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { - struct arphdr *rarp = (struct arphdr *)skb->h.raw; - unsigned char *rarp_ptr = (unsigned char *)(rarp+1); - unsigned long sip, tip; - unsigned char *sha, *tha; /* s for "source", t for "target" */ + struct arphdr *rarp = (struct arphdr *)skb->h.raw; + unsigned char *rarp_ptr = (unsigned char *)(rarp+1); + unsigned long sip, tip; + unsigned char *sha, *tha; /* s for "source", t for "target" */ - /* If this test doesn't pass, its not IP, or we should ignore it anyway */ - if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) { - kfree_skb(skb, FREE_READ); - return 0; - } + /* + * If this test doesn't pass, its not IP, or we should ignore it anyway + */ + + if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) + { + kfree_skb(skb, FREE_READ); + return 0; + } - /* If it's not a RARP reply, delete it. */ - if (rarp->ar_op != htons(ARPOP_RREPLY)) { - kfree_skb(skb, FREE_READ); - return 0; - } + /* + * If it's not a RARP reply, delete it. + */ + + if (rarp->ar_op != htons(ARPOP_RREPLY)) + { + kfree_skb(skb, FREE_READ); + return 0; + } - /* If it's not ethernet or AX25, delete it. */ - if ((rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) || + /* + * If it's not ethernet or AX25, delete it. + */ + + if ((rarp->ar_pro != htons(ETH_P_IP) && dev->type != ARPHRD_AX25) || #ifdef CONFIG_AX25 - (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) || + (rarp->ar_pro != htons(AX25_P_IP) && dev->type == ARPHRD_AX25) || #endif - rarp->ar_pln != 4) { - kfree_skb(skb, FREE_READ); - return 0; - } + rarp->ar_pln != 4) + { + kfree_skb(skb, FREE_READ); + return 0; + } - /* Extract variable width fields */ - sha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&sip, rarp_ptr, 4); - rarp_ptr += 4; - tha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&tip, rarp_ptr, 4); - - /* Discard packets which are not meant for us. */ - if (memcmp(tha, dev->dev_addr, dev->addr_len)) { - kfree_skb(skb, FREE_READ); - return 0; - } + /* + * Extract variable width fields + */ + + sha = rarp_ptr; + rarp_ptr += dev->addr_len; + memcpy(&sip, rarp_ptr, 4); + rarp_ptr += 4; + tha = rarp_ptr; + rarp_ptr += dev->addr_len; + memcpy(&tip, rarp_ptr, 4); + + /* + * Discard packets which are not meant for us. + */ + + if (memcmp(tha, dev->dev_addr, dev->addr_len)) + { + kfree_skb(skb, FREE_READ); + return 0; + } - /* The packet is what we were looking for. Setup the global variables. */ - cli(); - if (root_dev != NULL) { + /* + * The packet is what we were looking for. Setup the global variables. + */ + + cli(); + if (root_dev != NULL) + { + sti(); + kfree_skb(skb, FREE_READ); + return 0; + } + root_dev = dev; sti(); - kfree_skb(skb, FREE_READ); - return 0; - } - root_dev = dev; - sti(); - myaddr.sin_family = dev->family; - myaddr.sin_addr.s_addr = tip; - server.sin_family = dev->family; - if (!server.sin_addr.s_addr) - server.sin_addr.s_addr = sip; + myaddr.sin_family = dev->family; + myaddr.sin_addr.s_addr = tip; + server.sin_family = dev->family; + if (!server.sin_addr.s_addr) + server.sin_addr.s_addr = sip; - kfree_skb(skb, FREE_READ); - return 0; + kfree_skb(skb, FREE_READ); + return 0; } /* - * Send RARP request packet over all devices which allow RARP. + * Send RARP request packet over all devices which allow RARP. */ + static void root_rarp_send(void) { - struct open_dev *openp; - struct device *dev; + struct open_dev *openp; + struct device *dev; #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Sending RARP request...\n"); + printk(KERN_NOTICE "NFS: Sending RARP request...\n"); #endif - for (openp = open_base; openp != NULL; openp = openp->next) { - dev = openp->dev; - arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, - dev->dev_addr, dev->dev_addr); - } + for (openp = open_base; openp != NULL; openp = openp->next) + { + dev = openp->dev; + arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, + dev->dev_addr, dev->dev_addr); + } } /* - * Determine client and server IP numbers and appropriate device by using - * the RARP protocol. + * Determine client and server IP numbers and appropriate device by using + * the RARP protocol. */ + static int do_rarp(void) { - int retries = 0; - unsigned long timeout; + int retries = 0; + unsigned long timeout; + + /* + * Open all devices and setup RARP protocol + */ + + if (!root_rarp_open()) + { + printk(KERN_ERR "NFS: No network device found to send RARP request to\n"); + return -1; + } + + /* + * Send RARP request and wait, until we get an answer. This loop seems + * to be a terrible waste of cpu time, but actually there is no process + * running at all, so we don't need to use any scheduler functions. + * [Actually we could now, but the nothing else running note still + * applies.. - AC] + */ + + for (retries = 0; retries < RARP_RETRIES && root_dev == NULL; retries++) + { + root_rarp_send(); + timeout = jiffies + (RARP_TIMEOUT * HZ); + while (jiffies < timeout && root_dev == NULL) + ;; + } + + if (root_dev == NULL) + { + printk(KERN_ERR "NFS: Timed out while waiting for RARP answer\n"); + return -1; + } + + root_rarp_close(); - /* Open all devices and setup RARP protocol */ - if (!root_rarp_open()) { - printk(KERN_ERR "NFS: No network device found to send RARP request to\n"); - return -1; - } - - /* Send RARP request and wait, until we get an answer. This loop seems - * to be a terrible waste of cpu time, but actually there is no process - * running at all, so we don't need to use any scheduler functions. - */ - for (retries = 0; retries < RARP_RETRIES && root_dev == NULL; retries++) { - root_rarp_send(); - timeout = jiffies + (RARP_TIMEOUT * HZ); - while (jiffies < timeout && root_dev == NULL) - ;; - } - - if (root_dev == NULL) { - printk(KERN_ERR "NFS: Timed out while waiting for RARP answer\n"); - return -1; - } - - root_rarp_close(); - - printk(KERN_NOTICE "NFS: "); - printk("Got RARP answer from %s, ", in_ntoa(server.sin_addr.s_addr)); - printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr)); + printk(KERN_NOTICE "NFS: "); + printk("Got RARP answer from %s, ", in_ntoa(server.sin_addr.s_addr)); + printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr)); - return 0; + return 0; } @@ -311,7 +373,10 @@ unsigned short mss, unsigned long window); -/* The following integer options are recognized */ +/* + * The following integer options are recognized + */ + static struct nfs_int_opts { char *name; @@ -329,7 +394,10 @@ { NULL, NULL }}; -/* And now the flag options */ +/* + * And now the flag options + */ + static struct nfs_bool_opts { char *name; @@ -346,125 +414,145 @@ { "nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO }, { "ac", ~NFS_MOUNT_NOAC, 0 }, { "noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC }, - { NULL, 0, 0 }}; + { NULL, 0, 0 } +}; -static unsigned long get_address (char **str) +static unsigned long nfs_get_address (char **str) { - unsigned long l; - unsigned int val; - int i; + unsigned long l; + unsigned int val; + int i; - l = 0; - for (i = 0; i < 4; i++) - { - - l <<= 8; - if (**str != '\0') - { - - val = 0; - while (**str != '\0' && **str != '.' && **str != ':') - { - - val *= 10; - val += **str - '0'; - (*str)++; - } - - l |= val; - if (**str != '\0') - (*str)++; - } - - } - - return(htonl(l)); + l = 0; + for (i = 0; i < 4; i++) + { + l <<= 8; + if (**str != '\0') + { + val = 0; + while (**str != '\0' && **str != '.' && **str != ':') + { + val *= 10; + val += **str - '0'; + (*str)++; + } + l |= val; + if (**str != '\0') + (*str)++; + } + } + return(htonl(l)); } /* - * Prepare the NFS data structure and parse any options + * Prepare the NFS data structure and parse any options */ + static int root_nfs_parse(char *name) { - char buf[NFS_MAXPATHLEN]; - char *cp, *options, *val; + char buf[NFS_MAXPATHLEN]; + char *cp, *options, *val; + + /* + * Get the host ip number + */ + + if (*name >= '0' && *name <= '9') + { + server.sin_addr.s_addr = nfs_get_address (&name); + } - /* get the host ip number */ - if (*name >= '0' && *name <= '9'){ - server.sin_addr.s_addr = get_address (&name); - } - /* Setup the server hostname */ - cp = in_ntoa(server.sin_addr.s_addr); - strncpy(nfs_data.hostname, cp, 255); - nfs_data.addr = server; - - /* Set the name of the directory to mount */ - cp = in_ntoa(myaddr.sin_addr.s_addr); - strncpy(buf, name, 255); - if ((options = strchr(buf, ','))) - *options++ = '\0'; - if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { - printk(KERN_ERR "NFS: Pathname for remote directory too long\n"); - return -1; - } - sprintf(nfs_path, buf, cp); - - /* Set some default values */ - nfs_port = -1; - nfs_data.version = NFS_MOUNT_VERSION; - nfs_data.flags = 0; - nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; - nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; - nfs_data.timeo = 7; - nfs_data.retrans = 3; - nfs_data.acregmin = 3; - nfs_data.acregmax = 60; - nfs_data.acdirmin = 30; - nfs_data.acdirmax = 60; - - /* Process any options */ - if (options) { - cp = strtok(options, ","); - while (cp) { - if ((val = strchr(cp, '='))) { - struct nfs_int_opts *opts = root_int_opts; - *val++ = '\0'; - while (opts->name && strcmp(opts->name, cp)) - opts++; - if (opts->name) - *(opts->val) = (int) simple_strtoul(val, NULL, 10); - } else { - struct nfs_bool_opts *opts = root_bool_opts; - while (opts->name && strcmp(opts->name, cp)) - opts++; - if (opts->name) { - nfs_data.flags &= opts->and_mask; - nfs_data.flags |= opts->or_mask; + /* + * Setup the server hostname + */ + + cp = in_ntoa(server.sin_addr.s_addr); + strncpy(nfs_data.hostname, cp, 255); + nfs_data.addr = server; + + /* + * Set the name of the directory to mount + */ + + cp = in_ntoa(myaddr.sin_addr.s_addr); + strncpy(buf, name, 255); + if ((options = strchr(buf, ','))) + *options++ = '\0'; + if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) + { + printk(KERN_ERR "NFS: Pathname for remote directory too long\n"); + return -1; + } + sprintf(nfs_path, buf, cp); + + /* + * Set some default values + */ + + nfs_port = -1; + nfs_data.version = NFS_MOUNT_VERSION; + nfs_data.flags = 0; + nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; + nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; + nfs_data.timeo = 7; + nfs_data.retrans = 3; + nfs_data.acregmin = 3; + nfs_data.acregmax = 60; + nfs_data.acdirmin = 30; + nfs_data.acdirmax = 60; + + /* + * Process any options + */ + + if (options) + { + cp = strtok(options, ","); + while (cp) + { + if ((val = strchr(cp, '='))) + { + struct nfs_int_opts *opts = root_int_opts; + *val++ = '\0'; + while (opts->name && strcmp(opts->name, cp)) + opts++; + if (opts->name) + *(opts->val) = (int) simple_strtoul(val, NULL, 10); } + else + { + struct nfs_bool_opts *opts = root_bool_opts; + while (opts->name && strcmp(opts->name, cp)) + opts++; + if (opts->name) + { + nfs_data.flags &= opts->and_mask; + nfs_data.flags |= opts->or_mask; + } + } + cp = strtok(NULL, ","); } - cp = strtok(NULL, ","); } - } - - return 0; + return 0; } /* - * Tell the user what's going on. + * Tell the user what's going on. */ + static void root_nfs_print(void) { #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Mounting %s on server %s as root\n", + printk(KERN_NOTICE "NFS: Mounting %s on server %s as root\n", nfs_path, nfs_data.hostname); - printk(KERN_NOTICE "NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", + printk(KERN_NOTICE "NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans); - printk(KERN_NOTICE "NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", + printk(KERN_NOTICE "NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", nfs_data.acregmin, nfs_data.acregmax, nfs_data.acdirmin, nfs_data.acdirmax); - printk(KERN_NOTICE "NFS: port = %d, flags = %08x\n", + printk(KERN_NOTICE "NFS: port = %d, flags = %08x\n", nfs_port, nfs_data.flags); #endif } @@ -475,53 +563,62 @@ */ static void root_nfs_setup(void) { - struct rtentry server_route; - struct sockaddr_in *sin; + struct rtentry server_route; + struct sockaddr_in *sin; - /* Setup the device correctly */ - root_dev->family = myaddr.sin_family; - root_dev->pa_addr = myaddr.sin_addr.s_addr; - root_dev->pa_mask = ip_get_mask(myaddr.sin_addr.s_addr); - root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask; - root_dev->pa_dstaddr = 0; - - sin=(struct sockaddr_in *)&server_route.rt_dst; - *sin=server; - sin=(struct sockaddr_in *)&server_route.rt_genmask; - sin->sin_family=AF_INET; - sin->sin_addr.s_addr= root_dev->pa_mask; - server_route.rt_dev=NULL; - server_route.rt_flags=RTF_HOST|RTF_UP; + /* + * Setup the device correctly + */ + + root_dev->family = myaddr.sin_family; + root_dev->pa_addr = myaddr.sin_addr.s_addr; + root_dev->pa_mask = ip_get_mask(myaddr.sin_addr.s_addr); + root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask; + root_dev->pa_dstaddr = 0; + + sin=(struct sockaddr_in *)&server_route.rt_dst; + *sin=server; + sin=(struct sockaddr_in *)&server_route.rt_genmask; + sin->sin_family=AF_INET; + sin->sin_addr.s_addr= root_dev->pa_mask; + server_route.rt_dev=NULL; + server_route.rt_flags=RTF_HOST|RTF_UP; - /* Now add a route to the server */ - if(ip_rt_new(&server_route)==-1) - printk("Unable to add NFS server route.\n"); + /* + * Now add a route to the server + */ + + if(ip_rt_new(&server_route)==-1) + printk("Unable to add NFS server route.\n"); } /* - * Get the necessary IP addresses and prepare for mounting the required - * NFS filesystem. + * Get the necessary IP addresses and prepare for mounting the required + * NFS filesystem. */ + int nfs_root_init(char *nfsname) { - /* Initialize network device and get local and server IP address */ - if (do_rarp() < 0) - return -1; - - /* Initialize the global variables necessary for NFS. The server - * directory is actually mounted after init() has been started. - */ - if (root_nfs_parse(nfsname) < 0) - return -1; - root_nfs_print(); - root_nfs_setup(); - return 0; + /* + * Initialize network device and get local and server IP address + */ + + if (do_rarp() < 0) + return -1; + + /* + * Initialize the global variables necessary for NFS. The server + * directory is actually mounted after init() has been started. + */ + + if (root_nfs_parse(nfsname) < 0) + return -1; + root_nfs_print(); + root_nfs_setup(); + return 0; } - - - /*************************************************************************** Routines to actually mount the root directory @@ -537,313 +634,385 @@ /* - * Open a UDP socket. + * Open a UDP socket. */ + static int root_nfs_open(void) { - struct file *filp; - unsigned long opt[] = { AF_INET, SOCK_DGRAM, IPPROTO_UDP }; + struct file *filp; + unsigned long opt[] = { AF_INET, SOCK_DGRAM, IPPROTO_UDP }; - /* Open the socket */ - if ((nfs_data.fd = sys_socketcall(SYS_SOCKET, opt)) < 0) { - printk(KERN_ERR "NFS: Cannot open UDP socket\n"); - return -1; - } - - /* Copy the file and inode data area so that we can remove the - * file lateron without killing the socket. After all this the - * closing routine just needs to remove the file pointer from - * the init-task descriptor. - */ - filp = current->files->fd[nfs_data.fd]; - memcpy(&nfs_file, filp, sizeof(struct file)); - nfs_file.f_next = nfs_file.f_prev = NULL; - current->files->fd[nfs_data.fd] = &nfs_file; - filp->f_count = 0; /* Free the file descriptor */ - - memcpy(&nfs_inode, nfs_file.f_inode, sizeof(struct inode)); - nfs_inode.i_hash_next = nfs_inode.i_hash_prev = NULL; - nfs_inode.i_next = nfs_inode.i_prev = NULL; - clear_inode(nfs_file.f_inode); - nfs_file.f_inode = &nfs_inode; - nfs_inode.u.socket_i.inode = &nfs_inode; - nfs_file.private_data = NULL; - - return 0; + /* + * Open the socket + */ + + if ((nfs_data.fd = sys_socketcall(SYS_SOCKET, opt)) < 0) + { + printk(KERN_ERR "NFS: Cannot open UDP socket\n"); + return -1; + } + + /* + * Copy the file and inode data area so that we can remove the + * file lateron without killing the socket. After all this the + * closing routine just needs to remove the file pointer from + * the init-task descriptor. + */ + + filp = current->files->fd[nfs_data.fd]; + memcpy(&nfs_file, filp, sizeof(struct file)); + nfs_file.f_next = nfs_file.f_prev = NULL; + current->files->fd[nfs_data.fd] = &nfs_file; + filp->f_count = 0; /* Free the file descriptor */ + + memcpy(&nfs_inode, nfs_file.f_inode, sizeof(struct inode)); + nfs_inode.i_hash_next = nfs_inode.i_hash_prev = NULL; + nfs_inode.i_next = nfs_inode.i_prev = NULL; + clear_inode(nfs_file.f_inode); + nfs_file.f_inode = &nfs_inode; + nfs_inode.u.socket_i.inode = &nfs_inode; + nfs_file.private_data = NULL; + + return 0; } /* - * Close the UDP file descriptor. The main part of preserving the socket - * has already been done after opening it. Now we have to remove the - * file descriptor from the init task. + * Close the UDP file descriptor. The main part of preserving the socket + * has already been done after opening it. Now we have to remove the + * file descriptor from the init task. */ + static void root_nfs_close(int close_all) { - /* Remove the file from the list of open files */ - current->files->fd[nfs_data.fd] = NULL; - if (current->files->count > 0) - current->files->count--; - - /* Clear memory use by the RPC packet */ - if (rpc_packet != NULL) - kfree_s(rpc_packet, nfs_data.wsize + 1024); - - /* In case of an error we also have to close the socket again (sigh) */ - if (close_all) { - nfs_inode.u.socket_i.inode = NULL; /* The inode is already cleared */ - if (nfs_file.f_op->release) - nfs_file.f_op->release(&nfs_inode, &nfs_file); - } + /* + * Remove the file from the list of open files + */ + + current->files->fd[nfs_data.fd] = NULL; + if (current->files->count > 0) + current->files->count--; + + /* + * Clear memory use by the RPC packet + */ + + if (rpc_packet != NULL) + kfree_s(rpc_packet, nfs_data.wsize + 1024); + + /* + * In case of an error we also have to close the socket again (sigh) + */ + + if (close_all) + { + nfs_inode.u.socket_i.inode = NULL; /* The inode is already cleared */ + if (nfs_file.f_op->release) + nfs_file.f_op->release(&nfs_inode, &nfs_file); + } } /* - * Find a suitable listening port and bind to it + * Find a suitable listening port and bind to it */ + static int root_nfs_bind(void) { - int res = -1; - short port = STARTPORT; - struct sockaddr_in *sin = &myaddr; - int i; - - if (nfs_inode.u.socket_i.ops->bind) { - for (i = 0; i < NPORTS && res < 0; i++) { - sin->sin_port = htons(port++); - if (port > ENDPORT) { - port = STARTPORT; + int res = -1; + short port = STARTPORT; + struct sockaddr_in *sin = &myaddr; + int i; + + if (nfs_inode.u.socket_i.ops->bind) + { + for (i = 0; i < NPORTS && res < 0; i++) + { + sin->sin_port = htons(port++); + if (port > ENDPORT) + { + port = STARTPORT; + } + res = nfs_inode.u.socket_i.ops->bind(&nfs_inode.u.socket_i, + (struct sockaddr *) sin, sizeof(struct sockaddr_in)); } - res = nfs_inode.u.socket_i.ops->bind(&nfs_inode.u.socket_i, - (struct sockaddr *) sin, sizeof(struct sockaddr_in)); } - } - if (res < 0) { - printk(KERN_ERR "NFS: Cannot find a suitable listening port\n"); - root_nfs_close(1); - return -1; - } - + if (res < 0) + { + printk(KERN_ERR "NFS: Cannot find a suitable listening port\n"); + root_nfs_close(1); + return -1; + } #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Binding to listening port %d\n", port); + printk(KERN_NOTICE "NFS: Binding to listening port %d\n", port); #endif - return 0; + return 0; } /* - * Send an RPC request and wait for the answer + * Send an RPC request and wait for the answer */ + static int *root_nfs_call(int *end) { - struct file *filp; - struct socket *sock; - int dummylen; - static struct nfs_server s = - { &nfs_file, /* struct file * */ - 0, /* struct rsock * */ - { - 0, "", - }, /* toaddr */ - 0, /* lock */ - NULL, /* wait queue */ - NFS_MOUNT_SOFT, /* flags */ - 0, 0, /* rsize, wsize */ - 0, /* timeo */ - 0, /* retrans */ - 3*HZ, 60*HZ, 30*HZ, 60*HZ, "\0" }; + struct file *filp; + struct socket *sock; + int dummylen; + static struct nfs_server s = { + &nfs_file, /* struct file * */ + 0, /* struct rsock * */ + { + 0, "", + }, /* toaddr */ + 0, /* lock */ + NULL, /* wait queue */ + NFS_MOUNT_SOFT, /* flags - this seems a ___BAD___ default - AC */ + 0, 0, /* rsize, wsize */ + 0, /* timeo */ + 0, /* retrans */ + 3*HZ, 60*HZ, 30*HZ, 60*HZ, "\0" + }; - filp = &nfs_file; - sock = &((filp->f_inode)->u.socket_i); + filp = &nfs_file; + sock = &((filp->f_inode)->u.socket_i); - /* extract the other end of the socket into server->toaddr */ - sock->ops->getname(sock, &(s.toaddr), &dummylen, 1) ; - ((struct sockaddr_in *) &s.toaddr)->sin_port = server.sin_port; - ((struct sockaddr_in *) &s.toaddr)->sin_family = server.sin_family; - ((struct sockaddr_in *) &s.toaddr)->sin_addr.s_addr = server.sin_addr.s_addr; + /* + * extract the other end of the socket into server->toaddr + */ + + sock->ops->getname(sock, &(s.toaddr), &dummylen, 1) ; + ((struct sockaddr_in *) &s.toaddr)->sin_port = server.sin_port; + ((struct sockaddr_in *) &s.toaddr)->sin_family = server.sin_family; + ((struct sockaddr_in *) &s.toaddr)->sin_addr.s_addr = server.sin_addr.s_addr; - s.rsock = rpc_makesock(filp); - s.flags = nfs_data.flags; - s.rsize = nfs_data.rsize; - s.wsize = nfs_data.wsize; - s.timeo = nfs_data.timeo * HZ / 10; - s.retrans = nfs_data.retrans; - strcpy(s.hostname, nfs_data.hostname); - - /* First connect the UDP socket to a server port, then send the packet - * out, and finally check wether the answer is OK. - */ - if (nfs_inode.u.socket_i.ops->connect && - nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i, + s.rsock = rpc_makesock(filp); + s.flags = nfs_data.flags; + s.rsize = nfs_data.rsize; + s.wsize = nfs_data.wsize; + s.timeo = nfs_data.timeo * HZ / 10; + s.retrans = nfs_data.retrans; + strcpy(s.hostname, nfs_data.hostname); + + /* + * First connect the UDP socket to a server port, then send the packet + * out, and finally check wether the answer is OK. + */ + + if (nfs_inode.u.socket_i.ops->connect && + nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i, (struct sockaddr *) &server, sizeof(struct sockaddr_in), nfs_file.f_flags) < 0) - return NULL; - if (nfs_rpc_call(&s, rpc_packet, end, nfs_data.wsize) < 0) - return NULL; - return rpc_verify(rpc_packet); + { + return NULL; + } + + if (nfs_rpc_call(&s, rpc_packet, end, nfs_data.wsize) < 0) + return NULL; + return rpc_verify(rpc_packet); } /* - * Create an RPC packet header + * Create an RPC packet header */ + static int *root_nfs_header(int proc, int program, int version) { - int groups[] = { 0, NOGROUP }; + int groups[] = { 0, NOGROUP }; - if (rpc_packet == NULL) { - if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS))) { - printk(KERN_ERR "NFS: Cannot allocate UDP buffer\n"); - return NULL; + if (rpc_packet == NULL) + { + if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS))) + { + printk(KERN_ERR "NFS: Cannot allocate UDP buffer\n"); + return NULL; + } } - } - strcpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr)); - return rpc_header(rpc_packet, proc, program, version, 0, 0, groups); + strcpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr)); + return rpc_header(rpc_packet, proc, program, version, 0, 0, groups); } /* - * Query server portmapper for the port of a daemon program + * Query server portmapper for the port of a daemon program */ + static int root_nfs_get_port(int program, int version) { - int *p; + int *p; - /* Prepare header for portmap request */ - server.sin_port = htons(NFS_PMAP_PORT); - p = root_nfs_header(NFS_PMAP_PROC, NFS_PMAP_PROGRAM, NFS_PMAP_VERSION); - if (!p) - return -1; + /* + * Prepare header for portmap request + */ + + server.sin_port = htons(NFS_PMAP_PORT); + p = root_nfs_header(NFS_PMAP_PROC, NFS_PMAP_PROGRAM, NFS_PMAP_VERSION); + if (!p) + return -1; - /* Set arguments for portmapper */ - *p++ = htonl(program); - *p++ = htonl(version); - *p++ = htonl(IPPROTO_UDP); - *p++ = 0; + /* + * Set arguments for portmapper + */ + + *p++ = htonl(program); + *p++ = htonl(version); + *p++ = htonl(IPPROTO_UDP); + *p++ = 0; - /* Send request to server portmapper */ - if ((p = root_nfs_call(p)) == NULL) - return -1; + /* + * Send request to server portmapper + */ + + if ((p = root_nfs_call(p)) == NULL) + return -1; - return ntohl(*p); + return ntohl(*p); } /* - * Get portnumbers for mountd and nfsd from server + * Get portnumbers for mountd and nfsd from server */ + static int root_nfs_ports(void) { - int port; + int port; - if (nfs_port < 0) { - if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0) { - printk(KERN_ERR "NFS: Unable to get nfsd port number from server, using default\n"); - port = NFS_NFS_PORT; - } - nfs_port = port; + if (nfs_port < 0) + { + if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0) + { + printk(KERN_ERR "NFS: Unable to get nfsd port number from server, using default\n"); + port = NFS_NFS_PORT; + } + nfs_port = port; #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Portmapper on server returned %d as nfsd port\n", port); + printk(KERN_NOTICE "NFS: Portmapper on server returned %d as nfsd port\n", port); #endif - } + } - if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0) { - printk(KERN_ERR "NFS: Unable to get mountd port number from server, using default\n"); - port = NFS_MOUNT_PORT; - } - server.sin_port = htons(port); + if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0) + { + printk(KERN_ERR "NFS: Unable to get mountd port number from server, using default\n"); + port = NFS_MOUNT_PORT; + } + server.sin_port = htons(port); #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Portmapper on server returned %d as mountd port\n", port); + printk(KERN_NOTICE "NFS: Portmapper on server returned %d as mountd port\n", port); #endif - - return 0; + return 0; } /* - * Get a file handle from the server for the directory which is to be mounted + * Get a file handle from the server for the directory which is to be mounted */ + static int root_nfs_get_handle(void) { - int len, status, *p; + int len, status, *p; + + /* + * Prepare header for mountd request + */ + + p = root_nfs_header(NFS_MOUNT_PROC, NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION); + if (!p) + { + root_nfs_close(1); + return -1; + } - /* Prepare header for mountd request */ - p = root_nfs_header(NFS_MOUNT_PROC, NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION); - if (!p) { - root_nfs_close(1); - return -1; - } - - /* Set arguments for mountd */ - len = strlen(nfs_path); - *p++ = htonl(len); - memcpy(p, nfs_path, len); - len = (len + 3) >> 2; - p[len] = 0; - p += len; - - /* Send request to server portmapper */ - if ((p = root_nfs_call(p)) == NULL) { - root_nfs_close(1); - return -1; - } - - status = ntohl(*p++); - if (status == 0) { - nfs_data.root = *((struct nfs_fh *) p); - } else { - printk(KERN_ERR "NFS: Server returned error %d while mounting %s\n", - status, nfs_path); - root_nfs_close(1); - return -1; - } + /* + * Set arguments for mountd + */ + + len = strlen(nfs_path); + *p++ = htonl(len); + memcpy(p, nfs_path, len); + len = (len + 3) >> 2; + p[len] = 0; + p += len; + + /* + * Send request to server portmapper + */ + + if ((p = root_nfs_call(p)) == NULL) + { + root_nfs_close(1); + return -1; + } - return 0; + status = ntohl(*p++); + if (status == 0) + { + nfs_data.root = *((struct nfs_fh *) p); + } + else + { + printk(KERN_ERR "NFS: Server returned error %d while mounting %s\n", + status, nfs_path); + root_nfs_close(1); + return -1; + } + return 0; } /* - * Now actually mount the given directory + * Now actually mount the given directory */ + static int root_nfs_do_mount(struct super_block *sb) { - /* First connect to the nfsd port on the server */ - server.sin_port = htons(nfs_port); - nfs_data.addr = server; - if (nfs_inode.u.socket_i.ops->connect && - nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i, + /* + * First connect to the nfsd port on the server + */ + + server.sin_port = htons(nfs_port); + nfs_data.addr = server; + if (nfs_inode.u.socket_i.ops->connect && + nfs_inode.u.socket_i.ops->connect(&nfs_inode.u.socket_i, (struct sockaddr *) &server, sizeof(struct sockaddr_in), - nfs_file.f_flags) < 0) { - root_nfs_close(1); - return -1; - } + nfs_file.f_flags) < 0) + { + root_nfs_close(1); + return -1; + } - /* Now (finally ;-)) read the super block for mounting */ - if (nfs_read_super(sb, &nfs_data, 1) == NULL) { - root_nfs_close(1); - return -1; - } + /* + * Now (finally ;-)) read the super block for mounting + */ + + if (nfs_read_super(sb, &nfs_data, 1) == NULL) + { + root_nfs_close(1); + return -1; + } - return 0; + return 0; } /* - * Get the NFS port numbers and file handle, and then read the super- - * block for mounting. + * Get the NFS port numbers and file handle, and then read the super- + * block for mounting. */ + int nfs_root_mount(struct super_block *sb) { - if (root_nfs_open() < 0) - return -1; - if (root_nfs_bind() < 0) - return -1; - if (root_nfs_ports() < 0) - return -1; - if (root_nfs_get_handle() < 0) - return -1; - if (root_nfs_do_mount(sb) < 0) - return -1; - root_nfs_close(0); - return 0; + if (root_nfs_open() < 0) + return -1; + if (root_nfs_bind() < 0) + return -1; + if (root_nfs_ports() < 0) + return -1; + if (root_nfs_get_handle() < 0) + return -1; + if (root_nfs_do_mount(sb) < 0) + return -1; + root_nfs_close(0); + return 0; } diff -u --recursive --new-file v1.3.43/linux/fs/pipe.c linux/fs/pipe.c --- v1.3.43/linux/fs/pipe.c Wed Aug 2 13:21:15 1995 +++ linux/fs/pipe.c Fri Nov 24 07:46:12 1995 @@ -240,10 +240,6 @@ return 0; } -/* - * Ok, these three routines NOW keep track of readers/writers, - * Linus previously did it with inode->i_count checking. - */ static void pipe_read_release(struct inode * inode, struct file * filp) { PIPE_READERS(*inode)--; @@ -263,6 +259,25 @@ wake_up_interruptible(&PIPE_WAIT(*inode)); } +static int pipe_read_open(struct inode * inode, struct file * filp) +{ + PIPE_READERS(*inode)++; + return 0; +} + +static int pipe_write_open(struct inode * inode, struct file * filp) +{ + PIPE_WRITERS(*inode)++; + return 0; +} + +static int pipe_rdwr_open(struct inode * inode, struct file * filp) +{ + PIPE_READERS(*inode)++; + PIPE_WRITERS(*inode)++; + return 0; +} + /* * The file_operations structs are not static because they * are also used in linux/fs/fifo.c to do operations on fifo's. @@ -275,7 +290,7 @@ connect_select, pipe_ioctl, NULL, /* no mmap on pipes.. surprise */ - NULL, /* no special open code */ + pipe_read_open, pipe_read_release, NULL }; @@ -288,7 +303,7 @@ fifo_select, pipe_ioctl, NULL, /* no mmap on pipes.. surprise */ - NULL, /* no special open code */ + pipe_read_open, pipe_read_release, NULL }; @@ -301,7 +316,7 @@ fifo_select, pipe_ioctl, NULL, /* mmap */ - NULL, /* no special open code */ + pipe_write_open, pipe_write_release, NULL }; @@ -314,7 +329,7 @@ fifo_select, pipe_ioctl, NULL, /* mmap */ - NULL, /* no special open code */ + pipe_rdwr_open, pipe_rdwr_release, NULL }; @@ -327,7 +342,7 @@ pipe_select, pipe_ioctl, NULL, /* no mmap on pipes.. surprise */ - NULL, /* no special open code */ + pipe_read_open, pipe_read_release, NULL }; @@ -340,7 +355,7 @@ pipe_select, pipe_ioctl, NULL, /* mmap */ - NULL, /* no special open code */ + pipe_write_open, pipe_write_release, NULL }; @@ -353,7 +368,7 @@ pipe_select, pipe_ioctl, NULL, /* mmap */ - NULL, /* no special open code */ + pipe_rdwr_open, pipe_rdwr_release, NULL }; diff -u --recursive --new-file v1.3.43/linux/fs/proc/fd.c linux/fs/proc/fd.c --- v1.3.43/linux/fs/proc/fd.c Mon Sep 18 14:54:07 1995 +++ linux/fs/proc/fd.c Fri Nov 24 07:17:49 1995 @@ -50,7 +50,7 @@ NULL /* permission */ }; -static int proc_lookupfd(struct inode * dir,const char * name, int len, +static int proc_lookupfd(struct inode * dir, const char * name, int len, struct inode ** result) { unsigned int ino, pid, fd, c; @@ -167,7 +167,7 @@ if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0) break; - /* filldir() migth have slept, so we must re-validate "p" */ + /* filldir() might have slept, so we must re-validate "p" */ if (p != task[task_nr] || p->pid != pid) break; } diff -u --recursive --new-file v1.3.43/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v1.3.43/linux/include/asm-alpha/io.h Thu Nov 9 11:23:52 1995 +++ linux/include/asm-alpha/io.h Thu Nov 23 11:26:03 1995 @@ -128,6 +128,20 @@ # define outb_p outb #endif +#ifndef inw_p +# define inw_p inw +#endif +#ifndef outw_p +# define outw_p outw +#endif + +#ifndef inl_p +# define inl_p inl +#endif +#ifndef outl_p +# define outl_p outl +#endif + /* * The "address" in IO memory space is not clearly either a integer or a * pointer. We will accept both, thus the casts. diff -u --recursive --new-file v1.3.43/linux/include/asm-alpha/segment.h linux/include/asm-alpha/segment.h --- v1.3.43/linux/include/asm-alpha/segment.h Tue Jun 27 14:11:44 1995 +++ linux/include/asm-alpha/segment.h Sat Nov 25 11:54:56 1995 @@ -4,6 +4,16 @@ #include /* + * This is a gcc optimization barrier, which essentially + * inserts a sequence point in the gcc RTL tree that gcc + * can't move code around. This is needed when we enter + * or exit a critical region (in this case around user-level + * accesses that may sleep, and we can't let gcc optimize + * global state around them). + */ +#define __gcc_barrier() __asm__ __volatile__("": : :"memory") + +/* * Uh, these should become the main single-value transfer routines.. * They automatically use the right size if we just have the right * pointer type.. @@ -21,6 +31,7 @@ /* I should make this use unaligned transfers etc.. */ static inline void __put_user(unsigned long x, void * y, int size) { + __gcc_barrier(); switch (size) { case 1: *(char *) y = x; @@ -37,84 +48,58 @@ default: bad_user_access_length(); } + __gcc_barrier(); } /* I should make this use unaligned transfers etc.. */ static inline unsigned long __get_user(const void * y, int size) { + unsigned long result; + + __gcc_barrier(); switch (size) { case 1: - return *(unsigned char *) y; + result = *(unsigned char *) y; + break; case 2: - return *(unsigned short *) y; + result = *(unsigned short *) y; + break; case 4: - return *(unsigned int *) y; + result = *(unsigned int *) y; + break; case 8: - return *(unsigned long *) y; + result = *(unsigned long *) y; + break; default: - return bad_user_access_length(); + result = bad_user_access_length(); } + __gcc_barrier(); + return result; } -static inline unsigned char get_user_byte(const char * addr) -{ - return *addr; -} - -#define get_fs_byte(addr) get_user_byte((char *)(addr)) - -static inline unsigned short get_user_word(const short *addr) -{ - return *addr; -} - -#define get_fs_word(addr) get_user_word((short *)(addr)) - -static inline unsigned long get_user_long(const int *addr) -{ - return *addr; -} - -#define get_fs_long(addr) get_user_long((int *)(addr)) - -static inline unsigned long get_user_quad(const long *addr) -{ - return *addr; -} +#define get_fs_byte(addr) get_user((unsigned char *)(addr)) +#define get_fs_word(addr) get_user((unsigned short *)(addr)) +#define get_fs_long(addr) get_user((unsigned int *)(addr)) +#define get_fs_quad(addr) get_user((unsigned long *)(addr)) -#define get_fs_quad(addr) get_user_quad((long *)(addr)) +#define put_fs_byte(x,addr) put_user((x),(char *)(addr)) +#define put_fs_word(x,addr) put_user((x),(short *)(addr)) +#define put_fs_long(x,addr) put_user((x),(int *)(addr)) +#define put_fs_quad(x,addr) put_user((x),(long *)(addr)) -static inline void put_user_byte(char val,char *addr) +static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) { - *addr = val; + __gcc_barrier(); + memcpy(to, from, n); + __gcc_barrier(); } -#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr)) - -static inline void put_user_word(short val,short * addr) +static inline void memcpy_tofs(void * to, const void * from, unsigned long n) { - *addr = val; + __gcc_barrier(); + memcpy(to, from, n); + __gcc_barrier(); } - -#define put_fs_word(x,addr) put_user_word((x),(short *)(addr)) - -static inline void put_user_long(unsigned long val,int * addr) -{ - *addr = val; -} - -#define put_fs_long(x,addr) put_user_long((x),(int *)(addr)) - -static inline void put_user_quad(unsigned long val,long * addr) -{ - *addr = val; -} - -#define put_fs_quad(x,addr) put_user_quad((x),(long *)(addr)) - -#define memcpy_fromfs(to, from, n) memcpy((to),(from),(n)) - -#define memcpy_tofs(to, from, n) memcpy((to),(from),(n)) /* * For segmented architectures, these are used to specify which segment diff -u --recursive --new-file v1.3.43/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h --- v1.3.43/linux/include/asm-alpha/system.h Mon Nov 13 12:36:46 1995 +++ linux/include/asm-alpha/system.h Sat Nov 25 11:54:56 1995 @@ -79,7 +79,7 @@ "bis %0,%0,$16\n\t" \ "call_pal 53" \ : : "r" (__new_ipl) \ - : "$0", "$1", "$16", "$22", "$23", "$24", "$25") + : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory") #define swpipl(__new_ipl) \ ({ unsigned long __old_ipl; \ @@ -89,7 +89,7 @@ "bis $0,$0,%0" \ : "=r" (__old_ipl) \ : "r" (__new_ipl) \ - : "$0", "$1", "$16", "$22", "$23", "$24", "$25"); \ + : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"); \ __old_ipl; }) #define cli() setipl(7) diff -u --recursive --new-file v1.3.43/linux/include/asm-i386/socket.h linux/include/asm-i386/socket.h --- v1.3.43/linux/include/asm-i386/socket.h Tue Jul 11 10:02:59 1995 +++ linux/include/asm-i386/socket.h Fri Nov 24 16:39:54 1995 @@ -25,6 +25,7 @@ #define SO_NO_CHECK 11 #define SO_PRIORITY 12 #define SO_LINGER 13 -/* To add :#define SO_REUSEPORT 14 */ +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ #endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v1.3.43/linux/include/asm-i386/unistd.h Tue Nov 21 13:22:13 1995 +++ linux/include/asm-i386/unistd.h Fri Nov 24 16:13:33 1995 @@ -152,6 +152,7 @@ #define __NR_msync 144 #define __NR_readv 145 #define __NR_writev 146 +#define __NR_getsid 147 #define __NR_mlock 150 #define __NR_munlock 151 diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/a.out.h linux/include/asm-sparc/a.out.h --- v1.3.43/linux/include/asm-sparc/a.out.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/a.out.h Sat Nov 25 04:31:10 1995 @@ -0,0 +1,50 @@ +/* $Id: a.out.h,v 1.8 1995/11/25 02:31:09 davem Exp $ */ +#ifndef __SPARC_A_OUT_H__ +#define __SPARC_A_OUT_H__ + +#define SPARC_PGSIZE 0x2000 /* Thanks to the sun4 architecture... */ +#define SEGMENT_SIZE SPARC_PGSIZE /* whee... */ + +struct exec { + unsigned char a_dynamic:1; /* A __DYNAMIC is in this image */ + unsigned char a_toolversion:7; + unsigned char a_machtype; + unsigned short a_info; + unsigned long a_text; /* length of text, in bytes */ + unsigned long a_data; /* length of data, in bytes */ + unsigned long a_bss; /* length of bss, in bytes */ + unsigned long a_syms; /* length of symbol table, in bytes */ + unsigned long a_entry; /* where program begins */ + unsigned long a_trsize; + unsigned long a_drsize; +}; + +/* Where in the file does the text information begin? */ +#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? 0 : sizeof (struct exec)) + +/* Where do the Symbols start? */ +#define N_SYMOFF(x) (N_TXTOFF(x) + (x).a_text + \ + (x).a_data + (x).a_trsize + \ + (x).a_drsize) + +/* Where does text segment go in memory after being loaded? */ +#define N_TXTADDR(x) (((N_MAGIC(x) == ZMAGIC) && \ + ((x).a_entry < SPARC_PGSIZE)) ? \ + 0 : SPARC_PGSIZE) + +/* And same for the data segment.. */ +#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ? \ + (N_TXTADDR(x) + (x).a_text) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#ifdef __KERNEL__ + +#define STACK_TOP TASK_SIZE + +#endif + +#endif /* __SPARC_A_OUT_H__ */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/asi.h linux/include/asm-sparc/asi.h --- v1.3.43/linux/include/asm-sparc/asi.h Wed Nov 8 07:11:41 1995 +++ linux/include/asm-sparc/asi.h Sat Nov 25 04:31:12 1995 @@ -1,3 +1,4 @@ +/* $Id: asi.h,v 1.11 1995/11/25 02:31:11 davem Exp $ */ #ifndef _SPARC_ASI_H #define _SPARC_ASI_H @@ -9,39 +10,29 @@ * Joint edition for sun4c+sun4m: Pete A. Zaitcev */ -/* These are sun4c, beware on other architectures. Although things should - * be similar under regular sun4's. - */ +/* The first batch are for the sun4c. */ -#define ASI_NULL1 0x0 -#define ASI_NULL2 0x1 +#define ASI_NULL1 0x00 +#define ASI_NULL2 0x01 /* sun4c and sun4 control registers and mmu/vac ops */ -#define ASI_CONTROL 0x2 -#define ASI_SEGMAP 0x3 -#define ASI_PTE 0x4 -#define ASI_HWFLUSHSEG 0x5 /* These are to initiate hw flushes of the cache */ -#define ASI_HWFLUSHPAGE 0x6 -#define ASI_REGMAP 0x6 /* Top level segmaps on Sun4's with MUTANT MMU */ -#define ASI_HWFLUSHCONTEXT 0x7 - - -#define ASI_USERTXT 0x8 -#define ASI_KERNELTXT 0x9 -#define ASI_USERDATA 0xa -#define ASI_KERNELDATA 0xb +#define ASI_CONTROL 0x02 +#define ASI_SEGMAP 0x03 +#define ASI_PTE 0x04 +#define ASI_HWFLUSHSEG 0x05 +#define ASI_HWFLUSHPAGE 0x06 +#define ASI_REGMAP 0x06 +#define ASI_HWFLUSHCONTEXT 0x07 + +#define ASI_USERTXT 0x08 +#define ASI_KERNELTXT 0x09 +#define ASI_USERDATA 0x0a +#define ASI_KERNELDATA 0x0b /* VAC Cache flushing on sun4c and sun4 */ - -#define ASI_FLUSHSEG 0xc /* These are for "software" flushes of the cache */ -#define ASI_FLUSHPG 0xd -#define ASI_FLUSHCTX 0xe - -/* The following are now not so SS5 specific any more, it is pretty - * much a complete generic sun4m/V8 ASI assignment listing now. - * - * -- davem@caip.rutgers.edu - */ +#define ASI_FLUSHSEG 0x0c +#define ASI_FLUSHPG 0x0d +#define ASI_FLUSHCTX 0x0e /* SPARCstation-5: only 6 bits are decoded. */ /* wo = Write Only, rw = Read Write; */ @@ -64,8 +55,8 @@ #define ASI_M_DATAC_DATA 0x0F /* Data Cache Data; rw, ss */ /* The following cache flushing ASIs work only with the 'sta' - * instruction results are unpredictable for 'swap' and 'ldstuba' etc. - * So don't do it. + * instruction. Results are unpredictable for 'swap' and 'ldstuba', + * so don't do it. */ /* These ASI flushes affect external caches too. */ @@ -75,7 +66,7 @@ #define ASI_M_FLUSH_CTX 0x13 /* Flush I&D Cache Line (context); wo, ss */ #define ASI_M_FLUSH_USER 0x14 /* Flush I&D Cache Line (user); wo, ss */ -/* Block-copy operations are available on certain V8 cpus */ +/* Block-copy operations are available only on certain V8 cpus. */ #define ASI_M_BCOPY 0x17 /* Block copy */ /* These affect only the ICACHE and are Ross HyperSparc specific. */ @@ -108,7 +99,7 @@ #define ASI_M_DCDR 0x39 /* Data Cache Diagnostics Registerl rw, ss */ -/* Sparc V9 TI UltraSparc ASI's */ +/* Sparc V9 TI UltraSparc ASI's (V8 ploos ploos) */ /* ASIs 0x0-0x7f are Supervisor Only. 0x80-0xff are for anyone. */ @@ -126,9 +117,9 @@ #define ASI_V9_USER_SEC 0x11 /* User secondary address space */ #define ASI_V9_MMUPASS 0x14 /* OBMEM (external cache, no data cache) */ -#define ASI_V9_IOPASS 0x15 /* Like MMUPASS but for I/O areas (uncached) */ -#define ASI_V9_USER_PRIML 0x18 /* User primary address space, little-endian. */ -#define ASI_V9_USER_SECL 0x19 /* User secondary address space, little-endian. */ +#define ASI_V9_IOPASS 0x15 /* Like MMUPASS, for I/O areas (uncached) */ +#define ASI_V9_USER_PRIML 0x18 /* User primary addr space, lil-endian. */ +#define ASI_V9_USER_SECL 0x19 /* User secondary addr space, lil-endian. */ #define ASI_V9_MMUPASSL 0x1C /* OBMEM little-endian */ #define ASI_V9_IOPASSL 0x1D /* Like IOPASS but little-endian */ #define ASI_V9_ATOMICQ 0x24 /* Atomic 128-bit load address space */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/asi4m.h linux/include/asm-sparc/asi4m.h --- v1.3.43/linux/include/asm-sparc/asi4m.h Sun Feb 26 20:46:20 1995 +++ linux/include/asm-sparc/asi4m.h Thu Jan 1 02:00:00 1970 @@ -1,29 +0,0 @@ -#ifndef _SPARC_ASI4M_H -#define _SPARC_ASI4M_H - -/* asi4m.h: Address Space Identifier values for sun4m - - Copyright (C) 1995 Paul Hatchman (paul@sfe.com.au) -*/ - -#define ASI_PTE 0x0 - -#define ASI_NULL1 0x0 -#define ASI_NULL2 0x1 -#define ASI_CONTROL 0x4 /* hmm? */ -#define ASI_USERTXT 0x8 /* user text */ -#define ASI_KERNELTXT 0x9 /* kernel text */ -#define ASI_USERDATA 0xA /* user data */ -#define ASI_KERNELDATA 0xB /* kernel data */ - -/* cache flushing */ -#define ASI_FLUSHPG 0x10 -#define ASI_FLUSHSEG 0x11 -#define ASI_FLUSHRGN 0x12 -#define ASI_FLUSHCTX 0x13 - -/* MMU REGS */ -#define SRMMU_CTL 0x000 -#define SRMMU_CTP 0x100 /* set/get context pointer */ -#define SRMMU_CTX 0x200 /* get/set context */ -#endif _SPARC_ASI4M_H diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h --- v1.3.43/linux/include/asm-sparc/auxio.h Tue Jun 27 14:11:44 1995 +++ linux/include/asm-sparc/auxio.h Sat Nov 25 04:31:14 1995 @@ -1,35 +1,69 @@ -/* auxio.h: Definitons and code for the Auxiliary I/O register. +/* $Id: auxio.h,v 1.8 1995/11/25 02:31:13 davem Exp $ + * auxio.h: Definitons and code for the Auxiliary I/O register. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ #ifndef _SPARC_AUXIO_H #define _SPARC_AUXIO_H -/* This defines the register as I know it on the Sun4c, it may be - * different or not exist at all on sun4m's. - */ - -#define AUXIO_IOADDR 0xf7400000 /* Physical address is IO space */ +#include +#include /* This register is an unsigned char in IO space. It does two things. * First, it is used to control the front panel LED light on machines * that have it (good for testing entry points to trap handlers and irq's) - * Secondly, it controls various floppy drive parameters on machines that - * have a drive. + * Secondly, it controls various floppy drive parameters. */ #define AUXIO_ORMEIN 0xf0 /* All writes must set these bits. */ -#define AUXIO_FLPY_DENS 0x20 /* Floppy density, high if set. */ -#define AUXIO_FLPY_DCHG 0x10 /* A disk change occurred. */ -#define AUXIO_FLPY_DSEL 0x08 /* Drive select, 0 'a drive' 1 'b drive'. */ -#define AUXIO_FLPY_TCNT 0x04 /* Floppy terminal count... ??? */ -#define AUXIO_FLPY_EJCT 0x02 /* Eject floppy disk. */ -#define AUXIO_LED 0x01 /* On if set, off if unset. */ - -#define AUXREG ((volatile unsigned char *)(AUXIO_VADDR + 3)) - -#define TURN_ON_LED *AUXREG = AUXIO_ORMEIN | AUXIO_FLPY_EJCT | AUXIO_LED -#define TURN_OFF_LED *AUXREG = AUXIO_ORMEIN | AUXIO_FLPY_EJCT -#define FLIP_LED *AUXREG = (*AUXREG | AUXIO_ORMEIN) ^ AUXIO_LED +#define AUXIO_ORMEIN4M 0xc0 /* sun4m - All writes must set these bits. */ +#define AUXIO_FLPY_DENS 0x20 /* Floppy density, high if set. Read only. */ +#define AUXIO_FLPY_DCHG 0x10 /* A disk change occurred. Read only. */ +#define AUXIO_EDGE_ON 0x10 /* sun4m - On means Jumper block is in. */ +#define AUXIO_FLPY_DSEL 0x08 /* Drive select/start-motor. Write only. */ + +/* Set the following to one, then zero, after doing a pseudo DMA transfer. */ +#define AUXIO_FLPY_TCNT 0x04 /* Floppy terminal count. Write only. */ + +/* Set the following to zero to eject the floppy. */ +#define AUXIO_FLPY_EJCT 0x02 /* Eject floppy disk. Write only. */ +#define AUXIO_LED 0x01 /* On if set, off if unset. Read/Write */ + +#define AUXREG ((volatile unsigned char *)(AUXIO_VADDR + 3)) +#define AUXREG4M ((volatile unsigned char *)(AUXIO_VADDR)) + +#define TURN_ON_LED *AUXREG = (*AUXREG | AUXIO_ORMEIN | AUXIO_LED) +#define TURN_OFF_LED *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_LED)) +#define FLIP_LED *AUXREG = ((*AUXREG | AUXIO_ORMEIN) ^ AUXIO_LED) +#define FLPY_MOTORON *AUXREG = ((*AUXREG | AUXIO_ORMEIN) | AUXIO_FLPY_DSEL) +#define FLPY_MOTOROFF *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_FLPY_DSEL)) +#define FLPY_TCNTON *AUXREG = ((*AUXREG | AUXIO_ORMEIN) | AUXIO_FLPY_TCNT) +#define FLPY_TCNTOFF *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_FLPY_TCNT)) + +#ifndef __ASSEMBLY__ +extern inline void set_auxio(unsigned char bits_on, unsigned char bits_off) +{ + unsigned char regval; + + cli(); + + switch(sparc_cpu_model) { + case sun4c: + regval = *AUXREG; + *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN; + break; + case sun4m: + regval = *AUXREG4M; + *AUXREG4M = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M; + break; + default: + panic("Can't set AUXIO register on this machine."); + }; + + sti(); + + return; +} +#endif /* !(__ASSEMBLY__) */ #endif /* !(_SPARC_AUXIO_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v1.3.43/linux/include/asm-sparc/bitops.h Tue Aug 15 20:39:04 1995 +++ linux/include/asm-sparc/bitops.h Sat Nov 25 04:31:16 1995 @@ -1,13 +1,17 @@ +/* $Id: bitops.h,v 1.17 1995/11/25 02:31:15 davem Exp $ + * bitops.h: Bit string operations on the Sparc. + * + * Copyright 1995, David S. Miller (davem@caip.rutgers.edu). + */ + #ifndef _SPARC_BITOPS_H #define _SPARC_BITOPS_H #include -#include - -/* - * Copyright 1995, David S. Miller (davem@caip.rutgers.edu). - */ +#ifdef __KERNEL__ +#include +#endif /* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' * is in the highest of the four bytes and bit '31' is the high bit @@ -15,264 +19,67 @@ * all bit-ops return 0 if bit was previously clear and != 0 otherwise. */ -/* For now, the sun4c implementation will disable and enable traps - * in order to insure atomicity. Things will have to be different - * for sun4m (ie. SMP) no doubt. - */ - -/* These routines now do things in little endian byte order. */ - -/* Our unsigned long accesses on the Sparc look like this: - * Big Endian: - * byte 0 byte 1 byte 2 byte 3 - * 0000 0000 0000 0000 0000 0000 0000 0000 - * 31 24 23 16 15 8 7 0 - * - * We want to set the bits in a little-endian fashion: - * Little Endian: - * byte 3 byte 2 byte 1 byte 0 - * 0000 0000 0000 0000 0000 0000 0000 0000 - * 31 24 23 16 15 8 7 0 - */ - -/* #define __LITTLE_ENDIAN_BITOPS */ - -extern __inline__ unsigned int set_bit(unsigned int nr, void *vaddr) +extern __inline__ unsigned long set_bit(unsigned long nr, void *addr) { + int mask, flags; + unsigned long *ADDR = (unsigned long *) addr; + unsigned long oldbit; - -#ifdef __LITTLE_ENDIAN_BITOPS - - - int retval; - unsigned char *addr = (unsigned char *)vaddr; - unsigned char mask; -#ifndef TEST_BITOPS - unsigned long flags; -#endif - - addr += nr >> 3; - mask = 1 << (nr & 0x7); - -#ifndef TEST_BITOPS - save_flags(flags); - cli(); -#endif - - retval = (mask & *addr) != 0; - *addr |= mask; - -#ifndef TEST_BITOPS - restore_flags(flags); -#endif - - return retval; - -#else /* BIG ENDIAN BITOPS */ - - - int retval; - unsigned long *addr = vaddr; - unsigned long mask; -#ifndef TEST_BITOPS - unsigned long flags; -#endif - - addr += nr>>5; - mask = 1 << (nr&31); - -#ifndef TEST_BITOPS - save_flags(flags); - cli(); -#endif - - retval = (mask & *addr) != 0; - *addr |= mask; - -#ifndef TEST_BITOPS + ADDR += nr >> 5; + mask = 1 << (nr & 31); + save_flags(flags); cli(); + oldbit = (mask & *ADDR); + *ADDR |= mask; restore_flags(flags); -#endif - - return retval; - - -#endif + return oldbit != 0; } -extern __inline__ unsigned int clear_bit(unsigned int nr, void *vaddr) +extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr) { -#ifdef __LITTLE_ENDIAN_BITOPS - - - int retval; - unsigned char *addr = (unsigned char *)vaddr; - unsigned char mask; -#ifndef TEST_BITOPS - unsigned long flags; -#endif - - addr += nr >> 3; - mask = 1 << (nr & 7); - -#ifndef TEST_BITOPS - save_flags(flags); - cli(); -#endif + int mask, flags; + unsigned long *ADDR = (unsigned long *) addr; + unsigned long oldbit; - retval = (mask & *addr) != 0; - *addr &= ~mask; - -#ifndef TEST_BITOPS + ADDR += nr >> 5; + mask = 1 << (nr & 31); + save_flags(flags); cli(); + oldbit = (mask & *ADDR); + *ADDR &= ~mask; restore_flags(flags); -#endif - - return retval; - - -#else /* BIG ENDIAN BITOPS */ - - - int retval; - unsigned long *addr = vaddr; - unsigned long mask; -#ifndef TEST_BITOPS - unsigned long flags; -#endif - - addr += nr>>5; - mask = 1 << (nr&31); - -#ifndef TEST_BITOPS - save_flags(flags); - cli(); -#endif - - retval = (mask & *addr) != 0; - *addr &= ~mask; - -#ifndef TEST_BITOPS - restore_flags(flags); -#endif - - return retval; - - -#endif + return oldbit != 0; } -extern __inline__ unsigned int change_bit(unsigned int nr, void *vaddr) +extern __inline__ unsigned long change_bit(unsigned long nr, void *addr) { -#ifdef __LITTLE_ENDIAN_BITOPS - - - int retval; - unsigned char *addr = (unsigned char *)vaddr; - unsigned char mask; -#ifndef TEST_BITOPS - unsigned long flags; -#endif - - addr += nr >> 3; - mask = 1 << (nr & 7); - -#ifndef TEST_BITOPS - save_flags(flags); - cli(); -#endif - - retval = (mask & *addr) != 0; - *addr ^= mask; - -#ifndef TEST_BITOPS - restore_flags(flags); -#endif - - return retval; - - -#else /* BIG ENDIAN BITOPS */ - - - int retval; - unsigned long *addr = vaddr; - unsigned long mask; -#ifndef TEST_BITOPS - unsigned long flags; -#endif - - addr += nr>>5; - mask = 1 << (nr&31); - -#ifndef TEST_BITOPS - save_flags(flags); - cli(); -#endif + int mask, flags; + unsigned long *ADDR = (unsigned long *) addr; + unsigned long oldbit; - retval = (mask & *addr) != 0; - *addr ^= mask; - -#ifndef TEST_BITOPS + ADDR += nr >> 5; + mask = 1 << (nr & 31); + save_flags(flags); cli(); + oldbit = (mask & *ADDR); + *ADDR ^= mask; restore_flags(flags); -#endif - - return retval; - - -#endif + return oldbit != 0; } /* The following routine need not be atomic. */ - -extern __inline__ unsigned int test_bit(int nr, void *vaddr) +extern __inline__ unsigned long test_bit(int nr, const void *addr) { -#ifdef __LITTLE_ENDIAN_BITOPS - - unsigned char mask; - unsigned char *addr = (unsigned char *)vaddr; - - addr += nr >> 3; - mask = 1 << (nr & 7); - return ((mask & *addr) != 0); - -#else /* BIG ENDIAN BITOPS */ - - unsigned long mask; - unsigned long *addr = vaddr; - - addr += (nr>>5); - mask = 1 << (nr&31); - return ((mask & *addr) != 0); - -#endif + return 1UL & (((int *) addr)[nr >> 5] >> (nr & 31)); } -/* There has to be a faster way to do this, sigh... */ - +/* The easy/cheese version for now. */ extern __inline__ unsigned long ffz(unsigned long word) { - register unsigned long cnt; - - cnt = 0; - -#ifdef __LITTLE_ENDIAN_BITOPS - - for(int byte_bit = 24; byte_bit >=0; byte_bit -= 8) - for(int bit = 0; bit<8; bit++) - if((word>>(byte_bit+bit))&1) - cnt++; - else - return cnt; - -#else /* BIT ENDIAN BITOPS */ - while(cnt<32) { - if(!((word>>cnt)&1)) - return cnt; - else - cnt++; - } - return cnt; -#endif + unsigned long result = 0; + while(word & 1) { + result++; + word >>= 1; + } + return result; } /* find_next_zero_bit() finds the first zero bit in a bit string of length @@ -280,15 +87,9 @@ * on Linus's ALPHA routines, which are pretty portable BTW. */ -extern __inline__ unsigned long -find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { -#ifdef __LITTLE_ENDIAN_BITOPS - - /* FOO, needs to be written */ - -#else /* BIG ENDIAN BITOPS */ - unsigned long *p = ((unsigned long *) addr) + (offset >> 6); + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; unsigned long tmp; @@ -296,10 +97,9 @@ return size; size -= result; offset &= 31UL; - if (offset) - { + if (offset) { tmp = *(p++); - tmp |= ~0UL >> (32-offset); + tmp |= ~0UL << (32-offset); if (size < 32) goto found_first; if (~tmp) @@ -307,8 +107,7 @@ size -= 32; result += 32; } - while (size & ~32UL) - { + while (size & ~31UL) { if (~(tmp = *(p++))) goto found_middle; result += 32; @@ -319,10 +118,9 @@ tmp = *p; found_first: - tmp |= ~0UL << size; + tmp |= ~0UL >> size; found_middle: return result + ffz(tmp); -#endif } /* Linus sez that gcc can optimize the following correctly, we'll see if this @@ -332,6 +130,85 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) +/* Now for the ext2 filesystem bit operations and helper routines. */ + +extern __inline__ int ext2_set_bit(int nr,void * addr) +{ + int mask, retval, flags; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + save_flags(flags); cli(); + retval = (mask & *ADDR) != 0; + *ADDR |= mask; + restore_flags(flags); + return retval; +} + +extern __inline__ int ext2_clear_bit(int nr, void * addr) +{ + int mask, retval, flags; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + save_flags(flags); cli(); + retval = (mask & *ADDR) != 0; + *ADDR &= ~mask; + restore_flags(flags); + return retval; +} + +extern __inline__ int ext2_test_bit(int nr, const void * addr) +{ + int mask; + const unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return ((mask & *ADDR) != 0); +} + +#define ext2_find_first_zero_bit(addr, size) \ + ext2_find_next_zero_bit((addr), (size), 0) + +extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if(offset) { + tmp = *(p++); + tmp |= ~0UL << (32-offset); + if(size < 32) + goto found_first; + if(~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while(size & ~31UL) { + if(~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if(!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; +found_middle: + tmp = ((tmp>>24) | ((tmp>>8)&0xff00) | ((tmp<<8)&0xff0000) | (tmp<<24)); + return result + ffz(tmp); +} #endif /* defined(_SPARC_BITOPS_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/bsderrno.h linux/include/asm-sparc/bsderrno.h --- v1.3.43/linux/include/asm-sparc/bsderrno.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/bsderrno.h Sat Nov 25 04:31:17 1995 @@ -0,0 +1,94 @@ +/* $Id: bsderrno.h,v 1.2 1995/11/25 02:31:17 davem Exp $ + * bsderrno.h: Error numbers for NetBSD binary compatability + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_BSDERRNO_H +#define _SPARC_BSDERRNO_H + +#define BSD_EPERM 1 /* Operation not permitted */ +#define BSD_ENOENT 2 /* No such file or directory */ +#define BSD_ESRCH 3 /* No such process */ +#define BSD_EINTR 4 /* Interrupted system call */ +#define BSD_EIO 5 /* Input/output error */ +#define BSD_ENXIO 6 /* Device not configured */ +#define BSD_E2BIG 7 /* Argument list too long */ +#define BSD_ENOEXEC 8 /* Exec format error */ +#define BSD_EBADF 9 /* Bad file descriptor */ +#define BSD_ECHILD 10 /* No child processes */ +#define BSD_EDEADLK 11 /* Resource deadlock avoided */ +#define BSD_ENOMEM 12 /* Cannot allocate memory */ +#define BSD_EACCES 13 /* Permission denied */ +#define BSD_EFAULT 14 /* Bad address */ +#define BSD_ENOTBLK 15 /* Block device required */ +#define BSD_EBUSY 16 /* Device busy */ +#define BSD_EEXIST 17 /* File exists */ +#define BSD_EXDEV 18 /* Cross-device link */ +#define BSD_ENODEV 19 /* Operation not supported by device */ +#define BSD_ENOTDIR 20 /* Not a directory */ +#define BSD_EISDIR 21 /* Is a directory */ +#define BSD_EINVAL 22 /* Invalid argument */ +#define BSD_ENFILE 23 /* Too many open files in system */ +#define BSD_EMFILE 24 /* Too many open files */ +#define BSD_ENOTTY 25 /* Inappropriate ioctl for device */ +#define BSD_ETXTBSY 26 /* Text file busy */ +#define BSD_EFBIG 27 /* File too large */ +#define BSD_ENOSPC 28 /* No space left on device */ +#define BSD_ESPIPE 29 /* Illegal seek */ +#define BSD_EROFS 30 /* Read-only file system */ +#define BSD_EMLINK 31 /* Too many links */ +#define BSD_EPIPE 32 /* Broken pipe */ +#define BSD_EDOM 33 /* Numerical argument out of domain */ +#define BSD_ERANGE 34 /* Result too large */ +#define BSD_EAGAIN 35 /* Resource temporarily unavailable */ +#define BSD_EWOULDBLOCK EAGAIN /* Operation would block */ +#define BSD_EINPROGRESS 36 /* Operation now in progress */ +#define BSD_EALREADY 37 /* Operation already in progress */ +#define BSD_ENOTSOCK 38 /* Socket operation on non-socket */ +#define BSD_EDESTADDRREQ 39 /* Destination address required */ +#define BSD_EMSGSIZE 40 /* Message too long */ +#define BSD_EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define BSD_ENOPROTOOPT 42 /* Protocol not available */ +#define BSD_EPROTONOSUPPORT 43 /* Protocol not supported */ +#define BSD_ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define BSD_EOPNOTSUPP 45 /* Operation not supported */ +#define BSD_EPFNOSUPPORT 46 /* Protocol family not supported */ +#define BSD_EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define BSD_EADDRINUSE 48 /* Address already in use */ +#define BSD_EADDRNOTAVAIL 49 /* Can't assign requested address */ +#define BSD_ENETDOWN 50 /* Network is down */ +#define BSD_ENETUNREACH 51 /* Network is unreachable */ +#define BSD_ENETRESET 52 /* Network dropped connection on reset */ +#define BSD_ECONNABORTED 53 /* Software caused connection abort */ +#define BSD_ECONNRESET 54 /* Connection reset by peer */ +#define BSD_ENOBUFS 55 /* No buffer space available */ +#define BSD_EISCONN 56 /* Socket is already connected */ +#define BSD_ENOTCONN 57 /* Socket is not connected */ +#define BSD_ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define BSD_ETOOMANYREFS 59 /* Too many references: can't splice */ +#define BSD_ETIMEDOUT 60 /* Operation timed out */ +#define BSD_ECONNREFUSED 61 /* Connection refused */ +#define BSD_ELOOP 62 /* Too many levels of symbolic links */ +#define BSD_ENAMETOOLONG 63 /* File name too long */ +#define BSD_EHOSTDOWN 64 /* Host is down */ +#define BSD_EHOSTUNREACH 65 /* No route to host */ +#define BSD_ENOTEMPTY 66 /* Directory not empty */ +#define BSD_EPROCLIM 67 /* Too many processes */ +#define BSD_EUSERS 68 /* Too many users */ +#define BSD_EDQUOT 69 /* Disc quota exceeded */ +#define BSD_ESTALE 70 /* Stale NFS file handle */ +#define BSD_EREMOTE 71 /* Too many levels of remote in path */ +#define BSD_EBADRPC 72 /* RPC struct is bad */ +#define BSD_ERPCMISMATCH 73 /* RPC version wrong */ +#define BSD_EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define BSD_EPROGMISMATCH 75 /* Program version wrong */ +#define BSD_EPROCUNAVAIL 76 /* Bad procedure for program */ +#define BSD_ENOLCK 77 /* No locks available */ +#define BSD_ENOSYS 78 /* Function not implemented */ +#define BSD_EFTYPE 79 /* Inappropriate file type or format */ +#define BSD_EAUTH 80 /* Authentication error */ +#define BSD_ENEEDAUTH 81 /* Need authenticator */ +#define BSD_ELAST 81 /* Must be equal largest errno */ + +#endif /* !(_SPARC_BSDERRNO_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/bugs.h linux/include/asm-sparc/bugs.h --- v1.3.43/linux/include/asm-sparc/bugs.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/bugs.h Sat Nov 25 04:31:19 1995 @@ -1,49 +1,7 @@ -/* include/asm-sparc/bugs.h: Sparc probes for various bugs. +/* $Id: bugs.h,v 1.5 1995/11/25 02:31:18 davem Exp $ + * include/asm-sparc/bugs.h: Sparc probes for various bugs. * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) */ -/* - * This is included by init/main.c to check for architecture-dependent bugs. - * - * Needs: - * void check_bugs(void); - */ - -#define CONFIG_BUGSPARC - -#include -#include - -extern pgd_t swapper_pg_dir[16384]; - -static void check_mmu(void) -{ - register struct linux_romvec *lvec; - register int root_node; - unsigned int present; - - lvec = romvec; - - root_node = (*(romvec->pv_nodeops->no_nextnode))(0); - - present = 0; - (*(romvec->pv_nodeops->no_getprop))(root_node, "buserr-type", - (char *) &present); - if(present == 1) - { - printk("MMU bug found: uncaching trap table\n"); - for(present = (unsigned long) &trapbase; present < (unsigned long) - &swapper_pg_dir; present+=PAGE_SIZE) - put_pte(present, (get_pte(present) | PTE_NC)); - } - - return; -} - - -static void -check_bugs(void) -{ - check_mmu(); -} +static void check_bugs(void) { } diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h --- v1.3.43/linux/include/asm-sparc/byteorder.h Tue Aug 15 20:39:04 1995 +++ linux/include/asm-sparc/byteorder.h Sat Nov 25 04:31:21 1995 @@ -1,85 +1,15 @@ +/* $Id: byteorder.h,v 1.6 1995/11/25 02:31:20 davem Exp $ */ #ifndef _SPARC_BYTEORDER_H #define _SPARC_BYTEORDER_H -#undef ntohl -#undef ntohs -#undef htonl -#undef htons +#define ntohl(x) x +#define ntohs(x) x +#define htonl(x) x +#define htons(x) x +#ifdef __KERNEL__ #define __BIG_ENDIAN -#define __BIG_ENDIAN_BITFIELD - -extern unsigned long int ntohl(unsigned long int); -extern unsigned short int ntohs(unsigned short int); -extern unsigned long int htonl(unsigned long int); -extern unsigned short int htons(unsigned short int); - -extern unsigned long int __ntohl(unsigned long int); -extern unsigned short int __ntohs(unsigned short int); -extern unsigned long int __constant_ntohl(unsigned long int); -extern unsigned short int __constant_ntohs(unsigned short int); - -/* - * The constant and non-constant versions here are the same. - * Maybe I'll come up with an alpha-optimized routine for the - * non-constant ones (the constant ones don't need it: gcc - * will optimize it to the correct constant) - */ - -extern __inline__ unsigned long int -__ntohl(unsigned long int x) -{ - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); -} - -extern __inline__ unsigned long int -__constant_ntohl(unsigned long int x) -{ - return (((x & 0x000000ffU) << 24) | - ((x & 0x0000ff00U) << 8) | - ((x & 0x00ff0000U) >> 8) | - ((x & 0xff000000U) >> 24)); -} - -extern __inline__ unsigned short int -__ntohs(unsigned short int x) -{ - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); -} - -extern __inline__ unsigned short int -__constant_ntohs(unsigned short int x) -{ - return (((x & 0x00ff) << 8) | - ((x & 0xff00) >> 8)); -} - -#define __htonl(x) __ntohl(x) -#define __htons(x) __ntohs(x) -#define __constant_htonl(x) __constant_ntohl(x) -#define __constant_htons(x) __constant_ntohs(x) - -#ifdef __OPTIMIZE__ -# define ntohl(x) \ -(__builtin_constant_p((long)(x)) ? \ - __constant_ntohl((x)) : \ - __ntohl((x))) -# define ntohs(x) \ -(__builtin_constant_p((short)(x)) ? \ - __constant_ntohs((x)) : \ - __ntohs((x))) -# define htonl(x) \ -(__builtin_constant_p((long)(x)) ? \ - __constant_htonl((x)) : \ - __htonl((x))) -# define htons(x) \ -(__builtin_constant_p((short)(x)) ? \ - __constant_htons((x)) : \ - __htons((x))) #endif +#define __BIG_ENDIAN_BITFIELD #endif /* !(_SPARC_BYTEORDER_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/cache.h linux/include/asm-sparc/cache.h --- v1.3.43/linux/include/asm-sparc/cache.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/cache.h Sat Nov 25 04:31:23 1995 @@ -1,4 +1,5 @@ -/* cache.h: Cache specific code for the Sparc. These include flushing +/* $Id: cache.h,v 1.3 1995/11/25 02:31:22 davem Exp $ + * cache.h: Cache specific code for the Sparc. These include flushing * and direct tag/data line access. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -38,7 +39,6 @@ __asm__ __volatile__("sta %0, [%1] %2\n\t" : : "r" (entry), "r" (vaddr), "i" (ASI_M_TXTC_TAG) : "memory"); - return; } /* Second cache-data access. The data is returned two-32bit quantities @@ -49,7 +49,8 @@ { unsigned int value1, value2, vaddr; - vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | ((subblock&0x3) << 3); + vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | + ((subblock&0x3) << 3); __asm__ __volatile__("ldda [%2] %3, %%g2\n\t" "or %%g0, %%g2, %0\n\t" "or %%g0, %%g3, %1\n\t" : @@ -57,7 +58,6 @@ "r" (vaddr), "i" (ASI_M_TXTC_DATA) : "g2", "g3"); data[0] = value1; data[1] = value2; - return; } extern inline void put_icache_data(int setnum, int tagnum, int subblock, @@ -65,7 +65,8 @@ { unsigned int value1, value2, vaddr; - vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | ((subblock&0x3) << 3); + vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | + ((subblock&0x3) << 3); value1 = data[0]; value2 = data[1]; __asm__ __volatile__("or %%g0, %0, %%g2\n\t" "or %%g0, %1, %%g3\n\t" @@ -73,7 +74,6 @@ "r" (value1), "r" (value2), "r" (vaddr), "i" (ASI_M_TXTC_DATA) : "g2", "g3", "memory" /* no joke */); - return; } /* Different types of flushes with the ICACHE. Some of the flushes @@ -90,7 +90,6 @@ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r" (addr), "i" (ASI_M_FLUSH_PAGE) : "memory"); - return; } extern inline void flush_ei_seg(unsigned int addr) @@ -98,7 +97,6 @@ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r" (addr), "i" (ASI_M_FLUSH_SEG) : "memory"); - return; } extern inline void flush_ei_region(unsigned int addr) @@ -106,7 +104,6 @@ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r" (addr), "i" (ASI_M_FLUSH_REGION) : "memory"); - return; } extern inline void flush_ei_ctx(unsigned int addr) @@ -114,7 +111,6 @@ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r" (addr), "i" (ASI_M_FLUSH_CTX) : "memory"); - return; } extern inline void flush_ei_user(unsigned int addr) @@ -122,7 +118,6 @@ __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : "r" (addr), "i" (ASI_M_FLUSH_USER) : "memory"); - return; } #endif /* !(_SPARC_CACHE_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/checksum.h linux/include/asm-sparc/checksum.h --- v1.3.43/linux/include/asm-sparc/checksum.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/checksum.h Sat Nov 25 04:31:24 1995 @@ -0,0 +1,162 @@ +/* $Id: checksum.h,v 1.10 1995/11/25 02:31:23 davem Exp $ */ +#ifndef __SPARC_CHECKSUM_H +#define __SPARC_CHECKSUM_H + +/* checksum.h: IP/UDP/TCP checksum routines on the Sparc. + * + * Copyright(C) 1995 Linus Torvalds + * Copyright(C) 1995 Miguel de Icaza + */ + + +/* 32 bits version of the checksum routines written for the Alpha by Linus */ +extern inline unsigned short from32to16(unsigned long x) +{ + /* add up 16-bit and 17-bit words for 17+c bits */ + x = (x & 0xffff) + (x >> 16); + /* add up 16-bit and 2-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +extern inline unsigned long +do_csum(unsigned char * buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff << 8; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 4; + len -= 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += (*buff) << 8; + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +extern inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + return ~do_csum(iph,ihl*4); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +extern inline unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum) +{ + unsigned long result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + /* 32+c bits -> 32 bits */ + result = (result & 0xffff) + (result >> 16); + return result; +} + +/* + * the same as csum_partial, but copies from fs:src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +extern inline unsigned int csum_partial_copy(char *src, char *dst, int len, int sum) +{ + /* + * The whole idea is to do the copy and the checksum at + * the same time, but we do it the easy way now. + * + * At least csum on the source, not destination, for cache + * reasons.. + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + return sum; +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return ~from32to16(do_csum(buff,len)); +} + +#define csum_partial_copy_fromuser(s, d, l, w) \ + csum_partial_copy((char *) (s), (d), (l), (w)) + +/* + * Fold a partial checksum without adding pseudo headers + */ + +static inline unsigned short csum_fold(unsigned int sum) +{ + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + return ~sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return ~from32to16 (((saddr >> 16) + (saddr & 0xffff) + (daddr >> 16) + + (daddr & 0xffff) + (sum >> 16) + + (sum & 0xffff) + proto + len)); +} + +#endif /* !(__SPARC_CHECKSUM_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/clock.h linux/include/asm-sparc/clock.h --- v1.3.43/linux/include/asm-sparc/clock.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/clock.h Sat Nov 25 04:31:26 1995 @@ -1,4 +1,5 @@ -/* clock.h: Definitions for clock operations on the Sparc. +/* $Id: clock.h,v 1.3 1995/11/25 02:31:25 davem Exp $ + * clock.h: Definitions for clock operations on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/contregs.h linux/include/asm-sparc/contregs.h --- v1.3.43/linux/include/asm-sparc/contregs.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/contregs.h Sat Nov 25 04:31:28 1995 @@ -1,3 +1,4 @@ +/* $Id: contregs.h,v 1.6 1995/11/25 02:31:27 davem Exp $ */ #ifndef _SPARC_CONTREGS_H #define _SPARC_CONTREGS_H @@ -7,43 +8,43 @@ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -/* 4 = sun4 (as in sun4 sysmaint student book), c = sun4c (according to davem) */ +/* 4=sun4 (as in sun4 sysmaint student book), c=sun4c (according to davem) */ -#define AC_IDPROM 0x00000000 /* 4 ID PROM, R/O, byte, 32 bytes */ -#define AC_CONTEXT 0x30000000 /* 4c current mmu-context, handy for invalidate()'s ;-) */ -#define AC_SENABLE 0x40000000 /* 4c system dvma/cache enable, plus special reset poking */ -#define AC_UDVMA_ENB 0x50000000 /* 4 Not used on Sun boards, byte */ -#define AC_BUS_ERROR 0x60000000 /* 4 Cleared on read, byte. Probably same as sun4c. */ -#define AC_SYNC_ERR 0x60000000 /* c what type of synchronous memory error happened */ -#define AC_SYNC_VA 0x60000004 /* c what virtual address caused the error to occur */ -#define AC_ASYNC_ERR 0x60000008 /* c what type of asynchronous mem-error happened */ -#define AC_ASYNC_VA 0x6000000c /* c what virtual address caused the async-err to happen */ -#define AC_LEDS 0x70000000 /* 4 Zero turns on LEDs, byte */ -#define AC_CACHETAGS 0x80000000 /* 4c direct access to the VAC cache, unused... */ -#define AC_CACHEDDATA 0x90000000 /* c where the actual VAC cached data sits */ -#define AC_UDVMA_MAP 0xD0000000 /* 4 Not used on Sun boards, byte */ -#define AC_VME_VECTOR 0xE0000000 /* 4 For non-Autovector VME, byte */ -#define AC_BOOT_SCC 0xF0000000 /* 4 To bypass MMU and access Zilog 8530 on boot. byte. */ +#define AC_IDPROM 0x00000000 /* 4 ID PROM, R/O, byte, 32 bytes */ +#define AC_CONTEXT 0x30000000 /* 4c current mmu-context */ +#define AC_SENABLE 0x40000000 /* 4c system dvma/cache/reset enable reg */ +#define AC_UDVMA_ENB 0x50000000 /* 4 Not used on Sun boards, byte */ +#define AC_BUS_ERROR 0x60000000 /* 4 Cleared on read, byte. */ +#define AC_SYNC_ERR 0x60000000 /* c fault type */ +#define AC_SYNC_VA 0x60000004 /* c fault virtual address */ +#define AC_ASYNC_ERR 0x60000008 /* c asynchronous fault type */ +#define AC_ASYNC_VA 0x6000000c /* c async fault virtual address */ +#define AC_LEDS 0x70000000 /* 4 Zero turns on LEDs, byte */ +#define AC_CACHETAGS 0x80000000 /* 4c direct access to the VAC tags */ +#define AC_CACHEDDATA 0x90000000 /* c direct access to the VAC data */ +#define AC_UDVMA_MAP 0xD0000000 /* 4 Not used on Sun boards, byte */ +#define AC_VME_VECTOR 0xE0000000 /* 4 For non-Autovector VME, byte */ +#define AC_BOOT_SCC 0xF0000000 /* 4 bypass to access Zilog 8530. byte. */ -/* SPARCstation-5. I changed Paul's names to the hardware guy's ones. --P3 */ -#define AC_M_PCR 0x0000 /* 5 Processor Control Register */ -#define AC_M_CTPR 0x0100 /* 5 Context Table Pointer Register */ -#define AC_M_CXR 0x0200 /* 5 Context Register */ -#define AC_M_SFSR 0x0300 /* 5 Synchronous Fault Status Register */ -#define AC_M_SFAR 0x0400 /* 5 Synchronous Fault Address Register */ -#define AC_M_AFSR 0x0500 /* 5 Asynchronous Fault Status Register */ -#define AC_M_AFAR 0x0600 /* 5 Asynchronous Fault Address Register */ -#define AC_M_RESET 0x0700 /* 5 Reset Register Aieee! */ -#define AC_M_RPR 0x1000 /* 5 Root Pointer Register */ -#define AC_M_TSUTRCR 0x1000 /* 5 TLB Replacement Control Reg on Tsunami */ -#define AC_M_IAPTP 0x1100 /* 5 Instruction Access PTP */ -#define AC_M_DAPTP 0x1200 /* 5 Data Access PTP */ -#define AC_M_ITR 0x1300 /* 5 Index Tag Register */ -#define AC_M_TRCR 0x1400 /* 5 TLB Replacement Control Register */ - -/* The following are Ross HyperSparc only. */ -#define AC_M_RPR1 0x1500 /* 5 Root Pointer Register (entry 2) */ -#define AC_M_IAPTP1 0x1600 /* 5 Instruction Access PTP (entry 2) */ -#define AC_M_DAPTP1 0x1700 /* 5 Data Access PTP (entry 2) */ +/* s=Swift, h=Ross_HyperSPARC, v=TI_Viking, t=Tsunami, r=Ross_Cypress */ +#define AC_M_PCR 0x0000 /* shv Processor Control Reg */ +#define AC_M_CTPR 0x0100 /* shv Context Table Pointer Reg */ +#define AC_M_CXR 0x0200 /* shv Context Register */ +#define AC_M_SFSR 0x0300 /* shv Synchronous Fault Status Reg */ +#define AC_M_SFAR 0x0400 /* shv Synchronous Fault Address Reg */ +#define AC_M_AFSR 0x0500 /* hv Asynchronous Fault Status Reg */ +#define AC_M_AFAR 0x0600 /* hv Asynchronous Fault Address Reg */ +#define AC_M_RESET 0x0700 /* hv Reset Reg */ +#define AC_M_RPR 0x1000 /* hv Root Pointer Reg */ +#define AC_M_TSUTRCR 0x1000 /* s TLB Replacement Ctrl Reg */ +#define AC_M_IAPTP 0x1100 /* hv Instruction Access PTP */ +#define AC_M_DAPTP 0x1200 /* hv Data Access PTP */ +#define AC_M_ITR 0x1300 /* hv Index Tag Register */ +#define AC_M_TRCR 0x1400 /* hv TLB Replacement Control Reg */ +#define AC_M_SFSRX 0x1300 /* s Synch Fault Status Reg prim */ +#define AC_M_SFARX 0x1400 /* s Synch Fault Address Reg prim */ +#define AC_M_RPR1 0x1500 /* h Root Pointer Reg (entry 2) */ +#define AC_M_IAPTP1 0x1600 /* h Instruction Access PTP (entry 2) */ +#define AC_M_DAPTP1 0x1700 /* h Data Access PTP (entry 2) */ #endif /* _SPARC_CONTREGS_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/cprefix.h linux/include/asm-sparc/cprefix.h --- v1.3.43/linux/include/asm-sparc/cprefix.h Mon Feb 6 20:42:52 1995 +++ linux/include/asm-sparc/cprefix.h Tue Nov 21 12:31:53 1995 @@ -6,7 +6,8 @@ * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ - +#ifndef __SPARC_CPREFIX_H +#define __SPARC_CPREFIX_H #ifndef __svr4__ #define C_LABEL_PREFIX _ @@ -14,7 +15,9 @@ #define C_LABEL_PREFIX #endif -#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT(a, b) CONCAT2(a, b) #define CONCAT2(a, b) a##b -#define C_LABEL(name) CONCAT1(C_LABEL_PREFIX, name) +#define C_LABEL(name) CONCAT(C_LABEL_PREFIX, name) + +#endif /* !(__SPARC_CPREFIX_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/cypress.h linux/include/asm-sparc/cypress.h --- v1.3.43/linux/include/asm-sparc/cypress.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/cypress.h Sat Nov 25 04:31:30 1995 @@ -1,4 +1,5 @@ -/* cypress.h: Cypress module specific definitions and defines. +/* $Id: cypress.h,v 1.2 1995/11/25 02:31:29 davem Exp $ + * cypress.h: Cypress module specific definitions and defines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/delay.h linux/include/asm-sparc/delay.h --- v1.3.43/linux/include/asm-sparc/delay.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/delay.h Sat Nov 25 04:31:33 1995 @@ -1,38 +1,41 @@ -#ifndef __SPARC_DELAY_H -#define __SPARC_DELAY_H - -extern unsigned long loops_per_sec; - -/* - * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu). +/* $Id: delay.h,v 1.7 1995/11/25 02:31:32 davem Exp $ + * delay.h: Linux delay routines on the Sparc. * - * Delay quick inlined code using 'loops_per_second' which is - * calculated in calibrate_delay() in main.c (ie. BogoMIPS :-) + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu). */ -extern __inline__ void __delay(unsigned int loops) +#ifndef __SPARC_DELAY_H +#define __SPARC_DELAY_H + +extern __inline__ void __delay(unsigned long loops) { - __asm__ __volatile__("\n1:\tcmp %0, 0\n\t" - "bne,a 1b\n\t" - "sub %0, 1, %0\n": "=&r" (loops) : "0" (loops)); + __asm__ __volatile__("cmp %0, 0\n\t" + "1: bne 1b\n\t" + "subcc %0, 1, %0\n" : + "=&r" (loops) : + "0" (loops)); } -/* udelay(usecs) is used for very short delays up to 1 millisecond. */ +/* udelay(usecs) is used for very short delays up to 1 millisecond. On + * the Sparc (both sun4c and sun4m) we have a free running usec counter + * available to us already. + */ +extern volatile unsigned int *master_l10_counter; extern __inline__ void udelay(unsigned int usecs) { - usecs *= 0x000010c6; /* Sparc is 32-bit just like ix86 */ - - __delay(loops_per_sec*usecs); + unsigned int ccnt; + if(!master_l10_counter) + return; + ccnt=*master_l10_counter; + for(usecs+=1; usecs; usecs--, ccnt=*master_l10_counter) + while(*master_l10_counter == ccnt) + __asm__("": : :"memory"); } /* calibrate_delay() wants this... */ - -extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) -{ - return ((a*b)/c); -} +#define muldiv(a, b, c) (((a)*(b))/(c)) #endif /* defined(__SPARC_DELAY_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h --- v1.3.43/linux/include/asm-sparc/dma.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/dma.h Sat Nov 25 04:31:36 1995 @@ -1,29 +1,30 @@ -/* +/* $Id: dma.h,v 1.12 1995/11/25 02:31:34 davem Exp $ * include/asm-sparc/dma.h * - * Don't even ask, I am figuring out how this crap works - * on the Sparc. It may end up being real hairy to plug - * into this code, maybe not, we'll see. - * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) */ #ifndef _ASM_SPARC_DMA_H #define _ASM_SPARC_DMA_H +#include + #include /* for invalidate's, etc. */ #include #include #include -/* DMA probing routine */ -extern unsigned long probe_dma(unsigned long); - /* These are irrelevant for Sparc DMA, but we leave it in so that * things can compile. */ #define MAX_DMA_CHANNELS 8 -#define MAX_DMA_ADDRESS 0x0 +#define MAX_DMA_ADDRESS (~0UL) +#define DMA_MODE_READ 1 +#define DMA_MODE_WRITE 2 + +/* Useful constants */ +#define SIZE_16MB (16*1024*1024) +#define SIZE_64K (64*1024) /* Structure to describe the current status of DMA registers on the Sparc */ struct sparc_dma_registers { @@ -33,120 +34,162 @@ volatile unsigned long dma_test; /* DMA test register */ }; +/* DVMA chip revisions */ +enum dvma_rev { + dvmarev0, + dvmaesc1, + dvmarev1, + dvmarev2, + dvmarev3, + dvmarevplus +}; + +#define DMA_HASCOUNT(rev) ((rev)==dvmaesc1) + /* Linux DMA information structure, filled during probe. */ struct Linux_SBus_DMA { - struct linux_sbus_device *SBus_dev; /* pointer to sbus device struct */ - struct sparc_dma_registers *DMA_regs; /* Pointer to DMA regs in IO space */ + struct Linux_SBus_DMA *next; + struct linux_sbus_device *SBus_dev; + struct sparc_dma_registers *regs; + + /* Status, misc info */ + int node; /* Prom node for this DMA device */ + int running; /* Are we doing DMA now? */ + int allocated; /* Are we "owned" by anyone yet? */ + + /* Transfer information. */ + unsigned long addr; /* Start address of current transfer */ + int nbytes; /* Size of current transfer */ + int realbytes; /* For splitting up large transfers, etc. */ - /* Status, misc info */ - int node; /* Prom node for this DMA device */ - int dma_running; /* Are we using the DMA now? */ - - /* DMA revision: 0=REV0 1=REV1 2=REV2 3=DMA_PLUS */ - int dma_rev; + /* DMA revision */ + enum dvma_rev revision; }; -extern struct Linux_SBus_DMA Sparc_DMA; +extern struct Linux_SBus_DMA *dma_chain; + +/* Broken hardware... */ +#define DMA_ISBROKEN(dma) ((dma)->revision == dvmarev1) +#define DMA_ISESC1(dma) ((dma)->revision == dvmaesc1) /* Main routines in dma.c */ extern void dump_dma_regs(struct sparc_dma_registers *); -extern unsigned long probe_dma(unsigned long); -extern void sparc_dma_init_transfer(struct sparc_dma_registers *, - unsigned long, int, int); -extern int sparc_dma_interrupt(struct sparc_dma_registers *); +extern unsigned long dvma_init(struct linux_sbus *, unsigned long); /* Fields in the cond_reg register */ /* First, the version identification bits */ #define DMA_DEVICE_ID 0xf0000000 /* Device identification bits */ #define DMA_VERS0 0x00000000 /* Sunray DMA version */ +#define DMA_ESCV1 0x40000000 /* DMA ESC Version 1 */ #define DMA_VERS1 0x80000000 /* DMA rev 1 */ #define DMA_VERS2 0xa0000000 /* DMA rev 2 */ #define DMA_VERSPLUS 0x90000000 /* DMA rev 1 PLUS */ -#define DMA_HNDL_INTR 0x00000001 /* An interrupt needs to be handled */ -#define DMA_HNDL_ERROR 0x00000002 /* We need to take care of an error */ +#define DMA_HNDL_INTR 0x00000001 /* An IRQ needs to be handled */ +#define DMA_HNDL_ERROR 0x00000002 /* We need to take an error */ #define DMA_FIFO_ISDRAIN 0x0000000c /* The DMA FIFO is draining */ #define DMA_INT_ENAB 0x00000010 /* Turn on interrupts */ #define DMA_FIFO_INV 0x00000020 /* Invalidate the FIFO */ #define DMA_ACC_SZ_ERR 0x00000040 /* The access size was bad */ #define DMA_FIFO_STDRAIN 0x00000040 /* DMA_VERS1 Drain the FIFO */ #define DMA_RST_SCSI 0x00000080 /* Reset the SCSI controller */ -#define DMA_ST_WRITE 0x00000100 /* If set, write from device to memory */ +#define DMA_ST_WRITE 0x00000100 /* write from device to memory */ #define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */ -#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Read is pending */ +#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pendind Read */ #define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */ #define DMA_TERM_CNTR 0x00004000 /* Terminal counter */ #define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */ #define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */ +#define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */ #define DMA_BRST_SZ 0x000c0000 /* SBUS transfer r/w burst size */ #define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */ -#define DMA_2CLKS 0x00200000 /* Each transfer equals 2 clock ticks */ -#define DMA_3CLKS 0x00400000 /* Each transfer equals 3 clock ticks */ -#define DMA_CNTR_DISAB 0x00800000 /* No intr's when DMA_TERM_CNTR is set */ -#define DMA_AUTO_NADDR 0x01000000 /* Use "auto next address" feature */ +#define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */ +#define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */ +#define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */ +#define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */ #define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */ #define DMA_LOADED_ADDR 0x04000000 /* Address has been loaded */ #define DMA_LOADED_NADDR 0x08000000 /* Next address has been loaded */ -/* Only 24-bits of the byte count are significant */ -#define DMA_BYTE_CNT_MASK 0x00ffffff +/* Values describing the burst-size property from the PROM */ +#define DMA_BURST1 0x01 +#define DMA_BURST2 0x02 +#define DMA_BURST4 0x04 +#define DMA_BURST8 0x08 +#define DMA_BURST16 0x10 +#define DMA_BURST32 0x20 +#define DMA_BURST64 0x40 +#define DMA_BURSTBITS 0x7f + +/* Determine highest possible final transfer address given a base */ +#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL)) + +/* Yes, I hack a lot of elisp in my spare time... */ +#define DMA_ERROR_P(regs) ((((regs)->cond_reg) & DMA_HNDL_ERROR)) +#define DMA_IRQ_P(regs) ((((regs)->cond_reg) & DMA_HNDL_INTR)) +#define DMA_WRITE_P(regs) ((((regs)->cond_reg) & DMA_ST_WRITE)) +#define DMA_OFF(regs) ((((regs)->cond_reg) &= (~DMA_ENABLE))) +#define DMA_INTSOFF(regs) ((((regs)->cond_reg) &= (~DMA_INT_ENAB))) +#define DMA_INTSON(regs) ((((regs)->cond_reg) |= (DMA_INT_ENAB))) +#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV)) +#define DMA_SETSTART(regs, addr) ((((regs)->st_addr) = (char *) addr)) +#define DMA_BEGINDMA_W(regs) \ + ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB)))) +#define DMA_BEGINDMA_R(regs) \ + ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE))))) + +/* For certain DMA chips, we need to disable ints upon irq entry + * and turn them back on when we are done. So in any ESP interrupt + * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT + * when leaving the handler. You have been warned... + */ +#define DMA_IRQ_ENTRY(dma, dregs) do { \ + if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \ + } while (0) + +#define DMA_IRQ_EXIT(dma, dregs) do { \ + if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \ + } while(0) /* Pause until counter runs out or BIT isn't set in the DMA condition * register. */ -extern inline void sparc_dma_pause(struct sparc_dma_registers *dma_regs, +extern inline void sparc_dma_pause(struct sparc_dma_registers *regs, unsigned long bit) { - int ctr = 50000; /* Let's find some bugs ;) */ - - /* Busy wait until the bit is not set any more */ - while((dma_regs->cond_reg&bit) && (ctr>0)) { - ctr--; - __delay(1); - } - - /* Check for bogus outcome. */ - if(ctr==0) { - printk("DMA Grrr: I tried for wait for the assertion of bit %08xl to clear", - (unsigned int) bit); - printk(" in the DMA condition register and it did not!\n"); - printk("Cannot continue, halting...\n"); - prom_halt(); - } - - return; -} - -/* Enable DMA interrupts */ -extern inline void sparc_dma_enable_interrupts(struct sparc_dma_registers *dma_regs) -{ - dma_regs->cond_reg |= DMA_INT_ENAB; -} + int ctr = 50000; /* Let's find some bugs ;) */ -/* Disable DMA interrupts from coming in */ -extern inline void sparc_dma_disable_interrupts(struct sparc_dma_registers *dma_regs) -{ - dma_regs->cond_reg &= ~(DMA_INT_ENAB); + /* Busy wait until the bit is not set any more */ + while((regs->cond_reg&bit) && (ctr>0)) { + ctr--; + __delay(5); + } + + /* Check for bogus outcome. */ + if(!ctr) + panic("DMA timeout"); } -/* Reset the DMA module. */ -extern inline void sparc_dma_reset(struct sparc_dma_registers *dma_regs) -{ - /* Let the current FIFO drain itself */ - sparc_dma_pause(dma_regs, (DMA_FIFO_ISDRAIN)); - - /* Reset the logic */ - dma_regs->cond_reg |= (DMA_RST_SCSI); /* assert */ - __delay(400); /* let the bits set ;) */ - dma_regs->cond_reg &= ~(DMA_RST_SCSI); /* de-assert */ - - sparc_dma_enable_interrupts(dma_regs); /* Re-enable interrupts */ - - /* Enable FAST transfers if available */ - if(Sparc_DMA.dma_rev>1) { dma_regs->cond_reg |= DMA_3CLKS; } - Sparc_DMA.dma_running = 0; - - return; -} +/* Reset the friggin' thing... */ +#define DMA_RESET(dma) do { \ + struct sparc_dma_registers *regs = dma->regs; \ + /* Let the current FIFO drain itself */ \ + sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN)); \ + /* Reset the logic */ \ + regs->cond_reg |= (DMA_RST_SCSI); /* assert */ \ + __delay(400); /* let the bits set ;) */ \ + regs->cond_reg &= ~(DMA_RST_SCSI); /* de-assert */ \ + sparc_dma_enable_interrupts(regs); /* Re-enable interrupts */ \ + /* Enable FAST transfers if available */ \ + if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS; \ + dma->running = 0; \ +} while(0) + +#define for_each_dvma(dma) \ + for((dma) = dma_chain; (dma); (dma) = (dma)->next) + +extern int get_dma_list(char *); +extern int request_dma(unsigned int, const char *); +extern void free_dma(unsigned int); #endif /* !(_ASM_SPARC_DMA_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/ecc.h linux/include/asm-sparc/ecc.h --- v1.3.43/linux/include/asm-sparc/ecc.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/ecc.h Sat Nov 25 04:31:38 1995 @@ -1,4 +1,5 @@ -/* ecc.h: Definitions and defines for the external cache/memory +/* $Id: ecc.h,v 1.2 1995/11/25 02:31:37 davem Exp $ + * ecc.h: Definitions and defines for the external cache/memory * controller on the sun4m. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/eeprom.h linux/include/asm-sparc/eeprom.h --- v1.3.43/linux/include/asm-sparc/eeprom.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/eeprom.h Sat Nov 25 04:31:39 1995 @@ -1,4 +1,5 @@ -/* eeprom.h: Definitions for the Sun eeprom. +/* $Id: eeprom.h,v 1.3 1995/11/25 02:31:38 davem Exp $ + * eeprom.h: Definitions for the Sun eeprom. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/elf.h linux/include/asm-sparc/elf.h --- v1.3.43/linux/include/asm-sparc/elf.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/elf.h Sat Nov 25 04:31:41 1995 @@ -0,0 +1,18 @@ +/* $Id: elf.h,v 1.2 1995/11/25 02:31:40 davem Exp $ */ +#ifndef __ASMSPARC_ELF_H +#define __ASMSPARC_ELF_H + +/* + * ELF register definitions.. + */ + +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef unsigned long elf_fpregset_t; + +#endif diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/errno.h linux/include/asm-sparc/errno.h --- v1.3.43/linux/include/asm-sparc/errno.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/errno.h Sat Nov 25 04:31:42 1995 @@ -0,0 +1,133 @@ +/* $Id: errno.h,v 1.4 1995/11/25 02:31:41 davem Exp $ */ +#ifndef _SPARC_ERRNO_H +#define _SPARC_ERRNO_H + +/* These match the SunOS error numbering scheme. */ +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EWOULDBLOCK 35 /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Op not supported on transport endpoint */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Cannot assign requested address */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Net dropped connection because of reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Transport endpoint is already connected */ +#define ENOTCONN 57 /* Transport endpoint is not connected */ +#define ESHUTDOWN 58 /* No send after transport endpoint shutdown */ +#define ETOOMANYREFS 59 /* Too many references: cannot splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ +#define ELOOP 62 /* Too many symbolic links encountered */ +#define ENAMETOOLONG 63 /* File name too long */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ +#define EPROCLIM 67 /* SUNOS: Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Quota exceeded */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Object is remote */ +#define ENOSTR 72 /* Device not a stream */ +#define ETIME 73 /* Timer expired */ +#define ENOSR 74 /* Out of streams resources */ +#define ENOMSG 75 /* No message of desired type */ +#define EBADMSG 76 /* Not a data message */ +#define EIDRM 77 /* Identifier removed */ +#define EDEADLK 78 /* Resource deadlock would occur */ +#define ENOLCK 79 /* No record locks available */ +#define ENONET 80 /* Machine is not on the network */ +#define ERREMOTE 81 /* SunOS: Too many lvls of remote in path */ +#define ENOLINK 82 /* Link has been severed */ +#define EADV 83 /* Advertise error */ +#define ESRMNT 84 /* Srmount error */ +#define ECOMM 85 /* Communication error on send */ +#define EPROTO 86 /* Protocol error */ +#define EMULTIHOP 87 /* Multihop attempted */ +#define EDOTDOT 88 /* RFS specific error */ +#define EREMCHG 89 /* Remote address changed */ +#define ENOSYS 90 /* Function not implemented */ + +/* The rest have no SunOS equivalent. */ +#define ESTRPIPE 91 /* Streams pipe error */ +#define EOVERFLOW 92 /* Value too large for defined data type */ +#define EBADFD 93 /* File descriptor in bad state */ +#define ECHRNG 94 /* Channel number out of range */ +#define EL2NSYNC 95 /* Level 2 not synchronized */ +#define EL3HLT 96 /* Level 3 halted */ +#define EL3RST 97 /* Level 3 reset */ +#define ELNRNG 98 /* Link number out of range */ +#define EUNATCH 99 /* Protocol driver not attached */ +#define ENOCSI 100 /* No CSI structure available */ +#define EL2HLT 101 /* Level 2 halted */ +#define EBADE 102 /* Invalid exchange */ +#define EBADR 103 /* Invalid request descriptor */ +#define EXFULL 104 /* Exchange full */ +#define ENOANO 105 /* No anode */ +#define EBADRQC 106 /* Invalid request code */ +#define EBADSLT 107 /* Invalid slot */ +#define EDEADLOCK 108 /* File locking deadlock error */ +#define EBFONT 109 /* Bad font file format */ +#define ELIBEXEC 110 /* Cannot exec a shared library directly */ +#define ENODATA 111 /* No data available */ +#define ELIBBAD 112 /* Accessing a corrupted shared library */ +#define ENOPKG 113 /* Package not installed */ +#define ELIBACC 114 /* Can not access a needed shared library */ +#define ENOTUNIQ 115 /* Name not unique on network */ +#define ERESTART 116 /* Interrupted syscall should be restarted */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EILSEQ 122 /* Illegal byte sequence */ +#define ELIBMAX 123 /* Atmpt to link in too many shared libs */ +#define ELIBSCN 124 /* .lib section in a.out corrupted */ + +#endif diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v1.3.43/linux/include/asm-sparc/fcntl.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/fcntl.h Sat Nov 25 04:31:44 1995 @@ -0,0 +1,65 @@ +/* $Id: fcntl.h,v 1.5 1995/11/25 02:31:43 davem Exp $ */ +#ifndef _SPARC_FCNTL_H +#define _SPARC_FCNTL_H + +/* open/fcntl - O_SYNC is only implemented on blocks devices and on files + located on an ext2 file system */ +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_ACCMODE 0x0003 +#define O_NDELAY 0x0004 +#define O_APPEND 0x0008 +#define FASYNC 0x0040 /* fcntl, for BSD compatibility */ +#define O_CREAT 0x0200 /* not fcntl */ +#define O_EXCL 0x0800 /* not fcntl */ +#define O_NOCTTY 0x8000 /* not fcntl */ +#define O_TRUNC 0x0400 /* not fcntl */ +#define O_SYNC 0x2000 +#define O_NONBLOCK 0x4000 + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETOWN 5 /* for sockets. */ +#define F_SETOWN 6 /* for sockets. */ +#define F_GETLK 7 +#define F_SETLK 8 +#define F_SETLKW 9 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 1 +#define F_WRLCK 2 +#define F_UNLCK 3 + +/* for old implementation of bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#ifdef __KERNEL__ +#define F_POSIX 1 +#define F_FLOCK 2 +#endif /* __KERNEL__ */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; + short __unused; +}; + +#endif diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/floppy.h linux/include/asm-sparc/floppy.h --- v1.3.43/linux/include/asm-sparc/floppy.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/floppy.h Sat Nov 25 04:31:46 1995 @@ -0,0 +1,357 @@ +/* $Id: floppy.h,v 1.8 1995/11/25 02:31:45 davem Exp $ + * asm-sparc/floppy.h: Sparc specific parts of the Floppy driver. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __ASM_SPARC_FLOPPY_H +#define __ASM_SPARC_FLOPPY_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* References: + * 1) Netbsd Sun floppy driver. + * 2) NCR 82077 controller manual + * 3) Intel 82077 controller manual + */ +struct sun_flpy_controller { + volatile unsigned char status_82072; /* Main Status reg. */ +#define dcr_82072 status_82072 /* Digital Control reg. */ +#define status1_82077 status_82072 /* Auxiliary Status reg. 1 */ + + volatile unsigned char data_82072; /* Data fifo. */ +#define status2_82077 data_82072 /* Auxiliary Status reg. 2 */ + + volatile unsigned char dor_82077; /* Digital Output reg. */ + volatile unsigned char tapectl_82077; /* What the? Tape control reg? */ + + volatile unsigned char status_82077; /* Main Status Register. */ +#define drs_82077 status_82077 /* Digital Rate Select reg. */ + + volatile unsigned char data_82077; /* Data fifo. */ + volatile unsigned char ___unused; + volatile unsigned char dir_82077; /* Digital Input reg. */ +#define dcr_82077 dir_82077 /* Config Control reg. */ +}; + +/* You'll only ever find one controller on a SparcStation anyways. */ +static struct sun_flpy_controller *sun_fdc = NULL; +volatile unsigned char *fdc_status; + +struct sun_floppy_ops { + unsigned char (*fd_inb)(int port); + void (*fd_outb)(unsigned char value, int port); +}; + +static struct sun_floppy_ops sun_fdops; + +#define fd_inb(port) sun_fdops.fd_inb(port) +#define fd_outb(value,port) sun_fdops.fd_outb(value,port) +#define fd_enable_dma() sun_fd_enable_dma() +#define fd_disable_dma() sun_fd_disable_dma() +#define fd_request_dma() (0) /* nothing... */ +#define fd_free_dma() /* nothing... */ +#define fd_clear_dma_ff() /* nothing... */ +#define fd_set_dma_mode(mode) sun_fd_set_dma_mode(mode) +#define fd_set_dma_addr(addr) sun_fd_set_dma_addr(addr) +#define fd_set_dma_count(count) sun_fd_set_dma_count(count) +#define fd_enable_irq() /* nothing... */ +#define fd_disable_irq() /* nothing... */ +#define fd_cacheflush(addr, size) /* nothing... */ +#define fd_request_irq() sun_fd_request_irq() +#define fd_free_irq() /* nothing... */ + +/* It's all the same... */ +#define virt_to_bus(x) (x) +#define bus_to_virt(x) (x) + +/* XXX This isn't really correct. XXX */ +#define get_dma_residue(x) (0) + +#define FLOPPY0_TYPE 4 +#define FLOPPY1_TYPE 0 + +/* Super paranoid... */ +#undef HAVE_DISABLE_HLT + +/* Here is where we catch the floppy driver trying to initialize, + * therefore this is where we call the PROM device tree probing + * routine etc. on the Sparc. + */ +#define FDC1 sun_floppy_init() + +static int FDC2=-1; + +#define N_FDC 1 +#define N_DRIVE 8 + +/* No 64k boundry crossing problems on the Sparc. */ +#define CROSS_64KB(a,s) (0) + +/* Routines unique to each controller type on a Sun. */ +static unsigned char sun_82072_fd_inb(int port) +{ + switch(port & 7) { + default: + printk("floppy: Asked to read unknown port %d\n", port); + panic("floppy: Port bolixed."); + case 4: /* FD_STATUS */ + return sun_fdc->status_82072 & ~STATUS_DMA; + case 5: /* FD_DATA */ + return sun_fdc->data_82072; + case 7: /* FD_DIR */ + /* Always return 0, the disk never changes + * without the kernel explicitly doing so. + */ + return 0; + }; + panic("sun_82072_fd_inb: How did I get here?"); +} + +static void sun_82072_fd_outb(unsigned char value, int port) +{ + switch(port & 7) { + default: + printk("floppy: Asked to write to unknown port %d\n", port); + panic("floppy: Port bolixed."); + case 2: /* FD_DOR */ + /* Oh geese, 82072 on the Sun has no DOR register, + * the functionality is implemented via the AUXIO + * I/O register. So we must emulate the behavior. + * + * ASSUMPTIONS: There will only ever be one floppy + * drive attached to a Sun controller + * and it will be at drive zero. + */ + if(value & 0xf0) + set_auxio(AUXIO_FLPY_DSEL, 0); +#if 0 + else + set_auxio(0, AUXIO_FLPY_DSEL); +#endif + break; + case 5: /* FD_DATA */ + sun_fdc->data_82072 = value; + break; + case 7: /* FD_DCR */ + sun_fdc->dcr_82072 = value; + break; + case 4: /* FD_STATUS */ + sun_fdc->status_82072 = value; + break; + }; + return; +} + +static unsigned char sun_82077_fd_inb(int port) +{ + switch(port & 7) { + default: + printk("floppy: Asked to read unknown port %d\n", port); + panic("floppy: Port bolixed."); + case 4: /* FD_STATUS */ + return sun_fdc->status_82077 & ~STATUS_DMA; + case 5: /* FD_DATA */ + return sun_fdc->data_82077; + case 7: /* FD_DIR */ + /* Always return 0, the disk never changes + * without the kernel explicitly ejecting it. + */ + return 0; + }; + panic("sun_82072_fd_inb: How did I get here?"); +} + +static void sun_82077_fd_outb(unsigned char value, int port) +{ + switch(port & 7) { + default: + printk("floppy: Asked to write to unknown port %d\n", port); + panic("floppy: Port bolixed."); + case 2: /* FD_DOR */ + /* Happily, the 82077 has a real DOR register. */ + sun_fdc->dor_82077 = value; + break; + case 5: /* FD_DATA */ + sun_fdc->data_82077 = value; + break; + case 7: /* FD_DCR */ + sun_fdc->dcr_82077 = value; + break; + case 4: /* FD_STATUS */ + sun_fdc->status_82077 = value; + break; + }; + return; +} + +/* For pseudo-dma (Sun floppy drives have no real DMA available to + * them so we must eat the data fifo bytes directly ourselves) we have + * three state variables. doing_pdma tells our inline low-level + * assembly floppy interrupt entry point whether it should sit and eat + * bytes from the fifo or just transfer control up to the higher level + * floppy interrupt c-code. I tried very hard but I could not get the + * pseudo-dma to work in c-code without getting many overruns and + * underruns. If non-zero, doing_pdma encodes the direction of + * the transfer for debugging. 1=read 2=write + */ +char *pdma_vaddr; +char *pdma_vsave; +unsigned long pdma_size; +int doing_pdma = 0; + +/* Common routines to all controller types on the Sparc. */ +static inline void virtual_dma_init(void) +{ + /* nothing... */ +} + +static inline void sun_fd_disable_dma(void) +{ + doing_pdma = 0; +} + +static inline void sun_fd_set_dma_mode(int mode) +{ + switch(mode) { + case DMA_MODE_READ: + doing_pdma = 1; + break; + case DMA_MODE_WRITE: + doing_pdma = 2; + break; + default: + printk("Unknown dma mode %d\n", mode); + panic("floppy: Giving up..."); + } +} + +static inline void sun_fd_set_dma_addr(char *buffer) +{ + pdma_vaddr = buffer; +} + +static inline void sun_fd_set_dma_count(int length) +{ + pdma_size = length; +} + +static inline void sun_fd_enable_dma(void) +{ + /* We're about to let it rip, lock any tlb entries necessary. */ + pdma_vaddr = pdma_vsave = mmu_lockarea(pdma_vaddr, pdma_size); +} + +/* Our low-level entry point in arch/sparc/kernel/entry.S */ +extern void floppy_hardint(int irq, struct pt_regs *regs); + +static int sun_fd_request_irq(void) +{ + static int once = 0; + int error; + + if(!once) { + once = 1; + error = request_fast_irq(FLOPPY_IRQ, floppy_hardint, SA_INTERRUPT, "floppy"); + return ((error == 0) ? 0 : -1); + } else return 0; +} + +static struct linux_prom_registers fd_regs[2]; + +static int sun_floppy_init(void) +{ + char state[128]; + int tnode, fd_node, num_regs; + + FLOPPY_IRQ = 11; + /* Forget it if we aren't on a machine that could possibly + * ever have a floppy drive. + */ + if((sparc_cpu_model != sun4c && sparc_cpu_model != sun4m) || + ((idprom->id_machtype == (SM_SUN4C | SM_4C_SLC)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC)))) { + /* We certainly don't have a floppy controller. */ + goto no_sun_fdc; + } + /* Well, try and find one. */ + tnode = prom_getchild(prom_root_node); + fd_node = prom_searchsiblings(tnode, "obio"); + if(fd_node != 0) { + tnode = prom_getchild(fd_node); + fd_node = prom_searchsiblings(tnode, "SUNW,fdtwo"); + } else { + fd_node = prom_searchsiblings(tnode, "fd"); + } + if(fd_node == 0) { + goto no_sun_fdc; + } + + /* The sun4m lets us know if the controller is actually usable. */ + if(sparc_cpu_model == sun4m) { + prom_getproperty(fd_node, "status", state, sizeof(state)); + if(!strcmp(state, "disabled")) { + goto no_sun_fdc; + } + } + num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs, sizeof(fd_regs)); + num_regs = (num_regs / sizeof(fd_regs[0])); + prom_apply_obio_ranges(fd_regs, num_regs); + sun_fdc = (struct sun_flpy_controller *) sparc_alloc_io(fd_regs[0].phys_addr, + 0x0, + fd_regs[0].reg_size, + "floppy", + fd_regs[0].which_io, + 0x0); + /* Last minute sanity check... */ + if(sun_fdc->status_82072 == 0xff) { + sun_fdc = NULL; + goto no_sun_fdc; + } + + /* We need the version as early as possible to set up the + * function pointers correctly. Assume 82077 for probing + * purposes. + */ + sun_fdops.fd_inb = sun_82077_fd_inb; + sun_fdops.fd_outb = sun_82077_fd_outb; + fdc_status = &sun_fdc->status_82077; + + /* This controller detection technique is from the netbsd + * Sun floppy driver, origionally Chris Torek of BSDI came + * up with this. It seems to work pretty well. + */ + if(sun_fdc->dor_82077 == 0x80) { + sun_fdc->dor_82077 = 2; + if(sun_fdc->dor_82077 == 0x80) { + /* Ok, it's really an 82072. */ + sun_fdops.fd_inb = sun_82072_fd_inb; + sun_fdops.fd_outb = sun_82072_fd_outb; + fdc_status = &sun_fdc->status_82072; + } + } + + /* P3: The only realiable way which I found for ejection + * of boot floppy. AUXIO_FLPY_EJCT is not enougth alone. + */ + set_auxio(AUXIO_FLPY_EJCT, 0); + udelay(1000); + set_auxio(AUXIO_FLPY_DSEL, AUXIO_FLPY_EJCT); + udelay(1000); + set_auxio(0, AUXIO_FLPY_DSEL); + + /* Success... */ + return (int) sun_fdc; + +no_sun_fdc: + return -1; +} + +#endif /* !(__ASM_SPARC_FLOPPY_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h --- v1.3.43/linux/include/asm-sparc/head.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/head.h Sat Nov 25 04:31:48 1995 @@ -1,27 +1,30 @@ +/* $Id: head.h,v 1.19 1995/11/25 02:31:47 davem Exp $ */ #ifndef __SPARC_HEAD_H #define __SPARC_HEAD_H #define KERNBASE 0xf0000000 /* First address the kernel will eventually be */ #define LOAD_ADDR 0x4000 /* prom jumps to us here unless this is elf /boot */ -#define C_STACK 96 #define SUN4C_SEGSZ (1 << 18) #define SRMMU_L1_KBASE_OFFSET ((KERNBASE>>24)<<2) /* Used in boot remapping. */ -#define INTS_ENAB 0x01 /* entry.S uses this. */ +#define INTS_ENAB 0x01 /* entry.S uses this. */ -#define NCPUS 4 /* Architectual limit of sun4m. */ +#define NCPUS 4 /* Architectual limit of sun4m. */ -#define SUN4_PROM_VECTOR 0xFFE81000 /* To safely die on a SUN4 */ -#define SUN4_PRINTF 0x84 /* Offset into SUN4_PROM_VECTOR */ +#define SUN4_PROM_VECTOR 0xFFE81000 /* To safely die on a SUN4 */ +#define SUN4_PRINTF 0x84 /* Offset into SUN4_PROM_VECTOR */ -#define WRITE_PAUSE nop; nop; nop; - -#define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ +#define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ +#define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ /* Here are some trap goodies */ /* Generic trap entry. */ #define TRAP_ENTRY(type, label) \ - mov (type), %l3; b label; rd %psr, %l0; nop; + rd %psr, %l0; b label; rd %wim, %l3; nop; + +/* This is for traps we should NEVER get. */ +#define BAD_TRAP(num) \ + rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3; /* Notice that for the system calls we pull a trick. We load up a * different pointer to the system call vector table in %l7, but call @@ -31,19 +34,31 @@ /* Software trap for Linux system calls. */ #define LINUX_SYSCALL_TRAP \ - sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0; + sethi %hi(C_LABEL(sys_call_table)), %l7; \ + or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ + b linux_sparc_syscall; \ + rd %psr, %l0; /* Software trap for SunOS4.1.x system calls. */ #define SUNOS_SYSCALL_TRAP \ - sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0; + sethi %hi(C_LABEL(sunos_sys_table)), %l7; \ + or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; \ + b linux_sparc_syscall; \ + rd %psr, %l0; /* Software trap for Slowaris system calls. */ #define SOLARIS_SYSCALL_TRAP \ - sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0; + sethi %hi(C_LABEL(sys_call_table)), %l7; \ + or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ + b linux_sparc_syscall; \ + rd %psr, %l0; /* Software trap for Sparc-netbsd system calls. */ #define NETBSD_SYSCALL_TRAP \ - sethi %hi(C_LABEL(sys_call_table)), %l7; or %l7, %lo(C_LABEL(sys_call_table)), %l7; b linux_sparc_syscall; mov %psr, %l0; + sethi %hi(C_LABEL(sys_call_table)), %l7; \ + or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ + b linux_sparc_syscall; \ + rd %psr, %l0; /* The Get Condition Codes software trap for userland. */ #define GETCC_TRAP \ @@ -57,65 +72,31 @@ * gets handled with another macro. */ #define TRAP_ENTRY_INTERRUPT(int_level) \ - mov int_level, %l3; b real_irq_entry; rd %psr, %l0; nop; + mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; + +/* This is for software interrupts, which currently (atleast on the sun4c) + * correspond to IRQ levels 1, 4, and 6. + */ +#define TRAP_ENTRY_SOFTINT(int_level) \ + mov int_level, %l7; rd %psr, %l0; b soft_irq_entry; rd %wim, %l3; /* NMI's (Non Maskable Interrupts) are special, you can't keep them * from coming in, and basically if you get one, the shows over. ;( + * On the sun4c they are usually asyncronous memory errors, on the + * the sun4m they could be either due to mem errors or a software + * initiated interrupt from the prom/kern on an SMP box saying "I + * command you to do CPU tricks, read your mailbox for more info." */ #define NMI_TRAP \ - b linux_trap_nmi; mov %psr, %l0; nop; nop - -/* The above two macros are for generic traps. The following is made - * especially for timer interrupts at IRQ level 14. - */ -#define TRAP_ENTRY_TIMER \ - rd %psr, %l0; b sparc_timer; nop; nop; + rd %wim, %l3; b linux_trap_nmi; mov %psr, %l0; nop; -/* Trap entry code in entry.S needs the offsets into task_struct - * to get at the thread_struct goodies during window craziness. - * - * NOTE: We need to keep these values under 0x3ff in order to do - * efficient load/stores in the window fill/spill handlers. - * See TRAP_WIN_CLEAN in entry.S for details. +/* Window overflows/underflows are special and we need to try and be as + * efficient as possible here.... */ +#define WINDOW_SPILL \ + rd %psr, %l0; rd %wim, %l3; b spill_window_entry; andcc %l0, PSR_PS, %g0; -/* First generic task_struct offsets */ -#define TASK_STATE 0x000 -#define TASK_PRI 0x008 -#define TASK_KSTACK_PG 0x250 - -#define THREAD_UWINDOWS 0x3b8 -#define THREAD_WIM 0x3bc -#define THREAD_W_SAVED 0x3c0 -#define THREAD_KSP 0x3c4 -#define THREAD_USP 0x3c8 -#define THREAD_PSR 0x3cc -#define THREAD_PC 0x3d0 -#define THREAD_NPC 0x3d4 -#define THREAD_Y 0x3d8 -#define THREAD_REG_WINDOW 0x3e0 - -/* More fun offset macros. These are for pt_regs. */ - -#define PT_PSR 0x0 -#define PT_PC 0x4 -#define PT_NPC 0x8 -#define PT_Y 0xc -#define PT_G0 0x10 -#define PT_G1 0x14 -#define PT_G2 0x18 -#define PT_G3 0x1c -#define PT_G4 0x20 -#define PT_G5 0x24 -#define PT_G6 0x28 -#define PT_G7 0x2c -#define PT_I0 0x30 -#define PT_I1 0x34 -#define PT_I2 0x38 -#define PT_I3 0x3c -#define PT_I4 0x40 -#define PT_I5 0x44 -#define PT_I6 0x48 -#define PT_I7 0x4c +#define WINDOW_FILL \ + rd %psr, %l0; rd %wim, %l3; b fill_window_entry; andcc %l0, PSR_PS, %g0; #endif __SPARC_HEAD_H diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/idprom.h linux/include/asm-sparc/idprom.h --- v1.3.43/linux/include/asm-sparc/idprom.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/idprom.h Sat Nov 25 04:31:49 1995 @@ -1,4 +1,5 @@ -/* idprom.h: Macros and defines for idprom routines +/* $Id: idprom.h,v 1.5 1995/11/25 02:31:49 davem Exp $ + * idprom.h: Macros and defines for idprom routines * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h --- v1.3.43/linux/include/asm-sparc/io.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/io.h Sat Nov 25 04:31:51 1995 @@ -1,3 +1,4 @@ +/* $Id: io.h,v 1.8 1995/11/25 02:31:50 davem Exp $ */ #ifndef __SPARC_IO_H #define __SPARC_IO_H @@ -15,42 +16,42 @@ extern inline unsigned long inb_local(unsigned long addr) { - return 0; + return 0; } extern inline void outb_local(unsigned char b, unsigned long addr) { - return; + return; } extern inline unsigned long inb(unsigned long addr) { - return 0; + return 0; } extern inline unsigned long inw(unsigned long addr) { - return 0; + return 0; } extern inline unsigned long inl(unsigned long addr) { - return 0; + return 0; } extern inline void outb(unsigned char b, unsigned long addr) { - return; + return; } extern inline void outw(unsigned short b, unsigned long addr) { - return; + return; } extern inline void outl(unsigned int b, unsigned long addr) { - return; + return; } /* @@ -58,32 +59,32 @@ */ extern inline unsigned long readb(unsigned long addr) { - return 0; + return 0; } extern inline unsigned long readw(unsigned long addr) { - return 0; + return 0; } extern inline unsigned long readl(unsigned long addr) { - return 0; + return 0; } extern inline void writeb(unsigned short b, unsigned long addr) { - return; + return; } extern inline void writew(unsigned short b, unsigned long addr) { - return; + return; } extern inline void writel(unsigned int b, unsigned long addr) { - return; + return; } #define inb_p inb diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/ioctl.h linux/include/asm-sparc/ioctl.h --- v1.3.43/linux/include/asm-sparc/ioctl.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/ioctl.h Sat Nov 25 04:31:53 1995 @@ -0,0 +1,43 @@ +/* $Id: ioctl.h,v 1.4 1995/11/25 02:31:52 davem Exp $ */ +#ifndef _SPARC_IOCTL_H +#define _SPARC_IOCTL_H + +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 8 +#define _IOC_RESVBITS 5 +#define _IOC_DIRBITS 3 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_RESVMASK ((1 << _IOC_RESVBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) +#define _IOC_RESVSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) +#define _IOC_DIRSHIFT (_IOC_RESVSHIFT + _IOC_RESVBITS) + +#define _IOC_NONE 1U +#define _IOC_READ 2U +#define _IOC_WRITE 4U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IORW(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +#endif /* !(_SPARC_IOCTL_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/ipsum.h linux/include/asm-sparc/ipsum.h --- v1.3.43/linux/include/asm-sparc/ipsum.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/ipsum.h Thu Jan 1 02:00:00 1970 @@ -1,49 +0,0 @@ -#ifndef __SPARC_IPSUM_H -#define __SPARC_IPSUM_H -/* ipsum.h: IP/UDP/TCP checksum routines on the Sparc. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -/* - * This routine computes a UDP checksum. - */ -extern inline unsigned short udp_check(struct udphdr *uh, int len, u32 saddr, u32 daddr) -{ - /* uhh.. eventually */ - return 0; -} - -/* - * This routine computes a TCP checksum. - */ -extern inline unsigned short tcp_check(struct tcphdr *th, int len, u32 saddr, u32 daddr) -{ - /* uhh.. eventually */ - return 0; -} - - -/* - * This routine does all the checksum computations that don't - * require anything special (like copying or special headers). - */ - -extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) -{ - /* uhh.. eventually */ - return 0; -} - -/* - * This is a version of ip_compute_csum() optimized for IP headers, which - * always checksum on 4 octet boundaries. - */ - -static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen) -{ - /* uhh.. eventually */ - return 0; -} - -#endif /* !(__SPARC_IPSUM_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h --- v1.3.43/linux/include/asm-sparc/irq.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/irq.h Sat Nov 25 04:31:54 1995 @@ -1,19 +1,23 @@ -#ifndef _ALPHA_IRQ_H -#define _ALPHA_IRQ_H - -/* - * linux/include/asm-sparc/irq.h +/* $Id: irq.h,v 1.8 1995/11/25 02:31:54 davem Exp $ + * irq.h: IRQ registers on the Sparc. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#ifndef _SPARC_IRQ_H +#define _SPARC_IRQ_H + #include #include /* For NCPUS */ +#define NR_IRQS 15 + extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); +extern int request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *), unsigned long flags, const char *devname); + /* On the sun4m, just like the timers, we have both per-cpu and master * interrupt registers. */ @@ -64,37 +68,5 @@ #define SUN4M_INT_ENABLE 0x80000000 #define SUN4M_INT_E14 0x00000080 #define SUN4M_INT_E10 0x00080000 - -#if 0 /* These aren't used on the Sparc (yet), but kept for - * future reference, they could come in handy. - */ -#define __STR(x) #x -#define STR(x) __STR(x) - -#define SAVE_ALL "xx" - -#define SAVE_MOST "yy" - -#define RESTORE_MOST "zz" - -#define ACK_FIRST(mask) "aa" - -#define ACK_SECOND(mask) "dummy" - -#define UNBLK_FIRST(mask) "dummy" - -#define UNBLK_SECOND(mask) "dummy" - -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) -#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr) -#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) - -#define BUILD_IRQ(chip,nr,mask) \ -asmlinkage void IRQ_NAME(nr); \ -asmlinkage void FAST_IRQ_NAME(nr); \ -asmlinkage void BAD_IRQ_NAME(nr); \ -asm code comes here -#endif #endif diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/kdebug.h linux/include/asm-sparc/kdebug.h --- v1.3.43/linux/include/asm-sparc/kdebug.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/kdebug.h Sat Nov 25 04:31:56 1995 @@ -1,4 +1,5 @@ -/* kdebug.h: Defines and definitions for debugging the Linux kernel +/* $Id: kdebug.h,v 1.7 1995/11/25 02:31:55 davem Exp $ + * kdebug.h: Defines and definitions for debugging the Linux kernel * under various kernel debuggers. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -13,7 +14,7 @@ */ #define DEBUG_FIRSTVADDR 0xffc00000 -#define DEBUG_LASTVADDR LINUX_OPPROM_BEGVM +#define DEBUG_LASTVADDR LINUX_OPPROM_BEGVM /* Breakpoints are enter through trap table entry 126. So in sparc assembly * if you want to drop into the debugger you do: @@ -53,7 +54,6 @@ /* Use this macro in C-code to enter the debugger. */ extern __inline__ void sp_enter_debugger(void) { - printk("Entering debugger in file %s line %d\n", __FILE__, __LINE__); __asm__ __volatile__("jmpl %0, %%o7\n\t" "nop\n\t" : : "r" (linux_dbvec) : "o7", "memory"); diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/kgdb.h linux/include/asm-sparc/kgdb.h --- v1.3.43/linux/include/asm-sparc/kgdb.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/kgdb.h Sat Nov 25 04:31:58 1995 @@ -0,0 +1,90 @@ +/* $Id: kgdb.h,v 1.6 1995/11/25 02:31:57 davem Exp $ + * kgdb.h: Defines and declarations for serial line source level + * remote debugging of the Linux kernel using gdb. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifndef _SPARC_KGDB_H +#define _SPARC_KGDB_H + +#ifndef __ASSEMBLY__ +/* To init the kgdb engine. */ +extern void set_debug_traps(void); + +/* To enter the debugger explicitly. */ +extern void breakpoint(void); + +/* For convenience we define the format of a kgdb trap breakpoint + * frame here also. + */ +struct kgdb_frame { + unsigned long globals[8]; + unsigned long outs[8]; + unsigned long locals[8]; + unsigned long ins[8]; + unsigned long fpregs[32]; + unsigned long y; + unsigned long psr; + unsigned long wim; + unsigned long tbr; + unsigned long pc; + unsigned long npc; + unsigned long fpsr; + unsigned long cpsr; +}; +#endif /* !(__ASSEMBLY__) */ + +/* Macros for assembly usage of the kgdb breakpoint frame. */ +#define KGDB_G0 0x000 +#define KGDB_G1 0x004 +#define KGDB_G2 0x008 +#define KGDB_G4 0x010 +#define KGDB_G6 0x018 +#define KGDB_I0 0x020 +#define KGDB_I2 0x028 +#define KGDB_I4 0x030 +#define KGDB_I6 0x038 +#define KGDB_Y 0x100 +#define KGDB_PSR 0x104 +#define KGDB_WIM 0x108 +#define KGDB_TBR 0x10c +#define KGDB_PC 0x110 +#define KGDB_NPC 0x114 + +#define SAVE_KGDB_GLOBALS(reg) \ + std %g0, [%reg + STACKFRAME_SZ + KGDB_G0]; \ + std %g2, [%reg + STACKFRAME_SZ + KGDB_G2]; \ + std %g4, [%reg + STACKFRAME_SZ + KGDB_G4]; \ + std %g6, [%reg + STACKFRAME_SZ + KGDB_G6]; + +#define SAVE_KGDB_INS(reg) \ + std %i0, [%reg + STACKFRAME_SZ + KGDB_I0]; \ + std %i2, [%reg + STACKFRAME_SZ + KGDB_I2]; \ + std %i4, [%reg + STACKFRAME_SZ + KGDB_I4]; \ + std %i6, [%reg + STACKFRAME_SZ + KGDB_I6]; + +#define SAVE_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \ + st %reg_y, [%reg + STACKFRAME_SZ + KGDB_Y]; \ + st %reg_psr, [%reg + STACKFRAME_SZ + KGDB_PSR]; \ + st %reg_wim, [%reg + STACKFRAME_SZ + KGDB_WIM]; \ + st %reg_tbr, [%reg + STACKFRAME_SZ + KGDB_TBR]; \ + st %reg_pc, [%reg + STACKFRAME_SZ + KGDB_PC]; \ + st %reg_npc, [%reg + STACKFRAME_SZ + KGDB_NPC]; + +#define LOAD_KGDB_GLOBALS(reg) \ + ld [%reg + STACKFRAME_SZ + KGDB_G1], %g1; \ + ldd [%reg + STACKFRAME_SZ + KGDB_G2], %g2; \ + ldd [%reg + STACKFRAME_SZ + KGDB_G4], %g4; \ + ldd [%reg + STACKFRAME_SZ + KGDB_G6], %g6; + +#define LOAD_KGDB_INS(reg) \ + ldd [%reg + STACKFRAME_SZ + KGDB_I0], %i0; \ + ldd [%reg + STACKFRAME_SZ + KGDB_I2], %i2; \ + ldd [%reg + STACKFRAME_SZ + KGDB_I4], %i4; \ + ldd [%reg + STACKFRAME_SZ + KGDB_I6], %i6; + +#define LOAD_KGDB_SREGS(reg, reg_y_and_psr, reg_pc_and_npc) \ + ldd [%reg + STACKFRAME_SZ + KGDB_Y], %reg_y_and_psr; \ + ldd [%reg + STACKFRAME_SZ + KGDB_PC], %reg_pc_and_npc; + +#endif /* !(_SPARC_KGDB_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/machines.h linux/include/asm-sparc/machines.h --- v1.3.43/linux/include/asm-sparc/machines.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/machines.h Sat Nov 25 04:31:59 1995 @@ -1,4 +1,5 @@ -/* machines.h: Defines for taking apart the machine type value in the +/* $Id: machines.h,v 1.4 1995/11/25 02:31:58 davem Exp $ + * machines.h: Defines for taking apart the machine type value in the * idprom and determining the kind of machine we are on. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/mbus.h linux/include/asm-sparc/mbus.h --- v1.3.43/linux/include/asm-sparc/mbus.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/mbus.h Sat Nov 25 04:32:01 1995 @@ -1,4 +1,5 @@ -/* mbus.h: Various defines for MBUS modules. +/* $Id: mbus.h,v 1.5 1995/11/25 02:32:00 davem Exp $ + * mbus.h: Various defines for MBUS modules. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/memerr.h linux/include/asm-sparc/memerr.h --- v1.3.43/linux/include/asm-sparc/memerr.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/memerr.h Thu Jan 1 02:00:00 1970 @@ -1,32 +0,0 @@ -#ifndef _SPARC_MEMERR_H -#define _SPARC_MEMERR_H - -/* memerr.h: Bit fields in the asynchronous and synchronous memory error - * registers used to determine what 'type' of error has just - * induced a trap. - * - * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) - */ - -/* synchronous error register fields come first... */ - -#define SYNCER_WRITE 0x8000 /* write error... */ -#define SYNCER_INVAL 0x0080 /* invalid page access was attempted */ -#define SYNCER_PROT 0x0040 /* protection violation */ -#define SYNCER_TIMEOUT 0x0020 /* mem-bus access timeout (mem does not exist). */ -#define SYNCER_SBUSERR 0x0010 /* same as above, but for an SBUS access */ -#define SYNCER_MEMERR 0x0008 /* Bus parity error, lose lose... panic time */ -#define SYNCER_SZERR 0x0002 /* an attempted access was of BAD size, whoops */ -#define SYNCER_WATCHDOG 0x0001 /* although we never see these, the prom will.. */ - -/* asynchronous error bits go here */ - -#define ASYNCER_WBINVAL 0x80 /* situation arose where the cache tried to write - * back a page for which the valid bit was not set - * within the mmu. This is due to bad mm kernel bugs. - */ - -#define ASYNCER_TIMEOUT 0x20 /* mem-access bus timeout... */ -#define ASYNCER_DVMAERR 0x10 /* dvma transfer to/from memory bombed... */ - -#endif /* _SPARC_MEMERR_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/memreg.h linux/include/asm-sparc/memreg.h --- v1.3.43/linux/include/asm-sparc/memreg.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/memreg.h Sat Nov 25 04:32:02 1995 @@ -1,3 +1,4 @@ +/* $Id: memreg.h,v 1.4 1995/11/25 02:32:02 davem Exp $ */ #ifndef _SPARC_MEMREG_H #define _SPARC_MEMREG_H /* memreg.h: Definitions of the values found in the synchronous @@ -11,28 +12,25 @@ * normal page faults. */ -#define SUN4C_SYNC_WDRESET 0x1 /* watchdog reset, only the prom sees this */ -#define SUN4C_SYNC_SIZE 0x2 /* bad access size? whuz this? */ -#define SUN4C_SYNC_PARITY 0x8 /* bad ram chips caused a parity error */ -#define SUN4C_SYNC_SBUS 0x10 /* the SBUS had some problems... */ -#define SUN4C_SYNC_NOMEM 0x20 /* translation pointed to non-existant ram */ -#define SUN4C_SYNC_PROT 0x40 /* access violated pte protection settings */ -#define SUN4C_SYNC_NPRESENT 0x80 /* pte said that page was not present */ +#define SUN4C_SYNC_WDRESET 0x0001 /* watchdog reset */ +#define SUN4C_SYNC_SIZE 0x0002 /* bad access size? whuz this? */ +#define SUN4C_SYNC_PARITY 0x0008 /* bad ram chips caused a parity error */ +#define SUN4C_SYNC_SBUS 0x0010 /* the SBUS had some problems... */ +#define SUN4C_SYNC_NOMEM 0x0020 /* translation to non-existant ram */ +#define SUN4C_SYNC_PROT 0x0040 /* access violated pte protections */ +#define SUN4C_SYNC_NPRESENT 0x0080 /* pte said that page was not present */ #define SUN4C_SYNC_BADWRITE 0x8000 /* while writing something went bogus */ +#define SUN4C_SYNC_BOLIXED \ + (SUN4C_SYNC_WDRESET|SUN4C_SYNC_SIZE|SUN4C_SYNC_SBUS|SUN4C_SYNC_NOMEM) + /* Now the asynchronous error codes, these are almost always produced * by the cache writing things back to memory and getting a bad translation. * Bad DVMA transactions can cause these faults too. */ -#define SUN4C_ASYNC_BADDVMA 0x10 /* error during DVMA access */ -#define SUN4C_ASYNC_NOMEM 0x20 /* write back pointed to bad phys addr */ -#define SUN4C_ASYNC_BADWB 0x80 /* write back points to non-present page */ - -/* These are the values passed as the first arguement to the fault - * entry c-code from the assembly entry points. - */ -#define FAULT_ASYNC 0x0 -#define FAULT_SYNC 0x1 +#define SUN4C_ASYNC_BADDVMA 0x0010 /* error during DVMA access */ +#define SUN4C_ASYNC_NOMEM 0x0020 /* write back pointed to bad phys addr */ +#define SUN4C_ASYNC_BADWB 0x0080 /* write back points to non-present page */ #endif /* !(_SPARC_MEMREG_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/mman.h linux/include/asm-sparc/mman.h --- v1.3.43/linux/include/asm-sparc/mman.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/mman.h Sat Nov 25 04:32:04 1995 @@ -0,0 +1,45 @@ +/* $Id: mman.h,v 1.5 1995/11/25 02:32:03 davem Exp $ */ +#ifndef __SPARC_MMAN_H__ +#define __SPARC_MMAN_H__ + +/* SunOS'ified... */ + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_NONE 0x0 /* page can not be accessed */ + +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ +#define MAP_TYPE 0x0f /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ +#define MAP_RENAME MAP_ANONYMOUS /* In SunOS terminology */ +#define MAP_NORESERVE 0x40 /* don't reserve swap pages */ +#define MAP_INHERIT 0x80 /* SunOS doesn't do this, but... */ +#define MAP_LOCKED 0x100 /* lock the mapping */ +#define _MAP_NEW 0x80000000 /* Binary compatability is fun... */ + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as a executable */ + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */ +#define MCL_FUTURE 0x4000 /* lock all additions to address space */ + +/* XXX Need to add flags to SunOS's mctl, mlockall, and madvise system + * XXX calls. + */ + +/* SunOS sys_mctl() stuff... */ +#define MC_SYNC 1 /* Sync pages in memory with storage (usu. a file) */ +#define MC_LOCK 2 /* Lock pages into core ram, do not allow swapping of them */ +#define MC_UNLOCK 3 /* Unlock pages locked via previous mctl() with MC_LOCK arg */ +#define MC_LOCKAS 5 /* Lock an entire address space of the calling process */ +#define MC_UNLOCKAS 6 /* Unlock entire address space of calling process */ + +#endif /* __SPARC_MMAN_H__ */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/mostek.h linux/include/asm-sparc/mostek.h --- v1.3.43/linux/include/asm-sparc/mostek.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/mostek.h Sat Nov 25 04:32:06 1995 @@ -1,4 +1,5 @@ -/* mostek.h: Describes the various Mostek time of day clock registers. +/* $Id: mostek.h,v 1.4 1995/11/25 02:32:05 davem Exp $ + * mostek.h: Describes the various Mostek time of day clock registers. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/mp.h linux/include/asm-sparc/mp.h --- v1.3.43/linux/include/asm-sparc/mp.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/mp.h Sat Nov 25 04:32:08 1995 @@ -1,4 +1,5 @@ -/* mp.h: Multiprocessing definitions for the Sparc. +/* $Id: mp.h,v 1.2 1995/11/25 02:32:06 davem Exp $ + * mp.h: Multiprocessing definitions for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/mpmbox.h linux/include/asm-sparc/mpmbox.h --- v1.3.43/linux/include/asm-sparc/mpmbox.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/mpmbox.h Sat Nov 25 04:32:10 1995 @@ -1,4 +1,5 @@ -/* mpmbox.h: Interface and defines for the OpenProm mailbox +/* $Id: mpmbox.h,v 1.3 1995/11/25 02:32:09 davem Exp $ + * mpmbox.h: Interface and defines for the OpenProm mailbox * facilities for MP machines under Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/mxcc.h linux/include/asm-sparc/mxcc.h --- v1.3.43/linux/include/asm-sparc/mxcc.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/mxcc.h Sat Nov 25 04:32:12 1995 @@ -1,4 +1,5 @@ -/* mxcc.h: Definitions of the Viking MXCC registers +/* $Id: mxcc.h,v 1.2 1995/11/25 02:32:11 davem Exp $ + * mxcc.h: Definitions of the Viking MXCC registers * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/openprom.h linux/include/asm-sparc/openprom.h --- v1.3.43/linux/include/asm-sparc/openprom.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/openprom.h Sat Nov 25 04:32:14 1995 @@ -1,3 +1,4 @@ +/* $Id: openprom.h,v 1.15 1995/11/25 02:32:13 davem Exp $ */ #ifndef __SPARC_OPENPROM_H #define __SPARC_OPENPROM_H @@ -7,297 +8,176 @@ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -/* In the v0 interface of the openboot prom we could traverse a nice - * little list structure to figure out where in vm-space the prom had - * mapped itself and how much space it was taking up. In the v2 prom - * interface we have to rely on 'magic' values. :-( Most of the machines - * I have checked on have the prom mapped here all the time though. - */ - +/* Imperical constants... */ #define KADB_DEBUGGER_BEGVM 0xffc00000 /* Where kern debugger is in virt-mem */ - #define LINUX_OPPROM_BEGVM 0xffd00000 #define LINUX_OPPROM_ENDVM 0xfff00000 - #define LINUX_OPPROM_MAGIC 0x10010407 #ifndef __ASSEMBLY__ -/* The device functions structure for the v0 prom. Nice and neat, open, - * close, read & write divvied up between net + block + char devices. We - * also have a seek routine only usable for block devices. The divide - * and conquer strategy of this struct becomes unnecessary for v2. - * - * V0 device names are limited to two characters, 'sd' for scsi-disk, - * 'le' for local-ethernet, etc. Note that it is technically possible - * to boot a kernel off of a tape drive and use the tape as the root - * partition! In order to do this you have to have 'magic' formatted - * tapes from Sun supposedly :-) - */ - +/* V0 prom device operations. */ struct linux_dev_v0_funcs { - int (*v0_devopen)(char *device_str); - int (*v0_devclose)(int dev_desc); - int (*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, char* buf); - int (*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, char* buf); - int (*v0_wrnetdev)(int dev_desc, int num_bytes, char* buf); - int (*v0_rdnetdev)(int dev_desc, int num_bytes, char* buf); - int (*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, char* buf); - int (*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, char* buf); - int (*v0_seekdev)(int dev_desc, long logical_offst, int from); + int (*v0_devopen)(char *device_str); + int (*v0_devclose)(int dev_desc); + int (*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, char *buf); + int (*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, char *buf); + int (*v0_wrnetdev)(int dev_desc, int num_bytes, char *buf); + int (*v0_rdnetdev)(int dev_desc, int num_bytes, char *buf); + int (*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, char *buf); + int (*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, char *buf); + int (*v0_seekdev)(int dev_desc, long logical_offst, int from); }; -/* The OpenBoot Prom device operations for version-2 interfaces are both - * good and bad. They now allow you to address ANY device whatsoever - * that is in the machine via these funny "device paths". They look like - * this: - * - * "/sbus/esp@0,0xf004002c/sd@3,1" - * - * You can basically reference any device on the machine this way, and - * you pass this string to the v2 dev_ops. Producing these strings all - * the time can be a pain in the rear after a while. Why v2 has memory - * allocations in here are beyond me. Perhaps they figure that if you - * are going to use only the prom's device drivers then your memory - * management is either non-existent or pretty sad. :-) - */ - +/* V2 and later prom device operations. */ struct linux_dev_v2_funcs { - int (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */ - - /* "dumb" prom memory management routines, probably - * only safe to use for mapping device address spaces... - */ - - char* (*v2_dumb_mem_alloc)(char* va, unsigned sz); - void (*v2_dumb_mem_free)(char* va, unsigned sz); - - /* "dumb" mmap() munmap(), copy on write? what's that? */ - char* (*v2_dumb_mmap)(char* virta, int which_io, unsigned paddr, unsigned sz); - void (*v2_dumb_munmap)(char* virta, unsigned size); - - /* Basic Operations, self-explanatory */ - int (*v2_dev_open)(char *devpath); - void (*v2_dev_close)(int d); - int (*v2_dev_read)(int d, char* buf, int nbytes); - int (*v2_dev_write)(int d, char* buf, int nbytes); - void (*v2_dev_seek)(int d, int hi, int lo); + int (*v2_inst2pkg)(int d); /* Convert ihandle to phandle */ + char * (*v2_dumb_mem_alloc)(char *va, unsigned sz); + void (*v2_dumb_mem_free)(char *va, unsigned sz); + + /* To map devices into virtual I/O space. */ + char * (*v2_dumb_mmap)(char *virta, int which_io, unsigned paddr, unsigned sz); + void (*v2_dumb_munmap)(char *virta, unsigned size); + + int (*v2_dev_open)(char *devpath); + void (*v2_dev_close)(int d); + int (*v2_dev_read)(int d, char *buf, int nbytes); + int (*v2_dev_write)(int d, char *buf, int nbytes); + void (*v2_dev_seek)(int d, int hi, int lo); /* Never issued (multistage load support) */ - void (*v2_wheee2)(void); - void (*v2_wheee3)(void); + void (*v2_wheee2)(void); + void (*v2_wheee3)(void); }; -/* Just like the device ops, they slightly screwed up the mem-list - * from v0 to v2. Probably easier on the prom-writer dude, sucks for - * us though. See above comment about prom-vm mapped address space - * magic numbers. :-( - */ - struct linux_mlist_v0 { - struct linux_mlist_v0 *theres_more; - char* start_adr; + struct linux_mlist_v0 *theres_more; + char *start_adr; unsigned num_bytes; }; -/* The linux_mlist_v0's are pointed to by this structure. One list - * per description. This means one list for total physical memory, - * one for prom's address mapping, and one for physical mem left after - * the kernel is loaded. - */ - struct linux_mem_v0 { - struct linux_mlist_v0 **v0_totphys; /* all of physical */ - struct linux_mlist_v0 **v0_prommap; /* addresses map'd by prom */ - struct linux_mlist_v0 **v0_available; /* what phys. is left over */ + struct linux_mlist_v0 **v0_totphys; + struct linux_mlist_v0 **v0_prommap; + struct linux_mlist_v0 **v0_available; /* What we can use */ }; /* Arguments sent to the kernel from the boot prompt. */ - struct linux_arguments_v0 { - char *argv[8]; /* argv format for boot string */ - char args[100]; /* string space */ - char boot_dev[2]; /* e.g., "sd" for `b sd(...' */ - int boot_dev_ctrl; /* controller # */ - int boot_dev_unit; /* unit # */ - int dev_partition; /* partition # */ - char *kernel_file_name; /* kernel to boot, e.g., "vmunix" */ - void *aieee1; /* give me some time :> */ + char *argv[8]; + char args[100]; + char boot_dev[2]; + int boot_dev_ctrl; + int boot_dev_unit; + int dev_partition; + char *kernel_file_name; + void *aieee1; /* XXX */ }; -/* Prom version-2 gives us the raw strings for boot arguments and - * boot device path. We also get the stdin and stdout file pseudo - * descriptors for use with the mungy v2 device functions. - */ +/* V2 and up boot things. */ struct linux_bootargs_v2 { - char **bootpath; /* V2: Path to boot device */ - char **bootargs; /* V2: Boot args */ - int *fd_stdin; /* V2: Stdin descriptor */ - int *fd_stdout; /* V2: Stdout descriptor */ + char **bootpath; + char **bootargs; + int *fd_stdin; + int *fd_stdout; }; -/* This is the actual Prom Vector from which everything else is accessed - * via struct and function pointers, etc. The prom when it loads us into - * memory plops a pointer to this master structure in register %o0 before - * it jumps to the kernel start address. I will update this soon to cover - * the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-) - */ - +/* The top level PROM vector. */ struct linux_romvec { /* Version numbers. */ - unsigned int pv_magic_cookie; /* Magic Mushroom... */ - unsigned int pv_romvers; /* iface vers (0, 2, or 3) */ - unsigned int pv_plugin_revision; /* revision relative to above vers */ - unsigned int pv_printrev; /* print revision */ - - /* Version 0 memory descriptors (see below). */ - struct linux_mem_v0 pv_v0mem; /* V0: Memory description lists. */ + unsigned int pv_magic_cookie; + unsigned int pv_romvers; + unsigned int pv_plugin_revision; + unsigned int pv_printrev; + + /* Version 0 memory descriptors. */ + struct linux_mem_v0 pv_v0mem; - /* Node operations (see below). */ - struct linux_nodeops *pv_nodeops; /* node functions, gets device data */ + /* Node operations. */ + struct linux_nodeops *pv_nodeops; - char **pv_bootstr; /* Boot command, eg sd(0,0,0)vmunix */ + char **pv_bootstr; + struct linux_dev_v0_funcs pv_v0devops; - struct linux_dev_v0_funcs pv_v0devops; /* V0: device ops */ - - /* - * PROMDEV_* cookies. I fear these may vanish in lieu of fd0/fd1 - * (see below) in future PROMs, but for now they work fine. - */ - char *pv_stdin; /* stdin cookie */ - char *pv_stdout; /* stdout cookie */ + char *pv_stdin; + char *pv_stdout; #define PROMDEV_KBD 0 /* input from keyboard */ #define PROMDEV_SCREEN 0 /* output to screen */ #define PROMDEV_TTYA 1 /* in/out to ttya */ #define PROMDEV_TTYB 2 /* in/out to ttyb */ /* Blocking getchar/putchar. NOT REENTRANT! (grr) */ - int (*pv_getchar)(void); - void (*pv_putchar)(int ch); + int (*pv_getchar)(void); + void (*pv_putchar)(int ch); - /* Non-blocking variants that return -1 on error. */ - int (*pv_nbgetchar)(void); - int (*pv_nbputchar)(int ch); + /* Non-blocking variants. */ + int (*pv_nbgetchar)(void); + int (*pv_nbputchar)(int ch); - /* Put counted string (can be very slow). */ - void (*pv_putstr)(char *str, int len); + void (*pv_putstr)(char *str, int len); /* Miscellany. */ - void (*pv_reboot)(char *bootstr); - void (*pv_printf)(const char *fmt, ...); - void (*pv_abort)(void); /* BREAK key abort */ - int *pv_ticks; /* milliseconds since last reset */ - void (*pv_halt)(void); /* End the show */ - void (**pv_synchook)(void); /* "sync" ptr to function */ - - /* - * This eval's a FORTH string. Unfortunately, its interface - * changed between V0 and V2, which gave us much pain. - */ + void (*pv_reboot)(char *bootstr); + void (*pv_printf)(const char *fmt, ...); + void (*pv_abort)(void); + int *pv_ticks; + void (*pv_halt)(void); + void (**pv_synchook)(void); + + /* Evaluate a forth string, not different proto for V0 and V2->up. */ union { - void (*v0_eval)(int len, char *str); - void (*v2_eval)(char *str); + void (*v0_eval)(int len, char *str); + void (*v2_eval)(char *str); } pv_fortheval; - struct linux_arguments_v0 **pv_v0bootargs; /* V0: Boot args */ + struct linux_arguments_v0 **pv_v0bootargs; - /* Extract Ethernet address from network device. */ - unsigned int (*pv_enaddr)(int d, char *enaddr); + /* Get ether address. */ + unsigned int (*pv_enaddr)(int d, char *enaddr); - struct linux_bootargs_v2 pv_v2bootargs; /* V2: Boot args+std-in/out */ - struct linux_dev_v2_funcs pv_v2devops; /* V2: device operations */ + struct linux_bootargs_v2 pv_v2bootargs; + struct linux_dev_v2_funcs pv_v2devops; - int filler[15]; - - /* - * The following is machine-dependent. - * - * The sun4c needs a PROM function to set a PMEG for another - * context, so that the kernel can map itself in all contexts. - * It is not possible simply to set the context register, because - * contexts 1 through N may have invalid translations for the - * current program counter. The hardware has a mode in which - * all memory references go to the PROM, so the PROM can do it - * easily. - */ - void (*pv_setctxt)(int ctxt, char* va, int pmeg); + int filler[15]; + + /* This one is sun4c/sun4 only. */ + void (*pv_setctxt)(int ctxt, char *va, int pmeg); /* Prom version 3 Multiprocessor routines. This stuff is crazy. * No joke. Calling these when there is only one cpu probably * crashes the machine, have to test this. :-) - */ + */ /* v3_cpustart() will start the cpu 'whichcpu' in mmu-context * 'thiscontext' executing at address 'prog_counter' - */ - + */ int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr, - int thiscontext, char* prog_counter); + int thiscontext, char *prog_counter); /* v3_cpustop() will cause cpu 'whichcpu' to stop executing * until a resume cpu call is made. */ - int (*v3_cpustop)(unsigned int whichcpu); /* v3_cpuidle() will idle cpu 'whichcpu' until a stop or * resume cpu call is made. */ - int (*v3_cpuidle)(unsigned int whichcpu); /* v3_cpuresume() will resume processor 'whichcpu' executing * starting with whatever 'pc' and 'npc' were left at the * last 'idle' or 'stop' call. */ - int (*v3_cpuresume)(unsigned int whichcpu); - }; -/* - * In addition to the global stuff defined in the PROM vectors above, - * the PROM has quite a collection of `nodes'. A node is described by - * an integer---these seem to be internal pointers, actually---and the - * nodes are arranged into an N-ary tree. Each node implements a fixed - * set of functions, as described below. The first two deal with the tree - * structure, allowing traversals in either breadth- or depth-first fashion. - * The rest deal with `properties'. - * - * A node property is simply a name/value pair. The names are C strings - * (NUL-terminated); the values are arbitrary byte strings (counted strings). - * Many values are really just C strings. Sometimes these are NUL-terminated, - * sometimes not, depending on the the interface version; v0 seems to - * terminate and v2 not. Many others are simply integers stored as four - * bytes in machine order: you just get them and go. The third popular - * format is an `address', which is made up of one or more sets of three - * integers as defined below. - * - * One uses these functions to traverse the device tree to see what devices - * this machine has attached to it. - * - * N.B.: for the `next' functions, next(0) = first, and next(last) = 0. - * Whoever designed this part had good taste. On the other hand, these - * operation vectors are global, rather than per-node, yet the pointers - * are not in the openprom vectors but rather found by indirection from - * there. So the taste balances out. - */ - +/* Routines for traversing the prom device tree. */ struct linux_nodeops { - /* - * Tree traversal. - */ - int (*no_nextnode)(int node); /* next(node) */ - int (*no_child)(int node); /* first child */ - - /* - * Property functions. Proper use of getprop requires calling - * proplen first to make sure it fits. Kind of a pain, but no - * doubt more convenient for the PROM coder. - */ - int (*no_proplen)(int node, char* name); - int (*no_getprop)(int node, char* name, char* val); - int (*no_setprop)(int node, char* name, char* val, int len); - char* (*no_nextprop)(int node, char* name); + int (*no_nextnode)(int node); + int (*no_child)(int node); + int (*no_proplen)(int node, char *name); + int (*no_getprop)(int node, char *name, char *val); + int (*no_setprop)(int node, char *name, char *val, int len); + char * (*no_nextprop)(int node, char *name); }; /* More fun PROM structures for device probing. */ @@ -306,23 +186,23 @@ #define PROMINTR_MAX 15 struct linux_prom_registers { - int which_io; /* is this in OBIO space? */ - char *phys_addr; /* The physical address of this register */ - int reg_size; /* How many bytes does this register take up? */ + int which_io; /* is this in OBIO space? */ + char *phys_addr; /* The physical address of this register */ + int reg_size; /* How many bytes does this register take up? */ }; struct linux_prom_irqs { - int pri; /* IRQ priority */ - int vector; /* This is foobar, what does it do? */ + int pri; /* IRQ priority */ + int vector; /* This is foobar, what does it do? */ }; /* Element of the "ranges" vector */ struct linux_prom_ranges { - unsigned int ot_child_space; - unsigned int ot_child_base; /* Bus feels this */ - unsigned int ot_parent_space; - unsigned int ot_parent_base; /* CPU looks from here */ - unsigned int or_size; + unsigned int ot_child_space; + unsigned int ot_child_base; /* Bus feels this */ + unsigned int ot_parent_space; + unsigned int ot_parent_base; /* CPU looks from here */ + unsigned int or_size; }; #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h --- v1.3.43/linux/include/asm-sparc/oplib.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/oplib.h Sat Nov 25 04:32:16 1995 @@ -1,4 +1,5 @@ -/* oplib.h: Describes the interface and available routines in the +/* $Id: oplib.h,v 1.5 1995/11/25 02:32:14 davem Exp $ + * oplib.h: Describes the interface and available routines in the * Linux Prom library. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -40,7 +41,7 @@ /* You must call prom_init() before using any of the library services, * preferably as early as possible. Pass it the romvec pointer. */ -extern int prom_init(struct linux_romvec *rom_ptr); +extern void prom_init(struct linux_romvec *rom_ptr); /* Boot argument acquisition, returns the boot command line string. */ extern char *prom_getbootargs(void); @@ -148,6 +149,28 @@ /* Prom's internal printf routine, don't use in kernel/boot code. */ void prom_printf(char *fmt, ...); + +/* Query for input device type */ + +enum prom_input_device { + PROMDEV_IKBD, /* input from keyboard */ + PROMDEV_ITTYA, /* input from ttya */ + PROMDEV_ITTYB, /* input from ttyb */ + PROMDEV_I_UNK, +}; + +extern enum prom_input_device prom_query_input_device(void); + +/* Query for output device type */ + +enum prom_output_device { + PROMDEV_OSCREEN, /* to screen */ + PROMDEV_OTTYA, /* to ttya */ + PROMDEV_OTTYB, /* to ttyb */ + PROMDEV_O_UNK, +}; + +extern enum prom_output_device prom_query_output_device(void); /* Multiprocessor operations... */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h --- v1.3.43/linux/include/asm-sparc/page.h Wed Nov 8 07:11:41 1995 +++ linux/include/asm-sparc/page.h Sat Nov 25 04:32:17 1995 @@ -1,4 +1,5 @@ -/* page.h: Various defines and such for MMU operations on the Sparc for +/* $Id: page.h,v 1.22 1995/11/25 02:32:16 davem Exp $ + * page.h: Various defines and such for MMU operations on the Sparc for * the Linux kernel. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -12,15 +13,17 @@ #include /* for KERNBASE */ #define PAGE_SHIFT 12 /* This is the virtual page... */ -#define PAGE_OFFSET KERNBASE +#define PAGE_OFFSET KERNBASE #define PAGE_SIZE (1 << PAGE_SHIFT) /* to mask away the intra-page address bits */ -#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PAGE_MASK (~(PAGE_SIZE-1)) #ifdef __KERNEL__ #ifndef __ASSEMBLY__ +#include + /* The following structure is used to hold the physical * memory configuration of the machine. This is filled in * probe_memory() and is later used by mem_init() to set up @@ -86,7 +89,12 @@ */ extern void (*invalidate)(void); -extern void (*set_pte)(pte_t *ptep, pte_t entry); + +/* Certain architectures need to do special things when pte's + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +extern void (*set_pte)(pte_t *pteptr, pte_t pteval); /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) @@ -94,9 +102,7 @@ /* We now put the free page pool mapped contiguously in high memory above * the kernel. */ -#define MAP_NR(addr) ((((unsigned long)addr) - PAGE_OFFSET) >> PAGE_SHIFT) -#define MAP_PAGE_RESERVED (1<<15) - +#define MAP_NR(addr) ((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT) #endif /* !(__ASSEMBLY__) */ @@ -249,17 +255,18 @@ { register unsigned long entry; - __asm__ __volatile__("lduba [%1] %2, %0" : + __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : "=r" (entry) : "r" (addr), "i" (ASI_SEGMAP)); - return (entry&0xff); + return entry; } extern __inline__ void put_segmap(unsigned long addr, unsigned long entry) { - __asm__ __volatile__("stba %1, [%0] %2" : : "r" (addr), "r" (entry&0xff), + __asm__ __volatile__("\n\tstba %1, [%0] %2\n\t" : : + "r" (addr), "r" (entry), "i" (ASI_SEGMAP)); return; @@ -269,7 +276,7 @@ { register unsigned long entry; - __asm__ __volatile__("lda [%1] %2, %0" : + __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : "=r" (entry) : "r" (addr), "i" (ASI_PTE)); return entry; @@ -277,27 +284,33 @@ extern __inline__ void put_pte(unsigned long addr, unsigned long entry) { - __asm__ __volatile__("sta %1, [%0] %2" : : + __asm__ __volatile__("\n\tsta %1, [%0] %2\n\t" : : "r" (addr), "r" (entry), "i" (ASI_PTE)); return; } -extern void (*switch_to_context)(int); +extern void (*switch_to_context)(void *tsk); extern __inline__ int get_context(void) { register int ctx; - __asm__ __volatile__("lduba [%1] %2, %0" : + __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : "=r" (ctx) : "r" (AC_CONTEXT), "i" (ASI_CONTROL)); return ctx; } -typedef unsigned short mem_map_t; +extern __inline__ int set_context(int ctx) +{ + __asm__ __volatile__("\n\tstba %0, [%1] %2\n\t" : : + "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL)); + + return ctx; +} #endif /* __ASSEMBLY__ */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/param.h linux/include/asm-sparc/param.h --- v1.3.43/linux/include/asm-sparc/param.h Thu Feb 2 08:42:35 1995 +++ linux/include/asm-sparc/param.h Sat Nov 25 04:32:19 1995 @@ -1,3 +1,4 @@ +/* $Id: param.h,v 1.3 1995/11/25 02:32:18 davem Exp $ */ #ifndef _ASMSPARC_PARAM_H #define _ASMSPARC_PARAM_H @@ -5,7 +6,7 @@ #define HZ 100 #endif -#define EXEC_PAGESIZE 4096 +#define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */ #ifndef NGROUPS #define NGROUPS 32 diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/pconf.h linux/include/asm-sparc/pconf.h --- v1.3.43/linux/include/asm-sparc/pconf.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/pconf.h Sat Nov 25 04:32:21 1995 @@ -0,0 +1,25 @@ +/* $Id: pconf.h,v 1.2 1995/11/25 02:32:20 davem Exp $ + * pconf.h: pathconf() and fpathconf() defines for SunOS + * system call compatability. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_PCONF_H +#define _SPARC_PCONF_H + +#include +#include + +#define _PCONF_LINK 1 /* Max number of links to an object */ +#define _PCONF_CANON 2 /* TTY input buffer line size */ +#define _PCONF_INPUT 3 /* Biggest packet a tty can inbibe at once */ +#define _PCONF_NAME 4 /* Filename length max */ +#define _PCONF_PATH 5 /* Max size of a pathname */ +#define _PCONF_PIPE 6 /* Buffer size for a pipe */ +#define _PCONF_CHRESTRICT 7 /* Can only root chown files? */ +#define _PCONF_NOTRUNC 8 /* Are pathnames truncated if too big? */ +#define _PCONF_VDISABLE 9 /* Magic char to disable special tty chars */ +#define _PCONF_MAXPCONF 9 + +#endif /* !(_SPARC_PCONF_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v1.3.43/linux/include/asm-sparc/pgtable.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/pgtable.h Sat Nov 25 04:32:23 1995 @@ -1,3 +1,4 @@ +/* $Id: pgtable.h,v 1.25 1995/11/25 02:32:22 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -11,9 +12,26 @@ #include #include #include +#include +#include extern void load_mmu(void); +/* mmu-specific process creation/cloning/etc hooks. */ +extern void (*mmu_exit_hook)(void *); +extern void (*mmu_fork_hook)(void *, unsigned long); +extern void (*mmu_release_hook)(void *); +extern void (*mmu_flush_hook)(void *); +extern void (*mmu_task_cacheflush)(void *); + +/* Routines for data transfer buffers. */ +extern char *(*mmu_lockarea)(char *, unsigned long); +extern void (*mmu_unlockarea)(char *, unsigned long); + +/* Routines for getting a dvma scsi buffer. */ +extern char *(*mmu_get_scsi_buffer)(char *, unsigned long); +extern void (*mmu_release_scsi_buffer)(char *, unsigned long); + extern unsigned int pmd_shift; extern unsigned int pmd_size; extern unsigned int pmd_mask; @@ -67,69 +85,38 @@ /* Page table for 0-4MB for everybody, on the Sparc this * holds the same as on the i386. */ -extern unsigned long pg0[1024]; +extern pte_t pg0[1024]; extern unsigned long ptr_in_current_pgd; /* the no. of pointers that fit on a page: this will go away */ #define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*)) -/* I define these like the i386 does because the check for text or data fault - * is done at trap time by the low level handler. Maybe I can set these bits - * then once determined. I leave them like this for now though. - */ -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED - -/* Contexts on the Sparc. */ -#define MAX_CTXS 256 -#define NO_CTX 0xffff /* In tss.context means task has no context currently */ -extern struct task_struct * ctx_tasks[MAX_CTXS]; -extern int ctx_tasks_last_frd; +/* Here is a trick, since mmap.c need the initializer elements for + * protection_map[] to be constant at compile time, I set the following + * to all zeros. I set it to the real values after I link in the + * appropriate MMU page table routines at boot time. + */ +#define __P000 __pgprot(0) +#define __P001 __pgprot(0) +#define __P010 __pgprot(0) +#define __P011 __pgprot(0) +#define __P100 __pgprot(0) +#define __P101 __pgprot(0) +#define __P110 __pgprot(0) +#define __P111 __pgprot(0) + +#define __S000 __pgprot(0) +#define __S001 __pgprot(0) +#define __S010 __pgprot(0) +#define __S011 __pgprot(0) +#define __S100 __pgprot(0) +#define __S101 __pgprot(0) +#define __S110 __pgprot(0) +#define __S111 __pgprot(0) extern int num_contexts; -/* This routine allocates a new context. And 'p' must not be 'current'! */ -extern inline int alloc_mmu_ctx(struct task_struct *p) -{ - int i; - - for(i=0; itss.context = i; - ctx_tasks[i] = p; - return i; - } - - /* Have to free one up */ - ctx_tasks_last_frd++; - if(ctx_tasks_last_frd >= num_contexts) ctx_tasks_last_frd=0; - /* Right here is where we invalidate the user mappings that were - * present. TODO - */ - ctx_tasks[ctx_tasks_last_frd]->tss.context = NO_CTX; - ctx_tasks[ctx_tasks_last_frd] = p; - p->tss.context = ctx_tasks_last_frd; - return ctx_tasks_last_frd; -} - /* * BAD_PAGETABLE is used when we need a bogus page-table, while * BAD_PAGE is used for a bogus page. @@ -142,7 +129,6 @@ extern unsigned long __zero_page(void); - #define BAD_PAGETABLE __bad_pagetable() #define BAD_PAGE __bad_page() #define ZERO_PAGE __zero_page() @@ -153,7 +139,6 @@ /* to align the pointer to a pointer address */ #define PTR_MASK (~(sizeof(void*)-1)) - #define SIZEOF_PTR_LOG2 2 extern unsigned long (*pte_page)(pte_t); @@ -168,15 +153,12 @@ * all the pages since not all can be loaded at once in the mmu. * * Actually on the SRMMU things do work exactly like the i386, the - * page tables live in real physical ram, no funky TLB buisness. But - * we have to do lots of flushing. And we have to update the root level - * page table pointer for this process if it has a context. + * page tables live in real physical ram, no funky TLB buisness. */ extern void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir); -#define SET_PAGE_DIR(tsk,pgdir) \ -do { sparc_update_rootmmu_dir(tsk, pgdir); } while (0) +#define SET_PAGE_DIR(tsk,pgdir) sparc_update_rootmmu_dir(tsk, pgdir) /* to find an entry in a page-table */ #define PAGE_PTR(address) \ @@ -234,12 +216,12 @@ */ extern pte_t (*mk_pte)(unsigned long, pgprot_t); -extern void (*pgd_set)(pgd_t *, pte_t *); +extern void (*pgd_set)(pgd_t *, pmd_t *); extern pte_t (*pte_modify)(pte_t, pgprot_t); /* to find an entry in a page-table-directory */ -extern pgd_t * (*pgd_offset)(struct task_struct *, unsigned long); +extern pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long); /* Find an entry in the second-level page table.. */ extern pmd_t * (*pmd_offset)(pgd_t *, unsigned long); @@ -278,75 +260,45 @@ extern void (*pgd_free)(pgd_t *); -/* A page directory on the sun4c needs 16k, thus we request an order of - * two. - * - * I need 16k for a sun4c page table, so I use kmalloc since kmalloc_init() - * is called before pgd_alloc ever is (I think). - */ - extern pgd_t * (*pgd_alloc)(void); +/* Fault handler stuff... */ +#define FAULT_CODE_PROT 0x1 +#define FAULT_CODE_WRITE 0x2 +#define FAULT_CODE_USER 0x4 +extern int (*get_fault_info)(unsigned long *, unsigned long *, unsigned long); +extern void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte); + extern int invalid_segment; -/* Sun4c specific routines. They can stay inlined. */ -extern inline int alloc_sun4c_pseg(void) -{ - int oldseg, i; - /* First see if any are free already */ - for(i=0; ioldseg) ? phys_seg_life[i] : oldseg; - } - phys_seg_life[oldseg]=PSEG_BORN; - return oldseg; -} +#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) +#define SWP_OFFSET(entry) ((entry) >> 8) +#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8)) + +struct ctx_list { + struct ctx_list *next; + struct ctx_list *prev; + unsigned char ctx_number; + struct task_struct *ctx_task; /* Who has it now, if not free */ +}; + +extern struct ctx_list *ctx_list_pool; /* Dynamically allocated */ +extern struct ctx_list ctx_free; /* Head of free list */ +extern struct ctx_list ctx_used; /* Head of used contexts list */ -/* Age all psegs except pseg_skip */ -extern inline void age_sun4c_psegs(int pseg_skip) +extern inline void remove_from_ctx_list(struct ctx_list *entry) { - int i; - - for(i=0; inext->prev = entry->prev; + entry->prev->next = entry->next; } -/* - * This is only ever called when the sun4c page fault routines run - * so we can keep this here as the srmmu code will never get to it. - */ -extern inline void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +extern inline void add_to_ctx_list(struct ctx_list *head, struct ctx_list *entry) { - unsigned long clr_addr; - int segmap; - - segmap = (int) get_segmap(address & SUN4C_REAL_PGDIR_MASK); - if(segmap == invalid_segment) { - segmap = alloc_sun4c_pseg(); - put_segmap((address & SUN4C_REAL_PGDIR_MASK), segmap); - phys_seg_map[segmap] = PSEG_USED; - - /* We got a segmap, clear all the pte's in it. */ - for(clr_addr=(address&SUN4C_REAL_PGDIR_MASK); clr_addr<((address&SUN4C_REAL_PGDIR_MASK) + SUN4C_REAL_PGDIR_SIZE); - clr_addr+=PAGE_SIZE) - put_pte(clr_addr, 0); - } - - /* Do aging */ - age_sun4c_psegs(segmap); - put_pte((address & PAGE_MASK), pte_val(pte)); - return; - + entry->next = head; + (entry->prev = head->prev)->next = entry; + head->prev = entry; } +#define add_to_free_ctxlist(entry) add_to_ctx_list(&ctx_free, entry) +#define add_to_used_ctxlist(entry) add_to_ctx_list(&ctx_used, entry) #endif /* !(_SPARC_PGTABLE_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/pgtsfmmu.h linux/include/asm-sparc/pgtsfmmu.h --- v1.3.43/linux/include/asm-sparc/pgtsfmmu.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/pgtsfmmu.h Thu Jan 1 02:00:00 1970 @@ -1,29 +0,0 @@ -/* pgtsfmmu.h: Spitfire V9 MMU support goes here. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#ifndef _SPARC_PGTSFMMU_H -#define _SPARC_PGTSFMMU_H - -/* Spitfire is four-level.... I think... It also has a seperate TLB for - * data and instruction mappings. - */ -#define SFMMU_PMD_SHIFT 16 -#define SFMMU_PMD_SIZE (1UL << SFMMU_PMD_SHIFT) -#define SFMMU_PMD_MASK (~(SFMMU_PMD_SIZE-1)) -#define SFMMU_PMD_ALIGN(addr) (((addr)+SFMMU_PMD_SIZE-1)&SFMMU_PMD_MASK) - -#define SFMMU_PGDIR_SHIFT 19 -#define SFMMU_PGDIR_SIZE (1UL << SFMMU_PGDIR_SHIFT) -#define SFMMU_PGDIR_MASK (~(SFMMU_PGDIR_SIZE-1)) -#define SFMMU_PGDIR_ALIGN(addr) (((addr)+SFMMU_PGDIR_SIZE-1)&SFMMU_PGDIR_MASK) - -#define SFMMU_PGMAP_SHIFT 22 -#define SFMMU_PGDIR_SIZE (1UL << SFMMU_PGDIR_SHIFT) -#define SFMMU_PGDIR_MASK (~(SFMMU_PGDIR_SIZE-1)) -#define SFMMU_PGDIR_ALIGN(addr) (((addr)+SFMMU_PGDIR_SIZE-1)&SFMMU_PGDIR_MASK) - - -#endif /* !(_SPARC_PGTSFMMU_H) */ - diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/pgtsrmmu.h linux/include/asm-sparc/pgtsrmmu.h --- v1.3.43/linux/include/asm-sparc/pgtsrmmu.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/pgtsrmmu.h Sat Nov 25 04:32:25 1995 @@ -1,4 +1,5 @@ -/* pgtsrmmu.h: SRMMU page table defines and code. +/* $Id: pgtsrmmu.h,v 1.9 1995/11/25 02:32:24 davem Exp $ + * pgtsrmmu.h: SRMMU page table defines and code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/pgtsun4.h linux/include/asm-sparc/pgtsun4.h --- v1.3.43/linux/include/asm-sparc/pgtsun4.h Tue Jun 27 14:11:45 1995 +++ linux/include/asm-sparc/pgtsun4.h Sat Nov 25 04:32:27 1995 @@ -1,4 +1,5 @@ -/* pgtsun4.c: Regular Sun4 MMU support goes in here. +/* $Id: pgtsun4.h,v 1.2 1995/11/25 02:32:26 davem Exp $ + * pgtsun4.c: Regular Sun4 MMU support goes in here. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h --- v1.3.43/linux/include/asm-sparc/pgtsun4c.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/pgtsun4c.h Sat Nov 25 04:32:29 1995 @@ -1,18 +1,11 @@ -/* pgtsun4c.h: Sun4c specific pgtable.h defines and code. +/* $Id: pgtsun4c.h,v 1.16 1995/11/25 02:32:28 davem Exp $ + * pgtsun4c.h: Sun4c specific pgtable.h defines and code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ #ifndef _SPARC_PGTSUN4C_H #define _SPARC_PGTSUN4C_H -#define SUN4C_PAGE_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */ - -/* NOTE: Now we put the free page pool and the page structures - * up in high memory above the kernel image which itself - * starts at KERNBASE. Also note PAGE_OFFSET in page.h - * This is just like what Linus does on the ALPHA. - */ - /* PMD_SHIFT determines the size of the area a second-level page table can map */ #define SUN4C_PMD_SHIFT 22 #define SUN4C_PMD_SIZE (1UL << SUN4C_PMD_SHIFT) @@ -25,7 +18,7 @@ #define SUN4C_PGDIR_MASK (~(SUN4C_PGDIR_SIZE-1)) #define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK) -/* To make sun4c_paging_init() happy, I provide the following macros. */ +/* To represent how the sun4c mmu really lays things out. */ #define SUN4C_REAL_PGDIR_SHIFT 18 #define SUN4C_REAL_PGDIR_SIZE (1UL << SUN4C_REAL_PGDIR_SHIFT) #define SUN4C_REAL_PGDIR_MASK (~(SUN4C_REAL_PGDIR_SIZE-1)) @@ -34,92 +27,83 @@ /* * To be efficient, and not have to worry about allocating such * a huge pgd, we make the kernel sun4c tables each hold 1024 - * entries and the pgd similarly. + * entries and the pgd similarly just like the i386 tables. */ - #define SUN4C_PTRS_PER_PTE 1024 #define SUN4C_PTRS_PER_PMD 1 #define SUN4C_PTRS_PER_PGD 1024 -/* Just any arbitrary offset to the start of the vmalloc VM area: the - * current 8MB value just means that there will be a 8MB "hole" after the - * physical memory until the kernel virtual memory starts. That means that - * any out-of-bounds memory accesses will hopefully be caught. - * The vmalloc() routines leaves a hole of 4kB between each vmalloced - * area for the same reason. ;) +/* On the sun4c the physical ram limit is 128MB. We set up our I/O + * translations at KERNBASE + 128MB for 1MB, then we begin the VMALLOC + * area, makes sense. This works out to the value below. */ -#define SUN4C_VMALLOC_OFFSET (8*1024*1024) -#define SUN4C_VMALLOC_START ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1)) +#define SUN4C_VMALLOC_START (0xfe100000) /* - * Sparc SUN4C page table fields. (for now, basically the same as the i386) + * Sparc SUN4C pte fields. */ - #define _SUN4C_PAGE_VALID 0x80000000 /* valid page */ #define _SUN4C_PAGE_WRITE 0x40000000 /* can be written to */ +#define _SUN4C_PAGE_PRIV 0x20000000 /* bit to signify privileged page */ #define _SUN4C_PAGE_USER 0x00000000 /* User page */ #define _SUN4C_PAGE_NOCACHE 0x10000000 /* non-cacheable page */ -#define _SUN4C_PAGE_PRIV 0x20000000 /* bit to signify privileged page */ +#define _SUN4C_PAGE_IO 0x04000000 /* I/O page */ #define _SUN4C_PAGE_REF 0x02000000 /* Page has been accessed/referenced */ #define _SUN4C_PAGE_DIRTY 0x01000000 /* Page has been modified, is dirty */ #define _SUN4C_PAGE_COW 0x00800000 /* COW page */ -/* Sparc sun4c mmu has only a writable bit. Thus if a page is valid it can be - * read in a load, and executed as code automatically. Although, the memory - * fault hardware does make a distinction between data-read faults and - * insn-read faults which is determined by which trap happened plus magic - * sync/async fault register values which must be checked in the actual - * fault handler. - */ - -#define _SUN4C_PFN_MASK 0x0000ffff /* just the page frame number */ -#define _SUN4C_MMU_MASK 0xffff0000 /* just the non-page pte bits */ - -/* The following are for pgd/pmd's */ -#define _SUN4C_PGD_PFN_MASK 0x00ffffff /* bits to hold page tables address */ -#define _SUN4C_PGD_MMU_MASK 0xff000000 /* pgd/pfn protection bits */ -#define _SUN4C_PGD_PAGE_SHIFT 8 /* bits to shift to obtain address */ - -/* We want the swapper not to swap out page tables, thus dirty and writable - * so that the kernel can change the entries as needed. Also valid for - * obvious reasons. - */ -#define _SUN4C_PAGE_TABLE (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PAGE_PRIV | _SUN4C_PAGE_NOCACHE) /* No cache for now */ -#define _SUN4C_PAGE_CHG_MASK (_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PFN_MASK) -#define _SUN4C_PGD_CHG_MASK (_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PGD_PFN_MASK) - -#define SUN4C_PAGE_NONE __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF) -#define SUN4C_PAGE_SHARED __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_REF) -#define SUN4C_PAGE_COPY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF | _SUN4C_PAGE_COW) -#define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF) -#define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_PRIV | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY | _SUN4C_PAGE_NOCACHE) -#define SUN4C_PAGE_INVALID __pgprot(0) - -#define _SUN4C_PAGE_NORMAL(x) __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_REF | (x)) - -/* The Sun4c mmu physical segment map allocation data structure. - * For each physical segmap available on the mmu we have one entry, - * 127 on the sun4c (except SparcStation 2's which seem to have 255) - * and 512 on the sun4. Each segmap can be in various stages of - * allocation. - */ -#define PSEG_ENTRIES 513 /* We allocate 513 entries for simplicity */ -extern unsigned int phys_seg_map[PSEG_ENTRIES]; -extern unsigned int phys_seg_life[PSEG_ENTRIES]; - -/* for phys_seg_map entries */ -#define PSEG_AVL 0x0 /* Physical segment is available/free */ -#define PSEG_USED 0x1 /* A segmap currently being used */ -#define PSEG_RSV 0x2 /* This segmap is reserved (used for proms addr space) */ -#define PSEG_KERNEL 0x3 /* This is a kernel hard segment, cannot deallocate */ - -/* for phys_seg_life entries */ -/* The idea is, every call to update_mmu_cache we increment all the life - * counters. When we re-allocate or allocate a physical segment for the - * first time we set the phys_seg_life entry to PSEG_BORN. Also, when we - * fill a pte for a segment already loaded we *decrease* the life count - * by two for that segment. We'll see how this works. - */ -#define PSEG_BORN 0x00 /* Just allocated */ +/* Note that the 'non-cacheable' bit is not set in any of these settings, + * you may want to turn it on for debugging the flushing of the virtual + * cache on the SUN4C MMU. + */ +#define _SUN4C_PAGE_CHG_MASK (0xffff | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY) + +#define SUN4C_PAGE_NONE __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV | \ + _SUN4C_PAGE_REF) +#define SUN4C_PAGE_SHARED __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \ + _SUN4C_PAGE_USER | _SUN4C_PAGE_REF) +#define SUN4C_PAGE_COPY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \ + _SUN4C_PAGE_REF | _SUN4C_PAGE_COW) +#define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \ + _SUN4C_PAGE_REF) +#define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \ + _SUN4C_PAGE_PRIV | _SUN4C_PAGE_DIRTY | \ + _SUN4C_PAGE_REF) +#define SUN4C_PAGE_INVALID __pgprot(0) + +struct pseg_list { + struct pseg_list *next; + struct pseg_list *prev; + struct pseg_list *ctx_next; + struct pseg_list *ctx_prev; + unsigned long vaddr; /* Where the pseg is mapped. */ + unsigned char context; /* The context in which it is mapped. */ + unsigned char pseg; /* The pseg itself. */ + unsigned ref_cnt:21, + hardlock:1; +}; + +extern char *sun4c_lockarea(char *vaddr, unsigned long size); +extern void sun4c_unlockarea(char *vaddr, unsigned long size); + +extern __inline__ unsigned long sun4c_get_synchronous_error(void) +{ + unsigned long sync_err; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (sync_err) : + "r" (AC_SYNC_ERR), "i" (ASI_CONTROL)); + return sync_err; +} + +extern __inline__ unsigned long sun4c_get_synchronous_address(void) +{ + unsigned long sync_addr; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (sync_addr) : + "r" (AC_SYNC_VA), "i" (ASI_CONTROL)); + return sync_addr; +} #endif /* !(_SPARC_PGTSUN4C_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h --- v1.3.43/linux/include/asm-sparc/processor.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/processor.h Sat Nov 25 04:32:30 1995 @@ -1,4 +1,5 @@ -/* include/asm-sparc/processor.h +/* $Id: processor.h,v 1.28 1995/11/25 02:32:30 davem Exp $ + * include/asm-sparc/processor.h * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) */ @@ -6,9 +7,12 @@ #ifndef __ASM_SPARC_PROCESSOR_H #define __ASM_SPARC_PROCESSOR_H -#include /* For intr_count */ +#include -#include /* For pt_regs declaration */ +#include +#include +#include +#include /* * Bus types @@ -19,125 +23,89 @@ #define MCA_bus__is_a_macro /* for versions in ksyms.c */ /* - * Write Protection works right in supervisor mode on the Sparc + * Write Protection works right in supervisor mode on the Sparc... + * And then there came the Swift module, which isn't so swift... */ -#if 0 /* Let's try this out ;) */ -#define wp_works_ok 1 -#define wp_works_ok__is_a_macro /* for versions in ksyms.c */ -#else extern char wp_works_ok; -#endif -/* - * User space process size: 3GB. This is hardcoded into a few places, - * so don't change it unless you know what you are doing. - * - * With the way identity mapping works on the sun4c, this is the best - * value to use. - * - * This has to be looked into for a unified sun4c/sun4m task size. - */ -#define TASK_SIZE (0xC000000UL) +/* Whee, this is STACK_TOP and the lowest kernel address too... */ +#define TASK_SIZE (KERNBASE) -/* - * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. - */ -#define IO_BITMAP_SIZE 32 +/* The Sparc processor specific thread struct. */ +struct thread_struct { + unsigned long uwinmask __attribute__ ((aligned (8))); -/* The first four entries here MUST be the first four. This allows me to - * do %lo(offset) loads and stores in entry.S. See TRAP_WIN_CLEAN to see - * why. - */ + /* For signal handling */ + unsigned long sig_address __attribute__ ((aligned (8))); + unsigned long sig_desc; + + /* Context switch saved kernel state. */ + unsigned long ksp __attribute__ ((aligned (8))); + unsigned long kpc; + unsigned long kpsr; + unsigned long kwim; + + /* A place to store user windows and stack pointers + * when the stack needs inspection. + */ +#define NSWINS 8 + struct reg_window reg_window[NSWINS] __attribute__ ((aligned (8))); + unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8))); + unsigned long w_saved; -struct thread_struct { - unsigned long uwindows; /* how many user windows are in the set */ - unsigned long wim; /* user's window invalid mask */ - unsigned long w_saved; /* how many windows saved in reg_window[] */ - unsigned long ksp; /* kernel stack pointer */ - unsigned long usp; /* user's sp, throw reg windows here */ - unsigned long psr; /* save for condition codes */ - unsigned long pc; /* program counter */ - unsigned long npc; /* next program counter */ - unsigned long yreg; - unsigned long align; /* to get 8-byte alignment XXX */ - unsigned long reg_window[16]; + /* Where our page table lives. */ unsigned long pgd_ptr; - int context; /* The context allocated to this thread */ -/* 8 local registers + 8 in registers * 24 register windows. - * Most sparcs I know of only have 7 or 8 windows implemented, - * we determine how many at boot time and store that value - * in nwindows. - */ - unsigned long float_regs[64]; /* V8 and below have 32, V9 has 64 */ + /* The context currently allocated to this process + * or -1 if no context has been allocated to this + * task yet. + */ + int context; + + /* Floating point regs */ + unsigned long float_regs[64] __attribute__ ((aligned (8))); + unsigned long fsr; + unsigned long fpqdepth; + struct fpq { + unsigned long *insn_addr; + unsigned long insn; + } fpqueue[16]; + struct sigstack sstk_info; }; -#define INIT_MMAP { &init_task, (PAGE_OFFSET), (0xff000000UL), \ - 0x0 , VM_READ | VM_WRITE | VM_EXEC } +#define INIT_MMAP { &init_mm, (0xf0000000UL), (0xffffffffUL), \ + __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC } #define INIT_TSS { \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ - (long) &swapper_pg_dir, -1, \ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ +/* uwinmask, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \ + 0, 0, 0, 0, 0, 0, 0, \ +/* reg_window */ \ +{ { { 0, }, { 0, } }, }, \ +/* rwbuf_stkptrs */ \ +{ 0, 0, 0, 0, 0, 0, 0, 0, }, \ +/* w_saved, pgd_ptr, context */ \ + 0, (long) &swapper_pg_dir, -1, \ +/* FPU regs */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ +/* FPU status, FPU qdepth, FPU queue */ \ + 0, 0, { { 0, 0, }, }, \ +/* sstk_info */ \ +{ 0, 0, }, \ } -/* The thread_frame is what needs to be set up in certain circumstances - * upon entry to a trap. It is also loaded sometimes during a window - * spill if things don't go right (bad user stack pointer). In reality - * it is not per-process per se, it just sits in the kernel stack while - * the current process is in a handler then it is basically forgotten - * about the next time flow control goes back to that process. - */ - -/* Sparc stack save area allocated for each save, not very exciting. */ -struct sparc_save_stack { - unsigned int locals[8]; - unsigned int ins[8]; - unsigned int padd[8]; -}; - -/* - * These are the "cli()" and "sti()" for software interrupts - * They work by increasing/decreasing the "intr_count" value, - * and as such can be nested arbitrarily. - */ -extern inline void start_bh_atomic(void) +/* Return saved PC of a blocked thread. */ +extern inline unsigned long thread_saved_pc(struct thread_struct *t) { - __asm__ __volatile__("rd %%psr, %%g2\n\t" - "wr %%g2, 0x20, %%psr\n\t" /* disable traps */ - "ld %0,%%g3\n\t" - "add %%g3,1,%%g3\n\t" - "st %%g3,%0\n\t" - "wr %%g2, 0x0, %%psr\n\t" /* enable traps */ - : "=m" (intr_count) - : : "g2", "g3", "memory"); -} - -extern inline void end_bh_atomic(void) -{ - __asm__ __volatile__("rd %%psr, %%g2\n\t" - "wr %%g2, 0x20, %%psr\n\t" - "ld %0,%%g3\n\t" - "sub %%g3,1,%%g3\n\t" - "st %%g3,%0\n\t" - "wr %%g2, 0x0, %%psr\n\t" - : "=m" (intr_count) - : : "g2", "g3", "memory"); + return ((struct pt_regs *) + ((t->ksp&(~0xfff))+(0x1000-TRACEREG_SZ)))->pc; } /* * Do necessary setup to start up a newly executed thread. */ -static inline void start_thread(struct pt_regs * regs, unsigned long sp, - unsigned long fp) -{ - printk("start_thread called, halting..n"); - halt(); -} +extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); #endif /* __ASM_SPARC_PROCESSOR_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/psr.h linux/include/asm-sparc/psr.h --- v1.3.43/linux/include/asm-sparc/psr.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/psr.h Sat Nov 25 04:32:32 1995 @@ -1,11 +1,12 @@ -/* psr.h: This file holds the macros for masking off various parts of - the processor status register on the Sparc. This is valid - for Version 8. On the V9 this is renamed to the PSTATE - register and its members are accessed as fields like - PSTATE.PRIV for the current CPU privilege level. - - Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) -*/ +/* $Id: psr.h,v 1.5 1995/11/25 02:32:31 davem Exp $ + * psr.h: This file holds the macros for masking off various parts of + * the processor status register on the Sparc. This is valid + * for Version 8. On the V9 this is renamed to the PSTATE + * register and its members are accessed as fields like + * PSTATE.PRIV for the current CPU privilege level. + * + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + */ #ifndef __LINUX_SPARC_PSR_H #define __LINUX_SPARC_PSR_H @@ -15,21 +16,12 @@ #ifdef __LINUX_SPARC_V8 /* The Sparc PSR fields are laid out as the following: - - ------------------------------------------------------------------------ - | impl | vers | icc | resv | EC | EF | PIL | S | PS | ET | CWP | -bits| 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6 | 5 | 4-0 | - ------------------------------------------------------------------------ - - The PSR can only be directly be written/read by the privileged instructions - 'rd' and 'wr'. Certain fields are changed as a side effect due to the 'Ticc', - 'save', 'restore', and 'rett' instructions. Also the integer condition codes - 'icc' are modified by various arithmetic instructions. - - For example: wr %o2, or'd_bit_pattern, %psr - rd %psr, %o3 - -*/ + * + * ------------------------------------------------------------------------ + * | impl | vers | icc | resv | EC | EF | PIL | S | PS | ET | CWP | + * | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6 | 5 | 4-0 | + * ------------------------------------------------------------------------ + */ #define PSR_CWP 0x0000001f /* current window pointer */ #define PSR_ET 0x00000020 /* enable traps field */ @@ -87,18 +79,18 @@ #ifdef __LINUX_SPARC_V9 /* The information available in the %psr on the V8 is spread amongst - a whole bunch of registers on the V9. The main one being PSTATE. - - -------------------------------------------------------- - | CLE | TLE | MM | RED | PEF | AM | PRIV | IE | AG | -bits | 9 | 8 | 7-6 | 5 | 4 | 3 | 2 | 1 | 0 | - -------------------------------------------------------- - - Writes and reads to PSTATE are done via 'wrpr' and 'rdpr' instructions. - - For example: wrpr %o2, or'd_bit_pattern, %pstate - rdpr %pstate, %o3 -*/ + * a whole bunch of registers on the V9. The main one being PSTATE. + * + * -------------------------------------------------------- + * | CLE | TLE | MM | RED | PEF | AM | PRIV | IE | AG | + * | 9 | 8 | 7-6 | 5 | 4 | 3 | 2 | 1 | 0 | + * -------------------------------------------------------- + * + * Writes and reads to PSTATE are done via 'wrpr' and 'rdpr' instructions. + * + * For example: wrpr %o2, or'd_bit_pattern, %pstate + * rdpr %pstate, %o3 + */ #define PSTATE_AG 0x001 /* Alternate Globals */ #define PSTATE_IE 0x002 /* Interrupt Enable */ @@ -132,13 +124,13 @@ } /* The Version Register holds vendor information for the chip: - - --------------------------------------------------------------------------- - | manufacturer | implementation | mask | reserved | maxtl | resv | maxwin | -bits| 63-48 | 47-32 | 31-24| 23-16 | 15-8 | 7-5 | 4-0 | - --------------------------------------------------------------------------- - -*/ + * + * --------------------------------------------------------------------------- + * | manufacturer | implementation | mask | reserved | maxtl | resv | maxwin | + * | 63-48 | 47-32 | 31-24| 23-16 | 15-8 | 7-5 | 4-0 | + * --------------------------------------------------------------------------- + * + */ #define VERS_MAXWIN 0x000000000000001f /* 'nwindows' on this chip */ #define VERS_MAXTL 0x00000000000ff000 /* Maximum Trap-level supported */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h --- v1.3.43/linux/include/asm-sparc/ptrace.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/ptrace.h Sat Nov 25 04:32:34 1995 @@ -1,29 +1,170 @@ +/* $Id: ptrace.h,v 1.14 1995/11/25 02:32:33 davem Exp $ */ #ifndef _SPARC_PTRACE_H #define _SPARC_PTRACE_H -/* I have not looked enough into how this should be done. Without playing - * lots of tricks to optimize I think we need to save the whole register - * window frame plus the floating-point registers. We'll see... +#include + +/* This struct defines the way the registers are stored on the + * stack during a system call and basically all traps. */ -/* this struct defines the way the registers are stored on the - stack during a system call. */ +#ifndef __ASSEMBLY__ struct pt_regs { - unsigned long psr; /* for condition codes */ - unsigned long pc; /* current and next program counter */ + unsigned long psr; + unsigned long pc; unsigned long npc; unsigned long y; - /* not sure yet whether all regs are necessary - * but this is how it is traditionally done on the sparc. - */ unsigned long u_regs[16]; /* globals and ins */ }; +#define UREG_G0 0 +#define UREG_G1 1 +#define UREG_G2 2 +#define UREG_G3 3 +#define UREG_G4 4 +#define UREG_G5 5 +#define UREG_G6 6 +#define UREG_G7 7 +#define UREG_I0 8 +#define UREG_I1 9 +#define UREG_I2 10 +#define UREG_I3 11 +#define UREG_I4 12 +#define UREG_I5 13 +#define UREG_I6 14 +#define UREG_I7 15 +#define UREG_WIM UREG_G0 +#define UREG_FP UREG_I6 +#define UREG_RETPC UREG_I7 + +/* A register window */ +struct reg_window { + unsigned long locals[8]; + unsigned long ins[8]; +}; + + +/* A Sparc stack frame */ +struct sparc_stackf { + unsigned long locals[8]; + unsigned long ins[6]; + struct sparc_stackf *fp; + unsigned long callers_pc; + char *structptr; + unsigned long xargs[6]; + unsigned long xxargs[1]; +}; + +#define TRACEREG_SZ sizeof(struct pt_regs) +#define STACKFRAME_SZ sizeof(struct sparc_stackf) +#define REGWIN_SZ sizeof(struct reg_window) + #ifdef __KERNEL__ -/* if previous supervisor is 0, came from user */ -#define user_mode(regs) (0x0) +#define user_mode(regs) (!((regs)->psr & PSR_PS)) +#define instruction_pointer(regs) ((regs)->pc) extern void show_regs(struct pt_regs *); #endif +#else /* __ASSEMBLY__ */ +/* For assembly code. */ +#define TRACEREG_SZ 0x50 +#define STACKFRAME_SZ 0x60 +#define REGWIN_SZ 0x40 #endif + +/* First generic task_struct offsets. sizeof(task_struct)=1536 */ +#define TASK_STATE 0x000 +#define TASK_PRIORITY 0x008 +#define TASK_SIGNAL 0x00c +#define TASK_BLOCKED 0x010 +#define TASK_FLAGS 0x014 +#define TASK_SAVED_KSTACK 0x054 +#define TASK_KSTACK_PG 0x058 + +/* Thread stuff. */ +#define THREAD_UMASK 0x210 +#define THREAD_SADDR 0x218 +#define THREAD_SDESC 0x21c +#define THREAD_KSP 0x220 +#define THREAD_KPC 0x224 +#define THREAD_KPSR 0x228 +#define THREAD_KWIM 0x22c +#define THREAD_REG_WINDOW 0x230 +#define THREAD_STACK_PTRS 0x430 +#define THREAD_W_SAVED 0x450 +#define THREAD_PGD_PTR 0x454 +#define THREAD_CONTEXT 0x458 +#define THREAD_FLOAT_REGS 0x460 +#define THREAD_FSR 0x560 +#define THREAD_SIGSTK 0x5e8 + +/* These are for pt_regs. */ +#define PT_PSR 0x0 +#define PT_PC 0x4 +#define PT_NPC 0x8 +#define PT_Y 0xc +#define PT_G0 0x10 +#define PT_WIM PT_G0 +#define PT_G1 0x14 +#define PT_G2 0x18 +#define PT_G3 0x1c +#define PT_G4 0x20 +#define PT_G5 0x24 +#define PT_G6 0x28 +#define PT_G7 0x2c +#define PT_I0 0x30 +#define PT_I1 0x34 +#define PT_I2 0x38 +#define PT_I3 0x3c +#define PT_I4 0x40 +#define PT_I5 0x44 +#define PT_I6 0x48 +#define PT_FP PT_I6 +#define PT_I7 0x4c + +/* Reg_window offsets */ +#define RW_L0 0x00 +#define RW_L1 0x04 +#define RW_L2 0x08 +#define RW_L3 0x0c +#define RW_L4 0x10 +#define RW_L5 0x14 +#define RW_L6 0x18 +#define RW_L7 0x1c +#define RW_I0 0x20 +#define RW_I1 0x24 +#define RW_I2 0x28 +#define RW_I3 0x2c +#define RW_I4 0x30 +#define RW_I5 0x34 +#define RW_I6 0x38 +#define RW_I7 0x3c + +/* Stack_frame offsets */ +#define SF_L0 0x00 +#define SF_L1 0x04 +#define SF_L2 0x08 +#define SF_L3 0x0c +#define SF_L4 0x10 +#define SF_L5 0x14 +#define SF_L6 0x18 +#define SF_L7 0x1c +#define SF_I0 0x20 +#define SF_I1 0x24 +#define SF_I2 0x28 +#define SF_I3 0x2c +#define SF_I4 0x30 +#define SF_I5 0x34 +#define SF_FP 0x38 +#define SF_PC 0x3c +#define SF_RETP 0x40 +#define SF_XARG0 0x44 +#define SF_XARG1 0x48 +#define SF_XARG2 0x4c +#define SF_XARG3 0x50 +#define SF_XARG4 0x54 +#define SF_XARG5 0x58 +#define SF_XXARG 0x5c + +#endif /* !(_SPARC_PTRACE_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/resource.h linux/include/asm-sparc/resource.h --- v1.3.43/linux/include/asm-sparc/resource.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/resource.h Sat Nov 25 04:32:35 1995 @@ -0,0 +1,38 @@ +/* $Id: resource.h,v 1.5 1995/11/25 02:32:35 davem Exp $ + * resource.h: Resource definitions. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_RESOURCE_H +#define _SPARC_RESOURCE_H + +/* + * Resource limits + */ + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ +#define RLIMIT_NOFILE 6 /* max number of open files */ +#define RLIMIT_NPROC 7 /* max number of processes */ +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ +#define RLIM_NLIMITS 9 + +#ifdef __KERNEL__ + +#define INIT_RLIMITS \ +{ \ + {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ + {LONG_MAX, LONG_MAX}, {_STK_LIM, _STK_LIM}, \ + { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ + {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, {NR_OPEN, NR_OPEN}, \ + {LONG_MAX, LONG_MAX}, \ +} + +#endif /* __KERNEL__ */ + +#endif /* !(_SPARC_RESOURCE_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/ross.h linux/include/asm-sparc/ross.h --- v1.3.43/linux/include/asm-sparc/ross.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/ross.h Sat Nov 25 04:32:38 1995 @@ -1,4 +1,5 @@ -/* ross.h: Ross module specific definitions and defines. +/* $Id: ross.h,v 1.3 1995/11/25 02:32:37 davem Exp $ + * ross.h: Ross module specific definitions and defines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h --- v1.3.43/linux/include/asm-sparc/sbus.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/sbus.h Sat Nov 25 04:32:39 1995 @@ -1,4 +1,5 @@ -/* sbus.h: Defines for the Sun SBus. +/* $Id: sbus.h,v 1.8 1995/11/25 02:32:38 davem Exp $ + * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -6,7 +7,7 @@ #ifndef _SPARC_SBUS_H #define _SPARC_SBUS_H -#include /* For linux_prom_registers and linux_prom_irqs */ +#include /* We scan which devices are on the SBus using the PROM node device * tree. SBus devices are described in two different ways. You can @@ -37,21 +38,20 @@ return (unsigned long) (((dev_addr)-SUN_SBUS_BVADDR)&SBUS_OFF_MASK); } -/* Handy macro */ -#define STRUCT_ALIGN(addr) ((addr+7)&(~7)) +struct linux_sbus; -/* Linus SBUS device tables */ +/* Linux SBUS device tables */ struct linux_sbus_device { struct linux_sbus_device *next; /* next device on this SBus or null */ + struct linux_sbus_device *child; /* For ledma and espdma on sun4m */ + struct linux_sbus *my_bus; /* Back ptr to sbus */ int prom_node; /* PROM device tree node for this device */ - char *prom_name; /* PROM device name */ - char *linux_name; /* Name used internally by Linux */ + char prom_name[64]; /* PROM device name */ + char linux_name[64]; /* Name used internally by Linux */ - /* device register addresses */ struct linux_prom_registers reg_addrs[PROMREG_MAX]; int num_registers; - /* List of IRQ's this device uses. */ struct linux_prom_irqs irqs[PROMINTR_MAX]; int num_irqs; @@ -59,18 +59,32 @@ unsigned long sbus_vaddrs[PROMVADDR_MAX]; unsigned long num_vaddrs; unsigned long offset; /* Offset given by PROM */ - int slot; /* Device slot number */ + int slot; }; -/* This struct describes the SBus-es found on this machine. */ +/* This struct describes the SBus(s) found on this machine. */ struct linux_sbus { struct linux_sbus *next; /* next SBus, if more than one SBus */ struct linux_sbus_device *devices; /* Link to devices on this SBus */ int prom_node; /* PROM device tree node for this SBus */ - char *prom_name; /* Usually "sbus" */ - int clock_freq; /* Speed of this SBus */ + char prom_name[64]; /* Usually "sbus" */ + int clock_freq; }; -extern struct linux_sbus Linux_SBus; +extern struct linux_sbus *SBus_chain; + +extern inline int +sbus_is_slave(struct linux_sbus_device *dev) +{ + /* Have to write this for sun4c's */ + return 0; +} + +/* Device probing routines could find these handy */ +#define for_each_sbus(bus) \ + for((bus) = SBus_chain; (bus); (bus)=(bus)->next) + +#define for_each_sbusdev(device, bus) \ + for((device) = (bus)->devices; (device); (device)=(device)->next) #endif /* !(_SPARC_SBUS_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/segment.h linux/include/asm-sparc/segment.h --- v1.3.43/linux/include/asm-sparc/segment.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/segment.h Sat Nov 25 04:32:41 1995 @@ -1,15 +1,68 @@ +/* $Id: segment.h,v 1.6 1995/11/25 02:32:40 davem Exp $ */ #ifndef _ASM_SEGMENT_H #define _ASM_SEGMENT_H -#define KERNEL_CS 0x0 -#define KERNEL_DS 0x0 - -#define USER_CS 0x1 -#define USER_DS 0x1 +/* Sparc is not segmented, these are just place holders. */ +#define KERNEL_DS 0 +#define USER_DS 1 #include #include +#ifndef __ASSEMBLY__ + +/* + * Uh, these should become the main single-value transfer routines.. + * They automatically use the right size if we just have the right + * pointer type.. + */ +#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))) +#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))) + +/* + * This is a silly but good way to make sure that + * the __put_user function is indeed always optimized, + * and that we use the correct sizes.. + */ +extern int bad_user_access_length(void); + +/* I should make this use unaligned transfers etc.. */ +static inline void __put_user(unsigned long x, void * y, int size) +{ + switch (size) { + case 1: + *(char *) y = x; + break; + case 2: + *(short *) y = x; + break; + case 4: + *(int *) y = x; + break; + default: + bad_user_access_length(); + } +} + +/* I should make this use unaligned transfers etc.. */ +static inline unsigned long __get_user(const void * y, int size) +{ + switch (size) { + case 1: + return *(unsigned char *) y; + case 2: + return *(unsigned short *) y; + case 4: + return *(unsigned int *) y; + default: + return bad_user_access_length(); + } +} + +/* + * Deprecated routines + */ + static inline unsigned char get_user_byte(const char * addr) { return *addr; @@ -31,13 +84,6 @@ #define get_fs_long(addr) get_user_long((int *)(addr)) -static inline unsigned long get_user_quad(const long *addr) -{ - return *addr; -} - -#define get_fs_quad(addr) get_user_quad((long *)(addr)) - static inline void put_user_byte(char val,char *addr) { *addr = val; @@ -59,33 +105,27 @@ #define put_fs_long(x,addr) put_user_long((x),(int *)(addr)) -static inline void put_user_quad(unsigned long val,long * addr) -{ - *addr = val; -} - -#define put_fs_quad(x,addr) put_user_quad((x),(long *)(addr)) - #define memcpy_fromfs(to, from, n) memcpy((to),(from),(n)) #define memcpy_tofs(to, from, n) memcpy((to),(from),(n)) +extern int current_user_segment; + static inline unsigned long get_fs(void) { - return 0; + return current_user_segment; } static inline unsigned long get_ds(void) { - return 0; + return KERNEL_DS; } static inline void set_fs(unsigned long val) { - unsigned long foo; - foo = val; - - return; + current_user_segment = val; } + +#endif /* __ASSEMBLY__ */ #endif /* _ASM_SEGMENT_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/shmparam.h linux/include/asm-sparc/shmparam.h --- v1.3.43/linux/include/asm-sparc/shmparam.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/shmparam.h Sat Nov 25 04:32:43 1995 @@ -0,0 +1,45 @@ +/* $Id: shmparam.h,v 1.3 1995/11/25 02:32:42 davem Exp $ */ +#ifndef _ASMSPARC_SHMPARAM_H +#define _ASMSPARC_SHMPARAM_H + +/* address range for shared memory attaches if no address passed to shmat() */ +#define SHM_RANGE_START 0x10000000 +#define SHM_RANGE_END 0x20000000 + +/* + * Format of a swap-entry for shared memory pages currently out in + * swap space (see also mm/swap.c). + * + * SWP_TYPE = SHM_SWP_TYPE + * SWP_OFFSET is used as follows: + * + * bits 0..6 : id of shared memory segment page belongs to (SHM_ID) + * bits 7..21: index of page within shared memory segment (SHM_IDX) + * (actually fewer bits get used since SHMMAX is so low) + */ + +/* + * Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and + * there is a static array of size SHMMNI. + */ +#define _SHM_ID_BITS 7 +#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) + +#define SHM_IDX_SHIFT (_SHM_ID_BITS) +#define _SHM_IDX_BITS 15 +#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1) + +/* + * _SHM_ID_BITS + _SHM_IDX_BITS must be <= 24 on the i386 and + * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS). + */ + +#define SHMMAX (1024 * 1024) /* max shared seg size (bytes) */ +#define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */ +#define SHMMNI (1<<_SHM_ID_BITS) /* max num of segs system wide */ +#define SHMALL /* max shm system wide (pages) */ \ + (1<<(_SHM_IDX_BITS+_SHM_ID_BITS)) +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ +#define SHMSEG SHMMNI /* max shared segs per process */ + +#endif /* _ASMSPARC_SHMPARAM_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h --- v1.3.43/linux/include/asm-sparc/sigcontext.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/sigcontext.h Sat Nov 25 04:32:45 1995 @@ -0,0 +1,37 @@ +/* $Id: sigcontext.h,v 1.7 1995/11/25 02:32:44 davem Exp $ */ +#ifndef _ASMsparc_SIGCONTEXT_H +#define _ASMsparc_SIGCONTEXT_H + +#include + +/* SunOS system call sigstack() uses this arg. */ +struct sunos_sigstack { + unsigned long sig_sp; + int onstack_flag; +}; + +/* This is what SunOS does, so shall I. */ +#define SUNOS_MAXWIN 31 +struct sigcontext_struct { + int sigc_onstack; /* state to restore */ + int sigc_mask; /* sigmask to restore */ + int sigc_sp; /* stack pointer */ + int sigc_pc; /* program counter */ + int sigc_npc; /* next program counter */ + int sigc_psr; /* for condition codes etc */ + int sigc_g1; /* User uses these two registers */ + int sigc_o0; /* within the trampoline code. */ + + /* Now comes information regarding the users window set + * at the time of the signal. + */ + int sigc_oswins; /* outstanding windows */ + + /* stack ptrs for each regwin buf */ + char *sigc_spbuf[SUNOS_MAXWIN]; + + /* Windows to restore after signal */ + struct reg_window sigc_wbuf[SUNOS_MAXWIN]; +}; + +#endif /* !(_ASMsparc_SIGCONTEXT_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/signal.h linux/include/asm-sparc/signal.h --- v1.3.43/linux/include/asm-sparc/signal.h Thu Feb 2 08:42:35 1995 +++ linux/include/asm-sparc/signal.h Sat Nov 25 04:32:47 1995 @@ -1,11 +1,139 @@ +/* $Id: signal.h,v 1.14 1995/11/25 02:32:46 davem Exp $ */ #ifndef _ASMSPARC_SIGNAL_H #define _ASMSPARC_SIGNAL_H -struct sigcontext_struct { - /* - * Have to find out what SUNOS and Solaris do. This could - * get real ugly. David S. Miller (davem@caip.rutgers.edu) - */ +/* On the Sparc the signal handlers get passed a 'sub-signal' code + * for certain signal types, which we document here. + */ +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SUBSIG_STACK 0 +#define SUBSIG_ILLINST 2 +#define SUBSIG_PRIVINST 3 +#define SUBSIG_BADTRAP(t) (0x80 + (n)) + +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 + +#define SIGEMT 7 +#define SUBSIG_TAG 10 + +#define SIGFPE 8 +#define SUBSIG_FPDISABLED 0x400 +#define SUBSIG_FPERROR 0x404 +#define SUBSIG_FPINTOVFL 0x001 +#define SUBSIG_FPSTSIG 0x002 +#define SUBSIG_IDIVZERO 0x014 +#define SUBSIG_FPINEXACT 0x0c4 +#define SUBSIG_FPDIVZERO 0x0c8 +#define SUBSIG_FPUNFLOW 0x0cc +#define SUBSIG_FPOPERROR 0x0d0 +#define SUBSIG_FPOVFLOW 0x0d4 + +#define SIGKILL 9 +#define SIGBUS 10 +#define SUBSIG_BUSTIMEOUT 1 +#define SUBSIG_ALIGNMENT 2 +#define SUBSIG_MISCERROR 5 + +#define SIGSEGV 11 +#define SUBSIG_NOMAPPING 3 +#define SUBSIG_PROTECTION 4 +#define SUBSIG_SEGERROR 5 + +#define SIGSYS 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGURG 16 + +/* SunOS values which deviate from the Linux/i386 ones */ +#define SIGSTOP 17 +#define SIGTSTP 18 +#define SIGCONT 19 +#define SIGCHLD 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGIO 23 +#define SIGPOLL SIGIO /* SysV name for SIGIO */ +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGLOST 29 +#define SIGUSR1 30 +#define SIGUSR2 31 + +#ifndef __ASSEMBLY__ + +typedef unsigned long sigset_t; + +#ifdef __KERNEL__ +#include +#endif + +/* A SunOS sigstack */ +struct sigstack { + char *the_stack; + int cur_status; }; +/* Sigvec flags */ +#define SV_SSTACK 1 /* This signal handler should use sig-stack */ +#define SV_INTR 2 /* Sig return should not restart system ??? */ +#define SV_RESET 4 /* Set handler to SIG_DFL upon taken signal */ +#define SV_IGNCHILD 8 /* Do not send SIGCHLD */ + +/* + * sa_flags values: SA_STACK is not currently supported, but will allow the + * usage of signal stacks by using the (now obsolete) sa_restorer field in + * the sigaction structure as a stack pointer. This is now possible due to + * the changes in signal handling. LBT 010493. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + */ +#define SA_NOCLDSTOP SV_IGNCHILD +#define SA_STACK SV_SSTACK +#define SA_RESTART SV_RESET +#define SA_INTERRUPT SV_INTR +#define SA_NOMASK 0x10 +#define SA_ONESHOT 0x20 + +#define SIG_BLOCK 0x00 /* for blocking signals */ +#define SIG_UNBLOCK 0x40 /* for unblocking signals */ +#define SIG_SETMASK 0x80 /* for setting the signal mask */ + +#ifdef __KERNEL__ +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART #endif + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int, int, struct sigcontext_struct *, char *); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +struct sigaction { + __sighandler_t sa_handler; + sigset_t sa_mask; + unsigned long sa_flags; +}; + +#endif /* !(__ASSEMBLY__) */ + +#endif /* !(_ASMSPARC_SIGNAL_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/smpprim.h linux/include/asm-sparc/smpprim.h --- v1.3.43/linux/include/asm-sparc/smpprim.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/smpprim.h Sat Nov 25 04:32:48 1995 @@ -1,4 +1,5 @@ -/* smpprim.h: SMP locking primitives on the Sparc +/* $Id: smpprim.h,v 1.4 1995/11/25 02:32:47 davem Exp $ + * smpprim.h: SMP locking primitives on the Sparc * * God knows we won't be actually using this code for some time * but I thought I'd write it since I knew how. diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/socket.h linux/include/asm-sparc/socket.h --- v1.3.43/linux/include/asm-sparc/socket.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/socket.h Sat Nov 25 04:32:50 1995 @@ -0,0 +1,37 @@ +/* $Id: socket.h,v 1.4 1995/11/25 02:32:49 davem Exp $ */ +#ifndef _ASM_SOCKET_H +#define _ASM_SOCKET_H + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +/* For setsockoptions(2) */ +#define SOL_SOCKET 0xffff + +#define SO_DEBUG 0x0001 +#define SO_REUSEADDR 0x0004 +#define SO_KEEPALIVE 0x0008 +#define SO_DONTROUTE 0x0010 +#define SO_BROADCAST 0x0020 +#define SO_LINGER 0x0080 +#define SO_OOBINLINE 0x0100 +/* To add :#define SO_REUSEPORT 0x0200 */ + +/* wha!??? */ +#define SO_DONTLINGER (~SO_LINGER) /* Older SunOS compat. hack */ + +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +#define SO_ERROR 0x1007 +#define SO_TYPE 0x1008 + +/* Linux specific, keep the same. */ +#define SO_NO_CHECK 0x000b +#define SO_PRIORITY 0x000c + +#endif /* _ASM_SOCKET_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/solerrno.h linux/include/asm-sparc/solerrno.h --- v1.3.43/linux/include/asm-sparc/solerrno.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/solerrno.h Sat Nov 25 04:32:52 1995 @@ -0,0 +1,132 @@ +/* $Id: solerrno.h,v 1.3 1995/11/25 02:32:51 davem Exp $ + * solerrno.h: Solaris error return codes for compatability. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_SOLERRNO_H +#define _SPARC_SOLERRNO_H + +#define SOL_EPERM 1 /* Required superuser access perms */ +#define SOL_ENOENT 2 /* File or directory does not exist */ +#define SOL_ESRCH 3 /* Process did not exist */ +#define SOL_EINTR 4 /* System call was interrupted */ +#define SOL_EIO 5 /* An i/o error occurred */ +#define SOL_ENXIO 6 /* Device or Address does not exist */ +#define SOL_E2BIG 7 /* Too many arguments were given */ +#define SOL_ENOEXEC 8 /* Header of executable was munged */ +#define SOL_EBADF 9 /* Bogus file number */ +#define SOL_ECHILD 10 /* No children of process exist */ +#define SOL_EAGAIN 11 /* beep beep, "try again later" */ +#define SOL_ENOMEM 12 /* No memory available */ +#define SOL_EACCES 13 /* Access not allowed */ +#define SOL_EFAULT 14 /* Address passed was invalid */ +#define SOL_ENOTBLK 15 /* blkdev op on non-block device */ +#define SOL_EBUSY 16 /* Mounted device was busy */ +#define SOL_EEXIST 17 /* File specified already exists */ +#define SOL_EXDEV 18 /* Link request across diff devices */ +#define SOL_ENODEV 19 /* Device does not exist on system */ +#define SOL_ENOTDIR 20 /* Dir operation on non-directory */ +#define SOL_EISDIR 21 /* File was of directory type */ +#define SOL_EINVAL 22 /* Argument passed was invalid */ +#define SOL_ENFILE 23 /* No more room in file table */ +#define SOL_EMFILE 24 /* Proc has too many files open */ +#define SOL_ENOTTY 25 /* Ioctl was invalid for req device */ +#define SOL_ETXTBSY 26 /* Text file in busy state */ +#define SOL_EFBIG 27 /* Too big of a file for operation */ +#define SOL_ENOSPC 28 /* Disk is full */ +#define SOL_ESPIPE 29 /* Seek attempted on non-seeking dev*/ +#define SOL_EROFS 30 /* Write attempted on read-only fs */ +#define SOL_EMLINK 31 /* Too many links in file search */ +#define SOL_EPIPE 32 /* Call a plumber */ +#define SOL_EDOM 33 /* Argument was out of fct domain */ +#define SOL_ERANGE 34 /* Could not represent math result */ +#define SOL_ENOMSG 35 /* Message of req type doesnt exist */ +#define SOL_EIDRM 36 /* Identifier has been removed */ +#define SOL_ECHRNG 37 /* Req channel number out of range */ +#define SOL_EL2NSYNC 38 /* Could not sync at run level 2 */ +#define SOL_EL3HLT 39 /* Halted at run level 3 */ +#define SOL_EL3RST 40 /* Reset at run level 3 */ +#define SOL_ELNRNG 41 /* Out of range link number */ +#define SOL_EUNATCH 42 /* Driver for protocol not attached */ +#define SOL_ENOCSI 43 /* CSI structure not around */ +#define SOL_EL2HLT 44 /* Halted at run level 2 */ +#define SOL_EDEADLK 45 /* Deadlock condition detected */ +#define SOL_ENOLCK 46 /* Record locks unavailable */ +#define SOL_ECANCELED 47 /* Cancellation of oper. happened */ +#define SOL_ENOTSUP 48 /* Attempt of unsupported operation */ +#define SOL_EDQUOT 49 /* Users disk quota exceeded */ +#define SOL_EBADE 50 /* Invalid exchange */ +#define SOL_EBADR 51 /* Request descriptor was invalid */ +#define SOL_EXFULL 52 /* Full exchange */ +#define SOL_ENOANO 53 /* ano does not exist */ +#define SOL_EBADRQC 54 /* Req code was invalid */ +#define SOL_EBADSLT 55 /* Bad slot number */ +#define SOL_EDEADLOCK 56 /* Deadlock in fs error */ +#define SOL_EBFONT 57 /* Font file format invalid */ +/* YOW, I LOVE SYSV STREAMS!!!! */ +#define SOL_ENOSTR 60 /* Stream-op on non-stream dev */ +#define SOL_ENODATA 61 /* No data avail at this time */ +#define SOL_ETIME 62 /* Expiration of time occurred */ +#define SOL_ENOSR 63 /* Streams resources exhausted */ +#define SOL_ENONET 64 /* No network connected */ +#define SOL_ENOPKG 65 /* Non-installed package */ +#define SOL_EREMOTE 66 /* Object was on remote machine */ +#define SOL_ENOLINK 67 /* Cut link */ +#define SOL_EADV 68 /* Error in advertise */ +#define SOL_ESRMNT 69 /* Some magic srmount problem */ +#define SOL_ECOMM 70 /* During send, comm error occurred */ +#define SOL_EPROTO 71 /* Protocol botch */ +#define SOL_EMULTIHOP 74 /* Multihop attempted */ +#define SOL_EBADMSG 77 /* Message was unreadable */ +#define SOL_ENAMETOOLONG 78 /* Too long of a path name */ +#define SOL_EOVERFLOW 79 /* Data type too small for datum */ +#define SOL_ENOTUNIQ 80 /* Logical name was not unique */ +#define SOL_EBADFD 81 /* Op cannot be performed on fd */ +#define SOL_EREMCHG 82 /* Remote address is now different */ +#define SOL_ELIBACC 83 /* Shared lib could not be accessed */ +#define SOL_ELIBBAD 84 /* ShLib is corrupted in some way */ +#define SOL_ELIBSCN 85 /* A.out ShLib problems */ +#define SOL_ELIBMAX 86 /* Exceeded ShLib linkage limit */ +#define SOL_ELIBEXEC 87 /* Execution of ShLib attempted */ +#define SOL_EILSEQ 88 /* Bad byte sequence found */ +#define SOL_ENOSYS 89 /* Invalid filesystem operation */ +#define SOL_ELOOP 90 /* Detected loop in symbolic links */ +#define SOL_ERESTART 91 /* System call is restartable */ +#define SOL_ESTRPIPE 92 /* Do not sleep in head of stream */ +#define SOL_ENOTEMPTY 93 /* Rmdir of non-empty directory */ +#define SOL_EUSERS 94 /* Over abundance of users for ufs */ +#define SOL_ENOTSOCK 95 /* Sock-op on non-sock */ +#define SOL_EDESTADDRREQ 96 /* No dest addr given, but needed */ +#define SOL_EMSGSIZE 97 /* Msg too big */ +#define SOL_EPROTOTYPE 98 /* Bad socket protocol */ +#define SOL_ENOPROTOOPT 99 /* Unavailable protocol */ +#define SOL_EPROTONOSUPPORT 120 /* Unsupported protocol */ +#define SOL_ESOCKTNOSUPPORT 121 /* Unsupported socket type */ +#define SOL_EOPNOTSUPP 122 /* Unsupported sock-op */ +#define SOL_EPFNOSUPPORT 123 /* Unsupported protocol family */ +#define SOL_EAFNOSUPPORT 124 /* Unsup addr family for protocol */ +#define SOL_EADDRINUSE 125 /* Req addr is already in use */ +#define SOL_EADDRNOTAVAIL 126 /* Req addr not available right now */ +#define SOL_ENETDOWN 127 /* Your subnet is on fire */ +#define SOL_ENETUNREACH 128 /* Someone playing with gateway and */ + /* did not tell you he was going to */ +#define SOL_ENETRESET 129 /* Buy less-buggy ethernet cards */ +#define SOL_ECONNABORTED 130 /* Aborted connection due to sw */ +#define SOL_ECONNRESET 131 /* Your peers reset your connection */ +#define SOL_ENOBUFS 132 /* No buffer space available */ +#define SOL_EISCONN 133 /* Connect on already connected */ + /* socket attempted */ +#define SOL_ENOTCONN 134 /* Comm on non-connected socket */ +#define SOL_ESHUTDOWN 143 /* Op attempted after sock-shutdown */ +#define SOL_ETOOMANYREFS 144 /* Reference limit exceeded */ +#define SOL_ETIMEDOUT 145 /* Timed out connection */ +#define SOL_ECONNREFUSED 146 /* Connection refused by remote host*/ +#define SOL_EHOSTDOWN 147 /* Remote host in up in flames */ +#define SOL_EHOSTUNREACH 148 /* Make a left at Easton Ave..... */ +#define SOL_EWOULDBLOCK EAGAIN /* Just an alias */ +#define SOL_EALREADY 149 /* Operation is already occurring */ +#define SOL_EINPROGRESS 150 /* Operation is happening now */ +#define SOL_ESTALE 151 /* Fungus growth on NFS file handle */ + +#endif /* !(_SPARC_SOLERRNO_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/stat.h linux/include/asm-sparc/stat.h --- v1.3.43/linux/include/asm-sparc/stat.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/stat.h Sat Nov 25 04:32:53 1995 @@ -0,0 +1,41 @@ +/* $Id: stat.h,v 1.6 1995/11/25 02:32:53 davem Exp $ */ +#ifndef _SPARC_STAT_H +#define _SPARC_STAT_H + +#include + +struct old_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct new_stat { + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + short st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + time_t st_atime; + unsigned long __unused1; + time_t st_mtime; + unsigned long __unused2; + time_t st_ctime; + unsigned long __unused3; + off_t st_blksize; + off_t st_blocks; + unsigned long __unused4[2]; +}; + +#endif diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/statfs.h linux/include/asm-sparc/statfs.h --- v1.3.43/linux/include/asm-sparc/statfs.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/statfs.h Sat Nov 25 04:32:55 1995 @@ -0,0 +1,22 @@ +/* $Id: statfs.h,v 1.3 1995/11/25 02:32:54 davem Exp $ */ +#ifndef _SPARC_STATFS_H +#define _SPARC_STATFS_H + +typedef struct { + long val[2]; +} fsid_t; + +struct statfs { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + fsid_t f_fsid; + long f_namelen; /* SunOS ignores this field. */ + long f_spare[6]; +}; + +#endif diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h --- v1.3.43/linux/include/asm-sparc/string.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/string.h Sat Nov 25 04:32:57 1995 @@ -1,205 +1,13 @@ -/* string.h: External definitions for optimized assembly string +/* $Id: string.h,v 1.15 1995/11/25 02:32:56 davem Exp $ + * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -#ifndef _SPARC_STRING_H -#define _SPARC_STRING_H +#ifndef __SPARC_STRING_H__ +#define __SPARC_STRING_H__ -extern __inline__ size_t strlen(const char * str) -{ - const char *sc; +/* Nothing yet... */ - for (sc = str; *sc != '\0'; ++sc) - /* nothing */; - return sc - str; -} - -extern __inline__ int strcmp(const char* str1, const char* str2) -{ - register signed char __res; - - while (1) { - if ((__res = *str1 - *str2++) != 0 || !*str1++) - break; - } - - return __res; -} - -extern __inline__ int strncmp(const char* str1, const char* str2, size_t strlen) -{ - register signed char __res = 0; - - while (strlen) { - if ((__res = *str1 - *str2++) != 0 || !*str1++) - break; - strlen--; - } - - return __res; -} - - -extern __inline__ char *strcpy(char* dest, const char* source) -{ - char *tmp = dest; - - while ((*dest++ = *source++) != '\0') - /* nothing */; - return tmp; -} - -extern __inline__ char *strncpy(char *dest, const char *source, size_t cpylen) -{ - char *tmp = dest; - - while (cpylen-- && (*dest++ = *source++) != '\0') - /* nothing */; - - return tmp; -} - -extern __inline__ char *strcat(char *dest, const char *src) -{ - char *tmp = dest; - - while (*dest) - dest++; - while ((*dest++ = *src++) != '\0') - ; - - return tmp; -} - -extern __inline__ char *strncat(char *dest, const char *src, size_t len) -{ - char *tmp = dest; - - if (len) { - while (*dest) - dest++; - while ((*dest++ = *src++)) { - if (--len == 0) - break; - } - } - - return tmp; -} - -extern __inline__ char *strchr(const char *src, int c) -{ - for(; *src != c; ++src) - if (*src == '\0') - return NULL; - return (char *) src; -} - -extern __inline__ char *strpbrk(const char *cs, const char *ct) -{ - const char *sc1,*sc2; - - for( sc1 = cs; *sc1 != '\0'; ++sc1) { - for( sc2 = ct; *sc2 != '\0'; ++sc2) { - if (*sc1 == *sc2) - return (char *) sc1; - } - } - return NULL; -} - - -extern __inline__ size_t strspn(const char *s, const char *accept) -{ - const char *p; - const char *a; - size_t count = 0; - - for (p = s; *p != '\0'; ++p) { - for (a = accept; *a != '\0'; ++a) { - if (*p == *a) - break; - } - if (*a == '\0') - return count; - ++count; - } - - return count; -} - -extern __inline__ char *strtok(char *s, const char *ct) -{ - char *sbegin, *send; - - sbegin = s ? s : ___strtok; - if (!sbegin) { - return NULL; - } - sbegin += strspn(sbegin,ct); - if (*sbegin == '\0') { - ___strtok = NULL; - return( NULL ); - } - send = strpbrk( sbegin, ct); - if (send && *send != '\0') - *send++ = '\0'; - ___strtok = send; - return (sbegin); -} - - -extern __inline__ void *memset(void *src, int c, size_t count) -{ - char *xs = (char *) src; - - while (count--) - *xs++ = c; - - return src; -} - -extern __inline__ void *memcpy(void *dest, const void *src, size_t count) -{ - char *tmp = (char *) dest, *s = (char *) src; - - while (count--) - *tmp++ = *s++; - - return dest; -} - -extern __inline__ void *memmove(void *dest, const void *src, size_t count) -{ - char *tmp, *s; - - if (dest <= src) { - tmp = (char *) dest; - s = (char *) src; - while (count--) - *tmp++ = *s++; - } - else { - tmp = (char *) dest + count; - s = (char *) src + count; - while (count--) - *--tmp = *--s; - } - - return dest; -} - -extern __inline__ int memcmp(const void *cs, const void *ct, size_t count) -{ - const unsigned char *su1, *su2; - signed char res = 0; - - for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) - if ((res = *su1 - *su2) != 0) - break; - return res; -} - -#endif /* !(_SPARC_STRING_H) */ +#endif /* !(__SPARC_STRING_H__) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/sysen.h linux/include/asm-sparc/sysen.h --- v1.3.43/linux/include/asm-sparc/sysen.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/sysen.h Sat Nov 25 04:32:58 1995 @@ -1,4 +1,5 @@ -/* sysen.h: Bit fields within the "System Enable" register accessed via +/* $Id: sysen.h,v 1.3 1995/11/25 02:32:58 davem Exp $ + * sysen.h: Bit fields within the "System Enable" register accessed via * the ASI_CONTROL address space at address AC_SYSENABLE. * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h --- v1.3.43/linux/include/asm-sparc/system.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/system.h Sat Nov 25 04:33:00 1995 @@ -1,22 +1,13 @@ +/* $Id: system.h,v 1.19 1995/11/25 02:32:59 davem Exp $ */ #ifndef __SPARC_SYSTEM_H #define __SPARC_SYSTEM_H #include -/* - * I wish the boot time image was as beautiful as the Alpha's - * but no such luck. The icky PROM loads us at 0x0, and jumps - * to magic address 0x4000 to start things going. - * - * Sorry, I can't impress people with cool looking 64-bit values - * yet. Wait till V9 ;-) - */ - #include #include #include -#define START_ADDR (0x00004000) #define EMPTY_PGT (&empty_bad_page) #define EMPTY_PGE (&empty_bad_page_table) #define ZERO_PGE (&empty_zero_page) @@ -32,7 +23,7 @@ sun4m = 0x02, sun4d = 0x03, sun4e = 0x04, - sun4u = 0x05, + sun4u = 0x05, /* V8 ploos ploos */ sun_unknown = 0x06, }; @@ -42,98 +33,99 @@ extern unsigned long empty_bad_page_table; extern unsigned long empty_zero_page; -extern void wrent(void *, unsigned long); -extern void wrkgp(unsigned long); extern struct linux_romvec *romvec; - -#define halt() do { \ - printk("Entering monitor in file %s at line %d\n", __FILE__, __LINE__); \ -romvec->pv_halt(); } while(0) - -#define move_to_user_mode() halt() - -#ifndef stbar /* store barrier Sparc insn to synchronize stores in PSO */ -#define stbar() __asm__ __volatile__("stbar": : :"memory") -#endif +#define halt() romvec->pv_halt() /* When a context switch happens we must flush all user windows so that * the windows of the current process are flushed onto it's stack. This - * way the windows are all clean for the next process. + * way the windows are all clean for the next process and the stack + * frames are up to date. */ - -#define flush_user_windows() \ -do { __asm__ __volatile__( \ - "save %sp, -64, %sp\n\t" \ - "save %sp, -64, %sp\n\t" \ - "save %sp, -64, %sp\n\t" \ - "save %sp, -64, %sp\n\t" \ - "save %sp, -64, %sp\n\t" \ - "save %sp, -64, %sp\n\t" \ - "save %sp, -64, %sp\n\t" \ - "restore\n\t" \ - "restore\n\t" \ - "restore\n\t" \ - "restore\n\t" \ - "restore\n\t" \ - "restore\n\t" \ - "restore\n\t"); } while(0) - +extern void flush_user_windows(void); extern void sparc_switch_to(void *new_task); +#define switch_to(p) do { \ + flush_user_windows(); \ + switch_to_context(p); \ + sparc_switch_to(p); \ + } while(0) -#define switch_to(p) sparc_switch_to(p) +/* Changing the IRQ level on the Sparc. */ +extern inline void setipl(int __new_ipl) +{ + __asm__ __volatile__("rd %%psr, %%g1\n\t" + "andn %%g1, %1, %%g1\n\t" + "sll %0, 8, %%g2\n\t" + "and %%g2, %1, %%g2\n\t" + "or %%g1, %%g2, %%g1\n\t" + "wr %%g1, 0x0, %%psr\n\t" + "nop; nop; nop\n\t" : : + "r" (__new_ipl), "i" (PSR_PIL) : + "g1", "g2"); +} -/* Changing the PIL on the sparc is a bit hairy. I'll figure out some - * more optimized way of doing this soon. This is bletcherous code. - */ +extern inline int getipl(void) +{ + int retval; + + __asm__ __volatile__("rd %%psr, %0\n\t" + "and %0, %1, %0\n\t" + "srl %0, 8, %0\n\t" : + "=r" (retval) : + "i" (PSR_PIL)); + return retval; +} -#define swpipl(__new_ipl) \ -({ unsigned long psr, retval; \ -__asm__ __volatile__( \ - "rd %%psr, %0\n\t" : "=&r" (psr)); \ -retval = psr; \ -psr = (psr & ~(PSR_PIL)); \ -psr |= ((__new_ipl << 8) & PSR_PIL); \ -__asm__ __volatile__( \ - "wr %0, 0x0, %%psr\n\t" \ - : : "r" (psr)); \ -retval = ((retval>>8)&15); \ -retval; }) - -#define cli() swpipl(15) /* 15 = no int's except nmi's */ -#define sti() swpipl(0) /* I'm scared */ -#define save_flags(flags) do { flags = swpipl(15); } while (0) -#define restore_flags(flags) swpipl(flags) +extern inline int swpipl(int __new_ipl) +{ + int retval; -#define iret() __asm__ __volatile__ ("jmp %%l1\n\t" \ - "rett %%l2\n\t": : :"memory") + __asm__ __volatile__("rd %%psr, %%g1\n\t" + "srl %%g1, 8, %0\n\t" + "and %0, 15, %0\n\t" + "andn %%g1, %2, %%g1\n\t" + "and %1, 15, %%g2\n\t" + "sll %%g2, 8, %%g2\n\t" + "or %%g1, %%g2, %%g1\n\t" + "wr %%g1, 0x0, %%psr\n\t" + "nop; nop; nop\n\t" : + "=r" (retval) : + "r" (__new_ipl), "i" (PSR_PIL) : + "g1", "g2"); + return retval; +} -/* Must this be atomic? */ +#define cli() setipl(15) /* 15 = no int's except nmi's */ +#define sti() setipl(0) /* I'm scared */ +#define save_flags(flags) do { flags = getipl(); } while (0) +#define restore_flags(flags) setipl(flags) +#define nop() __asm__ __volatile__ ("nop"); -extern inline void *xchg_u32(int * m, unsigned long val) +extern inline unsigned long xchg_u32(volatile unsigned long *m, unsigned long val) { - unsigned long dummy; + unsigned long flags, retval; - __asm__ __volatile__( - "ld %1,%2\n\t" - "st %0, %1\n\t" - "or %%g0, %2, %0" - : "=r" (val), "=m" (*m), "=r" (dummy) - : "0" (val)); - return (void *) val; + save_flags(flags); cli(); + retval = *m; + *m = val; + restore_flags(flags); + return retval; } +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define tas(ptr) (xchg((ptr),1)) -/* pointers are 32 bits on the sparc (at least the v8, and they'll work - * on the V9 none the less). I don't need the xchg_u64 routine for now. - */ +extern void __xchg_called_with_bad_pointer(void); -extern inline void *xchg_ptr(void *m, void *val) +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) { - return (void *) xchg_u32((int *) m, (unsigned long) val); + switch (size) { + case 4: + return xchg_u32(ptr, x); + }; + __xchg_called_with_bad_pointer(); + return x; } - - #endif /* __ASSEMBLY__ */ -#endif +#endif /* !(__SPARC_SYSTEM_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h --- v1.3.43/linux/include/asm-sparc/termios.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/termios.h Sat Nov 25 04:33:02 1995 @@ -0,0 +1,384 @@ +/* $Id: termios.h,v 1.10 1995/11/25 02:33:01 davem Exp $ */ +#ifndef _SPARC_TERMIOS_H +#define _SPARC_TERMIOS_H + +#include + +#include + +struct sgttyb { + char sg_ispeed; + char sg_ospeed; + char sg_erase; + char sg_kill; + short sg_flags; +}; + +struct tchars { + char t_intrc; + char t_quitc; + char t_startc; + char t_stopc; + char t_eofc; + char t_brkc; +}; + +struct ltchars { + char t_suspc; + char t_dsuspc; + char t_rprntc; + char t_flushc; + char t_werasc; + char t_lnextc; +}; + +struct sunos_ttysize { + int st_lines; /* Lines on the terminal */ + int st_columns; /* Columns on the terminal */ +}; + +/* Big T */ +#define TCGETA _IOR('T', 1, struct termio) +#define TCSETA _IOW('T', 2, struct termio) +#define TCSETAW _IOW('T', 3, struct termio) +#define TCSETAF _IOW('T', 4, struct termio) +#define TCSBRK _IO('T', 5) +#define TCXONC _IO('T', 6) +#define TCFLSH _IO('T', 7) +#define TCGETS _IOR('T', 8, struct termios) +#define TCSETS _IOW('T', 9, struct termios) +#define TCSETSW _IOW('T', 10, struct termios) +#define TCSETSF _IOW('T', 11, struct termios) + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +#define TCGETSTAT _IO('T', 200) /* Rutgers specific */ +#define TCSETSTAT _IO('T', 201) /* Rutgers specific */ + +/* Little t */ +#define TIOCGETD _IOR('t', 0, int) +#define TIOCSETD _IOW('t', 1, int) +#define TIOCHPCL _IO('t', 2) /* SunOS Specific */ +#define TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ +#define TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ +#define TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ +#define TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ +#define TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ +#define TIOCEXCL _IO('t', 13) +#define TIOCNXCL _IO('t', 14) +#define TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ +#define TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ +#define TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ +#define TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ +#define TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ +#define TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ +#define TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ +#define TIOCCONS _IO('t', 36) +#define TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ +#define TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ +#define TIOCGSOFTCAR _IOR('t', 100, int) +#define TIOCSSOFTCAR _IOW('t', 101, int) +#define TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ +#define TIOCSWINSZ _IOW('t', 103, struct winsize) +#define TIOCGWINSZ _IOR('t', 104, struct winsize) +#define TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ +#define TIOCMGET _IOR('t', 106, int) +#define TIOCMBIC _IOW('t', 107, int) +#define TIOCMBIS _IOW('t', 108, int) +#define TIOCMSET _IOW('t', 109, int) +#define TIOCSTART _IO('t', 110) /* SunOS Specific */ +#define TIOCSTOP _IO('t', 111) /* SunOS Specific */ +#define TIOCPKT _IOW('t', 112, int) +#define TIOCNOTTY _IO('t', 113) +#define TIOCSTI _IOW('t', 114, char) +#define TIOCOUTQ _IOR('t', 115, int) +#define TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ +#define TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +#define TIOCCDTR _IO('t', 120) /* SunOS Specific */ +#define TIOCSDTR _IO('t', 121) /* SunOS Specific */ +#define TIOCCBRK _IO('t', 122) /* SunOS Specific */ +#define TIOCSBRK _IO('t', 123) /* SunOS Specific */ +#define TIOCLGET _IOW('t', 124, int) /* SunOS Specific */ +#define TIOCLSET _IOW('t', 125, int) /* SunOS Specific */ +#define TIOCLBIC _IOW('t', 126, int) /* SunOS Specific */ +#define TIOCLBIS _IOW('t', 127, int) /* SunOS Specific */ +#define TIOCISPACE _IOR('t', 128, int) /* SunOS Specific */ +#define TIOCISIZE _IOR('t', 129, int) /* SunOS Specific */ +#define TIOCSPGRP _IOW('t', 130, int) +#define TIOCGPGRP _IOR('t', 131, int) +#define TIOCSCTTY _IO('t', 132) + +/* Little f */ +#define FIOCLEX _IO('f', 1) +#define FIONCLEX _IO('f', 2) +#define FIOASYNC _IOW('f', 125, int) +#define FIONBIO _IOW('f', 126, int) +#define FIONREAD _IOR('f', 127, int) +#define TIOCINQ FIONREAD + +/* Linux specific, no SunOS equivalent. */ +#define TIOCLINUX 0x541C +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TCSBRKP 0x5425 +#define TIOCTTYGSTRUCT 0x5426 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#define NCCS 17 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VEOL 5 +#define VEOL2 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VMIN VEOF +#define VTIME VEOL + +#ifdef __KERNEL__ +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" +#endif + +/* c_iflag bits */ +#define IGNBRK 0x00000001 +#define BRKINT 0x00000002 +#define IGNPAR 0x00000004 +#define PARMRK 0x00000008 +#define INPCK 0x00000010 +#define ISTRIP 0x00000020 +#define INLCR 0x00000040 +#define IGNCR 0x00000080 +#define ICRNL 0x00000100 +#define IUCLC 0x00000200 +#define IXON 0x00000400 +#define IXANY 0x00000800 +#define IXOFF 0x00001000 +#define IMAXBEL 0x00002000 + +/* c_oflag bits */ +#define OPOST 0x00000001 +#define OLCUC 0x00000002 +#define ONLCR 0x00000004 +#define OCRNL 0x00000008 +#define ONOCR 0x00000010 +#define ONLRET 0x00000020 +#define OFILL 0x00000040 +#define OFDEL 0x00000080 +#define NLDLY 0x00000100 +#define NL0 0x00000000 +#define NL1 0x00000100 +#define CRDLY 0x00000600 +#define CR0 0x00000000 +#define CR1 0x00000200 +#define CR2 0x00000400 +#define CR3 0x00000600 +#define TABDLY 0x00001800 +#define TAB0 0x00000000 +#define TAB1 0x00000800 +#define TAB2 0x00001000 +#define TAB3 0x00001800 +#define XTABS 0x00001800 +#define BSDLY 0x00002000 +#define BS0 0x00000000 +#define BS1 0x00002000 +#define VTDLY 0x00004000 +#define VT0 0x00000000 +#define VT1 0x00004000 +#define FFDLY 0x00008000 +#define FF0 0x00000000 +#define FF1 0x00008000 +#define PAGEOUT 0x00010000 /* SUNOS specific */ +#define WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define CBAUD 0x0000000f +#define B0 0x00000000 /* hang up */ +#define B50 0x00000001 +#define B75 0x00000002 +#define B110 0x00000003 +#define B134 0x00000004 +#define B150 0x00000005 +#define B200 0x00000006 +#define B300 0x00000007 +#define B600 0x00000008 +#define B1200 0x00000009 +#define B1800 0x0000000a +#define B2400 0x0000000b +#define B4800 0x0000000c +#define B9600 0x0000000d +#define B19200 0x0000000e +#define B38400 0x0000000f +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0x00000030 +#define CS5 0x00000000 +#define CS6 0x00000010 +#define CS7 0x00000020 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 +/* We'll never see these speeds with the Zilogs' but for completeness... */ +#define CBAUDEX 0x00010000 +#define B57600 0x00010001 +#define B115200 0x00010002 +#define B230400 0x00010003 +#define CIBAUD 0x000f0000 /* input baud rate (not used) */ +#define CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0x00000001 +#define ICANON 0x00000002 +#define XCASE 0x00000004 +#define ECHO 0x00000008 +#define ECHOE 0x00000010 +#define ECHOK 0x00000020 +#define ECHONL 0x00000040 +#define NOFLSH 0x00000080 +#define TOSTOP 0x00000100 +#define ECHOCTL 0x00000200 +#define ECHOPRT 0x00000400 +#define ECHOKE 0x00000800 +#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define FLUSHO 0x00002000 +#define PENDIN 0x00004000 +#define IEXTEN 0x00008000 + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 + +#ifdef __KERNEL__ + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +extern inline void trans_from_termio(struct termio * termio, + struct termios * termios) +{ +#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y)) + SET_LOW_BITS(termios->c_iflag, termio->c_iflag); + SET_LOW_BITS(termios->c_oflag, termio->c_oflag); + SET_LOW_BITS(termios->c_cflag, termio->c_cflag); + SET_LOW_BITS(termios->c_lflag, termio->c_lflag); +#undef SET_LOW_BITS + memcpy(termios->c_cc, termio->c_cc, NCC); +} + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +extern inline void trans_to_termio(struct termios * termios, + struct termio * termio) +{ + termio->c_iflag = termios->c_iflag; + termio->c_oflag = termios->c_oflag; + termio->c_cflag = termios->c_cflag; + termio->c_lflag = termios->c_lflag; + termio->c_line = termios->c_line; + memcpy(termio->c_cc, termios->c_cc, NCC); +} + +#endif /* __KERNEL__ */ + +#endif /* _SPARC_TERMIOS_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/timer.h linux/include/asm-sparc/timer.h --- v1.3.43/linux/include/asm-sparc/timer.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/timer.h Sat Nov 25 04:33:04 1995 @@ -1,4 +1,5 @@ -/* timer.h: Definitions for the timer chips on the Sparc. +/* $Id: timer.h,v 1.10 1995/11/25 02:33:03 davem Exp $ + * timer.h: Definitions for the timer chips on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -78,6 +79,7 @@ }; extern struct sun4m_timer_regs *sun4m_timers; +extern volatile unsigned int *master_l10_counter; extern volatile unsigned int *master_l10_limit; #endif /* !(_SPARC_TIMER_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/traps.h linux/include/asm-sparc/traps.h --- v1.3.43/linux/include/asm-sparc/traps.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/traps.h Sat Nov 25 04:33:06 1995 @@ -1,4 +1,5 @@ -/* traps.h: Format of entries for the Sparc trap table. +/* $Id: traps.h,v 1.5 1995/11/25 02:33:05 davem Exp $ + * traps.h: Format of entries for the Sparc trap table. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -38,6 +39,14 @@ extern struct tt_v9_entry *sparc_v9_ttablel0; extern struct tt_v9_entry *sparc_v9_ttablel1; +extern __inline__ unsigned long get_tbr(void) +{ + unsigned long tbr; + + __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (tbr)); + return tbr; +} + /* For patching the trap table at boot time, we need to know how to * form various common Sparc instructions. Thus these macros... */ @@ -105,6 +114,16 @@ #define SP_TRAP_SOLARIS 0x88 /* Solaris System Call */ #define SP_TRAP_NETBSD 0x89 /* NetBSD System Call */ #define SP_TRAP_LINUX 0x90 /* Linux System Call */ + +/* Names used for compatibility with SunOS */ +#define ST_SYSCALL 0x00 +#define ST_BREAKPOINT 0x01 +#define ST_DIV0 0x02 +#define ST_FLUSH_WINDOWS 0x03 +#define ST_CLEAN_WINDOWS 0x04 +#define ST_RANGE_CHECK 0x05 +#define ST_FIX_ALIGN 0x06 +#define ST_INT_OVERFLOW 0x07 /* Special traps... */ #define SP_TRAP_KBPT1 0xfe /* KADB/PROM Breakpoint one */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/tsunami.h linux/include/asm-sparc/tsunami.h --- v1.3.43/linux/include/asm-sparc/tsunami.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/tsunami.h Sat Nov 25 04:33:07 1995 @@ -1,4 +1,5 @@ -/* tsunami.h: Module specific definitions for Tsunami V8 Sparcs +/* $Id: tsunami.h,v 1.2 1995/11/25 02:33:06 davem Exp $ + * tsunami.h: Module specific definitions for Tsunami V8 Sparcs * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/types.h linux/include/asm-sparc/types.h --- v1.3.43/linux/include/asm-sparc/types.h Thu Feb 2 08:42:35 1995 +++ linux/include/asm-sparc/types.h Sat Nov 25 04:33:09 1995 @@ -1,3 +1,4 @@ +/* $Id: types.h,v 1.8 1995/11/25 02:33:08 davem Exp $ */ #ifndef _SPARC_TYPES_H #define _SPARC_TYPES_H @@ -6,10 +7,6 @@ * header files exported to user space <-- Linus sez this */ -/* NOTE: I will have to change these when the V9 sparcs come into play, - * however this won't be for a while. - */ - #ifndef _SIZE_T #define _SIZE_T #ifdef __svr4__ @@ -26,9 +23,30 @@ #ifndef _PTRDIFF_T #define _PTRDIFF_T -typedef int ptrdiff_t; +typedef long int ptrdiff_t; +#endif + +#ifndef _TIME_T +#define _TIME_T +typedef long time_t; #endif +#ifndef _CLOCK_T +#define _CLOCK_T +typedef long clock_t; +#endif + +typedef int pid_t; +typedef unsigned short uid_t; +typedef unsigned short gid_t; +typedef unsigned short dev_t; +typedef unsigned long ino_t; +typedef unsigned short mode_t; +typedef unsigned short umode_t; +typedef short nlink_t; +typedef long daddr_t; +typedef long off_t; + typedef signed char __s8; typedef unsigned char __u8; @@ -38,8 +56,6 @@ typedef signed int __s32; typedef unsigned int __u32; -/* Only 32-bit sparcs for now so.... */ - typedef signed long long __s64; typedef unsigned long long __u64; @@ -54,11 +70,62 @@ typedef signed int s32; typedef unsigned int u32; -/* Again, only have to worry about 32-bits */ - typedef signed long long s64; typedef unsigned long long u64; #endif /* __KERNEL__ */ + +#undef __FD_SET +static __inline__ void __FD_SET(unsigned long fd, fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] |= (1UL<<_rem); +} + +#undef __FD_CLR +static __inline__ void __FD_CLR(unsigned long fd, fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); +} + +#undef __FD_ISSET +static __inline__ int __FD_ISSET(unsigned long fd, fd_set *p) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant cases (4 or 8 longs, + * for 256 and 512-bit fd_sets respectively) + */ +#undef __FD_ZERO +static __inline__ void __FD_ZERO(fd_set *p) +{ + unsigned int *tmp = p->fds_bits; + int i; + + if (__builtin_constant_p(__FDSET_INTS)) { + switch (__FDSET_INTS) { + case 8: + tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; + tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; + return; + case 4: + tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; + return; + } + } + i = __FDSET_INTS; + while (i) { + i--; + *tmp = 0; + tmp++; + } +} #endif /* defined(_SPARC_TYPES_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/ultra.h linux/include/asm-sparc/ultra.h --- v1.3.43/linux/include/asm-sparc/ultra.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/ultra.h Sat Nov 25 04:33:11 1995 @@ -1,4 +1,5 @@ -/* ultra.h: Definitions and defines for the TI V9 UltraSparc. +/* $Id: ultra.h,v 1.2 1995/11/25 02:33:10 davem Exp $ + * ultra.h: Definitions and defines for the TI V9 UltraSparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v1.3.43/linux/include/asm-sparc/unistd.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/unistd.h Sat Nov 25 04:33:14 1995 @@ -1,3 +1,4 @@ +/* $Id: unistd.h,v 1.15 1995/11/25 02:33:12 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -9,23 +10,271 @@ * before the trap into the system call with gcc 'asm' statements. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * + * SunOS compatability based upon preliminary work which is: + * + * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */ -/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ +#define __NR_setup 0 /* Used only by init, to get system going. */ +#define __NR_exit 1 /* Common */ +#define __NR_fork 2 /* Common */ +#define __NR_read 3 /* Common */ +#define __NR_write 4 /* Common */ +#define __NR_open 5 /* Common */ +#define __NR_close 6 /* Common */ +#define __NR_wait4 7 /* Common */ +#define __NR_creat 8 /* Common */ +#define __NR_link 9 /* Common */ +#define __NR_unlink 10 /* Common */ +#define __NR_execv 11 /* SunOS Specific */ +#define __NR_chdir 12 /* Common */ +/* #define __NR_ni_syscall 13 ENOSYS under SunOS */ +#define __NR_mknod 14 /* Common */ +#define __NR_chmod 15 /* Common */ +#define __NR_chown 16 /* Common */ +#define __NR_brk 17 /* Common */ +/* #define __NR_ni_syscall 18 ENOSYS under SunOS */ +#define __NR_lseek 19 /* Common */ +#define __NR_getpid 20 /* Common */ +/* #define __NR_ni_syscall 21 ENOSYS under SunOS */ +/* #define __NR_ni_syscall 22 ENOSYS under SunOS */ +#define __NR_setuid 23 /* Implemented via setreuid in SunOS */ +#define __NR_getuid 24 /* Common */ +/* #define __NR_ni_syscall 25 ENOSYS under SunOS */ +#define __NR_ptrace 26 /* Common */ +#define __NR_alarm 27 /* Implemented via setitimer in SunOS */ +/* #define __NR_ni_syscall 28 ENOSYS under SunOS */ +#define __NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ +#define __NR_utime 30 /* Implemented via utimes() under SunOS */ +#define __NR_stty 31 /* Implemented via ioctl() under SunOS */ +#define __NR_gtty 32 /* Implemented via ioctl() under SunOS */ +#define __NR_access 33 /* Common */ +#define __NR_nice 34 /* Implemented via get/setpriority() in SunOS */ +#define __NR_ftime 35 /* Implemented via gettimeofday() in SunOS */ +#define __NR_sync 36 /* Common */ +#define __NR_kill 37 /* Common */ +#define __NR_stat 38 /* Common */ +/* #define __NR_ni_syscall 39 ENOSYS under SunOS */ +#define __NR_lstat 40 /* Common */ +#define __NR_dup 41 /* Common */ +#define __NR_pipe 42 /* Common */ +#define __NR_times 43 /* Implemented via getrusage() in SunOS */ +#define __NR_profil 44 /* Common */ +/* #define __NR_ni_syscall 45 ENOSYS under SunOS */ +#define __NR_setgid 46 /* Implemented via setregid() in SunOS */ +#define __NR_getgid 47 /* Common */ +#define __NR_signal 48 /* Implemented via sigvec() in SunOS */ +#define __NR_geteuid 49 /* SunOS calls getuid() */ +#define __NR_getegid 50 /* SunOS calls getgid() */ +#define __NR_acct 51 /* Common */ +/* #define __NR_ni_syscall 52 ENOSYS under SunOS */ +#define __NR_mctl 53 /* SunOS specific */ +#define __NR_ioctl 54 /* Common */ +#define __NR_reboot 55 /* Common */ +/* #define __NR_ni_syscall 56 ENOSYS under SunOS */ +#define __NR_symlink 57 /* Common */ +#define __NR_readlink 58 /* Common */ +#define __NR_execve 59 /* Common */ +#define __NR_umask 60 /* Common */ +#define __NR_chroot 61 /* Common */ +#define __NR_fstat 62 /* Common */ +/* #define __NR_ni_syscall 63 ENOSYS under SunOS */ +#define __NR_getpagesize 64 /* Common */ +#define __NR_msync 65 /* Common in newer 1.3.x revs... */ +/* #define __NR_ni_syscall 66 ENOSYS under SunOS */ +/* #define __NR_ni_syscall 67 ENOSYS under SunOS */ +/* #define __NR_ni_syscall 68 ENOSYS under SunOS */ +#define __NR_sbrk 69 /* SunOS Specific */ +#define __NR_sstk 70 /* SunOS Specific */ +#define __NR_mmap 71 /* Common */ +#define __NR_vadvise 72 /* SunOS Specific */ +#define __NR_munmap 73 /* Common */ +#define __NR_mprotect 74 /* Common */ +#define __NR_madvise 75 /* SunOS Specific */ +#define __NR_vhangup 76 /* Common */ +/* #define __NR_ni_syscall 77 ENOSYS under SunOS */ +#define __NR_mincore 78 /* SunOS Specific */ +#define __NR_getgroups 79 /* Common */ +#define __NR_setgroups 80 /* Common */ +#define __NR_getpgrp 81 /* Common */ +#define __NR_setpgrp 82 /* setpgid, same difference... */ +#define __NR_setitimer 83 /* Common */ +/* #define __NR_ni_syscall 84 ENOSYS under SunOS */ +#define __NR_swapon 85 /* Common */ +#define __NR_getitimer 86 /* Common */ +#define __NR_gethostname 87 /* SunOS Specific */ +#define __NR_sethostname 88 /* Common */ +#define __NR_getdtablesize 89 /* SunOS Specific */ +#define __NR_dup2 90 /* Common */ +#define __NR_getdopt 91 /* SunOS Specific */ +#define __NR_fcntl 92 /* Common */ +#define __NR_select 93 /* Common */ +#define __NR_setdopt 94 /* SunOS Specific */ +#define __NR_fsync 95 /* Common */ +#define __NR_setpriority 96 /* Common */ +#define __NR_socket 97 /* SunOS Specific */ +#define __NR_connect 98 /* SunOS Specific */ +#define __NR_accept 99 /* SunOS Specific */ +#define __NR_getpriority 100 /* Common */ +#define __NR_send 101 /* SunOS Specific */ +#define __NR_recv 102 /* SunOS Specific */ +/* #define __NR_ni_syscall 103 ENOSYS under SunOS */ +#define __NR_bind 104 /* SunOS Specific */ +#define __NR_setsockopt 105 /* SunOS Specific */ +#define __NR_listen 106 /* SunOS Specific */ +/* #define __NR_ni_syscall 107 ENOSYS under SunOS */ +#define __NR_sigvec 108 /* SunOS Specific */ +#define __NR_sigblock 109 /* SunOS Specific */ +#define __NR_sigsetmask 110 /* SunOS Specific */ +#define __NR_sigpause 111 /* SunOS Specific */ +#define __NR_sigstack 112 /* SunOS Specific */ +#define __NR_recvmsg 113 /* SunOS Specific */ +#define __NR_sendmsg 114 /* SunOS Specific */ +#define __NR_vtrace 115 /* SunOS Specific */ +#define __NR_gettimeofday 116 /* Common */ +#define __NR_getrusage 117 /* Common */ +#define __NR_getsockopt 118 /* SunOS Specific */ +/* #define __NR_ni_syscall 119 ENOSYS under SunOS */ +#define __NR_readv 120 /* Common */ +#define __NR_writev 121 /* Common */ +#define __NR_settimeofday 122 /* Common */ +#define __NR_fchown 123 /* Common */ +#define __NR_fchmod 124 /* Common */ +#define __NR_recvfrom 125 /* SunOS Specific */ +#define __NR_setreuid 126 /* Common */ +#define __NR_setregid 127 /* Common */ +#define __NR_rename 128 /* Common */ +#define __NR_truncate 129 /* Common */ +#define __NR_ftruncate 130 /* Common */ +#define __NR_flock 131 /* Common */ +/* #define __NR_ni_syscall 132 ENOSYS under SunOS */ +#define __NR_sendto 133 /* SunOS Specific */ +#define __NR_shutdown 134 /* SunOS Specific */ +#define __NR_socketpair 135 /* SunOS Specific */ +#define __NR_mkdir 136 /* Common */ +#define __NR_rmdir 137 /* Common */ +#define __NR_utimes 138 /* SunOS Specific */ +/* #define __NR_ni_syscall 139 ENOSYS under SunOS */ +#define __NR_adjtime 140 /* SunOS Specific */ +#define __NR_getpeername 141 /* SunOS Specific */ +#define __NR_gethostid 142 /* SunOS Specific */ +/* #define __NR_ni_syscall 143 ENOSYS under SunOS */ +#define __NR_getrlimit 144 /* Common */ +#define __NR_setrlimit 145 /* Common */ +#define __NR_killpg 146 /* SunOS Specific */ +/* #define __NR_ni_syscall 147 ENOSYS under SunOS */ +/* #define __NR_ni_syscall 148 ENOSYS under SunOS */ +/* #define __NR_ni_syscall 149 ENOSYS under SunOS */ +#define __NR_getsockname 150 /* SunOS Specific */ +#define __NR_getmsg 151 /* SunOS Specific */ +#define __NR_putmsg 152 /* SunOS Specific */ +#define __NR_poll 153 /* SunOS Specific */ +/* #define __NR_ni_syscall 154 ENOSYS under SunOS */ +#define __NR_nfssvc 155 /* SunOS Specific */ +#define __NR_getdirentries 156 /* SunOS Specific */ +#define __NR_statfs 157 /* Common */ +#define __NR_fstatfs 158 /* Common */ +#define __NR_umount 159 /* Common */ +#define __NR_async_daemon 160 /* SunOS Specific */ +#define __NR_getfh 161 /* SunOS Specific */ +#define __NR_getdomainname 162 /* SunOS Specific */ +#define __NR_setdomainname 163 /* Common */ +/* #define __NR_ni_syscall 164 ENOSYS under SunOS */ +#define __NR_quotactl 165 /* Common */ +#define __NR_exportfs 166 /* SunOS Specific */ +#define __NR_mount 167 /* Common */ +#define __NR_ustat 168 /* Common */ +#define __NR_semsys 169 /* SunOS Specific */ +#define __NR_msgsys 170 /* SunOS Specific */ +#define __NR_shmsys 171 /* SunOS Specific */ +#define __NR_auditsys 172 /* SunOS Specific */ +#define __NR_rfssys 173 /* SunOS Specific */ +#define __NR_getdents 174 /* Common */ +#define __NR_setsid 175 /* Common */ +#define __NR_fchdir 176 /* Common */ +#define __NR_fchroot 177 /* SunOS Specific */ +#define __NR_vpixsys 178 /* SunOS Specific */ +#define __NR_aioread 179 /* SunOS Specific */ +#define __NR_aiowrite 180 /* SunOS Specific */ +#define __NR_aiowait 181 /* SunOS Specific */ +#define __NR_aiocancel 182 /* SunOS Specific */ +#define __NR_sigpending 183 /* Common */ +/* #define __NR_ni_syscall 184 ENOSYS under SunOS */ +#define __NR_setpgid 185 /* Common */ +#define __NR_pathconf 186 /* SunOS Specific */ +#define __NR_fpathconf 187 /* SunOS Specific */ +#define __NR_sysconf 188 /* SunOS Specific */ +#define __NR_uname 189 /* Linux Specific */ +#define __NR_init_module 190 /* Linux Specific */ +#define __NR_personality 191 /* Linux Specific */ +#define __NR_prof 192 /* Linux Specific */ +#define __NR_break 193 /* Linux Specific */ +#define __NR_lock 194 /* Linux Specific */ +#define __NR_mpx 195 /* Linux Specific */ +#define __NR_ulimit 196 /* Linux Specific */ +#define __NR_getppid 197 /* Linux Specific */ +#define __NR_sigaction 198 /* Linux Specific */ +#define __NR_sgetmask 199 /* Linux Specific */ +#define __NR_ssetmask 200 /* Linux Specific */ +#define __NR_sigsuspend 201 /* Linux Specific */ +#define __NR_oldlstat 202 /* Linux Specific */ +#define __NR_uselib 203 /* Linux Specific */ +#define __NR_readdir 204 /* Linux Specific */ +#define __NR_ioperm 205 /* Linux Specific - i386 specific, unused */ +#define __NR_socketcall 206 /* Linux Specific */ +#define __NR_syslog 207 /* Linux Specific */ +#define __NR_olduname 208 /* Linux Specific */ +#define __NR_iopl 209 /* Linux Specific - i386 specific, unused */ +#define __NR_idle 210 /* Linux Specific */ +#define __NR_vm86 211 /* Linux Specific - i386 specific, unused */ +#define __NR_waitpid 212 /* Linux Specific */ +#define __NR_swapoff 213 /* Linux Specific */ +#define __NR_sysinfo 214 /* Linux Specific */ +#define __NR_ipc 215 /* Linux Specific */ +#define __NR_sigreturn 216 /* Linux Specific */ +#define __NR_clone 217 /* Linux Specific */ +#define __NR_modify_ldt 218 /* Linux Specific - i386 specific, unused */ +#define __NR_adjtimex 219 /* Linux Specific */ +#define __NR_sigprocmask 220 /* Linux Specific */ +#define __NR_create_module 221 /* Linux Specific */ +#define __NR_delete_module 222 /* Linux Specific */ +#define __NR_get_kernel_syms 223 /* Linux Specific */ +#define __NR_getpgid 224 /* Linux Specific */ +#define __NR_bdflush 225 /* Linux Specific */ +#define __NR_sysfs 226 /* Linux Specific */ +#define __NR_afs_syscall 227 /* Linux Specific */ +#define __NR_setfsuid 228 /* Linux Specific */ +#define __NR_setfsgid 229 /* Linux Specific */ +#define __NR__newselect 230 /* Linux Specific */ +#define __NR_time 231 /* Linux Specific */ +#define __NR_oldstat 232 /* Linux Specific */ +#define __NR_stime 233 /* Linux Specific */ +#define __NR_oldfstat 234 /* Linux Specific */ +#define __NR_phys 235 /* Linux Specific */ +#define __NR__llseek 236 /* Linux Specific */ +#define __NR_mlock 237 +#define __NR_munlock 238 +#define __NR_mlockall 239 +#define __NR_munlockall 240 + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. + * XXX These need to be fixed to check the condition codes to see + * XXX the return value is an errorno or success. + */ #define _syscall0(type,name) \ type name(void) \ { \ long __res; \ -__asm__ volatile ("or %%g0, %0, %%o0\n\t" \ +__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ "t 0x10\n\t" \ - "nop\n\t" \ "or %%g0, %%o0, %0\n\t" \ : "=r" (__res) \ : "0" (__NR_##name) \ - : "o0"); \ + : "g1"); \ if (__res >= 0) \ return (type) __res; \ -errno = -__res; \ +errno = __res; \ return -1; \ } @@ -33,17 +282,16 @@ type name(type1 arg1) \ { \ long __res; \ -__asm__ volatile ("or %%g0, %0, %%o0\n\t" \ - "or %%g0, %1, %%o1\n\t" \ +__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ + "or %%g0, %1, %%o0\n\t" \ "t 0x10\n\t" \ - "nop\n\t" \ "or %%g0, %%o0, %0\n\t" \ : "=r" (__res), "=r" ((long)(arg1)) \ : "0" (__NR_##name),"1" ((long)(arg1)) \ - : "o0", "o1"); \ + : "g1", "o0"); \ if (__res >= 0) \ return (type) __res; \ -errno = -__res; \ +errno = __res; \ return -1; \ } @@ -51,18 +299,17 @@ type name(type1 arg1,type2 arg2) \ { \ long __res; \ -__asm__ volatile ("or %%g0, %0, %%o0\n\t" \ - "or %%g0, %1, %%o1\n\t" \ - "or %%g0, %2, %%o2\n\t" \ +__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ + "or %%g0, %1, %%o0\n\t" \ + "or %%g0, %2, %%o1\n\t" \ "t 0x10\n\t" \ - "nop\n\t" \ "or %%g0, %%o0, %0\n\t" \ - : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(args)) \ + : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \ - : "o0", "o1", "o2"); \ + : "g1", "o0", "o1"); \ if (__res >= 0) \ return (type) __res; \ -errno = -__res; \ +errno = __res; \ return -1; \ } @@ -70,21 +317,20 @@ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ long __res; \ -__asm__ volatile ("or %%g0, %0, %%o0\n\t" \ - "or %%g0, %1, %%o1\n\t" \ - "or %%g0, %2, %%o2\n\t" \ - "or %%g0, %3, %%o3\n\t" \ +__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ + "or %%g0, %1, %%o0\n\t" \ + "or %%g0, %2, %%o1\n\t" \ + "or %%g0, %3, %%o2\n\t" \ "t 0x10\n\t" \ - "nop\n\t" \ "or %%g0, %%o0, %0\n\t" \ : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \ "=r" ((long)(arg3)) \ : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \ "3" ((long)(arg3)) \ - : "o0", "o1", "o2", "o3"); \ + : "g1", "o0", "o1", "o2"); \ if (__res>=0) \ return (type) __res; \ -errno=-__res; \ +errno = __res; \ return -1; \ } @@ -92,22 +338,21 @@ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ long __res; \ -__asm__ volatile ("or %%g0, %0, %%o0\n\t" \ - "or %%g0, %1, %%o1\n\t" \ - "or %%g0, %2, %%o2\n\t" \ - "or %%g0, %3, %%o3\n\t" \ - "or %%g0, %4, %%o4\n\t" \ +__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ + "or %%g0, %1, %%o0\n\t" \ + "or %%g0, %2, %%o1\n\t" \ + "or %%g0, %3, %%o2\n\t" \ + "or %%g0, %4, %%o3\n\t" \ "t 0x10\n\t" \ - "nop\n\t" \ "or %%g0, %%o0, %0\n\t" \ : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \ "=r" ((long)(arg3)), "=r" ((long)(arg4)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \ "3" ((long)(arg3)),"4" ((long)(arg4)) \ - : "o0", "o1", "o2", "o3", "o4"); \ + : "g1", "o0", "o1", "o2", "o3"); \ if (__res>=0) \ return (type) __res; \ -errno=-__res; \ +errno = __res; \ return -1; \ } @@ -116,23 +361,22 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ { \ long __res; \ -__asm__ volatile ("or %%g0, %0, %%o0\n\t" \ - "or %%g0, %1, %%o1\n\t" \ - "or %%g0, %2, %%o2\n\t" \ - "or %%g0, %3, %%o3\n\t" \ - "or %%g0, %4, %%o4\n\t" \ - "or %%g0, %5, %%o5\n\t" \ +__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ + "or %%g0, %1, %%o0\n\t" \ + "or %%g0, %2, %%o1\n\t" \ + "or %%g0, %3, %%o2\n\t" \ + "or %%g0, %4, %%o3\n\t" \ + "or %%g0, %5, %%o4\n\t" \ "t 0x10\n\t" \ - "nop\n\t" \ "or %%g0, %%o0, %0\n\t" \ : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \ "=r" ((long)(arg3)), "=r" ((long)(arg4)), "=r" ((long)(arg5)) \ : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \ "3" ((long)(arg3)),"4" ((long)(arg4)),"5" ((long)(arg5)) \ - : "o0", "o1", "o2", "o3", "o4", "o5"); \ + : "g1", "o0", "o1", "o2", "o3", "o4"); \ if (__res>=0) \ return (type) __res; \ -errno=-__res; \ +errno = __res; \ return -1; \ } @@ -153,6 +397,7 @@ #define __NR__exit __NR_exit /* static inline _syscall0(int,idle) */ static inline _syscall0(int,fork) +static inline _syscall2(int,clone,unsigned long,flags,char *,ksp) static inline _syscall0(int,pause) /* static inline _syscall0(int,setup) */ static inline _syscall0(int,sync) @@ -168,32 +413,57 @@ extern void sys_idle(void); static inline void idle(void) { - printk("[%d]idle()\n",current->pid); sys_idle(); - for(;;); } extern int sys_setup(void); static inline int setup(void) { - int retval; - - printk("[%d]setup()\n",current->pid); - retval = sys_setup(); - printk("[%d]setup() returned %d\n",current->pid, retval); + return sys_setup(); } extern int sys_waitpid(int, int *, int); static inline pid_t wait(int * wait_stat) { - long retval, i; - printk("[%d]wait(%p)\n", current->pid, wait_stat); + long retval; retval = waitpid(-1,wait_stat,0); - printk("[%d]wait(%p) returned %ld\n", current->pid, wait_stat, retval); - for (i = 0; i < 1000000000; i++); return retval; } -#endif +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + + __asm__ __volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */ + "mov %5, %%g3\n\t" /* and arg. */ + "mov %1, %%g1\n\t" + "mov %2, %%o0\n\t" /* Clone flags. */ + "mov 0, %%o1\n\t" /* usp arg == 0 */ + "t 0x10\n\t" /* Linux/Sparc clone(). */ + "cmp %%o1, 0\n\t" + "be 1f\n\t" /* The parent, just return. */ + " nop\n\t" /* Delay slot. */ + "jmpl %%g2, %%o7\n\t" /* Call the function. */ + " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ + "mov %3, %%g1\n\t" + "t 0x10\n\t" /* Linux/Sparc exit(). */ + /* Notreached by child. */ + "1: mov %%o0, %0\n\t" : + "=r" (retval) : + "i" (__NR_clone), "r" (flags | CLONE_VM), + "i" (__NR_exit), "r" (fn), "r" (arg) : + "g1", "g2", "g3", "o0", "o1", "memory"); + return retval; +} + +#endif /* __KERNEL_SYSCALLS__ */ #endif /* _SPARC_UNISTD_H */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/user.h linux/include/asm-sparc/user.h --- v1.3.43/linux/include/asm-sparc/user.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/user.h Sat Nov 25 04:33:17 1995 @@ -0,0 +1,29 @@ +/* $Id: user.h,v 1.2 1995/11/25 02:33:15 davem Exp $ + * asm-sparc/user.h: Core file definitions for the Sparc. + * + * Copyright (C) 1995 (davem@caip.rutgers.edu) + */ +#ifndef _SPARC_USER_H +#define _SPARC_USER_H + +struct user { + unsigned long regs[24 + 32]; /* locals, ins, globals + fpu regs */ + size_t u_tsize; + size_t u_dsize; + size_t u_ssize; + unsigned long start_code; + unsigned long start_data; + unsigned long start_stack; + int signal; + unsigned long *u_ar0; + unsigned long magic; + char u_comm[32]; +}; + +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_DATA_START_ADDR (u.start_data) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* !(_SPARC_USER_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/vac-ops.h linux/include/asm-sparc/vac-ops.h --- v1.3.43/linux/include/asm-sparc/vac-ops.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/vac-ops.h Sat Nov 25 04:33:19 1995 @@ -1,89 +1,171 @@ +/* $Id: vac-ops.h,v 1.7 1995/11/25 02:33:18 davem Exp $ */ #ifndef _SPARC_VAC_OPS_H #define _SPARC_VAC_OPS_H /* vac-ops.h: Inline assembly routines to do operations on the Sparc - VAC (virtual address cache). - - Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu) -*/ - -extern unsigned long *trapbase; -extern char end, etext, edata; - -extern void flush_vac_context(void); -extern void flush_vac_segment(unsigned int foo_segment); -extern void flush_vac_page(unsigned int foo_addr); - -extern int vac_do_hw_vac_flushes, vac_size, vac_linesize; -extern int vac_entries_per_context, vac_entries_per_segment; -extern int vac_entries_per_page; - -/* enable_vac() enables the virtual address cache. It returns 0 on - success, 1 on failure. -*/ - -extern __inline__ int enable_vac(void) -{ - int success=0; - - __asm__ __volatile__("lduba [%1] 2, %0\n\t" - "or %0, 0x10, %0\n\t" - "stba %0, [%1] 2\n\t" - "or %%g0, %%g0, %0" : - "=r" (success) : - "r" ((unsigned int) 0x40000000), - "0" (success)); - return success; + * VAC (virtual address cache) for the sun4c. + * + * Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include + +/* The SUN4C models have a virtually addressed write-through + * cache. + * + * The cache tags are directly accessible through an ASI and + * each have the form: + * + * ------------------------------------------------------------ + * | MBZ | CONTEXT | WRITE | PRIV | VALID | MBZ | TagID | MBZ | + * ------------------------------------------------------------ + * 31 25 24 22 21 20 19 18 16 15 2 1 0 + * + * MBZ: These bits are either unused and/or reserved and should + * be written as zeroes. + * + * CONTEXT: Records the context to which this cache line belongs. + * + * WRITE: A copy of the writable bit from the mmu pte access bits. + * + * PRIV: A copy of the privileged bit from the pte access bits. + * + * VALID: If set, this line is valid, else invalid. + * + * TagID: Fourteen bits of tag ID. + * + * Every virtual address is seen by the cache like this: + * + * ---------------------------------------- + * | RESV | TagID | LINE | BYTE-in-LINE | + * ---------------------------------------- + * 31 30 29 16 15 4 3 0 + * + * RESV: Unused/reserved. + * + * TagID: Used to match the Tag-ID in that vac tags. + * + * LINE: Which line within the cache + * + * BYTE-in-LINE: Which byte within the cache line. + */ + +/* Sun4c VAC Tags */ +#define S4CVACTAG_CID 0x01c00000 +#define S4CVACTAG_W 0x00200000 +#define S4CVACTAG_P 0x00100000 +#define S4CVACTAG_V 0x00080000 +#define S4CVACTAG_TID 0x0000fffc + +/* Sun4c VAC Virtual Address */ +#define S4CVACVA_TID 0x3fff0000 +#define S4CVACVA_LINE 0x0000fff0 +#define S4CVACVA_BIL 0x0000000f + +/* The indexing of cache lines creates a problem. Because the line + * field of a virtual address extends past the page offset within + * the virtual address it is possible to have what are called + * 'bad aliases' which will create inconsistancies. So we must make + * sure that within a context that if a physical page is mapped + * more than once, that 'extra' line bits are the same. If this is + * not the case, and thus is a 'bad alias' we must turn off the + * cacheable bit in the pte's of all such pages. + */ +#define S4CVAC_BADBITS 0x0000f000 + +/* The following is true if vaddr1 and vaddr2 would cause + * a 'bad alias'. + */ +#define S4CVAC_BADALIAS(vaddr1, vaddr2) \ + (((unsigned long) (vaddr1)) ^ ((unsigned long) (vaddr2)) & \ + (S4CVAC_BADBITS)) + +/* The following structure describes the characteristics of a sun4c + * VAC as probed from the prom during boot time. + */ +struct sun4c_vac_props { + unsigned int num_bytes; /* Size of the cache */ + unsigned int num_lines; /* Number of cache lines */ + unsigned int do_hwflushes; /* Hardware flushing available? */ + unsigned int linesize; /* Size of each line in bytes */ + unsigned int log2lsize; /* log2(linesize) */ + unsigned int on; /* VAC is enabled */ +}; + +extern struct sun4c_vac_props sun4c_vacinfo; + +extern void sun4c_flush_all(void); + +/* sun4c_enable_vac() enables the sun4c virtual address cache. */ +extern __inline__ void sun4c_enable_vac(void) +{ + __asm__ __volatile__("lduba [%0] %1, %%g1\n\t" + "or %%g1, %2, %%g1\n\t" + "stba %%g1, [%0] %1\n\t" : : + "r" ((unsigned int) AC_SENABLE), + "i" (ASI_CONTROL), "i" (SENABLE_CACHE) : + "g1"); + sun4c_vacinfo.on = 1; +} + +/* sun4c_disable_vac() disables the virtual address cache. */ +extern __inline__ void sun4c_disable_vac(void) +{ + __asm__ __volatile__("lduba [%0] %1, %%g1\n\t" + "andn %%g1, %2, %%g1\n\t" + "stba %%g1, [%0] %1\n\t" : : + "r" ((unsigned int) AC_SENABLE), + "i" (ASI_CONTROL), "i" (SENABLE_CACHE) : + "g1"); + sun4c_vacinfo.on = 0; +} + +extern unsigned long sun4c_ctxflush; +extern unsigned long sun4c_segflush; +extern unsigned long sun4c_pgflush; + +extern void sun4c_ctxflush_hw64KB16B(void); +extern void sun4c_ctxflush_hw64KB32B(void); +extern void sun4c_ctxflush_sw64KB16B(void); +extern void sun4c_ctxflush_sw64KB32B(void); + +extern void sun4c_segflush_hw64KB16B(void); +extern void sun4c_segflush_hw64KB32B(void); +extern void sun4c_segflush_sw64KB16B(void); +extern void sun4c_segflush_sw64KB32B(void); + +extern void sun4c_pgflush_hw64KB16B(void); +extern void sun4c_pgflush_hw64KB32B(void); +extern void sun4c_pgflush_sw64KB16B(void); +extern void sun4c_pgflush_sw64KB32B(void); + +/* These do indirect calls to the in-line assembly routines + * in s4ctlb.S, see that file for more answers. + */ +extern inline void sun4c_flush_context(void) +{ + __asm__ __volatile__("jmpl %0, %%l4\n\t" + "nop\n\t" : : + "r" (sun4c_ctxflush) : + "l4", "l6", "l7", "memory"); +} + +extern inline void sun4c_flush_segment(unsigned long segment) +{ + __asm__ __volatile__("jmpl %0, %%l4\n\t" + "or %1, %%g0, %%l2\n\t" : : + "r" (sun4c_segflush), "r" (segment) : + "l2", "l4", "l6", "l7", "memory"); +} + +extern inline void sun4c_flush_page(unsigned long page) +{ + __asm__ __volatile__("jmpl %0, %%l4\n\t" + "or %1, %%g0, %%l2\n\t" : : + "r" (sun4c_pgflush), "r" (page) : + "l2", "l4", "l6", "l7", "memory"); } -/* disable_vac() disables the virtual address cache. It returns 0 on - success, 1 on failure. -*/ - -extern __inline__ int disable_vac(void) -{ - int success=0; - - __asm__ __volatile__("lduba [%1] 0x2, %0\n\t" - "xor %0, 0x10, %0\n\t" - "stba %0, [%1] 0x2\n\t" - "or %%g0, %%g0, %0" : - "=r" (success) : - "r" (0x40000000), - "0" (success)); - return success; -} - -/* Various one-shot VAC entry flushes on the Sparc */ - -extern __inline__ void hw_flush_vac_context_entry(char* addr) -{ - __asm__ __volatile__("sta %%g0, [%0] 0x7" : : "r" (addr)); -} - -extern __inline__ void sw_flush_vac_context_entry(char* addr) -{ - __asm__ __volatile__("sta %%g0, [%0] 0xe" : : "r" (addr)); -} - -extern __inline__ void hw_flush_vac_segment_entry(char* addr) -{ - __asm__ __volatile__("sta %%g0, [%0] 0x5" : : "r" (addr)); -} - -extern __inline__ void sw_flush_vac_segment_entry(char* addr) -{ - __asm__ __volatile__("sta %%g0, [%0] 0xc" : : "r" (addr)); -} - -extern __inline__ void hw_flush_vac_page_entry(unsigned long* addr) -{ - __asm__ __volatile__("sta %%g0, [%0] 0x6" : : "r" (addr)); -} - -extern __inline__ void sw_flush_vac_page_entry(unsigned long* addr) -{ - __asm__ __volatile__("sta %%g0, [%0] 0xd" : : "r" (addr)); -} - #endif /* !(_SPARC_VAC_OPS_H) */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h --- v1.3.43/linux/include/asm-sparc/vaddrs.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/vaddrs.h Sat Nov 25 04:33:20 1995 @@ -1,3 +1,4 @@ +/* $Id: vaddrs.h,v 1.15 1995/11/25 02:33:20 davem Exp $ */ #ifndef _SPARC_VADDRS_H #define _SPARC_VADDRS_H @@ -23,10 +24,11 @@ #define INTREG_VADDR (TIMER_VADDR+0x5000) #define IOBASE_VADDR 0xfe000000 /* Base for mapping pages */ -#define IOBASE_LEN 0x00400000 /* Length of the IO area */ -#define IOBASE_SUN4C_SEGMAP 100 -#define DVMA_VADDR 0xfff00000 /* Base area of the DVMA on the 4c */ -#define DVMA_LEN 0x000c0000 /* Size of the DVMA address space */ +#define IOBASE_LEN 0x00100000 /* Length of the IO area */ +#define IOBASE_END 0xfe100000 +#define DVMA_VADDR 0xfff00000 /* Base area of the DVMA on suns */ +#define DVMA_LEN 0x00040000 /* Size of the DVMA address space */ +#define DVMA_END 0xfff40000 /* On sun4m machines we need per-cpu virtual areas */ #define PERCPU_VADDR 0xff000000 /* Base for per-cpu virtual mappings */ diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h --- v1.3.43/linux/include/asm-sparc/viking.h Tue Jun 27 14:11:46 1995 +++ linux/include/asm-sparc/viking.h Sat Nov 25 04:33:23 1995 @@ -1,4 +1,5 @@ -/* viking.h: Defines specific to the TI Viking MBUS module. +/* $Id: viking.h,v 1.5 1995/11/25 02:33:21 davem Exp $ + * viking.h: Defines specific to the TI Viking MBUS module. * This is SRMMU stuff. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.43/linux/include/asm-sparc/winmacro.h linux/include/asm-sparc/winmacro.h --- v1.3.43/linux/include/asm-sparc/winmacro.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/winmacro.h Sat Nov 25 04:33:24 1995 @@ -0,0 +1,120 @@ +/* $Id: winmacro.h,v 1.11 1995/11/25 02:33:23 davem Exp $ + * winmacro.h: Window loading-unloading macros. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_WINMACRO_H +#define _SPARC_WINMACRO_H + +#include +#include + +/* These are just handy. */ +#define _SV save %sp, -REGWIN_SZ, %sp +#define _RS restore + +#define FLUSH_ALL_KERNEL_WINDOWS \ + _SV; _SV; _SV; _SV; _SV; _SV; _SV; \ + _RS; _RS; _RS; _RS; _RS; _RS; _RS; + +/* Store the register window onto the 8-byte aligned area starting + * at %reg. It might be %sp, it might not, we don't care. + */ +#define STORE_WINDOW(reg) \ + std %l0, [%reg + RW_L0]; \ + std %l2, [%reg + RW_L2]; \ + std %l4, [%reg + RW_L4]; \ + std %l6, [%reg + RW_L6]; \ + std %i0, [%reg + RW_I0]; \ + std %i2, [%reg + RW_I2]; \ + std %i4, [%reg + RW_I4]; \ + std %i6, [%reg + RW_I6]; + +/* Load a register window from the area beginning at %reg. */ +#define LOAD_WINDOW(reg) \ + ldd [%reg + RW_L0], %l0; \ + ldd [%reg + RW_L2], %l2; \ + ldd [%reg + RW_L4], %l4; \ + ldd [%reg + RW_L6], %l6; \ + ldd [%reg + RW_I0], %i0; \ + ldd [%reg + RW_I2], %i2; \ + ldd [%reg + RW_I4], %i4; \ + ldd [%reg + RW_I6], %i6; + +/* Loading and storing struct pt_reg trap frames. */ +#define LOAD_PT_INS(base_reg) \ + ldd [%base_reg + STACKFRAME_SZ + PT_I0], %i0; \ + ldd [%base_reg + STACKFRAME_SZ + PT_I2], %i2; \ + ldd [%base_reg + STACKFRAME_SZ + PT_I4], %i4; \ + ldd [%base_reg + STACKFRAME_SZ + PT_I6], %i6; + +#define LOAD_PT_GLOBALS(base_reg) \ + ld [%base_reg + STACKFRAME_SZ + PT_G1], %g1; \ + ldd [%base_reg + STACKFRAME_SZ + PT_G2], %g2; \ + ldd [%base_reg + STACKFRAME_SZ + PT_G4], %g4; \ + ldd [%base_reg + STACKFRAME_SZ + PT_G6], %g6; + +#define LOAD_PT_YREG(base_reg, scratch) \ + ld [%base_reg + STACKFRAME_SZ + PT_Y], %scratch; \ + wr %scratch, 0x0, %y; + +#define LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \ + ld [%base_reg + STACKFRAME_SZ + PT_PSR], %pt_psr; \ + ld [%base_reg + STACKFRAME_SZ + PT_PC], %pt_pc; \ + ld [%base_reg + STACKFRAME_SZ + PT_NPC], %pt_npc; + +#define LOAD_PT_ALL(base_reg, pt_psr, pt_pc, pt_npc, scratch) \ + LOAD_PT_YREG(base_reg, scratch) \ + LOAD_PT_INS(base_reg) \ + LOAD_PT_GLOBALS(base_reg) \ + LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) + +#define STORE_PT_INS(base_reg) \ + std %i0, [%base_reg + STACKFRAME_SZ + PT_I0]; \ + std %i2, [%base_reg + STACKFRAME_SZ + PT_I2]; \ + std %i4, [%base_reg + STACKFRAME_SZ + PT_I4]; \ + std %i6, [%base_reg + STACKFRAME_SZ + PT_I6]; + +#define STORE_PT_GLOBALS(base_reg) \ + st %g1, [%base_reg + STACKFRAME_SZ + PT_G1]; \ + std %g2, [%base_reg + STACKFRAME_SZ + PT_G2]; \ + std %g4, [%base_reg + STACKFRAME_SZ + PT_G4]; \ + std %g6, [%base_reg + STACKFRAME_SZ + PT_G6]; + +#define STORE_PT_YREG(base_reg, scratch) \ + rd %y, %scratch; \ + st %scratch, [%base_reg + STACKFRAME_SZ + PT_Y]; + +#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc, pt_wim) \ + st %pt_psr, [%base_reg + STACKFRAME_SZ + PT_PSR]; \ + st %pt_pc, [%base_reg + STACKFRAME_SZ + PT_PC]; \ + st %pt_npc, [%base_reg + STACKFRAME_SZ + PT_NPC]; \ + st %pt_wim, [%base_reg + STACKFRAME_SZ + PT_WIM]; + +#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, reg_wim, g_scratch) \ + STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc, reg_wim) \ + STORE_PT_GLOBALS(base_reg) \ + STORE_PT_YREG(base_reg, g_scratch) \ + STORE_PT_INS(base_reg) + +#define SAVE_BOLIXED_USER_STACK(cur_reg, scratch) \ + ld [%cur_reg + THREAD_W_SAVED], %scratch; \ + sll %scratch, 2, %scratch; \ + add %scratch, %cur_reg, %scratch; \ + st %sp, [%scratch + THREAD_STACK_PTRS]; \ + sub %scratch, %cur_reg, %scratch; \ + sll %scratch, 4, %scratch; \ + add %scratch, %cur_reg, %scratch; \ + STORE_WINDOW(scratch + THREAD_REG_WINDOW); \ + sub %scratch, %cur_reg, %scratch; \ + srl %scratch, 6, %scratch; \ + add %scratch, 1, %scratch; \ + st %scratch, [%cur_reg + THREAD_W_SAVED]; + +/* For now on a uniprocessor this is ok. */ +#define LOAD_CURRENT(dest_reg) \ + sethi %hi(C_LABEL(current_set)), %dest_reg; \ + ld [%dest_reg + %lo(C_LABEL(current_set))], %dest_reg; + +#endif /* !(_SPARC_WINMACRO_H) */ diff -u --recursive --new-file v1.3.43/linux/include/linux/aztcd.h linux/include/linux/aztcd.h --- v1.3.43/linux/include/linux/aztcd.h Sun Oct 29 11:38:49 1995 +++ linux/include/linux/aztcd.h Sat Nov 25 17:28:41 1995 @@ -1,4 +1,4 @@ -/* $Id: aztcd.h,v 1.90 1995/10/21 17:52:10 root Exp root $ +/* $Id: aztcd.h,v 2.0 1995/11/10 19:38:49 root Exp root $ * * Definitions for a AztechCD268 CD-ROM interface * Copyright (C) 1994, 1995 Werner Zimmermann @@ -57,6 +57,7 @@ /*---------------------------------------------------------------------------*/ /*-----nothing to be configured for normal applications below this line------*/ + /* Increase this if you get lots of timeouts; if you get kernel panic, replace STEN_LOW_WAIT by STEN_LOW in the source code */ diff -u --recursive --new-file v1.3.43/linux/include/linux/igmp.h linux/include/linux/igmp.h --- v1.3.43/linux/include/linux/igmp.h Wed Oct 4 14:14:34 1995 +++ linux/include/linux/igmp.h Fri Nov 24 16:39:54 1995 @@ -23,7 +23,7 @@ /* * Header in on cable format */ - + struct igmphdr { __u8 type; @@ -36,8 +36,8 @@ #define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ #define IGMP_DVMRP 0x13 /* DVMRP routing */ #define IGMP_PIM 0x14 /* PIM routing */ -#define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New version of 0x11 */ -#define IGMP_HOST_LEAVE_MESSAGE 0x17 /* An extra BSD seems to send */ +#define IGMP_HOST_NEW_MEMBERSHIP_REPORT 0x16 /* New version of 0x11 */ +#define IGMP_HOST_LEAVE_MESSAGE 0x17 /* An extra BSD seems to send */ #define IGMP_MTRACE_RESP 0x1e #define IGMP_MTRACE 0x1f @@ -53,12 +53,25 @@ #define IGMP_SLEEPING_MEMBER 0x04 #define IGMP_AWAKENING_MEMBER 0x05 -#define IGMP_OLD_ROUTER 0x00 -#define IGMP_NEW_ROUTER 0x01 +#define IGMP_OLD_ROUTER 0x00 +#define IGMP_NEW_ROUTER 0x01 + +#define IGMP_MINLEN 8 +#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */ + /* query (in seconds) */ +#define IGMP_TIMER_SCALE 10 /* denotes that the igmphdr->timer field */ + /* specifies time in 10th of seconds */ + +#define IGMP_AGE_THRESHOLD 540 /* If this host don't hear any IGMP V1 */ + /* message in this period of time, revert */ + /* to IGMP v2 router */ #define IGMP_ALL_HOSTS htonl(0xE0000001L) +#define IGMP_ALL_ROUTER htonl(0xE0000002L) +#define IGMP_LOCAL_GROUP htonl(0xE0000000L) +#define IGMP_LOCAL_GROUP_MASK htonl(0xFFFFFF00L) /* * struct for keeping the multicast list in @@ -71,7 +84,7 @@ struct device *multidev[IP_MAX_MEMBERSHIPS]; }; -struct ip_mc_list +struct ip_mc_list { struct device *interface; unsigned long multiaddr; @@ -80,13 +93,21 @@ int tm_running; int users; }; - + +struct router_info +{ + struct device *dev; + int type; /* type of router which is querier on this interface */ + int time; /* # of slow timeouts since last old query */ + struct router_info *next; +}; + extern struct ip_mc_list *ip_mc_head; extern int igmp_rcv(struct sk_buff *, struct device *, struct options *, __u32, unsigned short, __u32, int , struct inet_protocol *); -extern void ip_mc_drop_device(struct device *dev); +extern void ip_mc_drop_device(struct device *dev); extern int ip_mc_join_group(struct sock *sk, struct device *dev, unsigned long addr); extern int ip_mc_leave_group(struct sock *sk, struct device *dev,unsigned long addr); extern void ip_mc_drop_socket(struct sock *sk); diff -u --recursive --new-file v1.3.43/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v1.3.43/linux/include/linux/netdevice.h Fri Nov 17 08:42:28 1995 +++ linux/include/linux/netdevice.h Sat Nov 25 12:09:04 1995 @@ -171,8 +171,7 @@ int (*rebuild_header)(void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb); #define HAVE_MULTICAST - void (*set_multicast_list)(struct device *dev, - int num_addrs, void *addrs); + void (*set_multicast_list)(struct device *dev); #define HAVE_SET_MAC_ADDR int (*set_mac_address)(struct device *dev, void *addr); #define HAVE_PRIVATE_IOCTL diff -u --recursive --new-file v1.3.43/linux/include/linux/pci.h linux/include/linux/pci.h --- v1.3.43/linux/include/linux/pci.h Fri Nov 17 08:42:28 1995 +++ linux/include/linux/pci.h Tue Nov 21 16:27:33 1995 @@ -215,6 +215,9 @@ * Vendor and card ID's: sort these numerically according to vendor * (and according to card ID within vendor) */ +#define PCI_VENDOR_ID_COMPAQ 0x0e11 +#define PCI_DEVICE_ID_COMPAQ_1280 0x3033 + #define PCI_VENDOR_ID_NCR 0x1000 #define PCI_DEVICE_ID_NCR_53C810 0x0001 #define PCI_DEVICE_ID_NCR_53C820 0x0002 @@ -298,19 +301,9 @@ #define PCI_VENDOR_ID_HP 0x103c #define PCI_DEVICE_ID_HP_J2585A 0x1030 -#if 0 - -#define PCI_VENDOR_ID_SMC 0x1042 /* Is this really correct?? */ -#define PCI_DEVICE_ID_SMC_37C665 0x1000 -#define PCI_DEVICE_ID_SMC_37C922 0x1001 - -#else - -#define PCI_VENDOR_ID_PCTECH 0x1042 /* Known to be correct */ +#define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 -#endif - #define PCI_VENDOR_ID_DPT 0x1044 #define PCI_DEVICE_ID_DPT 0xa400 @@ -323,6 +316,7 @@ #define PCI_VENDOR_ID_BUSLOGIC 0x104B #define PCI_DEVICE_ID_BUSLOGIC_946C_2 0x0140 #define PCI_DEVICE_ID_BUSLOGIC_946C 0x1040 +#define PCI_DEVICE_ID_BUSLOGIC_930 0x8130 #define PCI_VENDOR_ID_PROMISE 0x105a #define PCI_DEVICE_ID_PROMISE_5300 0x5300 @@ -361,6 +355,9 @@ #define PCI_DEVICE_ID_VISION_QD8500 0x0001 #define PCI_DEVICE_ID_VISION_QD8580 0x0002 +#define PCI_VENDOR_ID_SIERRA 0x10a8 +#define PCI_DEVICE_ID_SIERRA_STB 0x0000 + #define PCI_VENDOR_ID_ACC 0x10aa #define PCI_VENDOR_ID_WINBOND 0x10ad @@ -379,9 +376,15 @@ #define PCI_DEVICE_ID_AL_M1461 0x1461 #define PCI_DEVICE_ID_AL_M4803 0x5215 +#define PCI_VENDOR_ID_ASP 0x10cd +#define PCI_DEVICE_ID_ASP_ABP940 0x1200 + #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_8849 0x8849 +#define PCI_VENDOR_ID_TEKRAM2 0x10e1 +#define PCI_DEVICE_ID_TEKRAM2_690c 0x690c + #define PCI_VENDOR_ID_REALTEK 0x10ec #define PCI_DEVICE_ID_REALTEK_8029 0x8029 @@ -394,7 +397,8 @@ #define PCI_DEVICE_ID_VORTEX_GDT 0x0001 #define PCI_VENDOR_ID_EF 0x111a -#define PCI_DEVICE_ID_EF_ATM 0x0000 +#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000 +#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002 #define PCI_VENDOR_ID_IMAGINGTECH 0x112f #define PCI_DEVICE_ID_IMAGINGTECH_ICPCI 0x0000 @@ -408,8 +412,11 @@ #define PCI_VENDOR_ID_MUTECH 0x1159 #define PCI_DEVICE_ID_MUTECH_MV1000 0x0001 -#define PCI_VENDOR_ID_ZEINET 0x1193 -#define PCI_DEVICE_ID_ZEINET_1221 0x0001 +#define PCI_VENDOR_ID_ZEITNET 0x1193 +#define PCI_DEVICE_ID_ZEITNET_1221 0x0001 + +#define PCI_VENDOR_ID_HAL 0x11cd +#define PCI_DEVICE_ID_HAL_RIO 0x8000 #define PCI_VENDOR_ID_CYCLADES 0x120e #define PCI_DEVICE_ID_CYCLADES_Y 0x0100 @@ -442,6 +449,7 @@ #define PCI_DEVICE_ID_INTEL_7116 0x1223 #define PCI_DEVICE_ID_INTEL_82596 0x1226 #define PCI_DEVICE_ID_INTEL_82865 0x1227 +#define PCI_DEVICE_ID_INTEL_82557 0x1229 #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371_0 0x122e #define PCI_DEVICE_ID_INTEL_82371_1 0x1230 @@ -452,6 +460,7 @@ #define PCI_DEVICE_ID_ADAPTEC_7870 0x7078 #define PCI_DEVICE_ID_ADAPTEC_7871 0x7178 #define PCI_DEVICE_ID_ADAPTEC_7872 0x7278 +#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378 #define PCI_DEVICE_ID_ADAPTEC_7880 0x8078 #define PCI_DEVICE_ID_ADAPTEC_7881 0x8178 #define PCI_DEVICE_ID_ADAPTEC_7882 0x8278 diff -u --recursive --new-file v1.3.43/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.3.43/linux/include/linux/skbuff.h Wed Nov 8 07:11:42 1995 +++ linux/include/linux/skbuff.h Sat Nov 25 12:09:04 1995 @@ -54,7 +54,6 @@ struct iphdr *iph; struct udphdr *uh; unsigned char *raw; - unsigned long seq; } h; union { /* As yet incomplete physical layer views */ @@ -64,10 +63,13 @@ struct iphdr *ip_hdr; /* For IPPROTO_RAW */ unsigned long len; /* Length of actual data */ - unsigned long saddr; /* IP source address */ - unsigned long daddr; /* IP target address */ - unsigned long raddr; /* IP next hop address */ unsigned long csum; /* Checksum */ + __u32 saddr; /* IP source address */ + __u32 daddr; /* IP target address */ + __u32 raddr; /* IP next hop address */ + __u32 seq; /* TCP sequence number */ + __u32 end_seq; /* seq [+ fin] [+ syn] + datalen */ + __u32 ack_seq; /* TCP ack sequence number */ unsigned char proto_priv[16]; /* Protocol private data */ volatile char acked, /* Are we acked ? */ used, /* Are we in use ? */ @@ -85,6 +87,9 @@ unsigned short users; /* User count - see datagram.c,tcp.c */ unsigned short protocol; /* Packet protocol from driver. */ unsigned short truesize; /* Buffer size */ + + int count; /* reference count */ + struct sk_buff *data_skb; /* Link to the actual data skb */ unsigned char *head; /* Head of buffer */ unsigned char *data; /* Data head pointer */ unsigned char *tail; /* Tail pointer */ diff -u --recursive --new-file v1.3.43/linux/include/net/sock.h linux/include/net/sock.h --- v1.3.43/linux/include/net/sock.h Fri Nov 17 08:42:29 1995 +++ linux/include/net/sock.h Sat Nov 25 12:09:05 1995 @@ -127,7 +127,8 @@ no_check, zapped, /* In ax25 & ipx means not linked */ broadcast, - nonagle; + nonagle, + bsdism; unsigned long lingertime; int proc; struct sock *next; diff -u --recursive --new-file v1.3.43/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.3.43/linux/kernel/ksyms.c Fri Nov 17 08:42:29 1995 +++ linux/kernel/ksyms.c Fri Nov 24 16:39:54 1995 @@ -90,6 +90,10 @@ #endif #include +#ifdef __SMP__ +#include +#endif + extern char *get_options(char *str, int *ints); extern void set_device_ro(int dev,int flag); extern struct file_operations * get_blkfops(unsigned int); diff -u --recursive --new-file v1.3.43/linux/kernel/sys.c linux/kernel/sys.c --- v1.3.43/linux/kernel/sys.c Sun Oct 29 11:38:49 1995 +++ linux/kernel/sys.c Fri Nov 24 16:29:29 1995 @@ -545,6 +545,19 @@ return current->pgrp; } +asmlinkage int sys_getsid(pid_t pid) +{ + struct task_struct * p; + + if (!pid) + return current->session; + for_each_task(p) { + if (p->pid == pid) + return p->session; + } + return -ESRCH; +} + asmlinkage int sys_setsid(void) { if (current->leader) diff -u --recursive --new-file v1.3.43/linux/net/802/p8022.c linux/net/802/p8022.c --- v1.3.43/linux/net/802/p8022.c Mon Jul 31 15:59:03 1995 +++ linux/net/802/p8022.c Fri Nov 24 16:39:54 1995 @@ -59,7 +59,7 @@ static struct packet_type p8022_packet_type = { - 0, /* MUTTER ntohs(ETH_P_IPX),*/ + 0, /* MUTTER ntohs(ETH_P_8022),*/ NULL, /* All devices */ p8022_rcv, NULL, diff -u --recursive --new-file v1.3.43/linux/net/Changes linux/net/Changes --- v1.3.43/linux/net/Changes Fri Nov 17 08:42:29 1995 +++ linux/net/Changes Fri Nov 24 16:39:54 1995 @@ -232,7 +232,7 @@ -------->>>>> 1.3.31 <<<<<<------- o IP_OPTIONS [A.N.Kuznetsov] [TESTED] -o TCP cache zap more fixes [TESTED.. STILL NO COOKIE] +o TCP cache zap more fixes [TESTED] o Most of the IP multicast routing cache added [TESTED - WORK NEEDED] o Kernel/user communication module (not used yet) [TESTED] @@ -252,28 +252,28 @@ -------->>>>> 1.3.35 <<<<<<-------- o Appletalk data now in the protinfo union [TESTED] -o BSD style bind to broadcast address supported [IN] +o BSD style bind to broadcast address supported [TESTED] o Standard loadable firewall chains [TESTED] o IPFW uses the firewall chains for firewall but not yet acct/masquerade [TESTED] o Firewall chain hooks in all other protocols [TESTED] o Sendmsg/recvmsg for IPX. [TESTED] o IPX uses sock_alloc_send_skb [TESTED] -o Recvmsg for all IP, sendmsg for TCP [IN] +o Recvmsg for all IP, sendmsg for TCP [TESTED] (nearly ready to go all *msg()) --------->>>>> 1.3.41 <<<<<<-------- +-------->>>>> 1.3.42 <<<<<<-------- o ip udp/raw nonblock bug fixed [TESTED] -o ICMP lockup fix [IN] -o Fundamental operations now only sendmsg/recvmsg [IN] +o ICMP lockup fix [TESTED] +o Fundamental operations now only sendmsg/recvmsg [TESTED] o bind() for SOCK_PACKET [IN] o set_mac_addr fixed up [IN] o BSD SIOCSIFADDR, AF_UNSPEC behaviour [IN] -o Updated this list [IN] +o Updated this list [OK] o Massive ARP/cache/routing rewrite [ANK] [IN] o AX.25 connect return fixed in using sock_error [IN] -o Proper netlink device major(36) [IN] +o Proper netlink device major(36) [TESTED] o First parts of the SKIP support [IN, not useful] o TCP ICMP (SOSS should work again) [IN] o IPFW support for TOS changing (Al Longyear) [IN] @@ -281,6 +281,17 @@ o NFS root [IN] o Path MTU discovery [ANK] [IN] +-------->>>>> 1.3.44 <<<<<<-------- + +o NFS root/ FPU clash fixed [IN] +o ARP lock bug fixed [IN] +o SO_BSDCOMPAT option(libbsd/ibcs2 ought to set) [IN] +o Changed to new set_multicast_list() [IN] +o ARP ioctl() call fixes [Bernd] [IN] +o Fixes to the name set functions (maybe fixes + netrom) [Steve] [IN] +o Packet protocol labelling (not IPX yet) [IN] + ---------- Things I thought Linus had for a while and not merged ---------------- @@ -288,61 +299,59 @@ o Improved IPX support for lwared. o Decnet pre pre pre pre pre Alpha 0.0. +o Chase Donald for new drivers, get people to sort out what net + drivers should cease to be 'Alpha'. +o IPX PPP support +o IPalias ---------- Things pending for me to merge -------------- o AF_UNIX garbage collect code o Faster closedown option for heavy use sites (me) o Tom May's insw_and_checksum() -o IPX PPP support o SPARC patches [Dave] [partly in] -o Path MTU and other goodies [ANK] --------------- Things That Need Doing Before 1.4 ------------------ -o Finish merging the bridge code -o Fast checksum/copy on outgoing TCP -o Fast dev_grab_next() transmit reload function - and dev_push_failed() ?? [Causes deadlock - cases with slow box, heavy networking] o Forwarding queue control (+ fairness algorithms ??) o IP forward flow control. +o IPX memory leak ????? o Clean up RAW AX.25 sockets. -o Finish 802.2 Class I code to be compliant to the oddities of 802.2 -o Tidy BPQ support to use a bpqip tunnel device -o Strange eth0-eth3 bug [Matti fixed ??] o Finish IPIP bug fixes [Done hopefully] -o Why doesnt the PROTO_UNREACH get sent ? [Should now work] -o Kill off old ip_queue_xmit/ip_send stuff. -o Remove kernel RARP and replace with user mode daemon. -o Throw out existing firewall ioctl()'s and use a single table load. +o Multicast routing [STARTED BITS] +o PPP/IPX +o IPX for Lwared +o SKIP [Available in user mode] +o AX.25/NetROM locking changes +o insw_and_csum +o IPAlias +o AF_UNIX fd passing 0.2 --- +o Fast checksum/copy on outgoing TCP o Better TCP window handling [Pedro Roque] o Add tty support to sonix driver. o PPP for Sonix ISDN. o Screend loadable firewall module -o LZ SLIP [Done, resolving patent issues - sod it use PPP] -o AXIP +o AXIP [AVAILABLE IN USER MODE] +o Finish merging the bridge code [LEAVE POST 1.4] +o Finish 802.2 Class I code to be compliant to the oddities of 802.2 +o Tidy BPQ support to use a bpqip tunnel device +o Kill off old ip_queue_xmit/ip_send stuff. +o Remove kernel RARP and replace with user mode daemon. +o Throw out existing firewall ioctl()'s and use a single table load. +o SPARC merge 0.3 --- o Merge the layered protocol support. [ABANDONED TOO SLOW] -o IP firewalling performance - caching and radix trees. -o Zebedee o 802.2 Class 2 services (eg netbios). o Multidrop KISS [NOW AVAILABLE IN USER MODE] -o Multicast routing [STARTED BITS] Possible projects for victim^H^H^H^H^Holunteers -1. Verifying the correctness of implementation against RFC1122 and -making a list of violations (BSD is sufficiently screwed up you can't -implement all of RFC1122 and talk to it usefully). [Done - Mike -Shaver] - 2. Verifying all the error returns match the BSD ones (grotty job I wouldn't wish on anyone). @@ -353,17 +362,11 @@ mathematician with some queue theory you can show this allows you to lose one frame per window full of data without measurable speed loss. -4. RFC1323 and RFC1191. These are the extensions for very fast nets -and for 'path MTU discovery' - a way of finding the best packetsize to use. +4. RFC1323. These are the extensions for very fast nets. RFC1323 will be useful for Linux talking to systems over 100Mb/sec ethernet and over ATM as it allows large windows and protects from some potential high speed TCP problems. -5. Fixing the IP fragment handling so that the total space allocated to -fragments is limited and old fragments are deleted to make room for new ones -when space is exhausted. Fixing the fragment handling to work at a decent -speed wouldn't be bad either. [In progress - Arnt Gulbrandsen] - 6. Delayed ack. This is mostly supported but not actually set up and used yet. Basically ack frames are held back 1/10th of a second in the hope that two acks can be merged into one or for interactive use the ack can @@ -375,27 +378,17 @@ is SLIP6) SLIP mode that does packet data compression [maybe use the code from term]. -8. Making SLIP/PPP dynamically allocate devices so you never run out -of channels. [Done (pending inclusion in the PPP case)] - 9. Implementing streams. Not as a blind slow SYS5.4 style copy but actually working out how to do it so it runs like greased lightning. Quite a big problem. 10. Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board driver but thats for an internal project and its general release is still -a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay]. - +a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is +Mike McLagan][Friz Elfert is doing the isdn4linux kit]. + 11. IP over SCSI. -12. Debugging and making the appletalk alpha test code useful. - [Done and in] - -13. Mrouted Multicast routing. Or possibly MOSPF and others - as they become available - [Started: see/join linux-multicast@www.linux.org.uk - if you wish to join in] - 14. Bidirectional PLIP. Also PLIP for the newer style parallel ports. 15. 802.2LLC and thus Netbeui sockets. Becoming less important since the @@ -406,6 +399,7 @@ their hands. [Provisionally taken] 17. PPP multilink. Another nasty job. +[In progress] 18. Implement swIPe under Linux. [Reportedly in progress] diff -u --recursive --new-file v1.3.43/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v1.3.43/linux/net/ax25/af_ax25.c Fri Nov 17 08:42:29 1995 +++ linux/net/ax25/af_ax25.c Fri Nov 24 16:39:54 1995 @@ -2162,6 +2162,7 @@ } #endif + skb->protocol = htons (ETH_P_AX25); if (dev->type == ARPHRD_ETHER) { diff -u --recursive --new-file v1.3.43/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c --- v1.3.43/linux/net/core/dev_mcast.c Mon Oct 23 18:02:22 1995 +++ linux/net/core/dev_mcast.c Fri Nov 24 16:39:54 1995 @@ -12,6 +12,7 @@ * Alan Cox : Update the device on a real delete * rather than any time but... * Alan Cox : IFF_ALLMULTI support. + * Alan Cox : New format set_multicast_list() calls. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -60,9 +61,6 @@ void dev_mc_upload(struct device *dev) { - struct dev_mc_list *dmi; - char *data, *tmp; - /* Don't do anything till we up the interface [dev_open will call this function so the list will stay sane] */ @@ -70,7 +68,6 @@ if(!(dev->flags&IFF_UP)) return; - /* * Devices with no set multicast don't get set */ @@ -78,55 +75,7 @@ if(dev->set_multicast_list==NULL) return; - /* - * Promiscuous is promiscuous - so no filter needed - */ - - if(dev->flags&IFF_PROMISC) - { - dev->set_multicast_list(dev, -1, NULL); - return; - } - - /* - * All multicasts. Older cards will interpret this as - * promisc mode, which is the next best thing. - */ - - if(dev->flags&IFF_ALLMULTI) - { - dev->set_multicast_list(dev, -2, NULL); - return; - } - - /* - * No multicasts - */ - - if(dev->mc_count==0) - { - dev->set_multicast_list(dev,0,NULL); - return; - } - - /* - * The drivers need changing to process the list themselves... this is - * a mess. - */ - - data=kmalloc(dev->mc_count*dev->addr_len, GFP_KERNEL); - if(data==NULL) - { - printk("Unable to get memory to set multicast list on %s\n",dev->name); - return; - } - for(tmp = data, dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) - { - memcpy(tmp,dmi->dmi_addr, dmi->dmi_addrlen); - tmp+=dev->addr_len; - } - dev->set_multicast_list(dev,dev->mc_count,data); - kfree(data); + dev->set_multicast_list(dev); } /* diff -u --recursive --new-file v1.3.43/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v1.3.43/linux/net/core/skbuff.c Wed Nov 8 07:11:45 1995 +++ linux/net/core/skbuff.c Thu Nov 23 11:26:03 1995 @@ -461,6 +461,7 @@ if (skb->next) printk("Warning: kfree_skb passed an skb still on a list (from %p).\n", __builtin_return_address(0)); + if(skb->destructor) skb->destructor(skb); if (skb->sk) @@ -542,6 +543,9 @@ skb=(struct sk_buff *)(bptr+size)-1; + skb->count = 1; /* only one reference to this */ + skb->data_skb = NULL; /* and we're our own data skb */ + skb->free = 2; /* Invalid so we pick up forgetful users */ skb->lock = 0; skb->pkt_type = PACKET_HOST; /* Default type */ @@ -579,10 +583,20 @@ void kfree_skbmem(struct sk_buff *skb) { unsigned long flags; + void * addr = skb->head; + save_flags(flags); cli(); - kfree((void *)skb->head); - net_skbcount--; + /* don't do anything if somebody still uses us */ + if (--skb->count <= 0) { + /* free the skb that contains the actual data if we've clone()'d */ + if (skb->data_skb) { + addr = skb; + kfree_skbmem(skb->data_skb); + } + kfree(addr); + net_skbcount--; + } restore_flags(flags); } @@ -590,7 +604,38 @@ * Duplicate an sk_buff. The new one is not owned by a socket or locked * and will be freed on deletion. */ +#if 1 +struct sk_buff *skb_clone(struct sk_buff *skb, int priority) +{ + struct sk_buff *n; + unsigned long flags; + IS_SKB(skb); + n = kmalloc(sizeof(*n), priority); + if (!n) + return NULL; + memcpy(n, skb, sizeof(*n)); + n->count = 1; + if (skb->data_skb) + skb = skb->data_skb; + save_flags(flags); + cli(); + skb->count++; + net_allocs++; + net_skbcount++; + restore_flags(flags); + n->data_skb = skb; + n->next = n->prev = n->link3 = NULL; + n->sk = NULL; + n->truesize = sizeof(*n); + n->free = 1; + n->tries = 0; + n->lock = 0; + n->users = 0; + return n; +} +#else +/* this is slower, and copies the whole data area */ struct sk_buff *skb_clone(struct sk_buff *skb, int priority) { struct sk_buff *n; @@ -628,6 +673,9 @@ n->saddr=skb->saddr; n->daddr=skb->daddr; n->raddr=skb->raddr; + n->raddr=skb->seq; + n->raddr=skb->end_seq; + n->raddr=skb->ack_seq; n->acked=skb->acked; memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv)); n->used=skb->used; @@ -642,7 +690,7 @@ IS_SKB(n); return n; } - +#endif /* * Skbuff device locking diff -u --recursive --new-file v1.3.43/linux/net/core/sock.c linux/net/core/sock.c --- v1.3.43/linux/net/core/sock.c Mon Oct 23 18:02:22 1995 +++ linux/net/core/sock.c Fri Nov 24 16:39:54 1995 @@ -207,7 +207,10 @@ } return 0; - + case SO_BSDCOMPAT: + sk->bsdism = valbool; + return 0; + default: return(-ENOPROTOOPT); } @@ -285,7 +288,9 @@ memcpy_tofs(optval,&ling,sizeof(ling)); return 0; - + case SO_BSDCOMPAT: + val = sk->bsdism; + break; default: return(-ENOPROTOOPT); diff -u --recursive --new-file v1.3.43/linux/net/ethernet/pe2.c linux/net/ethernet/pe2.c --- v1.3.43/linux/net/ethernet/pe2.c Mon Jul 31 15:59:04 1995 +++ linux/net/ethernet/pe2.c Fri Nov 24 16:39:54 1995 @@ -9,7 +9,8 @@ struct sk_buff *skb, unsigned char *dest_node) { struct device *dev = skb->dev; - + + skb->protocol = htons (ETH_P_IPX); dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len); } diff -u --recursive --new-file v1.3.43/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v1.3.43/linux/net/ipv4/af_inet.c Fri Nov 17 08:42:33 1995 +++ linux/net/ipv4/af_inet.c Fri Nov 24 16:39:54 1995 @@ -1016,10 +1016,11 @@ sk1 = (struct sock *) sock->data; /* - * We've been passed an extra socket. - * We need to free it up because the tcp module creates - * its own when it accepts one. + * We've been passed an extra socket. + * We need to free it up because the tcp module creates + * its own when it accepts one. */ + if (newsock->data) { struct sock *sk=(struct sock *)newsock->data; @@ -1031,7 +1032,10 @@ if (sk1->prot->accept == NULL) return(-EOPNOTSUPP); - /* Restore the state if we have been interrupted, and then returned. */ + /* + * Restore the state if we have been interrupted, and then returned. + */ + if (sk1->pair != NULL ) { sk2 = sk1->pair; diff -u --recursive --new-file v1.3.43/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.43/linux/net/ipv4/arp.c Tue Nov 21 13:22:14 1995 +++ linux/net/ipv4/arp.c Sat Nov 25 10:55:29 1995 @@ -50,6 +50,7 @@ * eg intelligent arp probing and generation * of host down events. * Alan Cox : Missing unlock in device events. + * Eckes : ARP ioctl control errors. */ /* RFC1122 Status: @@ -649,6 +650,7 @@ skb->arp = 1; skb->dev = dev; skb->free = 1; + skb->protocol = htons (ETH_P_IP); /* * Fill the device header for the ARP frame @@ -1057,7 +1059,7 @@ { for (entry = arp_tables[HASH(paddr)]; entry != NULL; entry = entry->next) - if (entry->ip == paddr && entry->dev == dev) + if (entry->ip == paddr && (!dev || entry->dev == dev)) break; return entry; } @@ -1066,13 +1068,14 @@ { for (entry = arp_proxy_list; entry != NULL; entry = entry->next) - if (entry->ip == paddr && entry->dev == dev) + if (entry->ip == paddr && (!dev || entry->dev == dev)) break; return entry; } for (entry=arp_proxy_list; entry != NULL; entry = entry->next) - if (!((entry->ip^paddr)&entry->mask) && entry->dev == dev) + if (!((entry->ip^paddr)&entry->mask) && + (!dev || entry->dev == dev)) break; return entry; } @@ -1597,6 +1600,19 @@ restore_flags(flags); } +/* + * Test if a hardware address is all zero + */ +static inline int empty(unsigned char * addr, int len) +{ + while (len > 0) { + if (*addr) + return 0; + len--; + addr++; + } + return 1; +} /* * Set (create) an ARP cache entry. @@ -1607,7 +1623,8 @@ struct arp_table *entry; struct sockaddr_in *si; struct rtable *rt; - struct device * dev1; + struct device *dev1; + unsigned char *ha; u32 ip; /* @@ -1626,12 +1643,19 @@ * Is it reachable ? */ - rt = ip_rt_route(ip, 0); - if (!rt) - return -ENETUNREACH; - dev1 = rt->rt_dev; - ip_rt_put(rt); + if (ip_chk_addr(ip) == IS_MYADDR) + dev1 = dev_get("lo"); + else { + rt = ip_rt_route(ip, 0); + if (!rt) + return -ENETUNREACH; + dev1 = rt->rt_dev; + ip_rt_put(rt); + } + if (!dev) /* this is can only be NULL if ATF_PUBL is not set */ + dev = dev1; + if (((r->arp_flags & ATF_PUBL) && dev == dev1) || (!(r->arp_flags & ATF_PUBL) && dev != dev1)) return -EINVAL; @@ -1697,11 +1721,10 @@ /* * We now have a pointer to an ARP entry. Update it! */ - - if ((r->arp_flags & ATF_COM) && !r->arp_ha.sa_data[0]) - memcpy(&entry->ha, dev->dev_addr, dev->addr_len); - else - memcpy(&entry->ha, &r->arp_ha.sa_data, dev->addr_len); + ha = r->arp_ha.sa_data; + if ((r->arp_flags & ATF_COM) && empty(ha, dev->addr_len)) + ha = dev->dev_addr; + memcpy(entry->ha, ha, dev->addr_len); entry->last_updated = entry->last_used = jiffies; entry->flags = r->arp_flags | ATF_COM; if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK)) @@ -1773,7 +1796,7 @@ for (entry = arp_tables[HASH(si->sin_addr.s_addr)]; entry != NULL; entry = entry->next) if (entry->ip == si->sin_addr.s_addr - && entry->dev == dev) + && (!dev || entry->dev == dev)) { arp_destroy(entry); arp_unlock(); @@ -1785,7 +1808,7 @@ for (entry = arp_proxy_list; entry != NULL; entry = entry->next) if (entry->ip == si->sin_addr.s_addr - && entry->dev == dev) + && (!dev || entry->dev == dev)) { arp_destroy(entry); arp_unlock(); @@ -1852,12 +1875,12 @@ } else { - /* - * Device was not specified. Take the first suitable one. - */ - if ((dev = dev_getbytype(r.arp_ha.sa_family)) == NULL) - return -ENODEV; - } + if ((r.arp_flags & ATF_PUBL) && + ((cmd == SIOCSARP) || (cmd == OLD_SIOCSARP))) { + if ((dev = dev_getbytype(r.arp_ha.sa_family)) == NULL) + return -ENODEV; + } + } switch(cmd) { diff -u --recursive --new-file v1.3.43/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c --- v1.3.43/linux/net/ipv4/igmp.c Fri Nov 17 08:42:33 1995 +++ linux/net/ipv4/igmp.c Fri Nov 24 16:39:54 1995 @@ -2,12 +2,12 @@ * Linux NET3: Internet Gateway Management Protocol [IGMP] * * This code implements the IGMP protocol as defined in RFC1122. There has - * been a further revision of this protocol since, but since it is not + * been a further revision of this protocol since, but since it is not * cleanly specified in any IETF standards we implement the old one properly * rather than play a game of guess the BSD unofficial extensions. * * Authors: - * Alan Cox + * Alan Cox * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. * * Fixes: - * + * * Alan Cox : Added lots of __inline__ to optimise * the memory usage of all the tiny little * functions. @@ -28,9 +28,19 @@ * desired by mrouted, fixed the fact it has been * broken since 1.3.6 and cleaned up a few minor * points. + * Chih-Jen Chang : Tried to revise IGMP to Version 2 + * Tsu-Sheng Tsao chihjenc@scf.usc.edu and tsusheng@scf.usc.edu + * The enhancements are based on Steve Deering's ipmulti-3.5 code + * Chih-Jen Chang : Added the igmp_get_mrouter_info and + * Tsu-Sheng Tsao igmp_set_mrouter_info to keep track of + * the mrouted version on that device. + * Chih-Jen Chang : Added the max_resp_time parameter to + * Tsu-Sheng Tsao igmp_heard_query(). Using this parameter + * to identify the multicast router verion + * and do what the IGMP version 2 specified. */ - - + + #include #include #include @@ -56,10 +66,75 @@ /* + * Multicast router info manager + */ + +struct router_info *router_info_head=(struct router_info *)0; + +/* + * Get the multicast router info on that device + */ + +static struct router_info *igmp_get_mrouter_info(struct device *dev) +{ + register struct router_info *i; + + for(i=router_info_head;i!=NULL;i=i->next) + { + if (i->dev == dev) + { + return i; + } + } + + /* + * Not found. Create a new entry. The default is IGMP V2 router + */ + i=(struct router_info *)kmalloc(sizeof(*i), GFP_KERNEL); + i->dev = dev; + i->type = IGMP_NEW_ROUTER; + i->time = IGMP_AGE_THRESHOLD; + i->next = router_info_head; + router_info_head = i; + return i; +} + +/* + * Set the multicast router info on that device + */ + +static struct router_info *igmp_set_mrouter_info(struct device *dev,int type,int time) +{ + register struct router_info *i; + + for(i=router_info_head;i!=NULL;i=i->next) + { + if (i->dev == dev) + { + i->type = type; + i->time = time; + return i; + } + } + + /* + * Not found. Create a new entry. + */ + i=(struct router_info *)kmalloc(sizeof(*i), GFP_KERNEL); + i->dev = dev; + i->type = type; + i->time = time; + i->next = router_info_head; + router_info_head = i; + return i; +} + + +/* * Timer management */ - - + + static void igmp_stop_timer(struct ip_mc_list *im) { del_timer(&im->timer); @@ -77,17 +152,17 @@ * Inlined as its only called once. */ -static void igmp_start_timer(struct ip_mc_list *im) +static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time) { int tv; if(im->tm_running) return; - tv=random()%(10*HZ); /* Pick a number any number 8) */ + tv=random()%(max_resp_time*HZ/IGMP_TIMER_SCALE); /* Pick a number any number 8) */ im->timer.expires=jiffies+tv; im->tm_running=1; add_timer(&im->timer); } - + /* * Send an IGMP report. */ @@ -99,7 +174,7 @@ struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC); int tmp; struct igmphdr *ih; - + if(skb==NULL) return; tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL, @@ -110,7 +185,7 @@ return; } ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr)); - ih->type=IGMP_HOST_MEMBERSHIP_REPORT; + ih->type=type; ih->code=0; ih->csum=0; ih->group=address; @@ -122,8 +197,13 @@ static void igmp_timer_expire(unsigned long data) { struct ip_mc_list *im=(struct ip_mc_list *)data; + struct router_info *r; igmp_stop_timer(im); - igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); + r=igmp_get_mrouter_info(im->interface); + if(r->type==IGMP_NEW_ROUTER) + igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT); + else + igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); } static void igmp_init_timer(struct ip_mc_list *im) @@ -133,7 +213,7 @@ im->timer.data=(unsigned long)im; im->timer.function=&igmp_timer_expire; } - + static void igmp_heard_report(struct device *dev, unsigned long address) { @@ -143,20 +223,72 @@ igmp_stop_timer(im); } -static void igmp_heard_query(struct device *dev) +static void igmp_heard_query(struct device *dev,unsigned char max_resp_time) { struct ip_mc_list *im; - for(im=dev->ip_mc_list;im!=NULL;im=im->next) + int mrouter_type; + + /* + * The max_resp_time is in units of 1/10 second. + */ + if(max_resp_time>0) { - if(!im->tm_running && im->multiaddr!=IGMP_ALL_HOSTS) - igmp_start_timer(im); + mrouter_type=IGMP_NEW_ROUTER; + + igmp_set_mrouter_info(dev,mrouter_type,0); + /* + * - Start the timers in all of our membership records + * that the query applies to for the interface on + * which the query arrived excl. those that belong + * to a "local" group (224.0.0.X) + * - For timers already running check if they need to + * be reset. + * - Use the igmp->igmp_code field as the maximum + * delay possible + */ + for(im=dev->ip_mc_list;im!=NULL;im=im->next) + { + if(im->tm_running) + { + if(im->timer.expires>max_resp_time*HZ/IGMP_TIMER_SCALE) + { + igmp_stop_timer(im); + igmp_start_timer(im,max_resp_time); + } + } + else + { + if((im->multiaddr & IGMP_LOCAL_GROUP_MASK)!=IGMP_LOCAL_GROUP) + igmp_start_timer(im,max_resp_time); + } + } + } + else + { + mrouter_type=IGMP_OLD_ROUTER; + max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE; + + igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD); + + /* + * Start the timers in all of our membership records for + * the interface on which the query arrived, except those + * that are already running and those that belong to a + * "local" group (224.0.0.X). + */ + + for(im=dev->ip_mc_list;im!=NULL;im=im->next) + { + if(!im->tm_running && (im->multiaddr & IGMP_LOCAL_GROUP_MASK)!=IGMP_LOCAL_GROUP) + igmp_start_timer(im,max_resp_time); + } } } /* * Map a multicast IP onto multicast MAC for type ethernet. */ - + extern __inline__ void ip_mc_map(unsigned long addr, char *buf) { addr=ntohl(addr); @@ -173,26 +305,26 @@ /* * Add a filter to a device */ - + void ip_mc_filter_add(struct device *dev, unsigned long addr) { char buf[6]; if(dev->type!=ARPHRD_ETHER) - return; /* Only do ethernet now */ - ip_mc_map(addr,buf); + return; /* Only do ethernet now */ + ip_mc_map(addr,buf); dev_mc_add(dev,buf,ETH_ALEN,0); } /* * Remove a filter from a device */ - + void ip_mc_filter_del(struct device *dev, unsigned long addr) { char buf[6]; if(dev->type!=ARPHRD_ETHER) - return; /* Only do ethernet now */ - ip_mc_map(addr,buf); + return; /* Only do ethernet now */ + ip_mc_map(addr,buf); dev_mc_delete(dev,buf,ETH_ALEN,0); } @@ -205,9 +337,14 @@ extern __inline__ void igmp_group_added(struct ip_mc_list *im) { + struct router_info *r; igmp_init_timer(im); ip_mc_filter_add(im->interface, im->multiaddr); - igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); + r=igmp_get_mrouter_info(im->interface); + if(r->type==IGMP_NEW_ROUTER) + igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT); + else + igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT); } int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, @@ -216,13 +353,13 @@ { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih; - + /* * Mrouted needs to able to query local interfaces. So * report for the device this was sent at. (Which can * be the loopback this time) */ - + if(dev->flags&IFF_LOOPBACK) { dev=ip_dev_find(saddr); @@ -230,17 +367,19 @@ dev=&loopback_dev; } ih=(struct igmphdr *)skb->h.raw; - + if(skb->len ip_hdr->ttl>1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr))) { kfree_skb(skb, FREE_READ); return 0; } - + if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS) - igmp_heard_query(dev); + igmp_heard_query(dev,ih->code); if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group) igmp_heard_report(dev,ih->group); + if(ih->type==IGMP_HOST_NEW_MEMBERSHIP_REPORT && daddr==ih->group) + igmp_heard_report(dev,ih->group); kfree_skb(skb, FREE_READ); return 0; } @@ -248,12 +387,12 @@ /* * Multicast list managers */ - - + + /* * A socket has joined a multicast group on device dev. */ - + static void ip_mc_inc_group(struct device *dev, unsigned long addr) { struct ip_mc_list *i; @@ -279,7 +418,7 @@ /* * A socket has left a multicast group on device dev */ - + static void ip_mc_dec_group(struct device *dev, unsigned long addr) { struct ip_mc_list **i; @@ -303,7 +442,7 @@ /* * Device going down: Clean up. */ - + void ip_mc_drop_device(struct device *dev) { struct ip_mc_list *i; @@ -319,13 +458,24 @@ /* * Device going up. Make sure it is in all hosts */ - + void ip_mc_allhost(struct device *dev) { struct ip_mc_list *i; + /* + * Don't add to non multicast units + */ + if(!(dev->flags&IFF_MULTICAST)) + return; + /* + * No duplicates + */ for(i=dev->ip_mc_list;i!=NULL;i=i->next) if(i->multiaddr==IGMP_ALL_HOSTS) return; + /* + * Add it + */ i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL); if(!i) return; @@ -337,12 +487,12 @@ dev->ip_mc_list=i; ip_mc_filter_add(i->interface, i->multiaddr); -} - +} + /* * Join a socket to a group */ - + int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr) { int unused= -1; @@ -364,7 +514,7 @@ if(sk->ip_mc_list->multidev[i]==NULL) unused=i; } - + if(unused==-1) return -ENOBUFS; sk->ip_mc_list->multiaddr[unused]=addr; @@ -376,7 +526,7 @@ /* * Ask a socket to leave a group. */ - + int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr) { int i; @@ -386,7 +536,7 @@ return -EADDRNOTAVAIL; if(sk->ip_mc_list==NULL) return -EADDRNOTAVAIL; - + for(i=0;iip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev) @@ -402,14 +552,14 @@ /* * A socket is closing. */ - + void ip_mc_drop_socket(struct sock *sk) { int i; - + if(sk->ip_mc_list==NULL) return; - + for(i=0;iip_mc_list->multidev[i]) diff -u --recursive --new-file v1.3.43/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v1.3.43/linux/net/ipv4/ip_forward.c Fri Nov 17 08:42:33 1995 +++ linux/net/ipv4/ip_forward.c Fri Nov 24 16:39:54 1995 @@ -274,6 +274,7 @@ /* * Add the physical headers. */ + skb2->protocol=htons(ETH_P_IP); #ifdef CONFIG_IP_MROUTE if(is_frag&16) { diff -u --recursive --new-file v1.3.43/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v1.3.43/linux/net/ipv4/ip_output.c Fri Nov 17 08:42:34 1995 +++ linux/net/ipv4/ip_output.c Fri Nov 24 16:39:54 1995 @@ -116,6 +116,7 @@ skb->dev = dev; skb->arp = 1; + skb->protocol = htons(ETH_P_IP); if (dev->hard_header) { /* @@ -152,6 +153,7 @@ skb->dev = dev; skb->arp = 1; + skb->protocol = ETH_P_IP; if (dev->hard_header) { skb_reserve(skb,MAX_HEADER); diff -u --recursive --new-file v1.3.43/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v1.3.43/linux/net/ipv4/ipmr.c Wed Nov 8 07:11:46 1995 +++ linux/net/ipv4/ipmr.c Fri Nov 24 16:39:54 1995 @@ -359,6 +359,7 @@ */ cli(); + cache=ipmr_cache_find(mfc->mfcc_origin.s_addr,mfc->mfcc_mcastgrp.s_addr); /* diff -u --recursive --new-file v1.3.43/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v1.3.43/linux/net/ipv4/raw.c Fri Nov 17 08:42:34 1995 +++ linux/net/ipv4/raw.c Sat Nov 25 18:23:09 1995 @@ -125,6 +125,16 @@ skb->dev = dev; skb->saddr = daddr; skb->daddr = saddr; + +#if 0 + /* + * For no adequately explained reasons BSD likes to mess up the header of + * the received frame. + */ + + if(sk->bsdism) + skb->ip_hdr->tot_len=ntohs(skb->ip_hdr->tot_len-4*skb->ip_hdr->ihl); +#endif /* Charge it to the socket. */ diff -u --recursive --new-file v1.3.43/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v1.3.43/linux/net/ipv4/tcp.c Fri Nov 17 08:42:34 1995 +++ linux/net/ipv4/tcp.c Thu Nov 23 12:21:50 1995 @@ -734,7 +734,7 @@ * this up by avoiding a full checksum. */ - th->ack_seq = ntohl(sk->acked_seq); + th->ack_seq = htonl(sk->acked_seq); th->window = ntohs(tcp_select_window(sk)); tcp_send_check(th, sk->saddr, sk->daddr, size, sk); @@ -1163,9 +1163,9 @@ do { - if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */ + if (before(counted, skb->seq)) /* Found a hole so stops here */ break; - sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */ + sum = skb->len - (counted - skb->seq); /* Length - header but start from where we are up to (avoid overlaps) */ if (skb->h.th->syn) sum++; if (sum > 0) @@ -1405,7 +1405,8 @@ */ tcp_statistics.TcpOutSegs++; - skb->h.seq = ntohl(th->seq) + size - 4*th->doff; + skb->seq = ntohl(th->seq); + skb->end_seq = skb->seq + size - 4*th->doff; /* * We must queue if @@ -1415,7 +1416,7 @@ * c) We have too many packets 'in flight' */ - if (after(skb->h.seq, sk->window_seq) || + if (after(skb->end_seq, sk->window_seq) || (sk->retransmits && sk->ip_xmit_timeout == TIME_WRITE) || sk->packets_out >= sk->cong_window) { @@ -1436,7 +1437,7 @@ * grief). */ - if (before(sk->window_seq, sk->write_queue.next->h.seq) && + if (before(sk->window_seq, sk->write_queue.next->end_seq) && sk->send_head == NULL && sk->ack_backlog == 0) reset_xmit_timer(sk, TIME_PROBE0, sk->rto); } @@ -1446,8 +1447,8 @@ * This is going straight out */ - th->ack_seq = ntohl(sk->acked_seq); - th->window = ntohs(tcp_select_window(sk)); + th->ack_seq = htonl(sk->acked_seq); + th->window = htons(tcp_select_window(sk)); tcp_send_check(th, sk->saddr, sk->daddr, size, sk); @@ -1645,7 +1646,7 @@ * Fill in the packet and send it */ - t1->ack_seq = ntohl(ack); + t1->ack_seq = htonl(ack); t1->doff = sizeof(*t1)/4; tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk); if (sk->debug) @@ -2117,8 +2118,8 @@ sk->ack_backlog = 0; sk->bytes_rcv = 0; sk->window = tcp_select_window(sk); - t1->window = ntohs(sk->window); - t1->ack_seq = ntohl(sk->acked_seq); + t1->window = htons(sk->window); + t1->ack_seq = htonl(sk->acked_seq); t1->doff = sizeof(*t1)/4; tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); sk->prot->queue_xmit(sk, dev, buff, 1); @@ -2343,9 +2344,9 @@ { if (!skb) break; - if (before(*seq, skb->h.th->seq)) + if (before(*seq, skb->seq)) break; - offset = *seq - skb->h.th->seq; + offset = *seq - skb->seq; if (skb->h.th->syn) offset--; if (offset < skb->len) @@ -2645,12 +2646,13 @@ t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr)); buff->dev = dev; memcpy(t1, th, sizeof(*t1)); - t1->seq = ntohl(sk->write_seq); + buff->seq = sk->write_seq; sk->write_seq++; - buff->h.seq = sk->write_seq; + buff->end_seq = sk->write_seq; + t1->seq = htonl(buff->seq); t1->ack = 1; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(sk->window=tcp_select_window(sk)); + t1->ack_seq = htonl(sk->acked_seq); + t1->window = htons(sk->window=tcp_select_window(sk)); t1->fin = 1; t1->rst = 0; t1->doff = sizeof(*t1)/4; @@ -2802,10 +2804,10 @@ { t1->ack = 1; if(!th->syn) - t1->ack_seq=htonl(th->seq); - else - t1->ack_seq=htonl(th->seq+1); - t1->seq=0; + t1->ack_seq = th->seq; + else + t1->ack_seq = htonl(ntohl(th->seq)+1); + t1->seq = 0; } t1->syn = 0; @@ -3021,9 +3023,9 @@ newsk->err = 0; newsk->shutdown = 0; newsk->ack_backlog = 0; - newsk->acked_seq = skb->h.th->seq+1; - newsk->copied_seq = skb->h.th->seq+1; - newsk->fin_seq = skb->h.th->seq; + newsk->acked_seq = skb->seq+1; + newsk->copied_seq = skb->seq+1; + newsk->fin_seq = skb->seq; newsk->state = TCP_SYN_RECV; newsk->timeout = 0; newsk->ip_xmit_timeout = 0; @@ -3061,8 +3063,8 @@ newsk->dummy_th.ack = 0; newsk->dummy_th.urg = 0; newsk->dummy_th.res2 = 0; - newsk->acked_seq = skb->h.th->seq + 1; - newsk->copied_seq = skb->h.th->seq + 1; + newsk->acked_seq = skb->seq + 1; + newsk->copied_seq = skb->seq + 1; newsk->socket = NULL; /* @@ -3167,13 +3169,14 @@ t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr)); memcpy(t1, skb->h.th, sizeof(*t1)); - buff->h.seq = newsk->write_seq; + buff->seq = newsk->write_seq++; + buff->end_seq = newsk->write_seq; /* * Swap the send and the receive. */ t1->dest = skb->h.th->source; t1->source = newsk->dummy_th.source; - t1->seq = ntohl(newsk->write_seq++); + t1->seq = ntohl(buff->seq); t1->ack = 1; newsk->window = tcp_select_window(newsk); newsk->sent_seq = newsk->write_seq; @@ -3184,7 +3187,7 @@ t1->urg = 0; t1->psh = 0; t1->syn = 1; - t1->ack_seq = ntohl(skb->h.th->seq+1); + t1->ack_seq = htonl(newsk->acked_seq); t1->doff = sizeof(*t1)/4+1; ptr = skb_put(buff,4); ptr[0] = 2; @@ -3305,10 +3308,10 @@ */ while((skb = skb_peek(&sk->write_queue)) != NULL && - before(skb->h.seq, sk->window_seq + 1) && + before(skb->end_seq, sk->window_seq + 1) && (sk->retransmits == 0 || sk->ip_xmit_timeout != TIME_WRITE || - before(skb->h.seq, sk->rcv_ack_seq + 1)) + before(skb->end_seq, sk->rcv_ack_seq + 1)) && sk->packets_out < sk->cong_window) { IS_SKB(skb); @@ -3318,7 +3321,7 @@ * See if we really need to send the packet. */ - if (before(skb->h.seq, sk->rcv_ack_seq +1)) + if (before(skb->end_seq, sk->rcv_ack_seq +1)) { /* * This is acked data. We can discard it. This @@ -3353,12 +3356,12 @@ } #endif - th->ack_seq = ntohl(sk->acked_seq); - th->window = ntohs(tcp_select_window(sk)); + th->ack_seq = htonl(sk->acked_seq); + th->window = htons(tcp_select_window(sk)); tcp_send_check(th, sk->saddr, sk->daddr, size, sk); - sk->sent_seq = skb->h.seq; + sk->sent_seq = skb->end_seq; /* * IP manages our queue for some crazy reason @@ -3494,7 +3497,7 @@ skb = skb2; skb2 = skb->link3; skb->link3 = NULL; - if (after(skb->h.seq, sk->window_seq)) + if (after(skb->end_seq, sk->window_seq)) { if (sk->packets_out > 0) sk->packets_out--; @@ -3603,7 +3606,7 @@ */ if (skb_peek(&sk->write_queue) != NULL && /* should always be non-null */ - ! before (sk->window_seq, sk->write_queue.next->h.seq)) + ! before (sk->window_seq, sk->write_queue.next->end_seq)) { sk->backoff = 0; @@ -3629,7 +3632,7 @@ { /* Check for a bug. */ if (sk->send_head->link3 && - after(sk->send_head->h.seq, sk->send_head->link3->h.seq)) + after(sk->send_head->end_seq, sk->send_head->link3->end_seq)) printk("INET: tcp.c: *** bug send_list out of order.\n"); /* @@ -3637,7 +3640,7 @@ * discard it as it's confirmed to have arrived the other end. */ - if (before(sk->send_head->h.seq, ack+1)) + if (before(sk->send_head->end_seq, ack+1)) { struct sk_buff *oskb; if (sk->retransmits) @@ -3761,10 +3764,10 @@ */ if (skb_peek(&sk->write_queue) != NULL) { - if (after (sk->window_seq+1, sk->write_queue.next->h.seq) && + if (after (sk->window_seq+1, sk->write_queue.next->end_seq) && (sk->retransmits == 0 || sk->ip_xmit_timeout != TIME_WRITE || - before(sk->write_queue.next->h.seq, sk->rcv_ack_seq + 1)) + before(sk->write_queue.next->end_seq, sk->rcv_ack_seq + 1)) && sk->packets_out < sk->cong_window) { /* @@ -3773,7 +3776,7 @@ flag |= 1; tcp_write_xmit(sk); } - else if (before(sk->window_seq, sk->write_queue.next->h.seq) && + else if (before(sk->window_seq, sk->write_queue.next->end_seq) && sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT) @@ -3985,7 +3988,7 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) { - sk->fin_seq = th->seq + skb->len + th->syn + th->fin; + sk->fin_seq = skb->end_seq; if (!sk->dead) { @@ -4119,7 +4122,7 @@ if(skb->len) /* We don't care if it's just an ack or a keepalive/window probe */ { - new_seq= th->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */ + new_seq = skb->seq + skb->len + th->syn; /* Right edge of _data_ part of frame */ /* Do this the way 4.4BSD treats it. Not what I'd regard as the meaning of the spec but it's what BSD @@ -4132,7 +4135,7 @@ * b) A fin takes effect when read not when received. */ - shut_seq=sk->acked_seq+1; /* Last byte */ + shut_seq = sk->acked_seq+1; /* Last byte */ if(after(new_seq,shut_seq)) { @@ -4181,8 +4184,8 @@ if(sk->debug) { printk("skb1=%p :", skb1); - printk("skb1->h.th->seq = %d: ", skb1->h.th->seq); - printk("skb->h.th->seq = %d\n",skb->h.th->seq); + printk("skb1->seq = %d: ", skb1->seq); + printk("skb->seq = %d\n",skb->seq); printk("copied_seq = %d acked_seq = %d\n", sk->copied_seq, sk->acked_seq); } @@ -4195,7 +4198,7 @@ * the new one in its place. */ - if (th->seq==skb1->h.th->seq && skb->len>= skb1->len) + if (skb->seq==skb1->seq && skb->len>=skb1->len) { skb_append(skb1,skb); skb_unlink(skb1); @@ -4209,7 +4212,7 @@ * Found where it fits */ - if (after(th->seq+1, skb1->h.th->seq)) + if (after(skb->seq+1, skb1->seq)) { skb_append(skb1,skb); break; @@ -4230,12 +4233,6 @@ * Figure out what the ack value for this frame is */ - th->ack_seq = th->seq + skb->len; - if (th->syn) - th->ack_seq++; - if (th->fin) - th->ack_seq++; - if (before(sk->acked_seq, sk->copied_seq)) { printk("*** tcp.c:tcp_data bug acked < copied\n"); @@ -4248,19 +4245,19 @@ * queue. */ - if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) + if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(skb->seq, sk->acked_seq+1)) { - if (before(th->seq, sk->acked_seq+1)) + if (before(skb->seq, sk->acked_seq+1)) { int newwindow; - if (after(th->ack_seq, sk->acked_seq)) + if (after(skb->end_seq, sk->acked_seq)) { - newwindow = sk->window-(th->ack_seq - sk->acked_seq); + newwindow = sk->window - (skb->end_seq - sk->acked_seq); if (newwindow < 0) newwindow = 0; sk->window = newwindow; - sk->acked_seq = th->ack_seq; + sk->acked_seq = skb->end_seq; } skb->acked = 1; @@ -4278,16 +4275,16 @@ skb2 != (struct sk_buff *)&sk->receive_queue; skb2 = skb2->next) { - if (before(skb2->h.th->seq, sk->acked_seq+1)) + if (before(skb2->seq, sk->acked_seq+1)) { - if (after(skb2->h.th->ack_seq, sk->acked_seq)) + if (after(skb2->end_seq, sk->acked_seq)) { newwindow = sk->window - - (skb2->h.th->ack_seq - sk->acked_seq); + (skb2->end_seq - sk->acked_seq); if (newwindow < 0) newwindow = 0; sk->window = newwindow; - sk->acked_seq = skb2->h.th->ack_seq; + sk->acked_seq = skb2->end_seq; } skb2->acked = 1; /* @@ -4403,7 +4400,7 @@ if (ptr) ptr--; - ptr += th->seq; + ptr += ntohl(th->seq); /* ignore urgent data that we've already seen and read */ if (after(sk->copied_seq, ptr)) @@ -4452,7 +4449,7 @@ * Is the urgent pointer pointing into this packet? */ - ptr = sk->urg_seq - th->seq + th->doff*4; + ptr = sk->urg_seq - ntohl(th->seq) + th->doff*4; if (ptr >= len) return 0; @@ -4608,9 +4605,10 @@ t1 = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr)); memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1)); - t1->seq = ntohl(sk->write_seq++); + buff->seq = sk->write_seq++; + t1->seq = htonl(buff->seq); sk->sent_seq = sk->write_seq; - buff->h.seq = sk->write_seq; + buff->end_seq = sk->write_seq; t1->ack = 0; t1->window = 2; t1->res1=0; @@ -4712,7 +4710,7 @@ /* if we have a zero window, we can't have any data in the packet.. */ if (next_seq && !sk->window) goto ignore_it; - next_seq += th->seq; + next_seq += ntohl(th->seq); /* * This isn't quite right. sk->acked_seq could be more recent @@ -4725,7 +4723,7 @@ if (!after(next_seq+1, sk->acked_seq)) goto ignore_it; /* or does it start beyond the window? */ - if (!before(th->seq, sk->acked_seq + sk->window + 1)) + if (!before(ntohl(th->seq), sk->acked_seq + sk->window + 1)) goto ignore_it; /* ok, at least part of this packet would seem interesting.. */ @@ -4864,7 +4862,10 @@ */ return(0); } - th->seq = ntohl(th->seq); + + skb->seq = ntohl(th->seq); + skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4; + skb->ack_seq = ntohl(th->ack_seq); /* See if we know about the socket. */ if (sk == NULL) @@ -4977,7 +4978,7 @@ } /* retransmitted SYN? */ - if (sk->state == TCP_SYN_RECV && th->syn && th->seq+1 == sk->acked_seq) + if (sk->state == TCP_SYN_RECV && th->syn && skb->seq+1 == sk->acked_seq) { kfree_skb(skb, FREE_READ); release_sock(sk); @@ -5021,8 +5022,8 @@ * move to established. */ syn_ok=1; /* Don't reset this connection for the syn */ - sk->acked_seq=th->seq+1; - sk->fin_seq=th->seq; + sk->acked_seq = skb->seq+1; + sk->fin_seq = skb->seq; tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr); tcp_set_state(sk, TCP_ESTABLISHED); tcp_options(sk,th); @@ -5080,7 +5081,7 @@ #define BSD_TIME_WAIT #ifdef BSD_TIME_WAIT if (sk->state == TCP_TIME_WAIT && th->syn && sk->dead && - after(th->seq, sk->acked_seq) && !th->rst) + after(skb->seq, sk->acked_seq) && !th->rst) { u32 seq = sk->write_seq; if(sk->debug) @@ -5310,8 +5311,8 @@ */ nth->ack = 1; - nth->ack_seq = ntohl(sk->acked_seq); - nth->window = ntohs(tcp_select_window(sk)); + nth->ack_seq = htonl(sk->acked_seq); + nth->window = htons(tcp_select_window(sk)); nth->check = 0; /* @@ -5330,8 +5331,8 @@ * Remember our right edge sequence number. */ - buff->h.seq = sk->sent_seq + win_size; - sk->sent_seq = buff->h.seq; /* Hack */ + buff->end_seq = sk->sent_seq + win_size; + sk->sent_seq = buff->end_seq; /* Hack */ #if 0 /* @@ -5411,8 +5412,8 @@ t1->psh = 0; t1->fin = 0; /* We are sending a 'previous' sequence, and 0 bytes of data - thus no FIN bit */ t1->syn = 0; - t1->ack_seq = ntohl(sk->acked_seq); - t1->window = ntohs(tcp_select_window(sk)); + t1->ack_seq = htonl(sk->acked_seq); + t1->window = htons(tcp_select_window(sk)); t1->doff = sizeof(*t1)/4; tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); diff -u --recursive --new-file v1.3.43/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v1.3.43/linux/net/ipv4/udp.c Fri Nov 17 08:42:34 1995 +++ linux/net/ipv4/udp.c Fri Nov 24 16:39:54 1995 @@ -196,6 +196,12 @@ if (code < 13 && icmp_err_convert[code].fatal) { + /* + * 4.x BSD compatibility item. Break RFC1122 to + * get BSD socket semantics. + */ + if(sk->bsdism && sk->state!=TCP_ESTABLISHED) + return; sk->err = icmp_err_convert[code].errno; sk->error_report(sk); } diff -u --recursive --new-file v1.3.43/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v1.3.43/linux/net/ipx/af_ipx.c Fri Nov 17 08:42:34 1995 +++ linux/net/ipx/af_ipx.c Fri Nov 24 16:39:54 1995 @@ -390,7 +390,19 @@ * that skb1 and skb2 point to it (them) so that it (they) can be * demuxed to sock1 and/or sock2. If we are unable to make enough * copies, we do as much as is possible. + * + * Firstly stop charging the sender for the space. We will + * charge the recipient or discard. If we are called from ipx_rcv + * this is ok as no socket owns an input buffer. */ + + if(skb->sk) + { + skb->sk->wmem_alloc -= skb->truesize; /* Adjust */ + skb->sk=NULL; /* Disown */ + } + + if (copy) { skb1 = skb_clone(skb, GFP_ATOMIC); if (skb1 != NULL) { @@ -529,14 +541,14 @@ /* set up data link and physical headers */ skb->dev = dev; dl->datalink_header(dl, skb, dest_node); - +#ifdef ALREADY_DONE_GUV if (skb->sk != NULL) { /* This is an outbound packet from this host. We need to * increment the write count. */ skb->sk->wmem_alloc += skb->truesize; } - +#endif #if 0 /* Now log the packet just before transmission */ dump_pkt("IPX snd:", (ipx_packet *)skb->h.raw); diff -u --recursive --new-file v1.3.43/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c --- v1.3.43/linux/net/netrom/nr_dev.c Fri Nov 17 08:42:34 1995 +++ linux/net/netrom/nr_dev.c Fri Nov 24 16:39:55 1995 @@ -14,6 +14,7 @@ * * History * NET/ROM 001 Jonathan(G4KLX) Cloned from loopback.c + * NET/ROM 002 Steve Whitehouse(GW7RRM) fixed the set_mac_address */ #include @@ -140,7 +141,8 @@ static int nr_set_mac_address(struct device *dev, void *addr) { - memcpy(dev->dev_addr, addr, dev->addr_len); + struct sockaddr *sa=addr; + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); return 0; } diff -u --recursive --new-file v1.3.43/linux/net/socket.c linux/net/socket.c --- v1.3.43/linux/net/socket.c Fri Nov 17 08:42:34 1995 +++ linux/net/socket.c Fri Nov 24 16:39:55 1995 @@ -670,21 +670,23 @@ asmlinkage int sys_listen(int fd, int backlog) { struct socket *sock; - + int err=-EOPNOTSUPP; + if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL) return(-EBADF); if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); if (sock->state != SS_UNCONNECTED) - { return(-EINVAL); - } if (sock->ops && sock->ops->listen) - sock->ops->listen(sock, backlog); - sock->flags |= SO_ACCEPTCON; - return(0); + { + err=sock->ops->listen(sock, backlog); + if(!err) + sock->flags |= SO_ACCEPTCON; + } + return(err); } diff -u --recursive --new-file v1.3.43/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v1.3.43/linux/net/unix/af_unix.c Thu Nov 9 11:23:56 1995 +++ linux/net/unix/af_unix.c Fri Nov 24 16:39:55 1995 @@ -313,6 +313,7 @@ sk->sndbuf=SK_WMEM_MAX; sk->allocation=GFP_KERNEL; sk->inuse=0; + sk->bsdism=0; sk->debug=0; sk->prot=NULL; sk->err=0;