diff -u +recursive +new-file 0.99pl15/linux/CHANGES linux/CHANGES --- 0.99pl15/linux/CHANGES Wed Dec 1 14:44:15 1993 +++ linux/CHANGES Mon Mar 14 00:25:31 1994 @@ -1,3 +1,13 @@ +CHANGES since 0.99 patchlevel 15: + + - removed all the bugs, of course. + - networking fixes. + - more changes than I really wanted.. + +CHANGES since 0.99 patchlevel 14: + + - too many to count, really. Besides, I've lost my notes. + CHANGES since 0.99 patchlevel 13: - new kernel source layout: drivers separated diff -u +recursive +new-file 0.99pl15/linux/CREDITS linux/CREDITS --- 0.99pl15/linux/CREDITS +++ linux/CREDITS Sun Mar 13 23:59:52 1994 @@ -0,0 +1,605 @@ + This is at least a partial credits-file of people that have + contributed to the linux project. It is sorted by name, and + formatted in a format that allows for easy grepping and + beautification by scripts. The fields are: name (N), email (E), + description (D) and snail-mail address (S). Thanks, + + Linus +---------- + +N: Krishna Balasubramanian +E: balasub@cis.ohio-state.edu +D: Wrote SYS V IPC (part of standard kernel since 0.99.10) + +N: Arindam Banerji +E: axb@cse.nd.edu +D: Contributed ESDI driver routines needed to port LINUX to the PS/2 MCA. +S: Department of Computer Science & Eng. +S: University of Notre Dame +S: Notre Dame, Indiana +S: USA + +N: Peter Bauer +E: 100136.3530@compuserve.com +D: Driver for depca-ethernet-board +S: 69259 Wilhemsfeld +S: Rainweg 15 +S: Germany + +N: Fred Baumgarten +E: dc6iq@insu1.etec.uni-karlsruhe.de +D: NET-2 & netstat(8) +S: Kandelstrasse 27 +S: 76297 Stutensee +S: Germany + +N: Donald Becker +E: becker@super.org +D: General low-level networking hacker +D: Most of the ethercard drivers +D: Original author of the NFS server +S: 17100 Science Drive +S: Bowie, Maryland 20715 +S: USA + +N: Stephen R. van den Berg (AKA BuGless) +E: berg@pool.informatik.rwth-aachen.de +D: General kernel, gcc, and libc hacker +D: Specialisation: tweaking, ensuring portability, tweaking, cleaning, +D: tweaking and occasionally debugging :-) +S: Bouwensstraat 22 +S: 6369 BG Simpelveld +S: The Netherlands + +N: Hennus Bergman +E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home] +E: csg279@wing.rug.nl [Alternate address] +D: Author and maintainer of the QIC-02 tape driver +S: The Netherlands + +N: Ross Biro +E: bir7@leland.Stanford.Edu +D: Original author of the Linux networking code + +N: Bill Bogstad +E: bogstad@cs.jhu.edu +D: Wrote /proc/self patch +S: Johns Hopkins University +S: Computer Science Department +S: Baltimore, Maryland 21218 +S: USA + +N: John Boyd +E: boyd@cis.ohio-state.edu +D: Co-author of wd7000 SCSI driver +S: 101 Curl Drive #591 +S: Columbus, Ohio 43210 +S: USA + +N: Andries Brouwer +E: aeb@cwi.nl +D: International character handling for keyboard and console +S: Bessemerstraat 21 +S: Amsterdam +S: The Netherlands + +N: Remy Card +E: Remy.Card@masi.ibp.fr +D: Extended file system designer and developer +D: Second extended file system designer and developer +S: Institut Blaise Pascal +S: 4 Place Jussieu, 75252 Paris Cedex 05 +S: France + +N: Ed Carp +E: ecarp@netcom.com +D: uucp, elm, pine, pico port +D: cron, at(1) developer +S: 48287 Sawleaf +S: Fremont, California 94539 +S: USA + +N: Raymond Chen +E: raymondc@microsoft.com +D: Author of Configure script +S: 14509 NE 39th St, #1096 +S: Bellevue WA 98007 +S: USA + +N: Alan Cox +E: iiitac@pyr.swan.ac.uk +E: gw4pts@gw4pts.ampr.org +E: GW4PTS@GB7SWN (packet radio) +D: NET2Debugged author +D: Network layer debugging +D: AX.25 & IPX alpha releases +S: + +N: Laurence Culhane +E: loz@holmes.demon.co.uk +D: Wrote the initial alpha SLIP code +S: 81 Hood Street +S: Northampton +S: NN1 3QT +S: England + +N: Wayne Davison +E: davison@borland.com +D: Second extended file system co-designer + +N: Thomas Dunbar +E: tdunbar@vtaix.cc.vt.edu +D: TeX & METAFONT hacking/maintainence +S: Dean, Graduate School +S: Virginia Tech +S: Blacksburg, Virginia 24061 +S: USA + +N: Torsten Duwe +E: Torsten.Duwe@informatik.uni-erlangen.de +D: Part-time kernel hacker +D: The Linux Support Team Erlangen +S: Grevenbroicher Str. 17 +S: 47807 Krefeld +S: Germany + +N: Drew Eckhardt +E: drew@cs.Colorado.EDU +D: SCSI code +D: Assorted snippets elsewhere +D: Boot sector "..." printing +S: 538 West Laurell Court +S: Louisville, Colorado 80027 +S: USA + +N: Bjorn Ekwall +E: bj0rn@blox.se +D: Driver for the D-Link parallel port Ethernet adapter +S: Myrstuguv. 83 +S: S-143 32 VARBY +S: Sweden + +N: Doug Evans +E: dje@cygnus.com +D: Wrote Xenix FS (part of standard kernel since 0.99.15) + +N: Rik Faith +E: faith@cs.unc.edu +D: Future Domain TMC-16x0 SCSI driver + +N: Juergen Fischer +E: fischer@server.et-inf.fho-emden.de +D: Author of Adaptec AHA-152x scsi driver +S: Schulstrasse 18 +S: 26506 Norden +S: Germany + +N: Jeremy Fitzhardinge +E: jeremy@sw.oz.au +D: Improved mmap and munmap handling +D: General mm minor tidyups +S: 99 Albermarle Street +S: Newtown 2042 +S: Australia + +N: Ralf Flaxa +E: rfflaxa@immd4.informatik.uni-erlangen.de +D: The Linux Support Team Erlangen + +N: Nigel Gamble +E: nigel%gamble.uucp@gate.net +D: Interrupt-driven printer driver +S: 301 Norwood Terrace, Apartment N226 +S: Boca Raton, Florida 33431-6588 +S: USA + +N: Philip Gladstone +E: philipg@onsett.com +D: Kernel / timekeeping stuff + +N: Bruno Haible +E: haible@ma2s2.mathematik.uni-karlsruhe.de +D: Unified SysV FS based on Xenix FS (part of standard kernel since 0.99.15) +S: Augartenstrasse 40 +S: D - 76137 Karlsruhe +S: Germany + +N: Andrew Haylett +E: ajh@gec-mrc.co.uk +D: Selection mechanism +S: GEC-Marconi Research Centre +S: West Hanningfield Road +S: Great Baddow, Essex CM2 8HN +S: UK + +N: Dirk Hohndel +E: hohndel@informatik.uni-wuerzburg.de +D: XFree86 +S: Universit"at W"urzburg, LS Informatik I +S: Am Hubland, 97218 W"urzburg +S: Germany + +N: Nick Holloway +E: alfie@dcs.warwick.ac.uk +D: Small patches for kernel, libc +D: Makedev +S: Department of Computer Science +S: University of Warwick +S: Coventry +S: CV4 7AL +S: UK + +N: Ron Holt +E: ron@novell.com +D: Kernel development +D: Contributed to kernel Wabi/Wine support +S: Novell, Inc. +S: 1700 South 122 East, Mailstop CP-1 +S: Provo, Utah 84606 +S: USA + +N: Rob W. W. Hooft +E: hooft@EMBL-Heidelberg.DE +D: Shared libs for graphics-tools and for the f2c compiler +D: Some kernel programming on the floppy and sounddrivers in early days +D: Some other hacks to get different kinds of programs to work for linux +S: Panoramastrasse 18 +S: D-69126 Heidelberg +S: Germany + +N: Michael K. Johnson +E: johnsonm@sunsite.unc.edu +D: The Linux Documentation Project +D: Kernel Hackers' Guide +D: Procps +D: Proc filesystem +D: Maintain tsx-11.mit.edu +D: LP driver +S: 201 Howell Street, Apartment 1C +S: Chapel Hill, North Carolina 27514-4818 +S: USA + +N: Fred N. van Kempen +E: waltje@uwalt.nl.mugnet.org +D: NET-2 +D: Drivers +D: Kernel cleanups +S: Hoefbladhof 27 +S: 2215 DV Voorhout +S: The Netherlands + +N: Olaf Kirch +E: okir@monad.swb.de +D: Author of the Linux Network Administrators' Guide +S: Kattreinstr 38 +S: D-64295 +S: Germany + +N: Ian Kluft +E: ikluft@thunder.sbay.org +D: Smail binary packages for Slackware and Debian +S: 2200 Monroe Street #1509 +S: Santa Clara, California 95050-3452 +S: USA + +N: Rudolf Koenig +E: rfkoenig@immd4.informatik.uni-erlangen.de +D: The Linux Support Team Erlangen + +N: Bas Laarhoven +E: bas@vimec.nl +D: Loadable modules and ftape driver +S: Mr. v. Boemellaan 39 +S: NL-5237 KA 's-Hertogenbosch +S: The Netherlands + +N: Warner Losh +E: imp@boulder.parcplace.com +D: Provided OI/OB for Linux, general hacker +S: 4909 Pearl East Circle Suite 200 +S: Boulder, Colorado 80303 +S: USA + +N: H.J. Lu +E: hjl@nynexst.com +D: GCC + libraries hacker + +N: Tuomas J. Lukka +E: Tuomas.Lukka@Helsinki.FI +D: Original dual-monitor patches +D: Console-mouse-tracking patches +S: Puistokaari 1 E 18 +S: 00200 Helsinki +S: Finland + +N: Kai M"akisara +E: Kai.Makisara@vtt.fi +D: SCSI Tape Driver + +N: James B. MacLean +E: jmaclean@fox.nstn.ns.ca +D: Coordinator of DOSEMU releases +D: Program in DOSEMU +S: PO BOX 220, HFX. CENTRAL +S: Halifax, Nova Scotia +S: Canada B3J 3C8 + +N: Pat Mackinlay +E: pat@it.com.au +D: 8 bit XT hard disk driver +D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking +S: 25 McMillan Street +S: Victoria Park, 6100 +S: Western Australia + +N: John A. Martin +E: jmartin@csc.com +E: jam@acm.org +E: j.a.martin@ieee.org +D: FSSTND contributor +D: Credit file compilator +S: Computer Sciences Corporation +S: 1100 West Street +S: Laurel, Maryland 20707-3587 +S: USA + +N: Bradley McLean +E: brad@bradpc.gaylord.com +D: Device driver hacker +D: General kernel debugger +S: 249 Nichols Avenue +S: Syracuse, New York 13206 +S: USA + +N: Craig Metz +E: cmetz@tjhsst.edu +D: Some of PAS 16 mixer & PCM support +S: 12305 Country Ridge Lane +S: Fairfax, Virginia 22033 +S: USA + +N: William (Bill) Metzenthen +E: billm@vaxc.cc.monash.edu.au +E: billm@jacobi.maths.monash.edu.au +D: Author of the FPU emulator. +D: Minor kernel hacker for other lost causes (Hercules mono, etc). +S: 22 Parker Street +S: Ormond +S: Victoria 3163 +S: Australia + +N: Rick Miller +E: rick@discus.mil.wi.us +D: Linux Device Registrar (Major/minor numbers), "au-play", "bwBASIC" +S: S78 W16203 Woods Road +S: Muskego, Wisconsin 53150 +S: USA + +N: Corey Minyard +E: minyard@wf-rch.cirr.com +D: Sony CDU31A CDROM Driver +S: 1805 Marquette +S: Richardson, Texas 75081 +S: USA + +N: Eberhard Moenkeberg +E: emoenke@gwdg.de +D: CDROM driver "sbpcd" (Matsushita/Panasonic/Soundblaster) +S: Reinholdstrasse 14 +S: D-37083 Goettingen +S: Germany + +N: Ian A. Murdock +E: imurdock@shell.portal.com +D: Creator of Debian distribution +S: 30 White Tail Lane +S: Lafayette, Indiana 47906 +S: USA + +N: Johan Myreen +E: jem@vipunen.hut.fi +D: PS/2 mouse driver writer etc. +S: Dragonvagen 1 A 13 +S: FIN-00330 Helsingfors +S: Finland + +N: Stefan Probst +E: snprobst@immd4.informatik.uni-erlangen.de +D: The Linux Support Team Erlangen + +N: Daniel Quinlan +E: quinlan@bucknell.edu +D: FSSTND Coordinator +S: Box C3529 +S: Bucknell University +S: Lewisburg, Pennsylvania 17837 +S: USA + +N: Florian La Roche +E: rzsfl@rz.uni-sb.de +E: flla@stud.uni-sb.de +D: Net programs and kernel net hacker +S: Gaildorfer Str. 27 +S: 7000 Stuttgart 50 +S: Germany + +N: Robert Sanders +E: gt8134b@prism.gatech.edu +D: Dosemu + +N: Peter De Schrijver +E: stud11@cc4.kuleuven.ac.be +D: Mitsumi CD-ROM driver patches March version +S: Molenbaan 29 +S: B2240 Zandhoven +S: Belgium + +N: Darren Senn +E: sinster@scintilla.santa-clara.ca.us +D: Whatever I notice needs doing (so far: itimers, /proc) +S: 620 Park View Drive #206 +S: Santa Clara, California 95054 +S: USA + +N: Chris Smith +E: csmith@convex.com +D: HPFS filesystem +S: Richardson, Texas +S: USA + +N: Drew Sullivan +E: drew@lethe.north.net +D: iBCS2 developer +S: 22 Irvington Cres. +S: Willowdale, Ontario +S: Canada, M2N 2Z1 + +N: Tommy Thorn +E: Tommy.Thorn@daimi.aau.dk +D: Device driver hacker (aha1542 & plip) +S: Aarhus University +S: Computer Science Department +S: Ny Munkegade 116 +S: DK-8000 Aarhus C +S: Denmark + +N: Jon Tombs +E: jon@gtex02.us.es +D: NFS mmap() +D: XF86_S3 +D: Kernel modules +S: C/ Teodosio 43 +S: Portal 6 1-A +S: Sevilla 41002 +S: Spain + +N: Linus Torvalds +E: Linus.Torvalds@Helsinki.FI +D: General kernel hacker +S: Kalevankatu 55 B 37 +S: 00180 Helsinki +S: Finland + +N: Theodore Ts'o +E: tytso@mit.edu +D: Random Linux hacker +D: Maintainer of tsx-11.mit.edu ftp archive +D: Maintainer of c.o.l.* Usenet<->mail gateway +D: Author of serial driver +D: Author of the new e2fsck +D: Author of job control and system call restart code +D: Author of ramdisk device driver +D: Author of loopback device driver +S: MIT Room E40-343 +S: 1 Amherst Street +S: Cambridge, Massachusetts 02139 +S: USA + +N: Simmule Turner +E: simmy@digex.com +D: Added swapping to filesystem +S: 8504 16th Street #406 +S: Silver Spring, Maryland 20910 +S: USA + +N: Stephen Tweedie +E: sct@dcs.ed.ac.uk +D: Second extended file system developer +D: General filesystem hacker +S: Dept. of Computer Science +S: University of Edinburgh +S: JCMB, The King's Buildings +S: Mayfield Road +S: Edinburgh EH9 3JZ +S: Scotland, UK + +N: Thomas Uhl +E: uhl@sun1.rz.fh-heilbronn.de +D: Application programmer +D: Linux promoter +D: Author of a German book on Linux +S: Obere Heerbergstrasse 17 +S: 97078 Wuerzburg +S: Germany + +N: Juergen Weigert +E: jnweiger@immd4.informatik.uni-erlangen.de +D: The Linux Support Team Erlangen + +N: Matt Welsh +E: mdw@sunsite.unc.edu +D: Linux Documentation Project coordinator +D: Author, Linux Installation and Getting Started +D: HOWTO coordinator and writer +D: Maintainer of sunsite.unc.edu Linux doc archives +D: Moderator, comp.os.linux.announce +S: 205 Gray Street NE +S: Wilson, North Caroilina 27893 +S: USA + + +N: Marco van Wieringen +E: mvw@mercury.mcs.nl.mugnet.org +D: Author of acct and quota +S: Breeburgsingel 12 +S: 2135 CN Hoofddorp +S: The Netherlands + +N: Stephen D. Williams +E: sdw@lig.net +E: sdw@meaddata.com +D: Consultant, entrepreneur, developer +S: 2464 Rosina Drive +S: Dayton, Ohio 45342-6430 +S: USA + +N: G\"unter Windau +E: gunter@mbfys.kun.nl +D: Some bug fixes in the polling printer driver (lp.c) +S: University of Nijmegen +S: Geert-Grooteplein Noord 21 +S: 6525 EZ Nijmegen +S: The Netherlands + +N: Lars Wirzenius +E: lars.wirzenius@helsinki.fi +D: Linux System Administrator's Guide +D: Co-moderator, comp.os.linux.announce +D: Original sprintf in kernel +D: Personal information about Linus +D: Original kernel README +D: Linux News (electronic magazine) +D: Meta-FAQ, originator +D: INFO-SHEET, former maintainer +S: Ohratie 16 C 198 +S: sf-01370 Vantaa +S: Finland + +N: Roger E. Wolff +E: wolff@dutecai.et.tudelft.nl +D: Written kmalloc/kfree +S: Oosterstraat 23 +S: 2611 TT Delft +S: The Netherlands + +N: Frank Xia +E: qx@math.columbia.edu +D: Xiafs filesystem +S: 542 West 112th Street, 5N +S: New York, New York 10025 +S: USA + +N: Eric Youngdale +E: eric@tantalus.nrl.navy.mil +D: General kernel hacker +D: SCSI iso9660 and ELF +S: 17 Canterbury Square #101 +S: Alexandria, Virginia 22304 +S: USA + +N: Orest Zborowski +E: orestz@microsoft.com +D: XFree86 and kernel development +S: 1507 145th Place SE #B5 +S: Bellevue, Washington 98007 +S: USA diff -u +recursive +new-file 0.99pl15/linux/Configure linux/Configure --- 0.99pl15/linux/Configure Wed Dec 1 14:44:15 1993 +++ linux/Configure Mon Feb 21 20:38:30 1994 @@ -158,8 +158,9 @@ eval "$2=$ans" } -CONFIG=.config~ +CONFIG=.tmpconfig CONFIG_H=include/linux/autoconf.h +trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2 # # Make sure we start out with a clean slate. diff -u +recursive +new-file 0.99pl15/linux/Makefile linux/Makefile --- 0.99pl15/linux/Makefile Thu Feb 3 14:16:43 1994 +++ linux/Makefile Mon Mar 14 00:38:57 1994 @@ -1,5 +1,5 @@ -VERSION = 0.99 -PATCHLEVEL = 15 +VERSION = 1 +PATCHLEVEL = 0 ALPHA = all: Version zImage @@ -116,10 +116,10 @@ config: $(CONFIG_SHELL) Configure $(OPTS) < config.in - @if grep -s '^CONFIG_SOUND' .config~ ; then \ + @if grep -s '^CONFIG_SOUND' .tmpconfig ; then \ $(MAKE) -C drivers/sound config; \ else : ; fi - mv .config~ .config + mv .tmpconfig .config linuxsubdirs: dummy set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done @@ -149,7 +149,7 @@ $(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $< tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs - $(LD) $(LDFLAGS) -T 1000 boot/head.o init/main.o tools/version.o \ + $(LD) $(LDFLAGS) -Ttext 1000 boot/head.o init/main.o tools/version.o \ $(ARCHIVES) \ $(FILESYSTEMS) \ $(DRIVERS) \ @@ -188,11 +188,13 @@ zlilo: $(CONFIGURE) zImage if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi + if [ -f /zSystem.map ]; then mv /zSystem.map /zSystem.old; fi cat zImage > /vmlinuz + cp zSystem.map / if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs - $(LD) $(LDFLAGS) -T 100000 boot/head.o init/main.o tools/version.o \ + $(LD) $(LDFLAGS) -Ttext 100000 boot/head.o init/main.o tools/version.o \ $(ARCHIVES) \ $(FILESYSTEMS) \ $(DRIVERS) \ @@ -229,7 +231,7 @@ rm -f zImage zSystem.map tools/zSystem tools/system rm -f Image System.map boot/bootsect boot/setup rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback - rm -f drivers/sound/configure + rm -f .tmp* drivers/sound/configure rm -f init/*.o tools/build boot/*.o tools/*.o mrproper: clean @@ -246,11 +248,11 @@ depend dep: touch tools/version.h - for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~ - for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~ + for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .tmpdepend + for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .tmpdepend set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done rm -f tools/version.h - mv .depend~ .depend + mv .tmpdepend .depend ifdef CONFIGURATION ..$(CONFIGURATION): diff -u +recursive +new-file 0.99pl15/linux/README linux/README --- 0.99pl15/linux/README Wed Dec 15 10:03:34 1993 +++ linux/README Mon Mar 14 00:11:20 1994 @@ -1,30 +1,44 @@ - Linux kernel release 0.99 patchlevel 14 + Linux kernel release 1.0 -These are the release notes for linux version 0.99.14. Read them -carefully, as they tell you what's new, explain how to install the +These are the release notes for linux version 1.0. Read them carefully, +as they tell you what this is all about, explain how to install the kernel, and what to do if something goes wrong. +WHAT IS LINUX? + + Linux is a Unix clone for 386/486-based PCs written from scratch by + Linus Torvalds with assistance from a loosely-knit team of hackers + across the Net. It aims towards POSIX compliance. + + It has all the features you would expect in a modern fully-fledged + Unix, including true multitasking, virtual memory, shared libraries, + demand loading, shared copy-on-write executables, proper memory + management and TCP/IP networking. + + It is distributed under the GNU General Public License - see the + accompanying COPYING file for more details. + INSTALLING the kernel: - - if you install by patching, you need a *clean* 0.99.13 source tree, + - If you install the full sources, do a + + cd /usr/src + tar xvf linux-1.0.tar + + to get it all put in place. + + - if you install by patching, you need a *clean* 0.99.15 source tree, which presumably exists in /usr/src/linux. If so, to get the kernel patched, just do a cd /usr/src - patch -p0 < linux-0.99.patch14 + patch -p0 < linux-1.0.patch and you should be ok. You may want to remove the backup files (xxx~ or xxx.orig), and make sure that there are no failed patches (xxx# or xxx.rej). - - If you install the full sources, do a - - cd /usr/src - tar xvf linux-0.99.14.tar - - to get it all put in place. - - make sure your /usr/include/linux and /usr/include/asm directories are just symlinks to the kernel sources: @@ -48,6 +62,9 @@ /bin/sh (in that order), so hopefully one of those is correct. NOTES on "make config": + - having unnecessary drivers will make the kernel bigger, and can + under some circumstances lead to problems: probing for a + nonexistent controller card may confuse your other controllers - compiling the kernel with "-m486" for a number of 486-specific will result in a kernel that still works on a 386: it may be slightly larger and possibly slower by an insignificant amount, @@ -74,10 +91,10 @@ COMPILING the kernel: - - make sure you have gcc-2.4.5 or newer available with g++. It seems - older gcc versions can have problems compiling linux 0.99.10 and - newer versions. If you upgrade, remember to get the new binutils - package too (for as/ld/nm and company) + - make sure you have gcc-2.4.5 or newer available. It seems older gcc + versions can have problems compiling newer versions of linux. If you + upgrade your compiler, remember to get the new binutils package too + (for as/ld/nm and company) - do a "make zImage" to create a compressed kernel image. If you want to make a bootdisk (without root filesystem or lilo), insert a floppy @@ -94,12 +111,13 @@ For some, this is on a floppy disk, in which case you can "cp /usr/src/linux/zImage /dev/fd0" to make a bootable floppy. - If you boot Linux from the hard drive, chances are you use LILO uses - the kernel image as specified in the file /etc/lilo/config. The - kernel image file is usually /vmlinux, or /Image, or /etc/Image. To - use the new kernel, copy the new image over the old one (save a - backup of the original!). Then, you MUST REINSTALL LILO!! If you - don't, you won't be able to boot the new kernel image. + If you boot Linux from the hard drive, chances are you use LILO which + uses the kernel image as specified in the file /etc/lilo/config. The + kernel image file is usually /vmlinuz, or /zImage, or /etc/zImage. + To use the new kernel, copy the new image over the old one (save a + backup of the original!). Then, you MUST RERUN LILO to update the + loading map!! If you don't, you won't be able to boot the new kernel + image. Reinstalling LILO is usually a matter of running /etc/lilo/install. You may wish to edit /etc/lilo/config to specify an entry for your diff -u +recursive +new-file 0.99pl15/linux/config.in linux/config.in --- 0.99pl15/linux/config.in Thu Feb 3 13:27:36 1994 +++ linux/config.in Sun Mar 13 02:17:37 1994 @@ -76,7 +76,7 @@ bool 'AT1700 support' CONFIG_AT1700 n #bool 'Zenith Z-Note support' CONFIG_ZNET n #bool 'EtherExpress support' CONFIG_EEXPRESS n -#bool 'DEPCA support' CONFIG_DEPCA n +bool 'DEPCA support' CONFIG_DEPCA n #bool 'NI52** support' CONFIG_NI52 n #bool 'NI65** support' CONFIG_NI65 n #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n @@ -106,7 +106,7 @@ * #bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y #bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y -bool 'Parallel printer support' CONFIG_PRINTER y +bool 'Parallel printer support' CONFIG_PRINTER n bool 'Logitech busmouse support' CONFIG_BUSMOUSE n bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y if [ "$CONFIG_PSMOUSE" = "y" ] @@ -114,7 +114,7 @@ fi bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n -bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y +bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n bool 'QIC-117 tape support' CONFIG_FTAPE n if [ "$CONFIG_FTAPE" = "y" ] diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/README linux/drivers/FPU-emu/README --- 0.99pl15/linux/drivers/FPU-emu/README Tue Jan 11 11:10:47 1994 +++ linux/drivers/FPU-emu/README Mon Feb 14 13:10:44 1994 @@ -47,7 +47,7 @@ --Bill Metzenthen - Jan 1994 + Feb 1994 ----------------------- Internals of wm-FPU-emu ----------------------- @@ -92,22 +92,13 @@ ----------------------- Limitations of wm-FPU-emu ----------------------- There are a number of differences between the current wm-FPU-emu -(version beta 1.5) and the 80486 FPU (apart from bugs). Some of the +(version beta 1.10) and the 80486 FPU (apart from bugs). Some of the more important differences are listed below: -Segment overrides don't do anything yet. +The Roundup flag does not have much meaning for the transcendental +functions and its 80486 value with these functions is likely to differ +from its emulator value. -All internal computations are performed at 64 bit or higher precision -and the results rounded etc as required by the PC bits of the FPU -control word. Under the crt0 version for Linux current at June 1993, -the FPU PC bits specify 64 bits precision. - -The precision flag (PE of the FPU status word) and the Roundup flag -(C1 of the status word) are now implemented. Does anyone write code -which uses these features? The Roundup flag does not have much meaning -for the transcendental functions and its 80486 value with these -functions is likely to differ from its emulator value. - In a few rare cases the Underflow flag obtained with the emulator will be different from that obtained with an 80486. This occurs when the following conditions apply simultaneously: @@ -139,6 +130,19 @@ result of any arithmetic operation. An 80486 can keep one of these numbers in an FPU register with its identity as a PseudoDenormal, but the emulator will not; they are always converted to a valid number. + +Self modifying code can cause the emulator to fail. An example of such +code is: + movl %esp,[%ebx] + fld1 +The FPU instruction may be (usually will be) loaded into the pre-fetch +queue of the cpu before the mov instruction is executed. If the +destination of the 'movl' overlaps the FPU instruction then the bytes +in the prefetch queue and memory will be inconsistent when the FPU +instruction is executed. The emulator will be invoked but will not be +able to find the instruction which caused the device-not-present +exception. For this case, the emulator cannot emulate the behaviour of +an 80486DX. ----------------------- Performance of wm-FPU-emu ----------------------- diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/control_w.h linux/drivers/FPU-emu/control_w.h --- 0.99pl15/linux/drivers/FPU-emu/control_w.h Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/control_w.h Wed Feb 16 13:07:55 1994 @@ -35,9 +35,10 @@ /* p 15-5: Precision control bits affect only the following: ADD, SUB(R), MUL, DIV(R), and SQRT */ -#define PR_24_BITS _Const_(0x000) -#define PR_53_BITS _Const_(0x200) -#define PR_64_BITS _Const_(0x300) +#define PR_24_BITS _Const_(0x000) +#define PR_53_BITS _Const_(0x200) +#define PR_64_BITS _Const_(0x300) +#define PR_RESERVED_BITS _Const_(0x100) /* FULL_PRECISION simulates all exceptions masked */ #define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/errors.c linux/drivers/FPU-emu/errors.c --- 0.99pl15/linux/drivers/FPU-emu/errors.c Thu Feb 3 12:11:37 1994 +++ linux/drivers/FPU-emu/errors.c Fri Feb 25 14:42:45 1994 @@ -84,16 +84,32 @@ RE_ENTRANT_CHECK_OFF; /* No need to verify_area(), we have previously fetched these bytes. */ - printk("At %p: ", (void *) address); - while ( 1 ) + printk("At %p:", (void *) address); +#define MAX_PRINTED_BYTES 20 + for ( i = 0; i < MAX_PRINTED_BYTES; i++ ) { byte1 = get_fs_byte((unsigned char *) address); - if ( (byte1 & 0xf8) == 0xd8 ) break; - printk("[%02x]", byte1); + if ( (byte1 & 0xf8) == 0xd8 ) + { + printk(" %02x", byte1); + break; + } + printk(" [%02x]", byte1); address++; } - printk("%02x ", byte1); - FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + if ( i == MAX_PRINTED_BYTES ) + printk(" [more..]\n"); + else + { + FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + + if (FPU_modrm >= 0300) + printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); + else + printk(" /%d, mod=%d rm=%d\n", + (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); + } + partial_status = status_word(); #ifdef DEBUGGING @@ -112,12 +128,6 @@ if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n"); #endif DEBUGGING - if (FPU_modrm >= 0300) - printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); - else - printk("/%d, mod=%d rm=%d\n", - (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); - printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0, /* busy */ (partial_status & 0x3800) >> 11, /* stack top pointer */ @@ -234,8 +244,9 @@ 0x126 in fpu_entry.c 0x127 in poly_2xm1.c 0x128 in fpu_entry.c + 0x130 in get_address.c 0x2nn in an *.S file: - 0x201 in reg_u_add.S, reg_round.S + 0x201 in reg_u_add.S 0x202 in reg_u_div.S 0x203 in reg_u_div.S 0x204 in reg_u_div.S @@ -250,11 +261,15 @@ 0x213 in wm_sqrt.S 0x214 in wm_sqrt.S 0x215 in wm_sqrt.S - 0x216 in reg_round.S - 0x217 in reg_round.S - 0x218 in reg_round.S 0x220 in reg_norm.S 0x221 in reg_norm.S + 0x230 in reg_round.S + 0x231 in reg_round.S + 0x232 in reg_round.S + 0x233 in reg_round.S + 0x234 in reg_round.S + 0x235 in reg_round.S + 0x236 in reg_round.S */ void exception(int n) @@ -307,11 +322,11 @@ #endif PRINT_MESSAGES } else - printk("FP emulator: Unknown Exception: 0x%04x!\n", n); + printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); if ( n == EX_INTERNAL ) { - printk("FP emulator: Internal error type 0x%04x\n", int_type); + printk("FPU emulator: Internal error type 0x%04x\n", int_type); emu_printall(); } #ifdef PRINT_MESSAGES diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_aux.c linux/drivers/FPU-emu/fpu_aux.c --- 0.99pl15/linux/drivers/FPU-emu/fpu_aux.c Thu Feb 3 12:11:37 1994 +++ linux/drivers/FPU-emu/fpu_aux.c Mon Feb 7 09:35:20 1994 @@ -17,6 +17,9 @@ #include "control_w.h" +static void fnop(void) +{ +} void fclex(void) { @@ -47,9 +50,16 @@ FPU_entry_eip = ip_offset = 0; } +/* + * These are nops on the i387.. + */ +#define feni fnop +#define fdisi fnop +#define fsetpm fnop + static FUNC const finit_table[] = { - Un_impl, Un_impl, fclex, finit, - Un_impl, FPU_illegal, FPU_illegal, FPU_illegal + feni, fdisi, fclex, finit, + fsetpm, FPU_illegal, FPU_illegal, FPU_illegal }; void finit_() @@ -74,11 +84,6 @@ (fstsw_table[FPU_rm])(); } - - -static void fnop(void) -{ -} static FUNC const fp_nop_table[] = { fnop, FPU_illegal, FPU_illegal, FPU_illegal, diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_emu.h linux/drivers/FPU-emu/fpu_emu.h --- 0.99pl15/linux/drivers/FPU-emu/fpu_emu.h Thu Feb 3 12:19:58 1994 +++ linux/drivers/FPU-emu/fpu_emu.h Wed Feb 16 13:07:55 1994 @@ -81,6 +81,12 @@ #define PREFIX_REPE 0xf3 #define PREFIX_REPNE 0xf2 #define PREFIX_LOCK 0xf0 +#define PREFIX_CS_ 1 +#define PREFIX_DS_ 2 +#define PREFIX_ES_ 3 +#define PREFIX_FS_ 4 +#define PREFIX_GS_ 5 +#define PREFIX_SS_ 6 /* These are to defeat the default action, giving the instruction no net effect: */ @@ -94,7 +100,11 @@ typedef void (*FUNC)(void); typedef struct fpu_reg FPU_REG; -typedef struct { unsigned char address_size, segment; } overrides; +typedef struct { unsigned char address_size, operand_size, segment; } + overrides; +/* This structure is 32 bits: */ +typedef struct { overrides override; + unsigned char vm86; } fpu_addr_modes; #define st(x) ( regs[((top+x) &7 )] ) diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_entry.c linux/drivers/FPU-emu/fpu_entry.c --- 0.99pl15/linux/drivers/FPU-emu/fpu_entry.c Thu Feb 3 12:27:17 1994 +++ linux/drivers/FPU-emu/fpu_entry.c Mon Feb 21 20:36:51 1994 @@ -137,13 +137,15 @@ char emulating=0; #endif PARANOID -static int valid_prefix(unsigned char *byte, overrides *override); +static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip, + overrides *override); asmlinkage void math_emulate(long arg) { unsigned char FPU_modrm, byte1; - overrides override; + unsigned short code; + fpu_addr_modes addr_modes; int unmasked; #ifdef PARANOID @@ -170,35 +172,40 @@ SETUP_DATA_AREA(arg); - FPU_ORIG_EIP = FPU_EIP; + addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0; - /* We cannot handle emulation in v86-mode */ - if (FPU_EFLAGS & 0x00020000) - { - math_abort(FPU_info,SIGILL); - } + if ( addr_modes.vm86 ) + FPU_EIP += FPU_CS << 4; - /* user code space? */ - if (FPU_CS == KERNEL_CS) - { - printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP); - panic("Math emulation needed in kernel"); - } + FPU_ORIG_EIP = FPU_EIP; - /* We cannot handle multiple segments yet */ - if (FPU_CS != USER_CS || FPU_DS != USER_DS) + if ( !addr_modes.vm86 ) { - math_abort(FPU_info,SIGILL); + /* user code space? */ + if (FPU_CS == KERNEL_CS) + { + printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP); + panic("Math emulation needed in kernel"); + } + + /* We cannot handle multiple segments yet */ + if (FPU_CS != USER_CS || FPU_DS != USER_DS) + { + math_abort(FPU_info,SIGILL); + } } FPU_lookahead = 1; if (current->flags & PF_PTRACED) - FPU_lookahead = 0; + FPU_lookahead = 0; - if ( !valid_prefix(&byte1, &override) ) + if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP, + &addr_modes.override) ) { RE_ENTRANT_CHECK_OFF; - printk("FPU emulator: Unknown prefix byte 0x%02x\n", byte1); + printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n" + "FPU emulator: self-modifying code! (emulation impossible)\n", + byte1); RE_ENTRANT_CHECK_ON; EXCEPTION(EX_INTERNAL|0x126); math_abort(FPU_info,SIGILL); @@ -244,7 +251,7 @@ but a real 80486 uses the following instructions: fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex. */ - unsigned short code = (FPU_modrm << 8) | byte1; + code = (FPU_modrm << 8) | byte1; if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */ (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv, fnstsw */ @@ -289,7 +296,11 @@ if ( FPU_modrm < 0300 ) { /* All of these instructions use the mod/rm byte to get a data address */ - get_address(FPU_modrm, override); + if ( addr_modes.vm86 + ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) ) + get_address_16(FPU_modrm, &FPU_EIP, addr_modes); + else + get_address(FPU_modrm, &FPU_EIP, addr_modes); if ( !(byte1 & 1) ) { unsigned short status1 = partial_status; @@ -303,16 +314,16 @@ switch ( (byte1 >> 1) & 3 ) { case 0: - unmasked = reg_load_single(override); + unmasked = reg_load_single(); break; case 1: - reg_load_int32(override); + reg_load_int32(); break; case 2: - unmasked = reg_load_double(override); + unmasked = reg_load_double(); break; case 3: - reg_load_int16(override); + reg_load_int16(); break; } @@ -440,7 +451,8 @@ } else { - load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, override); + load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, + addr_modes); } reg_mem_instr_done: @@ -527,10 +539,14 @@ if (FPU_lookahead && !need_resched) { FPU_ORIG_EIP = FPU_EIP; - if ( valid_prefix(&byte1, &override) ) + if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP, + &addr_modes.override) ) goto do_another_FPU_instruction; } + if ( addr_modes.vm86 ) + FPU_EIP -= FPU_CS << 4; + RE_ENTRANT_CHECK_OFF; } @@ -539,16 +555,17 @@ all prefix bytes, further changes are needed in the emulator code which accesses user address space. Access to separate segments is important for msdos emulation. */ -static int valid_prefix(unsigned char *Byte, overrides *override) +static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip, + overrides *override) { unsigned char byte; - unsigned long ip = FPU_EIP; + unsigned char *ip = *fpu_eip; - *override = (overrides) { 0, PREFIX_DS }; /* defaults */ + *override = (overrides) { 0, 0, PREFIX_DS_ }; /* defaults */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - byte = get_fs_byte((unsigned char *) FPU_EIP); + byte = get_fs_byte(ip); RE_ENTRANT_CHECK_ON; while ( 1 ) @@ -558,35 +575,43 @@ case ADDR_SIZE_PREFIX: override->address_size = ADDR_SIZE_PREFIX; goto do_next_byte; + + case OP_SIZE_PREFIX: + override->operand_size = OP_SIZE_PREFIX; + goto do_next_byte; + case PREFIX_CS: - override->segment = PREFIX_CS; + override->segment = PREFIX_CS_; goto do_next_byte; case PREFIX_ES: - override->segment = PREFIX_ES; + override->segment = PREFIX_ES_; goto do_next_byte; case PREFIX_SS: - override->segment = PREFIX_SS; + override->segment = PREFIX_SS_; goto do_next_byte; case PREFIX_FS: - override->segment = PREFIX_FS; + override->segment = PREFIX_FS_; goto do_next_byte; case PREFIX_GS: - override->segment = PREFIX_GS; + override->segment = PREFIX_GS_; goto do_next_byte; case PREFIX_DS: /* Redundant unless preceded by another override. */ - override->segment = PREFIX_DS; + override->segment = PREFIX_DS_; +/* lock is not a valid prefix for FPU instructions, + let the cpu handle it to generate a SIGILL. */ +/* case PREFIX_LOCK: */ + /* rep.. prefixes have no meaning for FPU instructions */ - case PREFIX_LOCK: case PREFIX_REPE: case PREFIX_REPNE: - case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */ + do_next_byte: - FPU_EIP++; + ip++; RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - byte = get_fs_byte((unsigned char *) (FPU_EIP)); + byte = get_fs_byte(ip); RE_ENTRANT_CHECK_ON; break; case FWAIT_OPCODE: @@ -596,11 +621,14 @@ if ( (byte & 0xf8) == 0xd8 ) { *Byte = byte; + *fpu_eip = ip; return 1; } else { - FPU_EIP = ip; + /* Not a valid sequence of prefix bytes followed by + an FPU instruction. */ + *Byte = byte; /* Needed for error message. */ return 0; } } @@ -608,7 +636,7 @@ } -void __math_abort(struct info * info, unsigned int signal) +void math_abort(struct info * info, unsigned int signal) { FPU_EIP = FPU_ORIG_EIP; current->tss.trap_no = 16; diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_proto.h linux/drivers/FPU-emu/fpu_proto.h --- 0.99pl15/linux/drivers/FPU-emu/fpu_proto.h Thu Feb 3 12:11:38 1994 +++ linux/drivers/FPU-emu/fpu_proto.h Wed Feb 16 13:07:56 1994 @@ -52,7 +52,7 @@ /* fpu_entry.c */ asmlinkage void math_emulate(long arg); -extern void __math_abort(struct info *info, unsigned int signal); +extern void math_abort(struct info *info, unsigned int signal); /* fpu_etc.c */ extern void fp_etc(void); @@ -63,10 +63,13 @@ extern void trig_b(void); /* get_address.c */ -extern void get_address(unsigned char FPU_modrm, overrides override); +extern void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, + fpu_addr_modes); +extern void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, + fpu_addr_modes); /* load_store.c */ -extern void load_store_instr(char type, overrides override); +extern void load_store_instr(char type, fpu_addr_modes addr_modes); /* poly_2xm1.c */ extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result); @@ -105,26 +108,26 @@ extern void fconst(void); /* reg_ld_str.c */ -extern int reg_load_extended(overrides override); -extern int reg_load_double(overrides override); -extern int reg_load_single(overrides override); -extern void reg_load_int64(overrides override); -extern void reg_load_int32(overrides override); -extern void reg_load_int16(overrides override); -extern void reg_load_bcd(overrides override); -extern int reg_store_extended(overrides override); -extern int reg_store_double(overrides override); -extern int reg_store_single(overrides override); -extern int reg_store_int64(overrides override); -extern int reg_store_int32(overrides override); -extern int reg_store_int16(overrides override); -extern int reg_store_bcd(overrides override); +extern int reg_load_extended(void); +extern int reg_load_double(void); +extern int reg_load_single(void); +extern void reg_load_int64(void); +extern void reg_load_int32(void); +extern void reg_load_int16(void); +extern void reg_load_bcd(void); +extern int reg_store_extended(void); +extern int reg_store_double(void); +extern int reg_store_single(void); +extern int reg_store_int64(void); +extern int reg_store_int32(void); +extern int reg_store_int16(void); +extern int reg_store_bcd(void); extern int round_to_int(FPU_REG *r); -extern char *fldenv(void); -extern void frstor(void); +extern char *fldenv(fpu_addr_modes addr_modes); +extern void frstor(fpu_addr_modes addr_modes); extern unsigned short tag_word(void); -extern char *fstenv(void); -extern void fsave(void); +extern char *fstenv(fpu_addr_modes addr_modes); +extern void fsave(fpu_addr_modes addr_modes); /* reg_mul.c */ extern int reg_mul(FPU_REG const *a, FPU_REG const *b, diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_system.h linux/drivers/FPU-emu/fpu_system.h --- 0.99pl15/linux/drivers/FPU-emu/fpu_system.h Tue Jan 25 11:03:59 1994 +++ linux/drivers/FPU-emu/fpu_system.h Wed Feb 16 13:07:56 1994 @@ -23,6 +23,7 @@ #define FPU_info (I387.soft.info) #define FPU_CS (*(unsigned short *) &(FPU_info->___cs)) +#define FPU_SS (*(unsigned short *) &(FPU_info->___ss)) #define FPU_DS (*(unsigned short *) &(FPU_info->___ds)) #define FPU_EAX (FPU_info->___eax) #define FPU_EFLAGS (FPU_info->___eflags) diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/get_address.c linux/drivers/FPU-emu/get_address.c --- 0.99pl15/linux/drivers/FPU-emu/get_address.c Thu Feb 3 12:11:39 1994 +++ linux/drivers/FPU-emu/get_address.c Wed Feb 16 13:07:56 1994 @@ -39,9 +39,21 @@ #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info)) +static int reg_offset_vm86[] = { + offsetof(struct info,___cs), + offsetof(struct info,___vm86_ds), + offsetof(struct info,___vm86_es), + offsetof(struct info,___vm86_fs), + offsetof(struct info,___vm86_gs), + offsetof(struct info,___ss) + }; +#define VM86_REG_(x) (*(unsigned short *) \ + (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info)) + + /* Decode the SIB byte. This function assumes mod != 0 */ -static void *sib(int mod) +static void *sib(int mod, unsigned long *fpu_eip) { unsigned char ss,index,base; long offset; @@ -48,9 +60,9 @@ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */ + base = get_fs_byte((char *) (*fpu_eip)); /* The SIB byte */ RE_ENTRANT_CHECK_ON; - FPU_EIP++; + (*fpu_eip)++; ss = base >> 6; index = (base >> 3) & 7; base &= 7; @@ -77,9 +89,9 @@ /* 8 bit signed displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - offset += (signed char) get_fs_byte((char *) FPU_EIP); + offset += (signed char) get_fs_byte((char *) (*fpu_eip)); RE_ENTRANT_CHECK_ON; - FPU_EIP++; + (*fpu_eip)++; } else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ { @@ -86,9 +98,9 @@ /* 32 bit displacment */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(4); - offset += (signed) get_fs_long((unsigned long *) FPU_EIP); + offset += (signed) get_fs_long((unsigned long *) (*fpu_eip)); RE_ENTRANT_CHECK_ON; - FPU_EIP += 4; + (*fpu_eip) += 4; } return (void *) offset; @@ -95,6 +107,20 @@ } +static unsigned long vm86_segment(unsigned char segment) +{ + segment--; +#ifdef PARANOID + if ( segment > PREFIX_SS_ ) + { + EXCEPTION(EX_INTERNAL|0x130); + math_abort(FPU_info,SIGSEGV); + } +#endif PARANOID + return (unsigned long)VM86_REG_(segment) << 4; +} + + /* MOD R/M byte: MOD == 3 has a special use for the FPU SIB byte used iff R/M = 100b @@ -112,7 +138,8 @@ */ -void get_address(unsigned char FPU_modrm, overrides override) +void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, + fpu_addr_modes addr_modes) { unsigned char mod; long *cpu_reg_ptr; @@ -123,11 +150,20 @@ FPU_data_selector = FPU_DS; #endif PECULIAR_486 + /* Memory accessed via the cs selector is write protected + in 32 bit protected mode. */ +#define FPU_WRITE_BIT 0x10 + if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT) + && (addr_modes.override.segment == PREFIX_CS_) ) + { + math_abort(FPU_info,SIGSEGV); + } + mod = (FPU_modrm >> 6) & 3; if (FPU_rm == 4 && mod != 3) { - FPU_data_address = sib(mod); + FPU_data_address = sib(mod, fpu_eip); return; } @@ -137,20 +173,11 @@ case 0: if (FPU_rm == 5) { - /* Special case: disp16 or disp32 */ + /* Special case: disp32 */ RE_ENTRANT_CHECK_OFF; - if ( override.address_size == ADDR_SIZE_PREFIX ) - { - FPU_code_verify_area(2); - offset = get_fs_word((unsigned short *) FPU_EIP); - FPU_EIP += 2; - } - else - { - FPU_code_verify_area(4); - offset = get_fs_long((unsigned long *) FPU_EIP); - FPU_EIP += 4; - } + FPU_code_verify_area(4); + offset = get_fs_long((unsigned long *) (*fpu_eip)); + (*fpu_eip) += 4; RE_ENTRANT_CHECK_ON; FPU_data_address = (void *) offset; return; @@ -165,33 +192,125 @@ /* 8 bit signed displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - offset = (signed char) get_fs_byte((char *) FPU_EIP); + offset = (signed char) get_fs_byte((char *) (*fpu_eip)); RE_ENTRANT_CHECK_ON; - FPU_EIP++; + (*fpu_eip)++; break; case 2: - /* 16 or 32 bit displacement */ + /* 32 bit displacement */ RE_ENTRANT_CHECK_OFF; - if ( override.address_size == ADDR_SIZE_PREFIX ) + FPU_code_verify_area(4); + offset = (signed) get_fs_long((unsigned long *) (*fpu_eip)); + (*fpu_eip) += 4; + RE_ENTRANT_CHECK_ON; + break; + case 3: + /* Not legal for the FPU */ + EXCEPTION(EX_Invalid); + } + + if ( addr_modes.vm86 ) + { + offset += vm86_segment(addr_modes.override.segment); + } + + FPU_data_address = offset + (char *)*cpu_reg_ptr; +} + + +void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, + fpu_addr_modes addr_modes) +{ + unsigned char mod; + int offset = 0; /* Default used for mod == 0 */ + +#ifndef PECULIAR_486 + /* This is a reasonable place to do this */ + FPU_data_selector = FPU_DS; +#endif PECULIAR_486 + + /* Memory accessed via the cs selector is write protected + in 32 bit protected mode. */ +#define FPU_WRITE_BIT 0x10 + if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT) + && (addr_modes.override.segment == PREFIX_CS_) ) + { + math_abort(FPU_info,SIGSEGV); + } + + mod = (FPU_modrm >> 6) & 3; + + switch (mod) + { + case 0: + if (FPU_rm == 6) { + /* Special case: disp16 */ + RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(2); - offset = (signed) get_fs_word((unsigned short *) FPU_EIP); - FPU_EIP += 2; - } - else - { - FPU_code_verify_area(4); - offset = (signed) get_fs_long((unsigned long *) FPU_EIP); - FPU_EIP += 4; + offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip)); + (*fpu_eip) += 2; + RE_ENTRANT_CHECK_ON; + goto add_segment; } + break; + case 1: + /* 8 bit signed displacement */ + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + offset = (signed char) get_fs_byte((signed char *) (*fpu_eip)); + RE_ENTRANT_CHECK_ON; + (*fpu_eip)++; + break; + case 2: + /* 16 bit displacement */ + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(2); + offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip)); + (*fpu_eip) += 2; RE_ENTRANT_CHECK_ON; break; case 3: /* Not legal for the FPU */ EXCEPTION(EX_Invalid); + break; + } + switch ( FPU_rm ) + { + case 0: + offset += FPU_info->___ebx + FPU_info->___esi; + break; + case 1: + offset += FPU_info->___ebx + FPU_info->___edi; + break; + case 2: + offset += FPU_info->___ebp + FPU_info->___esi; + break; + case 3: + offset += FPU_info->___ebp + FPU_info->___edi; + break; + case 4: + offset += FPU_info->___esi; + break; + case 5: + offset += FPU_info->___edi; + break; + case 6: + offset += FPU_info->___ebp; + break; + case 7: + offset += FPU_info->___ebx; + break; } - FPU_data_address = offset + (char *)*cpu_reg_ptr; - if ( override.address_size == ADDR_SIZE_PREFIX ) - FPU_data_address = (void *)((long)FPU_data_address & 0xffff); + add_segment: + offset &= 0xffff; + + if ( addr_modes.vm86 ) + { + offset += vm86_segment(addr_modes.override.segment); + } + + FPU_data_address = (void *)offset ; } + diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/load_store.c linux/drivers/FPU-emu/load_store.c --- 0.99pl15/linux/drivers/FPU-emu/load_store.c Thu Feb 3 12:11:39 1994 +++ linux/drivers/FPU-emu/load_store.c Mon Feb 14 13:10:46 1994 @@ -46,7 +46,7 @@ _NONE_, _REG0_, _NONE_, _REG0_ }; -void load_store_instr(char type, overrides override) +void load_store_instr(char type, fpu_addr_modes addr_modes) { FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't change if the emulator is re-entered. */ @@ -85,7 +85,7 @@ { case 000: /* fld m32real */ clear_C1(); - reg_load_single(override); + reg_load_single(); if ( (FPU_loaded_data.tag == TW_NaN) && real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) { @@ -96,12 +96,12 @@ break; case 001: /* fild m32int */ clear_C1(); - reg_load_int32(override); + reg_load_int32(); reg_move(&FPU_loaded_data, pop_ptr); break; case 002: /* fld m64real */ clear_C1(); - reg_load_double(override); + reg_load_double(); if ( (FPU_loaded_data.tag == TW_NaN) && real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) { @@ -112,58 +112,58 @@ break; case 003: /* fild m16int */ clear_C1(); - reg_load_int16(override); + reg_load_int16(); reg_move(&FPU_loaded_data, pop_ptr); break; case 010: /* fst m32real */ clear_C1(); - reg_store_single(override); + reg_store_single(); break; case 011: /* fist m32int */ clear_C1(); - reg_store_int32(override); + reg_store_int32(); break; case 012: /* fst m64real */ clear_C1(); - reg_store_double(override); + reg_store_double(); break; case 013: /* fist m16int */ clear_C1(); - reg_store_int16(override); + reg_store_int16(); break; case 014: /* fstp m32real */ clear_C1(); - if ( reg_store_single(override) ) + if ( reg_store_single() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 015: /* fistp m32int */ clear_C1(); - if ( reg_store_int32(override) ) + if ( reg_store_int32() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 016: /* fstp m64real */ clear_C1(); - if ( reg_store_double(override) ) + if ( reg_store_double() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 017: /* fistp m16int */ clear_C1(); - if ( reg_store_int16(override) ) + if ( reg_store_int16() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 020: /* fldenv m14/28byte */ - fldenv(); + fldenv(addr_modes); break; case 022: /* frstor m94/108byte */ - frstor(); + frstor(addr_modes); break; case 023: /* fbld m80dec */ clear_C1(); - reg_load_bcd(override); + reg_load_bcd(); reg_move(&FPU_loaded_data, pop_ptr); break; case 024: /* fldcw */ @@ -183,25 +183,25 @@ break; case 025: /* fld m80real */ clear_C1(); - reg_load_extended(override); + reg_load_extended(); reg_move(&FPU_loaded_data, pop_ptr); break; case 027: /* fild m64int */ clear_C1(); - reg_load_int64(override); + reg_load_int64(); reg_move(&FPU_loaded_data, pop_ptr); break; case 030: /* fstenv m14/28byte */ - fstenv(); + fstenv(addr_modes); NO_NET_DATA_EFFECT; break; case 032: /* fsave */ - fsave(); + fsave(addr_modes); NO_NET_DATA_EFFECT; break; case 033: /* fbstp m80dec */ clear_C1(); - if ( reg_store_bcd(override) ) + if ( reg_store_bcd() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; @@ -215,7 +215,7 @@ break; case 035: /* fstp m80real */ clear_C1(); - if ( reg_store_extended(override) ) + if ( reg_store_extended() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; @@ -229,7 +229,7 @@ break; case 037: /* fistp m64int */ clear_C1(); - if ( reg_store_int64(override) ) + if ( reg_store_int64() ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/reg_ld_str.c linux/drivers/FPU-emu/reg_ld_str.c --- 0.99pl15/linux/drivers/FPU-emu/reg_ld_str.c Thu Feb 3 12:11:41 1994 +++ linux/drivers/FPU-emu/reg_ld_str.c Wed Feb 16 13:07:56 1994 @@ -44,7 +44,7 @@ /* Get a long double from user memory */ -int reg_load_extended(overrides override) +int reg_load_extended(void) { long double *s = (long double *)FPU_data_address; unsigned long sigl, sigh, exp; @@ -145,7 +145,7 @@ /* Get a double from user memory */ -int reg_load_double(overrides override) +int reg_load_double(void) { double *dfloat = (double *)FPU_data_address; int exp; @@ -223,7 +223,7 @@ /* Get a float from user memory */ -int reg_load_single(overrides override) +int reg_load_single(void) { float *single = (float *)FPU_data_address; unsigned m32; @@ -292,7 +292,7 @@ /* Get a long long from user memory */ -void reg_load_int64(overrides override) +void reg_load_int64(void) { long long *_s = (long long *)FPU_data_address; int e; @@ -324,7 +324,7 @@ /* Get a long from user memory */ -void reg_load_int32(overrides override) +void reg_load_int32(void) { long *_s = (long *)FPU_data_address; long s; @@ -356,7 +356,7 @@ /* Get a short from user memory */ -void reg_load_int16(overrides override) +void reg_load_int16(void) { short *_s = (short *)FPU_data_address; int s, e; @@ -389,7 +389,7 @@ /* Get a packed bcd array from user memory */ -void reg_load_bcd(overrides override) +void reg_load_bcd(void) { char *s = (char *)FPU_data_address; int pos; @@ -436,7 +436,7 @@ /*===========================================================================*/ /* Put a long double into user memory */ -int reg_store_extended(overrides override) +int reg_store_extended(void) { /* The only exception raised by an attempt to store to an @@ -475,7 +475,7 @@ /* Put a double into user memory */ -int reg_store_double(overrides override) +int reg_store_double(void) { double *dfloat = (double *)FPU_data_address; unsigned long l[2]; @@ -670,7 +670,7 @@ /* Put a float into user memory */ -int reg_store_single(overrides override) +int reg_store_single(void) { float *single = (float *)FPU_data_address; long templ; @@ -859,7 +859,7 @@ /* Put a long long into user memory */ -int reg_store_int64(overrides override) +int reg_store_int64(void) { long long *d = (long long *)FPU_data_address; FPU_REG t; @@ -918,7 +918,7 @@ /* Put a long into user memory */ -int reg_store_int32(overrides override) +int reg_store_int32(void) { long *d = (long *)FPU_data_address; FPU_REG t; @@ -972,7 +972,7 @@ /* Put a short into user memory */ -int reg_store_int16(overrides override) +int reg_store_int16(void) { short *d = (short *)FPU_data_address; FPU_REG t; @@ -1026,7 +1026,7 @@ /* Put a packed bcd array into user memory */ -int reg_store_bcd(overrides override) +int reg_store_bcd(void) { char *d = (char *)FPU_data_address; FPU_REG t; @@ -1163,7 +1163,7 @@ /*===========================================================================*/ -char *fldenv(void) +char *fldenv(fpu_addr_modes addr_modes) { char *s = (char *)FPU_data_address; unsigned short tag_word = 0; @@ -1170,17 +1170,45 @@ unsigned char tag; int i; - RE_ENTRANT_CHECK_OFF; - FPU_verify_area(VERIFY_READ, s, 0x1c); - control_word = get_fs_word((unsigned short *) s); - partial_status = get_fs_word((unsigned short *) (s+4)); - tag_word = get_fs_word((unsigned short *) (s+8)); - ip_offset = get_fs_long((unsigned long *) (s+0x0c)); - cs_selector = get_fs_long((unsigned long *) (s+0x10)); - data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); - operand_selector = get_fs_long((unsigned long *) (s+0x18)); - RE_ENTRANT_CHECK_ON; + if ( addr_modes.vm86 + || (addr_modes.override.operand_size == OP_SIZE_PREFIX) ) + { + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 0x0e); + control_word = get_fs_word((unsigned short *) s); + partial_status = get_fs_word((unsigned short *) (s+2)); + tag_word = get_fs_word((unsigned short *) (s+4)); + ip_offset = get_fs_word((unsigned short *) (s+6)); + cs_selector = get_fs_word((unsigned short *) (s+8)); + data_operand_offset = get_fs_word((unsigned short *) (s+0x0a)); + operand_selector = get_fs_word((unsigned short *) (s+0x0c)); + RE_ENTRANT_CHECK_ON; + s += 0x0e; + if ( addr_modes.vm86 ) + { + ip_offset += (cs_selector & 0xf000) << 4; + data_operand_offset += (operand_selector & 0xf000) << 4; + } + } + else + { + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 0x1c); + control_word = get_fs_word((unsigned short *) s); + partial_status = get_fs_word((unsigned short *) (s+4)); + tag_word = get_fs_word((unsigned short *) (s+8)); + ip_offset = get_fs_long((unsigned long *) (s+0x0c)); + cs_selector = get_fs_long((unsigned long *) (s+0x10)); + data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); + operand_selector = get_fs_long((unsigned long *) (s+0x18)); + RE_ENTRANT_CHECK_ON; + s += 0x1c; + } +#ifdef PECULIAR_486 + control_word &= ~0xe080; +#endif PECULIAR_486 + top = (partial_status >> SW_Top_Shift) & 7; if ( partial_status & ~control_word & CW_Exceptions ) @@ -1226,21 +1254,21 @@ NO_NET_DATA_EFFECT; NO_NET_INSTR_EFFECT; - return s + 0x1c; + return s; } -void frstor(void) +void frstor(fpu_addr_modes addr_modes) { int i, stnr; unsigned char tag; - char *s = fldenv(); + char *s = fldenv(addr_modes); for ( i = 0; i < 8; i++ ) { /* Load each register. */ FPU_data_address = (void *)(s+i*10); - reg_load_extended((overrides){0,0}); + reg_load_extended(); stnr = (i+top) & 7; tag = regs[stnr].tag; /* Derived from the loaded tag word. */ reg_move(&FPU_loaded_data, ®s[stnr]); @@ -1285,46 +1313,79 @@ } -char *fstenv(void) +char *fstenv(fpu_addr_modes addr_modes) { char *d = (char *)FPU_data_address; - RE_ENTRANT_CHECK_OFF; - FPU_verify_area(VERIFY_WRITE,d,28); + if ( addr_modes.vm86 + || (addr_modes.override.operand_size == OP_SIZE_PREFIX) ) + { + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,14); +#ifdef PECULIAR_486 + put_fs_long(control_word & ~0xe080, (unsigned short *) d); +#else + put_fs_word(control_word, (unsigned short *) d); +#endif PECULIAR_486 + put_fs_word(status_word(), (unsigned short *) (d+2)); + put_fs_word(tag_word(), (unsigned short *) (d+4)); + put_fs_word(ip_offset, (unsigned short *) (d+6)); + put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a)); + if ( addr_modes.vm86 ) + { + put_fs_word((ip_offset & 0xf0000) >> 4, + (unsigned short *) (d+8)); + put_fs_word((data_operand_offset & 0xf0000) >> 4, + (unsigned short *) (d+0x0c)); + } + else + { + put_fs_word(cs_selector, (unsigned short *) (d+8)); + put_fs_word(operand_selector, (unsigned short *) (d+0x0c)); + } + RE_ENTRANT_CHECK_ON; + d += 0x0e; + } + else + { + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,28); #ifdef PECULIAR_486 - /* An 80486 sets all the reserved bits to 1. */ - put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d); - put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4)); - put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8)); + /* An 80486 sets all the reserved bits to 1. */ + put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d); + put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4)); + put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8)); #else - put_fs_word(control_word, (unsigned short *) d); - put_fs_word(status_word(), (unsigned short *) (d+4)); - put_fs_word(tag_word(), (unsigned short *) (d+8)); + put_fs_word(control_word, (unsigned short *) d); + put_fs_word(status_word(), (unsigned short *) (d+4)); + put_fs_word(tag_word(), (unsigned short *) (d+8)); #endif PECULIAR_486 - put_fs_long(ip_offset, (unsigned long *) (d+0x0c)); - put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10)); - put_fs_long(data_operand_offset, (unsigned long *) (d+0x14)); + put_fs_long(ip_offset, (unsigned long *) (d+0x0c)); + put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10)); + put_fs_long(data_operand_offset, (unsigned long *) (d+0x14)); #ifdef PECULIAR_486 - /* An 80486 sets all the reserved bits to 1. */ - put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18)); + /* An 80486 sets all the reserved bits to 1. */ + put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18)); #else - put_fs_long(operand_selector, (unsigned long *) (d+0x18)); + put_fs_long(operand_selector, (unsigned long *) (d+0x18)); #endif PECULIAR_486 - RE_ENTRANT_CHECK_ON; + RE_ENTRANT_CHECK_ON; + d += 0x1c; + } control_word |= CW_Exceptions; partial_status &= ~(SW_Summary | SW_Backward); - return d + 0x1c; + return d; } -void fsave(void) +void fsave(fpu_addr_modes addr_modes) { char *d; int i; - d = fstenv(); + d = fstenv(addr_modes); RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,80); RE_ENTRANT_CHECK_ON; diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/reg_mul.c linux/drivers/FPU-emu/reg_mul.c --- 0.99pl15/linux/drivers/FPU-emu/reg_mul.c Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/reg_mul.c Fri Feb 25 14:42:46 1994 @@ -51,11 +51,10 @@ one valid and the other zero. The result is therefore zero. */ reg_move(&CONST_Z, dest); -#ifdef PECULIAR_486 /* The 80486 book says that the answer is +0, but a real - 80486 appears to behave this way... */ + 80486 behaves this way. + IEEE-754 apparently says it should be this way. */ dest->sign = sign; -#endif PECULIAR_486 return 0; } else diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/reg_round.S linux/drivers/FPU-emu/reg_round.S --- 0.99pl15/linux/drivers/FPU-emu/reg_round.S Wed Dec 1 14:44:16 1993 +++ linux/drivers/FPU-emu/reg_round.S Wed Feb 16 13:07:57 1994 @@ -156,9 +156,19 @@ cmpl PR_24_BITS,%ecx je LRound_To_24 +#ifdef PECULIAR_486 +/* With the precision control bits set to 01 "(reserved)", a real 80486 + behaves as if the precision control bits were set to 11 "64 bits" */ + cmpl PR_RESERVED_BITS,%ecx + je LRound_To_64 +#ifdef PARANOID + jmp L_bugged_denorm_486 +#endif PARANOID +#else #ifdef PARANOID - jmp L_bugged /* There is no bug, just a bad control word */ + jmp L_bugged_denorm /* There is no bug, just a bad control word */ #endif PARANOID +#endif PECULIAR_486 /* Round etc to 24 bit precision */ @@ -178,7 +188,7 @@ je LDown_24 #ifdef PARANOID - jmp L_bugged + jmp L_bugged_round24 #endif PARANOID LUp_24: @@ -258,7 +268,7 @@ je LDown_53 #ifdef PARANOID - jmp L_bugged + jmp L_bugged_round53 #endif PARANOID LUp_53: @@ -332,7 +342,7 @@ je LDown_64 #ifdef PARANOID - jmp L_bugged + jmp L_bugged_round64 #endif PARANOID LUp_64: @@ -643,21 +653,46 @@ #ifdef PARANOID -/* If we ever get here then we have problems! */ -L_bugged: - pushl EX_INTERNAL|0x201 +#ifdef PECULIAR_486 +L_bugged_denorm_486: + pushl EX_INTERNAL|0x236 + call EXCEPTION + popl %ebx + jmp L_exception_exit +#else +L_bugged_denorm: + pushl EX_INTERNAL|0x230 + call EXCEPTION + popl %ebx + jmp L_exception_exit +#endif PECULIAR_486 + +L_bugged_round24: + pushl EX_INTERNAL|0x231 + call EXCEPTION + popl %ebx + jmp L_exception_exit + +L_bugged_round53: + pushl EX_INTERNAL|0x232 + call EXCEPTION + popl %ebx + jmp L_exception_exit + +L_bugged_round64: + pushl EX_INTERNAL|0x233 call EXCEPTION popl %ebx jmp L_exception_exit L_norm_bugged: - pushl EX_INTERNAL|0x216 + pushl EX_INTERNAL|0x234 call EXCEPTION popl %ebx jmp L_exception_exit L_entry_bugged: - pushl EX_INTERNAL|0x217 + pushl EX_INTERNAL|0x235 call EXCEPTION popl %ebx L_exception_exit: diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/version.h linux/drivers/FPU-emu/version.h --- 0.99pl15/linux/drivers/FPU-emu/version.h Thu Feb 3 12:11:41 1994 +++ linux/drivers/FPU-emu/version.h Mon Feb 14 13:10:47 1994 @@ -9,5 +9,5 @@ | | +---------------------------------------------------------------------------*/ -#define FPU_VERSION "wm-FPU-emu version Beta 1.9" +#define FPU_VERSION "wm-FPU-emu version Beta 1.10" diff -u +recursive +new-file 0.99pl15/linux/drivers/block/Makefile linux/drivers/block/Makefile --- 0.99pl15/linux/drivers/block/Makefile Sat Jan 29 14:55:06 1994 +++ linux/drivers/block/Makefile Sun Mar 6 16:08:21 1994 @@ -37,9 +37,6 @@ ifdef CONFIG_SBPCD OBJS := $(OBJS) sbpcd.o SRCS := $(SRCS) sbpcd.c -ifdef PATCHLEVEL -CFLAGS := $(CFLAGS) -DPATCHLEVEL=$(PATCHLEVEL) -endif endif #CONFIG_SBPCD ifdef CONFIG_BLK_DEV_HD diff -u +recursive +new-file 0.99pl15/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd --- 0.99pl15/linux/drivers/block/README.sbpcd Sun Jan 30 19:37:12 1994 +++ linux/drivers/block/README.sbpcd Sun Mar 6 16:08:21 1994 @@ -1,4 +1,4 @@ -This is release 1.2 of the SoundBlaster Pro (Matsushita, Kotobuki, +This is release 1.3 of the SoundBlaster Pro (Matsushita, Kotobuki, Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux. The driver is able to drive the whole family of IDE-style @@ -6,10 +6,10 @@ like CR-562 and CR-563, too), and it will work with the soundcard interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...). -The interface type has to get configured, because the behavior -is different. +The interface type has to get configured in /usr/include/linux/sbpcd.h, +because the behavior is different. -The driver respects different drive firmware releases - my drive +The driver respects different drive firmware releases - my old drive is a 2.11, but it should work with "old" drives <2.01 ... >3.00 and with "new" drives (which count the releases around 0.75 or 1.00). @@ -23,9 +23,6 @@ to it's drive ID. The drive IDs may be selected freely from 0 to 3 - they must not be in consecutive order. -If this driver doesn't work with your equipment, mail me a -description, please. - The driver supports reading of data from the CD and playing of audio tracks. The audio part should run with WorkMan, xcdplayer, with the "non-X11" products CDplayer and WorkBone - tell me if @@ -32,11 +29,8 @@ it is not compatible with other software. MultiSession is supported, "ManySession" (see below) alternatively. -Photo CDs should work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm -is a package to convert photo CD image files. - -I did not have a chance to play with XA or mixed mode CDs yet. -Send one over, if you would like sbpcd to support that. +Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is a package +to convert photo CD image files. The transfer rate will reach 150 kB/sec with standard drives and the full 300 kB/sec with double-speed drives. @@ -127,7 +121,7 @@ drop me a mail and some food for the soul. :-) Those "many-session" CDs can get made by CDROM writers like Philips CDD 521. -With this feature enabled, it is impossible to read true +If you enable this feature, it is impossible to read true multisession CDs. @@ -193,10 +187,6 @@ Currently, the detection of disk change or removal does not work as good as it should. - -Further, I do not know if this driver can live together with a -SCSI CD-ROM driver and/or device, but I hope so. - Bug reports, comments, wishes, donations (technical information diff -u +recursive +new-file 0.99pl15/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- 0.99pl15/linux/drivers/block/floppy.c Mon Dec 27 07:23:53 1993 +++ linux/drivers/block/floppy.c Tue Mar 1 08:27:32 1994 @@ -301,7 +301,7 @@ static void floppy_select(unsigned int nr) { - static struct timer_list select = { NULL, 0, 0, select_callback }; + static struct timer_list select = { NULL, NULL, 0, 0, select_callback }; if (current_drive == (current_DOR & 3)) { floppy_ready(); @@ -324,10 +324,10 @@ } static struct timer_list motor_on_timer[4] = { - { NULL, 0, 0, motor_on_callback }, - { NULL, 0, 1, motor_on_callback }, - { NULL, 0, 2, motor_on_callback }, - { NULL, 0, 3, motor_on_callback } + { NULL, NULL, 0, 0, motor_on_callback }, + { NULL, NULL, 0, 1, motor_on_callback }, + { NULL, NULL, 0, 2, motor_on_callback }, + { NULL, NULL, 0, 3, motor_on_callback } }; static void motor_off_callback(unsigned long nr) @@ -341,10 +341,10 @@ } static struct timer_list motor_off_timer[4] = { - { NULL, 0, 0, motor_off_callback }, - { NULL, 0, 1, motor_off_callback }, - { NULL, 0, 2, motor_off_callback }, - { NULL, 0, 3, motor_off_callback } + { NULL, NULL, 0, 0, motor_off_callback }, + { NULL, NULL, 0, 1, motor_off_callback }, + { NULL, NULL, 0, 2, motor_off_callback }, + { NULL, NULL, 0, 3, motor_off_callback } }; static void floppy_on(unsigned int nr) diff -u +recursive +new-file 0.99pl15/linux/drivers/block/mcd.c linux/drivers/block/mcd.c --- 0.99pl15/linux/drivers/block/mcd.c Thu Dec 2 17:25:41 1993 +++ linux/drivers/block/mcd.c Sun Mar 6 16:12:04 1994 @@ -852,7 +852,10 @@ mcd_port); return mem_start; } - + + if (result[0] == result[1] && result[1] == result[2]) + return mem_start; + printk("mcd: Mitsumi version : %02X %c %x\n", result[0],result[1],result[2]); diff -u +recursive +new-file 0.99pl15/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c --- 0.99pl15/linux/drivers/block/sbpcd.c Sun Jan 30 19:37:11 1994 +++ linux/drivers/block/sbpcd.c Sun Mar 6 16:08:22 1994 @@ -5,7 +5,7 @@ * and for "no-sound" interfaces like Lasermate and the * Panasonic CI-101P. * - * NOTE: This is release 1.2. + * NOTE: This is release 1.3. * It works with my SbPro & drive CR-521 V2.11 from 2/92 * and with the new CR-562-B V0.75 on a "naked" Panasonic * CI-101P interface. And vice versa. @@ -13,8 +13,8 @@ * * VERSION HISTORY * - * 0.1 initial release, April/May 93, after mcd.c - * + * 0.1 initial release, April/May 93, after mcd.c (Martin Harriss) + * * 0.2 the "repeat:"-loop in do_sbpcd_request did not check for * end-of-request_queue (resulting in kernel panic). * Flow control seems stable, but throughput is not better. @@ -60,7 +60,8 @@ * 1.2 Found the "workman with double-speed drive" bug: use the driver's * audio_state, not what the drive is reporting with ReadSubQ. * - * + * 1.3 Minor cleanups. + * Refinements regarding Workman. * * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine * elaborated speed-up experiments (and the fabulous results!), for @@ -92,17 +93,10 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ -#ifndef PATCHLEVEL -#define PATCHLEVEL 9 -#endif #include #include -#if SBPCD_USE_IRQ -#include -#endif SBPCD_USE_IRQ - #include #include #include @@ -111,13 +105,12 @@ #include #include -#if PATCHLEVEL>13 +#if SBPCD_USE_IRQ +#include +#endif SBPCD_USE_IRQ + #include #include -#else -#define DDIOCSDBG 0x9000 -#define MATSUSHITA_CDROM_MAJOR 25 -#endif #include #include @@ -127,14 +120,10 @@ #define MAJOR_NR MATSUSHITA_CDROM_MAJOR #include "blk.h" -#define VERSION "1.2" +#define VERSION "1.3 Eberhard Moenkeberg " #define SBPCD_DEBUG -#ifndef CONFIG_SBPCD -#error "SBPCD: \"make config\" again. Enable Matsushita/Panasonic CDROM support" -#endif - #ifndef CONFIG_ISO9660_FS #error "SBPCD: \"make config\" again. File system iso9660 is necessary." #endif @@ -145,7 +134,7 @@ #define MANY_SESSION 0 #define CDMKE #undef FUTURE -#define WORKMAN 0 /* some testing stuff to make it better */ +#define WORKMAN 1 /* some testing stuff to make it better */ /*==========================================================================*/ /*==========================================================================*/ @@ -154,17 +143,16 @@ * inspired by Adam J. Richter from Yggdrasil * * still not good enough - can cause a hang. - * example: a NE 2000 ehernet card at 300 will cause a hang probing 310. + * example: a NE 2000 ethernet card at 300 will cause a hang probing 310. * if that happens, reboot and use the LILO (kernel) command line. - * the conflicting possible ethernet card addresses get probed last - to - * minimize the hang possibilities. + * The possibly conflicting ethernet card addresses get NOT probed + * by default - to minimize the hang possibilities. * * The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error, * the 0x2xx-addresses must get checked before 0x6xx. * - * what are other cards' default and range ??? - * what about ESCOM PowerSound??? - * what about HighScreen??? + * send mail to emoenke@gwdg.de if your interface card is not FULLY + * represented here. */ static int autoprobe[] = { @@ -181,11 +169,14 @@ 0x650, 0, /* "sound card #9" */ 0x670, 0, /* "sound card #9" */ 0x690, 0, /* "sound card #9" */ +#if 0 +/* some "hazardous" locations (ethernet cards) */ 0x330, 0, /* Lasermate, CI-101P */ 0x350, 0, /* Lasermate, CI-101P */ 0x370, 0, /* Lasermate, CI-101P */ 0x290, 1, /* Soundblaster 16 */ 0x310, 0, /* Lasermate, CI-101P */ +#endif }; #define NUM_AUTOPROBE (sizeof(autoprobe) / sizeof(int)) @@ -221,6 +212,8 @@ * (1<i_rdev), cmd, arg)); if (!inode) return (-EINVAL); + i=MINOR(inode->i_rdev); + if ( (i<0) || (i>=NR_SBPCD) ) + { + printk("SBPCD: ioctl: bad device: %d\n", i); + return (-ENODEV); /* no such drive */ + } + switch_drive(i); + st=GetStatus(); if (st<0) return (-EIO); @@ -2004,16 +2006,7 @@ if (i<0) return (-EIO); /* error reading TOC */ } - i=MINOR(inode->i_rdev); - if ( (i<0) || (i>=NR_SBPCD) ) - { - DPRINTF((DBG_INF,"SBPCD: ioctl: bad device: %d\n", i)); - return (-ENODEV); /* no such drive */ - } - switch_drive(i); - - - DPRINTF((DBG_IOC,"SBPCD: ioctl: device %d, request %04X\n",i,cmd)); + DPRINTF((DBG_IO2,"SBPCD: ioctl: device %d, request %04X\n",i,cmd)); switch (cmd) /* Sun-compatible */ { case DDIOCSDBG: /* DDI Debug */ @@ -2194,7 +2187,7 @@ return (0); case CDROMSUBCHNL: /* Get subchannel info */ - DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSUBCHNL entered.\n")); + DPRINTF((DBG_IOS,"SBPCD: ioctl: CDROMSUBCHNL entered.\n")); if ((st_spinning)||(!subq_valid)) { i=xx_ReadSubQ(); if (i<0) return (-EIO); } @@ -2235,7 +2228,7 @@ SC.cdsc_reladdr.msf.frame=DS[d].SubQ_run_trk&0x00FF; } memcpy_tofs((void *) arg, &SC, sizeof(struct cdrom_subchnl)); - DPRINTF((DBG_IOC,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n", + DPRINTF((DBG_IOS,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n", SC.cdsc_format,SC.cdsc_audiostatus, SC.cdsc_adr,SC.cdsc_ctrl, SC.cdsc_trk,SC.cdsc_ind, @@ -2251,7 +2244,7 @@ return (-EINVAL); default: - DPRINTF((DBG_IOX,"SBPCD: ioctl: unknown function request %04X\n", cmd)); + DPRINTF((DBG_IOC,"SBPCD: ioctl: unknown function request %04X\n", cmd)); return (-EINVAL); } /* end switch(cmd) */ } @@ -2353,7 +2346,7 @@ dev = MINOR(CURRENT->dev); if ( (dev<0) || (dev>=NR_SBPCD) ) { - DPRINTF((DBG_INF,"SBPCD: do_request: bad device: %d\n", dev)); + printk("SBPCD: do_request: bad device: %d\n", dev); return; } switch_drive(dev); @@ -2364,7 +2357,7 @@ if (CURRENT->cmd != READ) { - DPRINTF((DBG_INF,"SBPCD: bad cmd %d\n", CURRENT->cmd)); + printk("SBPCD: bad cmd %d\n", CURRENT->cmd); end_request(0); goto request_loop; } @@ -2556,8 +2549,8 @@ if (j&s_not_data_ready) { if ((DS[d].ored_ctl_adr&0x40)==0) - DPRINTF((DBG_INF,"SBPCD: CD contains no data tracks.\n")); - else DPRINTF((DBG_INF,"SBPCD: sbp_data: DATA_READY timeout.\n")); + printk("SBPCD: CD contains no data tracks.\n"); + else printk("SBPCD: sbp_data: DATA_READY timeout.\n"); error_flag++; break; } @@ -2665,7 +2658,7 @@ i = MINOR(ip->i_rdev); if ( (i<0) || (i>=NR_SBPCD) ) { - DPRINTF((DBG_INF,"SBPCD: open: bad device: %d\n", i)); + printk("SBPCD: open: bad device: %d\n", i); return (-ENODEV); /* no such drive */ } switch_drive(i); @@ -2683,7 +2676,7 @@ DPRINTF((DBG_STA,"SBPCD: sbpcd_open: status %02X\n", DS[d].status_byte)); if (!st_door_closed||!st_caddy_in) { - DPRINTF((DBG_INF,"SBPCD: sbpcd_open: no disk in drive\n")); + printk("SBPCD: sbpcd_open: no disk in drive\n"); return (-EIO); } @@ -2716,7 +2709,7 @@ i = MINOR(ip->i_rdev); if ( (i<0) || (i>=NR_SBPCD) ) { - DPRINTF((DBG_INF,"SBPCD: release: bad device: %d\n", i)); + printk("SBPCD: release: bad device: %d\n", i); return; } switch_drive(i); @@ -2840,19 +2833,25 @@ DPRINTF((DBG_INI,"SBPCD: check_drives done.\n")); sti(); /* to avoid possible "printk" bug */ if (i>=0) break; /* drive found */ - printk ("\n"); + DPRINTF((DBG_INF,"\n")); sti(); /* to avoid possible "printk" bug */ } /* end of cycling through the set of possible I/O port addresses */ if (ndrives==0) { - DPRINTF((DBG_INF,"SBPCD: No drive found.\n")); + printk("SBPCD: No drive found.\n"); sti(); return (mem_start); } - DPRINTF((DBG_INF,"SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n", - ndrives, type, CDo_command)); + if (port_index>0) + { + printk("SBPCD: You should configure sbpcd.h for your hardware.\n"); + sti(); + } + + printk("SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n", + ndrives, type, CDo_command); sti(); /* to avoid possible "printk" bug */ check_datarate(); DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n")); @@ -2908,8 +2907,8 @@ if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0) { - DPRINTF((DBG_INF,"SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", - MATSUSHITA_CDROM_MAJOR)); + printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", + MATSUSHITA_CDROM_MAJOR); sti(); /* to avoid possible "printk" bug */ return (mem_start); } @@ -2921,8 +2920,7 @@ #if SBPCD_USE_IRQ if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction)) { - DPRINTF((DBG_INF,"SBPCD: Can't get IRQ%d for sbpcd driver\n", - SBPCD_INTR_NR)); + printk("SBPCD: Can't get IRQ%d for sbpcd driver\n", SBPCD_INTR_NR); sti(); /* to avoid possible "printk" bug */ } #endif SBPCD_USE_IRQ @@ -2954,7 +2952,7 @@ if (MAJOR(full_dev) != MATSUSHITA_CDROM_MAJOR) { - DPRINTF((DBG_INF,"SBPCD: media_check: invalid device.\n")); + printk("SBPCD: media_check: invalid device.\n"); return (-1); } diff -u +recursive +new-file 0.99pl15/linux/drivers/block/xd.c linux/drivers/block/xd.c --- 0.99pl15/linux/drivers/block/xd.c Wed Dec 1 14:44:15 1993 +++ linux/drivers/block/xd.c Sat Feb 12 18:27:33 1994 @@ -60,6 +60,7 @@ { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */ { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */ { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */ + { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */ }; static u_char *xd_bases[] = { @@ -578,6 +579,34 @@ } else printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive); +} + +/* Omti support courtesy Dirk Melchers */ +static void xd_omti_init_controller (u_char *address) +{ + switch ((u_long) address) { + case 0xC8000: xd_iobase = 0x320; break; + case 0xD0000: xd_iobase = 0x324; break; + case 0xD8000: xd_iobase = 0x328; break; + case 0xE0000: xd_iobase = 0x32C; break; + default: printk("xd_omti_init_controller: unsupported BIOS address %p\n",address); + xd_iobase = 0x320; break; + } + + xd_irq = 5; /* the IRQ and DMA channel are fixed on the Omti controllers */ + xd_dma = 3; + xd_maxsectors = 0x40; + + outb(0,XD_RESET); /* reset the controller */ +} + +static void xd_omti_init_drive (u_char drive) +{ + /* gets infos from drive */ + xd_override_init_drive(drive); + + /* set other parameters, Hardcoded, not that nice :-) */ + xd_info[drive].control = 2; } /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads diff -u +recursive +new-file 0.99pl15/linux/drivers/char/console.c linux/drivers/char/console.c --- 0.99pl15/linux/drivers/char/console.c Thu Feb 3 13:34:54 1994 +++ linux/drivers/char/console.c Wed Feb 23 08:52:24 1994 @@ -382,12 +382,18 @@ __set_origin(__real_origin); } -static inline void hide_cursor(int currcons) +/* + * Put the cursor just beyond the end of the display adaptor memory. + */ +static inline void hide_cursor(void) { + /* This is inefficient, we could just put the cursor at 0xffff, + but perhaps the delays due to the inefficiency are useful for + some hardware... */ outb_p(14, video_port_reg); - outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val); + outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val); outb_p(15, video_port_reg); - outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val); + outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val); } static inline void set_cursor(int currcons) @@ -405,7 +411,7 @@ outb_p(15, video_port_reg); outb_p(0xff&((pos-video_mem_base)>>1), video_port_val); } else - hide_cursor(currcons); + hide_cursor(); restore_flags(flags); } @@ -1546,7 +1552,7 @@ return; timer_table[BLANK_TIMER].fn = unblank_screen; get_scrmem(fg_console); - hide_cursor(fg_console); + hide_cursor(); console_blanked = 1; memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base ); } @@ -1800,12 +1806,11 @@ if (! *bp) return 0; unblank_screen(); - while (*bp) - { + while (*bp) { put_tty_queue(*bp, &tty->read_q); bp++; + TTY_READ_FLUSH(tty); } - TTY_READ_FLUSH(tty); return 0; } @@ -1823,6 +1828,14 @@ /* * PIO_FONT support. + * + * The font loading code goes back to the codepage package by + * Joel Hoffman (joel@wam.umd.edu). (He reports that the original + * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2 + * Video Systems_ by Richard Wilton. 1987. Microsoft Press".) + * + * Change for certain monochrome monitors by Yury Shevchuck + * (sizif@botik.yaroslavl.su). */ #define colourmap ((char *)0xa0000) @@ -1838,14 +1851,17 @@ #ifdef CAN_LOAD_EGA_FONTS int i; char *charmap; + int beg; /* no use to "load" CGA... */ - if (video_type == VIDEO_TYPE_EGAC) + if (video_type == VIDEO_TYPE_EGAC) { charmap = colourmap; - else if (video_type == VIDEO_TYPE_EGAM) + beg = 0x0e; + } else if (video_type == VIDEO_TYPE_EGAM) { charmap = blackwmap; - else + beg = 0x0a; + } else return -EINVAL; i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz); @@ -1892,7 +1908,7 @@ outb_p( 0x05, gr_port_reg ); outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */ outb_p( 0x06, gr_port_reg ); - outb_p( 0x0e, gr_port_val ); /* map starts at b800:0000 */ + outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */ sti(); return 0; diff -u +recursive +new-file 0.99pl15/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- 0.99pl15/linux/drivers/char/keyboard.c Tue Feb 1 13:04:29 1994 +++ linux/drivers/char/keyboard.c Thu Mar 3 08:05:22 1994 @@ -29,12 +29,19 @@ #define SIZE(x) (sizeof(x)/sizeof((x)[0])) +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + #ifndef KBD_DEFMODE #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) #endif #ifndef KBD_DEFLEDS -#define KBD_DEFLEDS (1 << VC_NUMLOCK) +/* + * Some laptops take the 789uiojklm,. keys as number pad when NumLock + * is on. This seems a good reason to start with NumLock off. + */ +#define KBD_DEFLEDS 0 #endif #ifndef KBD_DEFLOCK @@ -205,6 +212,17 @@ } else if (scancode == 0xfe) { resend = 1; goto end_kbd_intr; + } else if (scancode == 0) { +#ifdef KBD_REPORT_ERR + printk("keyboard buffer overflow\n"); +#endif + goto end_kbd_intr; + } else if (scancode == 0xff) { +#ifdef KBD_REPORT_ERR + printk("keyboard error\n"); +#endif + prev_scancode = 0; + goto end_kbd_intr; } tty = TTY_TABLE(0); kbd = kbd_table + fg_console; @@ -263,13 +281,17 @@ if (e0_keys[scancode]) scancode = e0_keys[scancode]; else if (!raw_mode) { +#ifdef KBD_REPORT_UNKN printk("keyboard: unknown scancode e0 %02x\n", scancode); +#endif goto end_kbd_intr; } } } else if (scancode >= E0_BASE && !raw_mode) { +#ifdef KBD_REPORT_UNKN printk("keyboard: scancode (%02x) not in range 00 - %2x\n", scancode, E0_BASE - 1); +#endif goto end_kbd_intr; } diff -u +recursive +new-file 0.99pl15/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- 0.99pl15/linux/drivers/char/psaux.c Tue Jan 11 11:08:20 1994 +++ linux/drivers/char/psaux.c Thu Feb 17 09:15:19 1994 @@ -442,7 +442,6 @@ int qp_found = 0; #ifdef CONFIG_82C710_MOUSE - printk("Probing 82C710 mouse port device.\n"); if ((qp_found = probe_qp())) { printk("82C710 type pointing device detected -- driver installed.\n"); /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ diff -u +recursive +new-file 0.99pl15/linux/drivers/char/pty.c linux/drivers/char/pty.c --- 0.99pl15/linux/drivers/char/pty.c Wed Feb 2 13:54:21 1994 +++ linux/drivers/char/pty.c Wed Feb 9 08:57:58 1994 @@ -55,14 +55,11 @@ { unsigned long count, n; struct tty_queue *fq, *tq; - int skip_readq; if (from->stopped || EMPTY(&from->write_q)) return; fq = &from->write_q; - /* Bypass the read_q if this is a pty master. */ - skip_readq = IS_A_PTY_MASTER(to->line) && to->disc == N_TTY; - tq = skip_readq ? &to->secondary : &to->read_q; + tq = &to->read_q; count = MIN(CHARS(fq), LEFT(tq)); while (count) { n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head), @@ -72,10 +69,7 @@ fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1); tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1); } - if (skip_readq) - wake_up_interruptible(&to->secondary.proc_list); - else - TTY_READ_FLUSH(to); + TTY_READ_FLUSH(to); if (LEFT(fq) > WAKEUP_CHARS) wake_up_interruptible(&fq->proc_list); if (from->write_data_cnt) { diff -u +recursive +new-file 0.99pl15/linux/drivers/char/serial.c linux/drivers/char/serial.c --- 0.99pl15/linux/drivers/char/serial.c Wed Jan 26 11:17:55 1994 +++ linux/drivers/char/serial.c Sun Mar 13 22:20:21 1994 @@ -258,7 +258,13 @@ struct async_struct *info; info = rs_table + DEV_TO_SL(tty->line); - + + if (info->flags & ASYNC_CLOSING) { + tty->stopped = 0; + tty->hw_stopped = 0; + return; + } + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; #ifdef ISR_HACK serial_out(info, UART_IER, info->IER); @@ -431,7 +437,7 @@ rs_sched_event(info, RS_EVENT_HANGUP); } } - if (C_CRTSCTS(info->tty)) { + if (C_CRTSCTS(info->tty) && !(info->flags & ASYNC_CLOSING)) { if (info->tty->hw_stopped) { if (status & UART_MSR_CTS) { #ifdef SERIAL_DEBUG_INTR @@ -456,7 +462,7 @@ static inline void figure_RS_timer(void) { - int timeout = 6000; /* 60 seconds; really big :-) */ + int timeout = jiffies + 60*HZ; /* 60 seconds; really big :-) */ int i, mask; if (!IRQ_active) @@ -467,7 +473,7 @@ if (IRQ_timer[i] < timeout) timeout = IRQ_timer[i]; } - timer_table[RS_TIMER].expires = jiffies + timeout; + timer_table[RS_TIMER].expires = timeout; timer_active |= 1 << RS_TIMER; } @@ -1029,9 +1035,11 @@ if (!tty || tty->stopped || tty->hw_stopped) return; info = rs_table + DEV_TO_SL(tty->line); - if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED)) - return; cli(); + if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED)) { + sti(); + return; + } restart_port(info); info->IER = (UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI); @@ -1520,11 +1528,7 @@ tty->hw_stopped = 0; if (info->flags & ASYNC_INITIALIZED) { rs_start(tty); - /* - * XXX There should be a timeout added to - * wait_until_sent, eventually. TYT 1/19/94 - */ - wait_until_sent(tty); + wait_until_sent(tty, 6000); /* 60 seconds timeout */ } else flush_output(tty); flush_input(tty); diff -u +recursive +new-file 0.99pl15/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- 0.99pl15/linux/drivers/char/tpqic02.c Wed Dec 1 14:44:15 1993 +++ linux/drivers/char/tpqic02.c Mon Feb 14 22:13:26 1994 @@ -1816,7 +1816,7 @@ int stat; if (TP_DIAGS(current_tape_dev)) - printk(TPQIC_NAME ": request READ, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n", + printk(TPQIC_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%x, flags=%x\n", MINOR(dev), buf, count, filp->f_pos, flags); if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */ @@ -1833,7 +1833,7 @@ /* Make sure buffer is safe to write into. */ error = verify_area(VERIFY_WRITE, buf, count); if (error) { - printk(TPQIC_NAME ": read: verify_area(WRITE, %lx, %x) failed\n", buf, count); + printk(TPQIC_NAME ": read: verify_area(WRITE, %p, %x) failed\n", buf, count); return error; } @@ -1985,7 +1985,7 @@ unsigned long bytes_todo, bytes_done, total_bytes_done = 0; if (TP_DIAGS(current_tape_dev)) - printk(TPQIC_NAME ": request WRITE, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n", + printk(TPQIC_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%x, flags=%x\n", MINOR(dev), buf, count, filp->f_pos, flags); if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */ @@ -2010,7 +2010,7 @@ /* Make sure buffer is safe to read from. */ error = verify_area(VERIFY_READ, buf, count); if (error) { - printk(TPQIC_NAME ": write: verify_area(READ, %lx, %x) failed\n", buf, count); + printk(TPQIC_NAME ": write: verify_area(READ, %p, %x) failed\n", buf, count); return error; } @@ -2107,7 +2107,7 @@ } } tpqputs("write request for <0 bytes"); - printk(TPQIC_NAME ": status_bytes_wr %x, buf %x, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count); + printk(TPQIC_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count); return -EINVAL; } /* tape_qic02_write */ diff -u +recursive +new-file 0.99pl15/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- 0.99pl15/linux/drivers/char/tty_io.c Tue Feb 1 13:04:30 1994 +++ linux/drivers/char/tty_io.c Tue Mar 1 19:00:15 1994 @@ -259,8 +259,10 @@ flush_input(tty); flush_output(tty); wake_up_interruptible(&tty->secondary.proc_list); - if (tty->session > 0) + if (tty->session > 0) { kill_sl(tty->session,SIGHUP,1); + kill_sl(tty->session,SIGCONT,1); + } tty->session = 0; tty->pgrp = -1; for_each_task(p) { @@ -297,7 +299,7 @@ * it wants to dissassociate itself from its controlling tty. * * It performs the following functions: - * (1) Sends a SIGHUP to the foreground process group + * (1) Sends a SIGHUP and SIGCONT to the foreground process group * (2) Clears the tty from being controlling the session * (3) Clears the controlling tty for all processes in the * session group. @@ -310,8 +312,10 @@ if (current->tty >= 0) { tty = tty_table[current->tty]; if (tty) { - if (tty->pgrp > 0) + if (tty->pgrp > 0) { kill_pg(tty->pgrp, SIGHUP, priv); + kill_pg(tty->pgrp, SIGCONT, priv); + } tty->session = 0; tty->pgrp = -1; } else @@ -926,10 +930,7 @@ static inline int input_available_p(struct tty_struct *tty) { /* Avoid calling TTY_READ_FLUSH unnecessarily. */ - if (L_ICANON(tty)) { - if (tty->canon_data || FULL(&tty->read_q)) - return 1; - } else if (!EMPTY(&tty->secondary)) + if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) return 1; /* Shuffle any pending data down the queues. */ @@ -937,10 +938,7 @@ if (tty->link) TTY_WRITE_FLUSH(tty->link); - if (L_ICANON(tty)) { - if (tty->canon_data || FULL(&tty->read_q)) - return 1; - } else if (!EMPTY(&tty->secondary)) + if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) return 1; return 0; } @@ -954,6 +952,24 @@ int minimum, time; int retval = 0; + /* Job control check -- must be done at start and after + every sleep (POSIX.1 7.1.1.4). */ + /* NOTE: not yet done after every sleep pending a thorough + check of the logic of this change. -- jlc */ + /* don't stop on /dev/console */ + if (file->f_inode->i_rdev != CONSOLE_DEV && + current->tty == tty->line) { + if (tty->pgrp <= 0) + printk("read_chan: tty->pgrp <= 0!\n"); + else if (current->pgrp != tty->pgrp) { + if (is_ignored(SIGTTIN) || + is_orphaned_pgrp(current->pgrp)) + return -EIO; + kill_pg(current->pgrp, SIGTTIN, 1); + return -ERESTARTSYS; + } + } + if (L_ICANON(tty)) { minimum = time = 0; current->timeout = (unsigned long) -1; @@ -974,24 +990,6 @@ add_wait_queue(&tty->secondary.proc_list, &wait); while (1) { - /* Job control check -- must be done at start and after - every sleep (POSIX.1 7.1.1.4). */ - /* don't stop on /dev/console */ - if (file->f_inode->i_rdev != CONSOLE_DEV && - current->tty == tty->line) { - if (tty->pgrp <= 0) - printk("read_chan: tty->pgrp <= 0!\n"); - else if (current->pgrp != tty->pgrp) { - if (is_ignored(SIGTTIN) || - is_orphaned_pgrp(current->pgrp)) { - retval = -EIO; - break; - } - kill_pg(current->pgrp, SIGTTIN, 1); - retval = -ERESTARTSYS; - break; - } - } /* First test for status change. */ if (tty->packet && tty->link->ctrl_status) { if (b != buf) @@ -1032,7 +1030,7 @@ nr--; } - while (nr > 0) { + while (1) { int eol; cli(); @@ -1043,6 +1041,24 @@ eol = clear_bit(tty->secondary.tail, &tty->secondary_flags); c = tty->secondary.buf[tty->secondary.tail]; + if (!nr) { + /* Gobble up an immediately following EOF if + there is no more room in buf (this can + happen if the user "pushes" some characters + using ^D). This prevents the next read() + from falsely returning EOF. */ + if (eol) { + if (c == __DISABLED_CHAR) { + tty->canon_data--; + INC(tty->secondary.tail); + } else { + set_bit(tty->secondary.tail, + &tty->secondary_flags); + } + } + sti(); + break; + } INC(tty->secondary.tail); sti(); if (eol) { @@ -1063,10 +1079,9 @@ /* If there is enough space in the secondary queue now, let the low-level driver know. */ if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) - && !clear_bit(TTY_SQ_THROTTLED, &tty->flags)) + && clear_bit(TTY_SQ_THROTTLED, &tty->flags)) tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); - /* XXX packet mode's status byte is mistakenly counted */ if (b - buf >= minimum || !nr) break; if (time) @@ -1117,6 +1132,10 @@ break; if (EMPTY(&tty->write_q) && !need_resched) continue; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } schedule(); } current->state = TASK_RUNNING; @@ -1590,7 +1609,7 @@ select_wait(&tty->secondary.proc_list, wait); return 0; case SEL_OUT: - if (!FULL(&tty->write_q)) + if (LEFT(&tty->write_q) > WAKEUP_CHARS) return 1; select_wait(&tty->write_q.proc_list, wait); return 0; diff -u +recursive +new-file 0.99pl15/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c --- 0.99pl15/linux/drivers/char/tty_ioctl.c Mon Jan 31 12:37:14 1994 +++ linux/drivers/char/tty_ioctl.c Tue Mar 1 19:00:15 1994 @@ -82,7 +82,7 @@ } } -void wait_until_sent(struct tty_struct * tty) +void wait_until_sent(struct tty_struct * tty, int timeout) { struct wait_queue wait = { current, NULL }; @@ -91,7 +91,11 @@ return; add_wait_queue(&tty->write_q.proc_list, &wait); current->counter = 0; /* make us low-priority */ - while (1) { + if (timeout) + current->timeout = timeout + jiffies; + else + current->timeout = (unsigned) -1; + do { current->state = TASK_INTERRUPTIBLE; if (current->signal & ~current->blocked) break; @@ -99,7 +103,7 @@ if (EMPTY(&tty->write_q)) break; schedule(); - } + } while (current->timeout); current->state = TASK_RUNNING; remove_wait_queue(&tty->write_q.proc_list, &wait); } @@ -297,7 +301,7 @@ return 0; /* We are already in the desired discipline */ /* Shutdown the current discipline. */ - wait_until_sent(tty); + wait_until_sent(tty, 0); flush_input(tty); if (ldiscs[tty->disc].close) ldiscs[tty->disc].close(tty); @@ -379,7 +383,7 @@ if (cmd == TCSETSF || cmd == TCSETSW) { if (cmd == TCSETSF) flush_input(termios_tty); - wait_until_sent(termios_tty); + wait_until_sent(termios_tty, 0); } return set_termios(termios_tty, (struct termios *) arg, termios_dev); @@ -394,7 +398,7 @@ if (cmd == TCSETAF || cmd == TCSETAW) { if (cmd == TCSETAF) flush_input(termios_tty); - wait_until_sent(termios_tty); + wait_until_sent(termios_tty, 0); } return set_termio(termios_tty, (struct termio *) arg, termios_dev); @@ -483,6 +487,8 @@ sizeof (pid_t)); if (retval) return retval; + if (current->tty != termios_dev) + return -ENOTTY; put_fs_long(termios_tty->pgrp, (pid_t *) arg); return 0; case TIOCSPGRP: @@ -522,7 +528,10 @@ return 0; case TIOCSTI: if ((current->tty != dev) && !suser()) - return -EACCES; + return -EPERM; + retval = verify_area(VERIFY_READ, (void *) arg, 1); + if (retval) + return retval; put_tty_queue(get_fs_byte((char *) arg), &tty->read_q); TTY_READ_FLUSH(tty); return 0; @@ -550,6 +559,9 @@ return set_selection(arg); case 3: return paste_selection(tty); + case 4: + unblank_screen(); + return 0; #endif /* CONFIG_SELECTION */ default: return -EINVAL; @@ -570,7 +582,7 @@ else if (IS_A_PTY_SLAVE(dev)) redirect = tty; else - return -EINVAL; + return -ENOTTY; return 0; case FIONBIO: arg = get_fs_long((unsigned long *) arg); @@ -580,8 +592,8 @@ file->f_flags &= ~O_NONBLOCK; return 0; case TIOCNOTTY: - if (MINOR(file->f_rdev) != current->tty) - return -EINVAL; + if (current->tty != dev) + return -ENOTTY; if (current->leader) disassociate_ctty(0); current->tty = -1; @@ -619,7 +631,7 @@ return 0; case TIOCPKT: if (!IS_A_PTY_MASTER(dev)) - return -EINVAL; + return -ENOTTY; retval = verify_area(VERIFY_READ, (void *) arg, sizeof (unsigned long)); if (retval) @@ -627,7 +639,7 @@ if (get_fs_long(arg)) { if (!tty->packet) { tty->packet = 1; - tty->ctrl_status = 0; + tty->link->ctrl_status = 0; } } else tty->packet = 0; @@ -636,7 +648,7 @@ retval = check_change(tty, dev); if (retval) return retval; - wait_until_sent(tty); + wait_until_sent(tty, 0); if (!tty->ioctl) return 0; tty->ioctl(tty, file, cmd, arg); diff -u +recursive +new-file 0.99pl15/linux/drivers/char/vt.c linux/drivers/char/vt.c --- 0.99pl15/linux/drivers/char/vt.c Tue Feb 1 13:04:30 1994 +++ linux/drivers/char/vt.c Fri Feb 11 13:06:42 1994 @@ -86,7 +86,7 @@ void kd_mksound(unsigned int count, unsigned int ticks) { - static struct timer_list sound_timer = { NULL, 0, 0, kd_nosound }; + static struct timer_list sound_timer = { NULL, NULL, 0, 0, kd_nosound }; cli(); del_timer(&sound_timer); diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- 0.99pl15/linux/drivers/net/3c501.c Wed Feb 2 17:30:01 1994 +++ linux/drivers/net/3c501.c Sun Mar 6 16:12:04 1994 @@ -17,7 +17,7 @@ */ static char *version = - "3c501.c:v13.13 1993 Donald Becker (becker@super.org).\n"; + "3c501.c: 3/3/94 Donald Becker (becker@super.org).\n"; /* Braindamage remaining: @@ -301,9 +301,6 @@ if (skb->len <= 0) return 0; - - if (el_debug > 2) - printk("%s: el_start_xmit(%d)...", dev->name, skb->len); /* Avoid timer-based retransmission conflicts. */ if (set_bit(0, (void*)&dev->tbusy) != 0) diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- 0.99pl15/linux/drivers/net/3c503.c Wed Dec 1 14:44:15 1993 +++ linux/drivers/net/3c503.c Sun Mar 6 16:12:04 1994 @@ -16,7 +16,7 @@ */ static char *version = - "3c503.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n"; + "3c503.c:v0.99.15k 3/3/93 Donald Becker (becker@super.org)\n"; #include #include @@ -200,9 +200,6 @@ dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE; dev->rmem_start = TX_PAGES*256 + dev->mem_start; } - if (ei_debug > 2) - printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n", - dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end); /* Finish setting the board's parameters. */ ei_status.name = "3C503"; @@ -228,7 +225,7 @@ dev->stop = &el2_close; if (dev->mem_start) - printk("\n%s: %s with shared memory at %#6x-%#6x,\n", + printk("\n%s: %s with shared memory at %#6lx-%#6lx,\n", dev->name, ei_status.name, dev->mem_start, dev->mem_end-1); else printk("\n%s: %s using programmed I/O (REJUMPER for SHARED MEMORY).\n", @@ -352,9 +349,6 @@ if (ei_debug > 2 && memcmp(dest_addr, buf, count)) printk("%s: 3c503 send_packet() bad memory copy @ %#5x.\n", dev->name, (int) dest_addr); - else if (ei_debug > 4) - printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n", - dev->name, (int) dest_addr); return; } /* No shared memory, put the packet out the slow way. */ @@ -395,19 +389,11 @@ if (dev->mem_start + ring_offset + count > end_of_ring) { /* We must wrap the input move. */ int semi_count = end_of_ring - (dev->mem_start + ring_offset); - if (ei_debug > 4) - printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n", - dev->name, dev->mem_start, ring_offset, - dev->mem_start + ring_offset); memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count); count -= semi_count; memcpy(buf + semi_count, (char *)dev->rmem_start, count); return dev->rmem_start + count; } - if (ei_debug > 4) - printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n", - dev->name, dev->mem_start, ring_offset, - dev->mem_start + ring_offset); memcpy(buf, (char *)dev->mem_start + ring_offset, count); return ring_offset + count; } diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- 0.99pl15/linux/drivers/net/3c507.c Wed Feb 2 17:30:02 1994 +++ linux/drivers/net/3c507.c Sun Mar 6 16:12:05 1994 @@ -11,6 +11,8 @@ Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings) and jrs@world.std.com (Rick Sladkey) for testing and bugfixes. + Mark Salazar made the changes for cards with + only 16K packet buffers. Things remaining to do: Verify that the tx and rx buffers don't have fencepost errors. @@ -19,7 +21,7 @@ */ static char *version = - "3c507.c:v0.03 10/27/93 Donald Becker (becker@super.org)\n"; + "3c507.c:v0.99-15f 2/17/94 Donald Becker (becker@super.org)\n"; #include @@ -145,6 +147,17 @@ #define iSCB_CBL 0xC /* Command BLock offset. */ #define iSCB_RFA 0xE /* Rx Frame Area offset. */ +/* Since the 3c507 maps the shared memory window so that the last byte is + at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or + 48K cooresponding to window sizes of 64K, 48K, 32K and 16K respectively. + We can account for this be setting the 'SBC Base' entry in the ISCP table + below for all the 16 bit offset addresses, and also adding the 'SCB Base' + value to all 24 bit physical addresses (in the SCP table and the TX and RX + Buffer Descriptors). + -Mark + */ +#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start)) + /* What follows in 'init_words[]' is the "program" that is downloaded to the 82586 memory. It's mostly tables and command blocks, and starts at the @@ -192,7 +205,7 @@ The Tx command chain and buffer list is setup as follows: A Tx command table, with the data buffer pointing to... A Tx data buffer descriptor. The packet is in a single buffer, rather than - chaining together several smaller buffers. + chaining together several smaller buffers. A NoOp command, which initially points to itself, And the packet data. @@ -213,13 +226,17 @@ */ -short init_words[] = { +unsigned short init_words[] = { + /* System Configuration Pointer (SCP). */ 0x0000, /* Set bus size to 16 bits. */ - 0x0000,0x0000, /* Set control mailbox (SCB) addr. */ - 0,0, /* pad to 0x000000. */ + 0,0, /* pad words. */ + 0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */ + + /* Intermediate System Configuration Pointer (ISCP). */ 0x0001, /* Status word that's cleared when init is done. */ 0x0008,0,0, /* SCB offset, (skip, skip) */ + /* System Control Block (SCB). */ 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */ CONFIG_CMD, /* Command list pointer, points to Configure. */ RX_BUF_START, /* Rx block list. */ @@ -270,11 +287,11 @@ /* Check for a network adaptor of this type, and return '0' iff one exists. - If dev->base_addr == 0, probe all likely locations. - If dev->base_addr == 1, always return failure. - If dev->base_addr == 2, (detachable devices only) alloate space for the - device and return success. - */ + If dev->base_addr == 0, probe all likely locations. + If dev->base_addr == 1, always return failure. + If dev->base_addr == 2, (detachable devices only) alloate space for the + device and return success. + */ int el16_probe(struct device *dev) { @@ -369,9 +386,6 @@ size = ((mem_config & 3) + 1) << 14; base = 0x0c0000 + ( (mem_config & 0x18) << 12); } - if (size != 0x10000) - printk("%s: Warning, this version probably only works with 64K of" - "shared memory.\n", dev->name); dev->mem_start = base; dev->mem_end = base + size; } @@ -380,7 +394,7 @@ dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0; dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; - printk(", IRQ %d, %sternal xcvr, memory %#x-%#x.\n", dev->irq, + printk(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq, dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1); if (net_debug) @@ -538,9 +552,9 @@ status = shmem[iSCB_STATUS>>1]; - if (net_debug > 4) { + if (net_debug > 4) { printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); - } + } /* Disable the 82586's input to the interrupt line. */ outb(0x80, ioaddr + MISC_CTRL); @@ -661,6 +675,7 @@ { struct net_local *lp = (struct net_local *)dev->priv; unsigned short *write_ptr; + unsigned short SCB_base = SCB_BASE; int cur_rxbuf = lp->rx_head = RX_BUF_START; @@ -683,7 +698,7 @@ *write_ptr++ = 0x0000; /* Buffer: Actual count */ *write_ptr++ = -1; /* Buffer: Next (none). */ - *write_ptr++ = cur_rxbuf + 0x20; /* Buffer: Address low */ + *write_ptr++ = cur_rxbuf + 0x20 + SCB_base; /* Buffer: Address low */ *write_ptr++ = 0x0000; /* Finally, the number of bytes in the buffer. */ *write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20; @@ -712,12 +727,13 @@ and hold the 586 in reset during the memory initialization. */ outb(0x20, ioaddr + MISC_CTRL); + /* Fix the ISCP address and base. */ + init_words[3] = SCB_BASE; + init_words[7] = SCB_BASE; + /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */ -#ifdef old - memcpy((void*)dev->mem_start+0xfff6, init_words, 10); -#else memcpy((void*)dev->mem_end-10, init_words, 10); -#endif + /* Write the words at 0x0000. */ memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10); @@ -776,7 +792,7 @@ /* Output the data buffer descriptor. */ *write_ptr++ = length | 0x8000; /* Byte count parameter. */ *write_ptr++ = -1; /* No next data buffer. */ - *write_ptr++ = tx_block+22; /* Buffer follows the NoOp command. */ + *write_ptr++ = tx_block+22+SCB_BASE;/* Buffer follows the NoOp command. */ *write_ptr++ = 0x0000; /* Buffer address high bits (always zero). */ /* Output the Loop-back NoOp command. */ @@ -796,10 +812,10 @@ if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) lp->tx_head = TX_BUF_START; - if (net_debug > 4) { + if (net_debug > 4) { printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", dev->name, ioaddr, length, tx_block, lp->tx_head); - } + } if (lp->tx_head != lp->tx_reap) dev->tbusy = 0; @@ -893,6 +909,7 @@ * version-control: t * kept-new-versions: 5 * tab-width: 4 + * c-indent-level: 4 * End: */ diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- 0.99pl15/linux/drivers/net/3c509.c Wed Feb 2 17:30:02 1994 +++ linux/drivers/net/3c509.c Tue Mar 8 07:40:10 1994 @@ -13,7 +13,7 @@ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 */ -static char *version = "3c509.c:pl13t 11/24/93 becker@super.org\n"; +static char *version = "3c509.c:pl15k 3/5/94 becker@super.org\n"; #include #include @@ -190,7 +190,7 @@ { char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c509 at %#3.3x tag %d, %s port, address ", + printk("%s: 3c509 at %#3.3x tag %d, %s port, address ", dev->name, dev->base_addr, current_tag, if_names[dev->if_port]); } @@ -377,7 +377,7 @@ return 0; if (el3_debug > 4) { - printk("%s: el3_start_xmit(lenght = %d) called, status %4.4x.\n", + printk("%s: el3_start_xmit(lenght = %ld) called, status %4.4x.\n", dev->name, skb->len, inw(ioaddr + EL3_STATUS)); } #ifndef final_version @@ -477,10 +477,12 @@ if (++i > 10) { printk("%s: Infinite loop in interrupt, status %4.4x.\n", dev->name, status); + /* Clear all interrupts we have handled. */ + outw(0x68FF, ioaddr + EL3_CMD); break; } - /* Clear the other interrupts we have handled. */ - outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */ + /* Acknowledge the IRQ. */ + outw(0x6891, ioaddr + EL3_CMD); /* Ack IRQ */ } if (el3_debug > 4) { @@ -549,19 +551,19 @@ inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ - short error = rx_status & 0x3C00; + short error = rx_status & 0x3800; lp->stats.rx_errors++; switch (error) { - case 0x2000: lp->stats.rx_over_errors++; break; - case 0x2C00: lp->stats.rx_length_errors++; break; - case 0x3400: lp->stats.rx_crc_errors++; break; - case 0x2400: lp->stats.rx_length_errors++; break; - case 0x3000: lp->stats.rx_frame_errors++; break; - case 0x0800: lp->stats.rx_frame_errors++; break; + case 0x0000: lp->stats.rx_over_errors++; break; + case 0x0800: lp->stats.rx_length_errors++; break; + case 0x1000: lp->stats.rx_frame_errors++; break; + case 0x1800: lp->stats.rx_length_errors++; break; + case 0x2000: lp->stats.rx_frame_errors++; break; + case 0x2800: lp->stats.rx_crc_errors++; break; } } if ( (! (rx_status & 0x4000)) - || ! (rx_status & 0x2000)) { /* Dribble bits are OK. */ + || ! (rx_status & 0x1000)) { /* Dribble bits are OK. */ short pkt_len = rx_status & 0x7ff; int sksize = sizeof(struct sk_buff) + pkt_len + 3; struct sk_buff *skb; diff -u +recursive +new-file 0.99pl15/linux/drivers/net/8390.c linux/drivers/net/8390.c --- 0.99pl15/linux/drivers/net/8390.c Wed Feb 2 17:30:02 1994 +++ linux/drivers/net/8390.c Tue Feb 22 08:12:27 1994 @@ -8,6 +8,8 @@ incorporated herein by reference. This is the chip-specific code for many 8390-based ethernet adaptors. + This is not a complete driver, it must be combined with board-specific + code such as ne.c, wd.c, 3c503.c, etc. The Author may be reached as becker@super.org or C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 @@ -14,17 +16,14 @@ */ static char *version = - "8390.c:v0.99-13f 10/18/93 Donald Becker (becker@super.org)\n"; + "8390.c:v0.99-15e 2/16/94 Donald Becker (becker@super.org)\n"; #include /* Braindamage remaining: + Much of this code should be cleaned up post-1.00, but it has been + extensively beta tested in the current form. - Ethernet devices should use a chr_drv device interface, with ioctl()s to - configure the card, bring the interface up or down, allow access to - statistics, and maybe read() and write() access to raw packets. - This won't be done until after Linux 1.00. - Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. The NE* programming info came from the Crynwr packet driver, and figuring @@ -59,11 +58,22 @@ #include "8390.h" -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(addr, size) kfree_s(addr,size) -#endif - +/* These are the operational function interfaces to board-specific + routines. + void reset_8390(struct device *dev) + Resets the board associated with DEV, including a hardware reset of + the 8390. This is only called when there is a transmit timeout, and + it is always followed by 8390_init(). + void block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) + Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The + "page" value uses the 8390's 256-byte pages. + int block_input(struct device *dev, int count, char *buf, int ring_offset) + Read COUNT bytes from the packet buffer into BUF. Start reading from + RING_OFFSET, the address as the 8390 sees it. The first read will + always be the 4 byte, page aligned 8390 header. *If* there is a + subsequent read, it will be of the rest of the packet. +*/ #define ei_reset_8390 (ei_local->reset_8390) #define ei_block_output (ei_local->block_output) #define ei_block_input (ei_local->block_input) @@ -75,14 +85,14 @@ int ei_debug = 1; #endif -/* Max number of packets received at one Intr. */ -/*static int high_water_mark = 0;*/ +/* Max number of packets received at one Intr. + Current this may only be examined by a kernel debugger. */ +static int high_water_mark = 0; /* Index to functions. */ -/* Put in the device structure. */ -int ei_open(struct device *dev); -/* Dispatch from interrupts. */ -void ei_interrupt(int reg_ptr); +int ei_open(struct device *dev); /* Put into the device structure. */ +void ei_interrupt(int reg_ptr); /* Installed as the interrupt handler. */ + static void ei_tx_intr(struct device *dev); static void ei_receive(struct device *dev); static void ei_rx_overrun(struct device *dev); @@ -107,17 +117,11 @@ if ( ! ei_local) { printk("%s: Opening a non-existent physical device\n", dev->name); - return 1; /* ENXIO would be more accurate. */ + return ENXIO; } irq2dev_map[dev->irq] = dev; NS8390_init(dev, 1); - ei_local->tx1 = ei_local->tx2 = 0; - /* The old local flags... */ - ei_local->txing = 0; - /* ... are now global. */ - dev->tbusy = 0; - dev->interrupt = 0; dev->start = 1; ei_local->irqlock = 0; return 0; @@ -128,31 +132,36 @@ int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int length, send_length; - int tmp_tbusy; /* we must lock dev_tint in dev.c with dev->t_busy =1 */ - /* because on a slow pc a quasi endless loop can appear */ + /* We normally shouldn't be called if dev->tbusy is set, but the + existing code does anyway. + If it has been too long (> 100 or 150ms.) since the last Tx we assume + the board has died and kick it. */ + if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */ int txsr = inb(e8390_base+EN0_TSR), isr; int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) { + if (tickssofar < 10 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) { return 1; } isr = inb(e8390_base+EN0_ISR); printk("%s: transmit timed out, TX status %#2x, ISR %#2x.\n", dev->name, txsr, isr); - /* It's possible to check for an IRQ conflict here. - I may have to do that someday. */ + /* Does the 8390 thinks it has posted an interrupt? */ if (isr) - printk("%s: Possible IRQ conflict on IRQ%d?", dev->name, dev->irq); - else + printk("%s: Possible IRQ conflict on IRQ%d?\n", dev->name, dev->irq); + else { + /* The 8390 probably hasn't gotten on the cable yet. */ printk("%s: Possible network cable problem?\n", dev->name); - /* It futile, but try to restart it anyway. */ + ei_local->interface_num ^= 1; /* Try a different xcvr. */ + } + /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); NS8390_init(dev, 1); - printk("\n"); + dev->trans_start = jiffies; } - /* This is new: it means some higher layer thinks we've missed an + /* Sending a NULL skb means some higher layer thinks we've missed an tx-done interrupt. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) { @@ -167,28 +176,22 @@ } skb->arp=1; + length = skb->len; if (skb->len <= 0) return 0; - length = skb->len; - send_length = ETH_ZLEN < length ? length : ETH_ZLEN; - /* Turn off interrupts so that we can put the packet out safely. */ - cli(); - if (dev->interrupt || ei_local->irqlock) { - /* We should never get here during an interrupt after 0.99.4. */ - sti(); - if (ei_debug > 2) - printk("%s: Attempt to reenter critical zone%s.\n", - dev->name, ei_local->irqlock ? " during interrupt" : ""); + + /* Block a timer-based transmit from overlapping. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); return 1; - } + } + /* Mask interrupts from the ethercard. */ outb(0x00, e8390_base + EN0_IMR); - - /* Atomically lock out dev.c:dev_tint(). */ - tmp_tbusy = set_bit(0, (void*)&dev->tbusy); - ei_local->irqlock = 1; - sti(); + + send_length = ETH_ZLEN < length ? length : ETH_ZLEN; + if (ei_local->pingpong) { int output_page; if (ei_local->tx1 == 0) { @@ -205,23 +208,19 @@ printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing); - } else { - /* We can get to here if we get an rx interrupt and queued - a tx packet just before masking 8390 irqs above. */ - if (ei_debug > 2) + } else { /* We should never get here. */ + if (ei_debug) printk("%s: No packet buffer space for ping-pong use.\n", dev->name); - cli(); ei_local->irqlock = 0; - dev->tbusy = tmp_tbusy; + dev->tbusy = 1; outb_p(ENISR_ALL, e8390_base + EN0_IMR); - sti(); return 1; } - dev->trans_start = jiffies; ei_block_output(dev, length, skb->data, output_page); if (! ei_local->txing) { NS8390_trigger_send(dev, send_length, output_page); + dev->trans_start = jiffies; if (output_page == ei_local->tx_start_page) ei_local->tx1 = -1, ei_local->lasttx = -1; else @@ -229,25 +228,22 @@ ei_local->txing = 1; } else ei_local->txqueue++; - if (ei_local->tx1 && ei_local->tx2) - tmp_tbusy = 1; - } else { - dev->trans_start = jiffies; - ei_block_output(dev, length, skb->data, - ei_local->tx_start_page); + + dev->tbusy = (ei_local->tx1 && ei_local->tx2); + } else { /* No pingpong, just a single Tx buffer. */ + ei_block_output(dev, length, skb->data, ei_local->tx_start_page); NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - tmp_tbusy = 1; - } /* PINGPONG */ + dev->trans_start = jiffies; + dev->tbusy = 1; + } + /* Turn 8390 interrupts back on. */ + ei_local->irqlock = 0; + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + if (skb->free) kfree_skb (skb, FREE_WRITE); - /* Turn 8390 interrupts back on. */ - cli(); - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - ei_local->irqlock = 0; - dev->tbusy=tmp_tbusy; - sti(); return 0; } @@ -289,7 +285,7 @@ /* !!Assumption!! -- we stay in page 0. Don't break this. */ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 - && ++boguscount < 20) { + && ++boguscount < 5) { if (interrupts & ENISR_RDC) { /* Ack meaningless DMA complete. */ outb_p(ENISR_RDC, e8390_base + EN0_ISR); @@ -374,24 +370,19 @@ ei_local->txing = 0; dev->tbusy = 0; } - - /* Do the statistics _after_ we start the next TX. */ + + /* Minimize Tx latency: update the statistics after we restart TXing. */ + if (status & ENTSR_COL) ei_local->stat.collisions++; if (status & ENTSR_PTX) ei_local->stat.tx_packets++; - else + else { ei_local->stat.tx_errors++; - if (status & ENTSR_COL) - ei_local->stat.collisions++; - if (status & ENTSR_ABT) - ei_local->stat.tx_aborted_errors++; - if (status & ENTSR_CRS) - ei_local->stat.tx_carrier_errors++; - if (status & ENTSR_FU) - ei_local->stat.tx_fifo_errors++; - if (status & ENTSR_CDH) - ei_local->stat.tx_heartbeat_errors++; - if (status & ENTSR_OWC) - ei_local->stat.tx_window_errors++; + if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++; + if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; + if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++; + if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; + if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++; + } mark_bh (INET_BH); } @@ -403,11 +394,11 @@ int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int rxing_page, this_frame, next_frame, current_offset; - int boguscount = 0; + int rx_pkt_count = 0; struct e8390_pkt_hdr rx_frame; int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page; - while (++boguscount < 10) { + while (++rx_pkt_count < 10) { int pkt_len; /* Get the rx page (incoming packet pointer). */ @@ -420,8 +411,9 @@ if (this_frame >= ei_local->stop_page) this_frame = ei_local->rx_start_page; - /* Someday we'll omit the previous step, iff we never get this message.*/ - if (ei_debug > 0 && this_frame != ei_local->current_page) + /* Someday we'll omit the previous, iff we never get this message. + (There is at least one clone claimed to have a problem.) */ + if (ei_debug > 0 && this_frame != ei_local->current_page) printk("%s: mismatched read page pointers %2x vs %2x.\n", dev->name, this_frame, ei_local->current_page); @@ -439,46 +431,23 @@ /* Check for bogosity warned by 3c503 book: the status byte is never written. This happened a lot during testing! This code should be cleaned up someday. */ - if ( rx_frame.next != next_frame + if (rx_frame.next != next_frame && rx_frame.next != next_frame + 1 && rx_frame.next != next_frame - num_rx_pages && rx_frame.next != next_frame + 1 - num_rx_pages) { -#ifndef EI_DEBUG ei_local->current_page = rxing_page; outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); + ei_local->stat.rx_errors++; continue; -#else - static int last_rx_bogosity = -1; - printk("%s: bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n", - dev->name, rx_frame.status, rx_frame.next, rx_frame.count, - current_offset); - - if (ei_local->stat.rx_packets != last_rx_bogosity) { - /* Maybe we can avoid resetting the chip... empty the packet ring. */ - ei_local->current_page = rxing_page; - printk("%s: setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n", - dev->name, ei_local->current_page, next_frame, - rx_frame.next, rx_frame.status); - last_rx_bogosity = ei_local->stat.rx_packets; - outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); - continue; - } else { - /* Oh no Mr Bill! Last ditch error recovery. */ - printk("%s: recovery failed, resetting at packet #%d..", - dev->name, ei_local->stat.rx_packets); - sti(); - ei_reset_8390(dev); - NS8390_init(dev, 1); - printk("restarting.\n"); - return; - } -#endif /* EI8390_NOCHECK */ } - - if ((pkt_len < 46 || pkt_len > 1535) && ei_debug) - printk("%s: bogus packet size, status=%#2x nxpg=%#2x size=%#x\n", - dev->name, rx_frame.status, rx_frame.next, rx_frame.count); - if ((rx_frame.status & 0x0F) == ENRSR_RXOK) { + + if (pkt_len < 60 || pkt_len > 1518) { + if (ei_debug) + printk("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", + dev->name, rx_frame.count, rx_frame.status, + rx_frame.next); + ei_local->stat.rx_errors++; + } else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) { int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; @@ -495,37 +464,28 @@ skb->len = pkt_len; skb->dev = dev; - /* 'skb->data' points to the start of sk_buff data area. */ ei_block_input(dev, pkt_len, (char *) skb->data, current_offset + sizeof(rx_frame)); -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev)) { - kfree_skbmem(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif ei_local->stat.rx_packets++; } } else { int errs = rx_frame.status; if (ei_debug) - printk("%s: bogus packet, status=%#2x nxpg=%#2x size=%d\n", - dev->name, rx_frame.status, rx_frame.next, rx_frame.count); + printk("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", + dev->name, rx_frame.status, rx_frame.next, + rx_frame.count); if (errs & ENRSR_FO) ei_local->stat.rx_fifo_errors++; } next_frame = rx_frame.next; - /* This should never happen, it's here for debugging. */ + /* This _should_ never happen: it's here for avoiding bad clones. */ if (next_frame >= ei_local->stop_page) { - printk("%s: next frame inconsistency, %#2x..", dev->name, next_frame); + printk("%s: next frame inconsistency, %#2x..", dev->name, + next_frame); next_frame = ei_local->rx_start_page; } - ei_local->current_page += 1 + ((pkt_len+4)>>8); ei_local->current_page = next_frame; outb(next_frame-1, e8390_base+EN0_BOUNDARY); } @@ -532,7 +492,11 @@ /* If any worth-while packets have been received, dev_rint() has done a mark_bh(INET_BH) for us and will work on them when we get to the bottom-half routine. */ - + + /* Record the maximum Rx packet queue. */ + if (rx_pkt_count > high_water_mark) + high_water_mark = rx_pkt_count; + /* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */ outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR); return; @@ -553,12 +517,13 @@ printk("%s: Receiver overrun.\n", dev->name); ei_local->stat.rx_over_errors++; - /* The we.c driver does dummy = inb_p( RBCR[01] ); at this point. + /* The old Biro driver does dummy = inb_p( RBCR[01] ); at this point. It might mean something -- magic to speed up a reset? A 8390 bug?*/ - /* Wait for reset in case the NIC is doing a tx or rx. This could take up to - 1.5msec, but we have no way of timing something in that range. The 'jiffies' - are just a sanity check. */ + /* Wait for the reset to complete. This should happen almost instantly, + but could take up to 1.5msec in certain rare instances. There is no + easy way of timing something in that range, so we use 'jiffies' as + a sanity check. */ while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 1) { printk("%s: reset did not complete at ei_rx_overrun.\n", @@ -565,7 +530,7 @@ dev->name); NS8390_init(dev, 1); return; - }; + } /* Remove packets right away. */ ei_receive(dev); @@ -713,6 +678,10 @@ outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); sti(); + dev->tbusy = 0; + dev->interrupt = 0; + ei_local->tx1 = ei_local->tx2 = 0; + ei_local->txing = 0; if (startp) { outb_p(0xff, e8390_base + EN0_ISR); outb_p(ENISR_ALL, e8390_base + EN0_IMR); @@ -751,6 +720,7 @@ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 8390.c" * version-control: t * kept-new-versions: 5 + * c-indent-level: 4 * tab-width: 4 * End: */ diff -u +recursive +new-file 0.99pl15/linux/drivers/net/CONFIG linux/drivers/net/CONFIG --- 0.99pl15/linux/drivers/net/CONFIG Fri Jan 28 09:32:24 1994 +++ linux/drivers/net/CONFIG Tue Feb 22 08:40:09 1994 @@ -30,6 +30,9 @@ # D_LINK_IO The D-Link I/O address (0x378 == typical) # D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == typical) # D_LINK_DEBUG Enable or disable D-Link debugging +# DEPCA The DIGITAL series of AT Ethernet Cards (DE100, DE200) +# DEPCA_IRQ Set the desired IRQ (=0, for autoprobe) +# DEPCA_DEBUG Set the desired debug level # # The following options exist, but cannot be set in this file. @@ -50,6 +53,7 @@ NE_OPTS = HP_OPTS = PLIP_OPTS = +DEPCA_OPTS = -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1 # The following are the only parameters that must be set in this file. DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG diff -u +recursive +new-file 0.99pl15/linux/drivers/net/Makefile linux/drivers/net/Makefile --- 0.99pl15/linux/drivers/net/Makefile Thu Dec 16 12:24:12 1993 +++ linux/drivers/net/Makefile Tue Feb 22 08:38:04 1994 @@ -105,6 +105,8 @@ endif ifdef CONFIG_DEPCA NETDRV_OBJS := $(NETDRV_OBJS) net.a(depca.o) +depca.o: depca.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $< endif ifdef CONFIG_ATP NETDRV_OBJS := $(NETDRV_OBJS) net.a(atp.o) diff -u +recursive +new-file 0.99pl15/linux/drivers/net/Space.c linux/drivers/net/Space.c --- 0.99pl15/linux/drivers/net/Space.c Wed Dec 1 14:44:15 1993 +++ linux/drivers/net/Space.c Fri Feb 18 11:18:28 1994 @@ -139,18 +139,15 @@ #endif /* The first device defaults to I/O base '0', which means autoprobe. */ -#ifdef EI8390 -# define ETH0_ADDR EI8390 -#else +#ifndef ETH0_ADDR # define ETH0_ADDR 0 #endif -#ifdef EI8390_IRQ -# define ETH0_IRQ EI8390_IRQ -#else +#ifndef ETH0_IRQ # define ETH0_IRQ 0 #endif -/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe". - Enable these with boot-time setup. 0.99pl13+ can optionally autoprobe. */ +/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20), + which means "don't probe". These entries exist to only to provide empty + slots which may be enabled at boot-time. */ static struct device eth3_dev = { "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; diff -u +recursive +new-file 0.99pl15/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- 0.99pl15/linux/drivers/net/at1700.c Wed Feb 2 17:30:03 1994 +++ linux/drivers/net/at1700.c Sun Mar 6 16:13:56 1994 @@ -12,7 +12,7 @@ */ static char *version = - "at1700.c:v0.03 11/16/93 Donald Becker (becker@super.org)\n"; + "at1700.c:v0.06 3/3/94 Donald Becker (becker@super.org)\n"; #include @@ -19,6 +19,9 @@ /* Sources: The Fujitsu MB86695 datasheet. + + After this driver was written, ATI provided their EEPROM configuration + code header file. Thanks to Gerry Sockins of ATI. */ #include @@ -30,12 +33,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include "dev.h" #include "eth.h" @@ -142,24 +145,28 @@ for (port = &ports[0]; *port; port++) { int ioaddr = *port; -#ifdef HAVE_PORTRESERVE if (check_region(ioaddr, 32)) continue; -#endif - if (inw(ioaddr) != 0x0000) - continue; if (at1700_probe1(dev, ioaddr) == 0) return 0; } - return ENODEV; /* ENODEV would be more accurate. */ + return ENODEV; } +/* The Fujitsu datasheet suggests that the NIC be probed for by checking its + "signature", the default bit pattern after a reset. This *doesn't* work -- + there is no way to reset the bus interface without a complete power-cycle! + + It turns out that ATI came to the same conclusion I did: the only thing + that can be done is checking a few bits and then diving right into an + EEPROM read. */ + int at1700_probe1(struct device *dev, short ioaddr) { - unsigned short signature[4] = {0x0000, 0xffff, 0x41f6, 0xefb6}; - unsigned short signature_invalid[4] = {0x0000, 0xffff, 0x00f0, 0x2f00}; - char irqmap[4] = {3, 4, 5, 9}; + unsigned short signature[4] = {0xffff, 0xffff, 0x7ff7, 0xff5f}; + unsigned short signature_invalid[4] = {0xffff, 0xffff, 0x7ff7, 0xdf0f}; + char irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned short *station_address = (unsigned short *)dev->dev_addr; unsigned int i, irq; @@ -168,18 +175,21 @@ */ for (i = 0; i < 4; i++) if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) { - if (net_debug > 1) + if (net_debug > 2) printk("AT1700 signature match failed at %d (%04x vs. %04x)\n", i, inw(ioaddr + 2*i), signature[i]); return -ENODEV; } -#ifdef HAVE_PORTRESERVE + if (read_eeprom(ioaddr, 4) != 0x0000 + || read_eeprom(ioaddr, 5) & 0x00ff != 0x00F4) + return -ENODEV; + /* Grab the region so that we can find another board if the IRQ request fails. */ snarf_region(ioaddr, 32); -#endif - irq = irqmap[ read_eeprom(ioaddr, 0) >> 14 ]; + irq = irqmap[(read_eeprom(ioaddr, 12)&0x04) + | (read_eeprom(ioaddr, 0)>>14)]; /* Snarf the interrupt vector now. */ if (request_irq(irq, &net_interrupt)) { @@ -417,10 +427,6 @@ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; - if (net_debug > 4) - printk("%s: Transmitting a packet of length %d.\n", dev->name, - skb->len); - /* Turn off the possible Tx interrupts. */ outb(0x00, ioaddr + TX_INTR); @@ -551,7 +557,6 @@ skb->len = pkt_len; skb->dev = dev; - /* 'skb->data' points to the start of sk_buff data area. */ insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1); if (net_debug > 5) { diff -u +recursive +new-file 0.99pl15/linux/drivers/net/atp.c linux/drivers/net/atp.c --- 0.99pl15/linux/drivers/net/atp.c Wed Feb 2 17:40:40 1994 +++ linux/drivers/net/atp.c Tue Mar 1 19:29:05 1994 @@ -12,7 +12,7 @@ */ static char *version = - "atp.c:v0.03 1/19/94 Donald Becker (becker@super.org)\n"; + "atp.c:v0.04 2/25/94 Donald Becker (becker@super.org)\n"; /* This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket @@ -611,7 +611,7 @@ } else if (num_tx_since_rx > 8 && jiffies > dev->last_rx + 100) { if (net_debug > 2) - printk("%s: Missed packet? No Rx after %d Tx and %d jiffies" + printk("%s: Missed packet? No Rx after %d Tx and %ld jiffies" " status %02x CMR1 %02x.\n", dev->name, num_tx_since_rx, jiffies - dev->last_rx, status, (read_nibble(ioaddr, CMR1) >> 3) & 15); @@ -623,6 +623,8 @@ break; } + /* This following code fixes a rare (and very difficult to track down) + problem where the adaptor forgets its ethernet address. */ { int i; for (i = 0; i < 6; i++) @@ -686,12 +688,12 @@ skb->len = pkt_len; skb->dev = dev; - /* 'skb->data' points to the start of sk_buff data area. */ read_block(ioaddr, pkt_len, skb->data, dev->if_port); if (net_debug > 6) { unsigned char *data = skb->data; - printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..", + printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x" + "%02x%02x%02x %02x%02x..", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13]); diff -u +recursive +new-file 0.99pl15/linux/drivers/net/depca.c linux/drivers/net/depca.c --- 0.99pl15/linux/drivers/net/depca.c +++ linux/drivers/net/depca.c Fri Mar 4 09:20:19 1994 @@ -0,0 +1,1362 @@ +/* depca.c: A DIGITAL DEPCA ethernet driver for linux. + + Written 1994 by David C. Davies. + + Copyright 1994 David C. Davies and United States Government as + represented by the Director, National Security Agency. This software + may be used and distributed according to the terms of the GNU Public + License, incorporated herein by reference. + + This driver is written for the Digital Equipment Corporation series + of DEPCA ethernet cards: + + DE100 DEPCA + DE200 DEPCA Turbo + DE202 DEPCA Turbo (TP BNC) + DE210 DEPCA + + The driver has been tested on DE100 and DE20x cards in a relatively busy + network. + + The author may be reached as davies@wanton.enet.dec.com or + Digital Equipment Corporation, 146 Main Street, Maynard MA 01754. + + ========================================================================= + The driver was based on the 'lance.c' driver from Donald Becker which is + included with the standard driver distribution for linux. Modifications + were made to most routines and the hardware recognition routines were + written from scratch. Primary references used were: + + 1) Lance.c code in /linux/drivers/net/ + 2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook", + AMD, 1992 [(800) 222-9323]. + 3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", + AMD, Pub. #17881, May 1993. + 4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA", + AMD, Pub. #16907, May 1992 + 5) "DEC EtherWORKS LC Ethernet Controller Owners Manual", + Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003 + 6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual", + Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003 + 7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR + Digital Equipment Corporation, 1989 + 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual", + Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001 + + Peter Bauer's depca.c (V0.5) was referred to when debugging this driver. + The hash filter code was derived from Reference 3 and has been tested + only to the extent that the Table A-1, page A-7, was confirmed to fill + the filter bit positions correctly. Hash filtering is not yet + implemented in the current driver set. + + The DE200 series boards have on-board 64kB RAM for use as a shared + memory network buffer. Only the DE100 cards make use of a 2kB buffer + mode which has not been implemented in this driver (only the 32kB and + 64kB modes are supported). + + At the most only 2 DEPCA cards can be supported because there is only + provision for two I/O base addresses on the cards (0x300 and 0x200). The + base address is 'autoprobed' by looking for the self test PROM and + detecting the card name. The shared memory base address is decoded by + 'autoprobing' the Ethernet PROM address information. The second DEPCA is + detected and information placed in the base_addr variable of the next + device structure (which is created if necessary), thus enabling + ethif_probe initialization for the device. + + ************************************************************************ + + NOTE: If you are using two DEPCAs, it is important that you assign the + base memory addresses correctly. The driver autoprobes I/O 0x300 then + 0x200. The base memory address for the first device must be less than + that of the second so that the auto probe will correctly assign the I/O + and memory addresses on the same card. I can't think of a way to do + this unambiguously at the moment, since there is nothing on the cards to + tie I/O and memory information together. + + I am unable to test 2 DEPCAs together for now, so this code is + unchecked. All reports, good or bad, are welcome. + + ************************************************************************ + + The board IRQ setting must be at an unused IRQ which is auto-probed + using Donald Becker's autoprobe routines. DE100 board IRQs are + {2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is + really IRQ9 in machines with 16 IRQ lines. + + No 16MB memory limitation should exist with this driver as DMA is not + used and the common memory area is in low memory on the network card (my + current system has 20MB and I've not had problems yet). + + The DE203, DE204 and DE205 cards may also work with this driver (I + haven't tested them so I don't know). If you have one of these cards, + place the name in the DEPCA_SIGNATURE string around line 160, recompile + the kernel and reboot. Check if the card is recognised and works - mail + me if so, so that I can add it into the list of supported cards! + + TO DO: + ------ + + 1. Implement the 2k buffer mode - does anyone need it?? + + Revision History + ---------------- + + Version Date Description + + 0.1 25-jan-94 Initial writing + 0.2 27-jan-94 Added LANCE TX buffer chaining + 0.3 1-feb-94 Added multiple DEPCA support + 0.31 4-feb-94 Added DE202 recognition + 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support. + + ========================================================================= +*/ + +static char *version = "depca.c:v0.32 2/19/94 davies@wanton.enet.dec.com\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "iow.h" +#include "eth.h" +#include "skbuff.h" +#include "arp.h" +#include "depca.h" + +#ifdef DEPCA_DEBUG +int depca_debug = DEPCA_DEBUG; +#else +int depca_debug = 1; +#endif + +#ifndef DEPCA_IRQ +/*#define DEPCA_IRQ {5,9,10,11,15,0}*/ +#define DEPCA_IRQ 5 +#endif + +#ifndef PROBE_LENGTH +#define PROBE_LENGTH 32 +#endif + +#ifndef PROBE_SEQUENCE +#define PROBE_SEQUENCE "FF0055AAFF0055AA" +#endif + +#ifndef DEPCA_SIGNATURE +#define DEPCA_SIGNATURE {"DEPCA","DE100","DE200","DE202","DE210",""} +#define DEPCA_NAME_LENGTH 8 +#endif + +#ifndef DEPCA_RAM_BASE_ADDRESSES +#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000} +#endif +static short mem_chkd = 0; /* holds which base addrs have been */ + /* checked, for multi-DEPCA case */ + +#ifndef DEPCA_IO_PORTS +#define DEPCA_IO_PORTS {0x300, 0x200, 0} +#endif + +#ifndef DEPCA_TOTAL_SIZE +#define DEPCA_TOTAL_SIZE 0x10 +#endif + +#ifndef MAX_NUM_DEPCAS +#define MAX_NUM_DEPCAS 2 +#endif + +/* +** Set the number of Tx and Rx buffers. +*/ +#ifndef DEPCA_BUFFER_LOG_SZ +#define RING_SIZE 16 /* 16 buffers */ +#else +#define RING_SIZE (1 << (DEPCA_BUFFERS_LOG_SZ)) +#endif /* DEPCA_BUFFER_LOG_SZ */ + +#define PKT_BUF_SZ 1544 /* Buffer size for each Tx/Rx buffer */ +#define PKT_SZ 1514 /* Maximum ethernet packet length */ +#define DAT_SZ 1500 /* Maximum ethernet data length */ +#define PKT_HDR_LEN 14 /* Addresses and data length info */ + +#ifdef HAVE_MULTICAST +#ifndef CRC_POLYNOMIAL +#define CRC_POLYNOMIAL 0x04c11db7 /* Ethernet CRC polynomial */ +#endif /* CRC_POLYNOMIAL */ +#endif /* HAVE_MULTICAST */ + +#ifndef HAVE_ALLOC_SKB +#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) +#define kfree_skbmem(buff, size) kfree_s(buff,size) +#endif /* HAVE_ALLOC_SKB */ + +/* +** The DEPCA Rx and Tx ring descriptors. +*/ +struct depca_rx_head { + long base; + short buf_length; /* This length is negative 2's complement! */ + short msg_length; /* This length is "normal". */ +}; + +struct depca_tx_head { + long base; + short length; /* This length is negative 2's complement! */ + short misc; /* Errors and TDR info */ +}; + +struct depca_ring_info { +}; + +/* +** The Lance initialization block, described in databook, in common memory. +*/ +struct depca_init { + unsigned short mode; /* Mode register */ + unsigned char phys_addr[ETH_ALEN]; /* Physical ethernet address */ + unsigned short filter[4]; /* Multicast filter. */ + unsigned long rx_ring; /* Rx ring base pointer & ring length */ + unsigned long tx_ring; /* Tx ring base pointer & ring length */ +}; + +struct depca_private { + char devname[8]; /* Not used */ + struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */ + struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */ + struct depca_init init_block;/* Initialization block */ + long dma_buffs; /* Start address of Rx and Tx buffers. */ + int cur_rx, cur_tx; /* The next free ring entry */ + int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + int dma; + struct enet_statistics stats; + char old_depca; + short ringSize; /* ring size based on available memory */ + short rmask; /* modulus mask based on ring size */ + long rlen; /* log2(ringSize) for the descriptors */ +}; + +/* +** Public Functions +*/ +static int depca_open(struct device *dev); +static int depca_start_xmit(struct sk_buff *skb, struct device *dev); +static void depca_interrupt(int reg_ptr); +static int depca_close(struct device *dev); +static struct enet_statistics *depca_get_stats(struct device *dev); +#ifdef HAVE_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif + +/* +** Private functions +*/ +static int depca_probe1(struct device *dev, short ioaddr); +static void depca_init_ring(struct device *dev); +static int depca_rx(struct device *dev); +static int depca_tx(struct device *dev); + +static void LoadCSRs(struct device *dev); +static int InitRestartDepca(struct device *dev); +static char *DepcaSignature(unsigned long mem_addr); +static int DevicePresent(short ioaddr); +#ifdef HAVE_MULTICAST +static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table); +#endif + +static int num_depcas = 0, num_eth = 0;; + +/* +** Miscellaneous defines... +*/ +#define STOP_DEPCA \ + outw(CSR0, DEPCA_ADDR);\ + outw(STOP, DEPCA_DATA) + + + +int depca_probe(struct device *dev) +{ + int *port, ports[] = DEPCA_IO_PORTS; + int base_addr = dev->base_addr; + int status; + struct device *eth0 = (struct device *) NULL; + + if (base_addr > 0x1ff) { /* Check a single specified location. */ + status = depca_probe1(dev, base_addr); + } else if (base_addr > 0) { /* Don't probe at all. */ + status = -ENXIO; + } else { /* First probe for the DEPCA test */ + /* pattern in ROM */ + + for (status = -ENODEV, port = &ports[0]; + *port && (num_depcas < MAX_NUM_DEPCAS); port++) { + int ioaddr = *port; + +#ifdef HAVE_PORTRESERVE + if (check_region(ioaddr, DEPCA_TOTAL_SIZE)) + continue; +#endif + if (DevicePresent(DEPCA_PROM) == 0) { + if (num_depcas > 0) { /* only gets here in autoprobe */ + + /* + ** Check the device structures for an end of list or unused device + */ + while (dev->next != (struct device *)NULL) { + if (dev->next->base_addr == 0xffe0) break; + dev = dev->next; /* walk through eth device list */ + num_eth++; /* increment eth device number */ + } + + /* + ** If no more device structures, malloc one up. If memory could + ** not be allocated, print an error message. + ** + */ + if (dev->next == (struct device *)NULL) { + dev->next = (struct device *)kmalloc(sizeof(struct device) + 8, + GFP_KERNEL); + } else { + printk("eth%d: Device not initialised, insufficient memory\n", + num_eth); + } + + /* + ** If the memory was allocated, point to the new memory area + ** and initialize it (name, I/O address, next device (NULL) and + ** initialisation probe routine). + */ + if ((dev->next != (struct device *)NULL) && + (num_eth > 0) && (num_eth < 9999)) { + dev = dev->next; /* point to the new device */ + dev->name = (char *)(dev + sizeof(struct device)); + sprintf(dev->name,"eth%d", num_eth); /* New device name */ + dev->base_addr = ioaddr; /* assign the io address */ + dev->next = (struct device *)NULL; /* mark the end of list */ + dev->init = &depca_probe;/* initialisation routine */ + } + } else { + eth0 = dev; /* remember the first device */ + status = depca_probe1(dev, ioaddr); + } + num_depcas++; + num_eth++; + } + } + if (eth0) dev = eth0; /* restore the first device */ + } + + if (status) dev->base_addr = base_addr; + + return status; /* ENODEV would be more accurate. */ +} + +static int +depca_probe1(struct device *dev, short ioaddr) +{ + struct depca_private *lp; + int i,j, status=0; + unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES; + char *name=(char *)NULL; + int nicsr, offset; + + + /* + ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot + */ + STOP_DEPCA; + + nicsr = inw(DEPCA_NICSR); + nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM); + outw(nicsr, DEPCA_NICSR); + + if (inw(DEPCA_DATA) == STOP) { + + /* Now find out what kind of DEPCA we have. The DE100 uses a different + ** addressing scheme for some registers compared to the DE2xx series. + ** Note that a base address location is marked as checked if no DEPCA is + ** there or one is found (when the search is immediately terminated). This + ** shortens the search time a little for multiple DEPCAs. + */ + + for (j = 0, i = 0; mem_base[i] && (j == 0);) { + if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */ + name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */ + mem_chkd |= (0x01 << i); /* mark location checked */ + if (*name != (char)NULL) { /* one found? */ + j = 1; /* set exit flag */ + } else { + i++; /* increment search index */ + } + } + } + + if (*name != (char)NULL) { /* found a DEPCA device */ + mem_start = mem_base[i]; + dev->base_addr = ioaddr; + + printk("%s: DEPCA at %#3x is a %s, ", dev->name, ioaddr, name); + + /* There is a 32 byte station address PROM at DEPCA_PROM address. + The first six bytes are the station address. They can be read + directly since the signature search set up the ROM address + counter correctly just before this function. + + For the DE100 we have to be careful about which port is used to + read the ROM info. + */ + + if (strstr(name,"DE100")!=(char *)NULL) { + j = 1; + } else { + j = 0; + } + + printk("ethernet address "); + for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */ + printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j)); + } + printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j)); + + for (;i<32;i++) { /* leave ROM counter in known state */ + j=inb(DEPCA_PROM); + } + +#ifdef HAVE_PORTRESERVE + snarf_region(ioaddr, DEPCA_TOTAL_SIZE); +#endif + + /* + ** Determine the base address for the DEPCA RAM from the NI-CSR + ** and make up a DEPCA-specific-data structure. + */ + + if (nicsr & BUF) { + offset = 0x8000; /* 32kbyte RAM */ + nicsr &= ~BS; /* DEPCA RAM in top 32k */ + printk(",\n with 32kB RAM"); + } else { + offset = 0x0000; /* 64kbyte RAM */ + printk(",\n with 64kB RAM"); + } + + mem_start += offset; + printk(" starting at 0x%.5lx", mem_start); + + /* + ** Enable the shadow RAM. + */ + nicsr |= SHE; + outw(nicsr, DEPCA_NICSR); + + /* + ** Calculate the ring size based on the available RAM + ** found above. Allocate an equal number of buffers, each + ** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx. Make sure + ** that this ring size is <= RING_SIZE. The ring size must be + ** a power of 2. + */ + + j = ((0x10000 - offset) / PKT_BUF_SZ) >> 1; + for (i=0;j>1;i++) { + j >>= 1; + } + + /* Hold the ring size information here before the depca + ** private structure is allocated. Need this for the memory + ** space calculations. + */ + j = 1 << i; + + /* + ** Set up memory information in the device structure. + ** Align the descriptor rings on an 8 byte (quadword) boundary. + ** + ** depca_private area + ** rx ring descriptors + ** tx ring descriptors + ** rx buffers + ** tx buffers + ** + */ + + /* private area & initialise */ + dev->priv = (void *)((mem_start + 0x07) & ~0x07); + lp = (struct depca_private *)dev->priv; + memset(dev->priv, 0, sizeof(struct depca_private)); + + /* Tx & Rx descriptors (aligned to a quadword boundary) */ + mem_start = ((((unsigned long)dev->priv + + sizeof(struct depca_private)) + + (unsigned long)0x07) & (unsigned long)~0x07); + lp->rx_ring = (struct depca_rx_head *)mem_start; + + mem_start += (sizeof(struct depca_rx_head) * j); + lp->tx_ring = (struct depca_tx_head *)mem_start; + + mem_start += (sizeof(struct depca_tx_head) * j); + lp->dma_buffs = mem_start & 0x00ffffff; + + mem_start += (PKT_BUF_SZ * j); + /* (mem_start now points to the start of the Tx buffers) */ + + /* Initialise the data structures */ + memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j); + memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j); + + /* This should never happen. */ + if ((int)(lp->rx_ring) & 0x07) { + printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n"); + return -ENXIO; + } + + /* + ** Finish initialising the ring information. + */ + lp->ringSize = j; + if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE; + lp->rmask = lp->ringSize - 1; + + /* + ** calculate the real RLEN size for the descriptors. It is + ** log2(ringSize). + */ + for (i=0, j = lp->ringSize; j>1; i++) { + j >>= 1; + } + lp->rlen = (unsigned long)(i << 29); + + /* + ** load the initialisation block + */ + depca_init_ring(dev); + + /* + ** Initialise the control and status registers + */ + LoadCSRs(dev); + + /* + ** Enable DEPCA board interrupts for autoprobing + */ + nicsr = ((nicsr & ~IM)|IEN); + outw(nicsr, DEPCA_NICSR); + + /* The DMA channel may be passed in on this parameter. */ + dev->dma = 0; + + /* To auto-IRQ we enable the initialization-done and DMA err, + interrupts. For now we will always get a DMA error. */ + if (dev->irq < 2) { + autoirq_setup(0); + + /* Trigger an initialization just for the interrupt. */ + outw(INEA | INIT, DEPCA_DATA); + + dev->irq = autoirq_report(1); + if (dev->irq) { + printk(" and probed IRQ%d.\n", dev->irq); + } else { + printk(". Failed to detect IRQ line.\n"); + status = -EAGAIN; + } + } else { + printk(". Assigned IRQ%d.\n", dev->irq); + } + } else { + status = -ENXIO; + } + if (!status) { + if (depca_debug > 0) { + printk(version); + } + + /* The DEPCA-specific entries in the device structure. */ + dev->open = &depca_open; + dev->hard_start_xmit = &depca_start_xmit; + dev->stop = &depca_close; + dev->get_stats = &depca_get_stats; +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_multicast_list; +#endif + + dev->mem_start = 0; + + /* Fill in the generic field of the device structure. */ + for (i = 0; i < DEV_NUMBUFFS; i++) { + dev->buffs[i] = NULL; + } + + dev->hard_header = eth_header; + dev->add_arp = eth_add_arp; + dev->queue_xmit = dev_queue_xmit; + dev->rebuild_header = eth_rebuild_header; + dev->type_trans = eth_type_trans; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 1500; /* eth_mtu */ + dev->addr_len = ETH_ALEN; + + for (i = 0; i < dev->addr_len; i++) { + dev->broadcast[i]=0xff; + } + + /* New-style flags. */ + dev->flags = IFF_BROADCAST; + dev->family = AF_INET; + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = sizeof(unsigned long); + } + } else { + status = -ENXIO; + } + + return status; +} + + +static int +depca_open(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + int i,nicsr,ioaddr = dev->base_addr; + + if (request_irq(dev->irq, &depca_interrupt)) { + printk("depca_open(): Requested IRQ%d is busy\n",dev->irq); + return -EAGAIN; + } + + irq2dev_map[dev->irq] = dev; + + /* + ** Stop the DEPCA & get the board status information. + */ + STOP_DEPCA; + nicsr = inw(DEPCA_NICSR); + + /* + ** Re-initialize the DEPCA... + */ + depca_init_ring(dev); /* initialize the descriptor rings */ + LoadCSRs(dev); + + if (depca_debug > 1){ + printk("%s: depca open with irq %d\n",dev->name,dev->irq); + printk("Descriptor head addresses:\n"); + printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring); + printk("Descriptor addresses:\n"); + for (i=0;iringSize;i++){ + printk("\t0x%8.8lx 0x%8.8lx\n",(long)&lp->rx_ring[i].base, + (long)&lp->tx_ring[i].base); + } + printk("Buffer addresses:\n"); + for (i=0;iringSize;i++){ + printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring[i].base, + (long)lp->tx_ring[i].base); + } + printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block); + printk("\tmode: 0x%4.4x\n",lp->init_block.mode); + printk("\tphysical address: "); + for (i=0;i<6;i++){ + printk("%2.2x:",(short)lp->init_block.phys_addr[i]); + } + printk("\n\tlogical address filter: 0x"); + for (i=0;i<4;i++){ + printk("%2.2x",(short)lp->init_block.filter[i]); + } + printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring); + printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring); + printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs); + printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n", + (short)lp->ringSize, + (char)lp->rmask, + (long)lp->rlen); + outw(CSR2,DEPCA_ADDR); + printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA)); + outw(CSR1,DEPCA_ADDR); + printk("%4.4x\n",inw(DEPCA_DATA)); + outw(CSR3,DEPCA_ADDR); + printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA)); + } + + /* + ** Enable DEPCA board interrupts + */ + nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN); + outw(nicsr, DEPCA_NICSR); + outw(CSR0,DEPCA_ADDR); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + InitRestartDepca(dev); /* ignore the return status */ + + if (depca_debug > 1){ + printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA)); + printk("nicsr: 0x%4.4x\n",inw(DEPCA_NICSR)); + } + + return 0; /* Always succeed */ +} + +/* Initialize the lance Rx and Tx descriptor rings. */ +static void +depca_init_ring(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + unsigned long i; + + lp->init_block.mode = DTX | DRX; /* Disable Rx and Tx. */ + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_rx = lp->dirty_tx = 0; + + /* Initialize the base addresses and length of each buffer in the ring */ + for (i = 0; i < lp->ringSize; i++) { + lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN; + lp->rx_ring[i].buf_length = -PKT_BUF_SZ; + lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) & + (unsigned long)(0x00ffffff); + } + + /* Set up the initialization block */ + for (i = 0; i < ETH_ALEN; i++) { + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + } + for (i = 0; i < 4; i++) { + lp->init_block.filter[i] = 0x0000; + } + lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen; + lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen; + + lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */ +} + +/* +** Writes a socket buffer to TX descriptor ring and starts transmission +*/ +static int +depca_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + int ioaddr = dev->base_addr; + int status = 0; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) { + status = -1; + } else { + STOP_DEPCA; + printk("%s: transmit timed out, status %4.4x, resetting.\n", + dev->name, inw(DEPCA_DATA)); + + depca_init_ring(dev); + LoadCSRs(dev); + InitRestartDepca(dev); + dev->tbusy=0; + dev->trans_start = jiffies; + } + return status; + } + + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* Fill in the ethernet header. */ + if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + skb->arp=1; + + if (skb->len <= 0) { + return 0; + } + + if (depca_debug > 3) { + outw(CSR0, DEPCA_ADDR); + printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name, + inw(DEPCA_DATA)); + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) + printk("%s: Transmitter access conflict.\n", dev->name); + + /* + ** The TX buffer, skb, has to be copied into the local network RAM + ** for the LANCE to access it. The skb may be at > 16MB for large + ** (memory) systems. + */ + { /* Fill in a Tx ring entry */ + unsigned char *buf; + int entry = lp->cur_tx++; + int len; + long skbL = skb->len; + char *p = (char *) skb->data; + + entry &= lp->rmask; /* Ring around buffer number. */ + buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); + + /* Wait for a full ring to free up */ + while (lp->tx_ring[entry].base < 0); + + /* + ** Caution: the write order is important here... don't set up the + ** ownership rights until all the other information is in place. + */ + len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */ + if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */ + skbL -= len; + lp->tx_ring[entry].length = -len; + + /* Clears various error flags */ + lp->tx_ring[entry].misc = 0x0000; + + /* copy the data from the socket buffer to the net memory */ + memcpy((unsigned char *)(buf), skb->data, len); + + /* Hand over buffer ownership to the LANCE */ + if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP); + lp->tx_ring[entry].base |= (T_OWN|T_STP); + + /* Trigger an immediate send demand. */ + outw(CSR0, DEPCA_ADDR); + outw(INEA | TDMD, DEPCA_DATA); + + dev->trans_start = jiffies; + + for (p += len; skbL > 0; p += len) { + + /* Get new buffer pointer */ + entry = lp->cur_tx++; + entry &= lp->rmask; /* Ring around buffer number. */ + buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); + + /* Wait for a full ring to free up */ + while (lp->tx_ring[entry].base < 0); + dev->tbusy=0; + + /* Copy ethernet header to the new buffer */ + memcpy((unsigned char *)buf, skb->data, PKT_HDR_LEN); + + /* Determine length of data buffer */ + len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */ + if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */ + skbL -= len; + lp->tx_ring[entry].length = -len; + + /* Clears various error flags */ + lp->tx_ring[entry].misc = 0x0000; + + /* copy the data from the socket buffer to the net memory */ + memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len); + + /* Hand over buffer ownership to the LANCE */ + if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP; + lp->tx_ring[entry].base |= T_OWN; + } + + if (depca_debug > 4) { + unsigned char *pkt = + (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff); + + printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n", + dev->name, entry, (unsigned long) &lp->tx_ring[entry], + lp->tx_ring[entry].base, -lp->tx_ring[entry].length); + printk("%s: Tx %2.2x %2.2x %2.2x ... %2.2x %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x %2.2x %2.2x.\n", + dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6], + pkt[7], pkt[8], pkt[11], pkt[12], pkt[13], + pkt[14], pkt[15]); + } + + /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */ + if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) { + dev->tbusy=0; + } + + if (skb->free) { + kfree_skb (skb, FREE_WRITE); + } + } + + return 0; +} + +/* +** The DEPCA interrupt handler. +*/ +static void +depca_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = (struct device *)(irq2dev_map[irq]); + struct depca_private *lp; + int csr0, ioaddr, nicsr; + + if (dev == NULL) { + printk ("depca_interrupt(): irq %d for unknown device.\n", irq); + return; + } else { + lp = (struct depca_private *)dev->priv; + ioaddr = dev->base_addr; + } + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = MASK_INTERRUPTS; + + /* mask the DEPCA board interrupts and turn on the LED */ + nicsr = inw(DEPCA_NICSR); + nicsr |= (IM|LED); + outw(nicsr, DEPCA_NICSR); + + outw(CSR0, DEPCA_ADDR); + csr0 = inw(DEPCA_DATA); + + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA); + + if (depca_debug > 5) + printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", + dev->name, csr0, inw(DEPCA_DATA)); + + if (csr0 & RINT) /* Rx interrupt (packet arrived) */ + depca_rx(dev); + + if (csr0 & TINT) /* Tx interrupt (packet sent) */ + depca_tx(dev); + + /* Clear the interrupts we've handled. */ + outw(CSR0, DEPCA_ADDR); + outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA); + + if (depca_debug > 4) { + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", + dev->name, inw(DEPCA_ADDR), + inw(DEPCA_DATA)); + } + + /* Unmask the DEPCA board interrupts and turn off the LED */ + nicsr = (nicsr & ~IM & ~LED); + outw(nicsr, DEPCA_NICSR); + + dev->interrupt = UNMASK_INTERRUPTS; + return; +} + +static int +depca_rx(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + int entry = lp->cur_rx & lp->rmask; + + /* If we own the next entry, it's a new packet. Send it up. */ + for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) { + int status = lp->rx_ring[entry].base >> 16 ; + + if (status & R_ERR) { /* There was an error. */ + lp->stats.rx_errors++; /* Update the error stats. */ + if (status & R_FRAM) lp->stats.rx_frame_errors++; + if (status & R_OFLO) lp->stats.rx_over_errors++; + if (status & R_CRC) lp->stats.rx_crc_errors++; + if (status & R_BUFF) lp->stats.rx_fifo_errors++; + } else { /* Malloc up new buffer, compatible with net-2e. */ + short pkt_len = lp->rx_ring[entry].msg_length; + int sksize = sizeof(struct sk_buff) + pkt_len; + struct sk_buff *skb; + + skb = alloc_skb(sksize, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + lp->stats.rx_dropped++; /* Really, deferred. */ + break; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + memcpy(skb->data, + (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), + pkt_len); + /* + ** Notify the upper protocol layers that there is another + ** packet to handle + */ +#ifdef HAVE_NETIF_RX + netif_rx(skb); +#else + skb->lock = 0; + if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { + kfree_skbmem(skb, sksize); + lp->stats.rx_dropped++; + break; + } +#endif + lp->stats.rx_packets++; + } + + /* turn over ownership of the current entry back to the LANCE */ + lp->rx_ring[entry].base |= R_OWN; + } + + /* + ** We should check that at least two ring entries are free. If not, + ** we should free one and mark stats->rx_dropped++. + */ + + return 0; +} + +/* +** Buffer sent - check for buffer errors. +*/ +static int +depca_tx(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + int dirty_tx = lp->dirty_tx & lp->rmask; + + if (depca_debug > 5) + printk("%s: Cleaning tx ring, dirty %d clean %d.\n", + dev->name, dirty_tx, (lp->cur_tx & lp->rmask)); + + /* + ** While the dirty entry is not the current one AND + ** the LANCE doesn't own it... + */ + for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0; + dirty_tx = ++lp->dirty_tx & lp->rmask) { + unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]); + int status = lp->tx_ring[dirty_tx].base >> 16; + + if (status < 0) { /* Packet not yet sent! */ + printk("interrupt for packet not yet sent!\n"); + break; + } + if (status & T_ERR) { /* There was an major error, log it. */ + int err_status = lp->tx_ring[dirty_tx].misc; + + lp->stats.tx_errors++; + if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++; + if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++; + if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++; + if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++; + /* We should re-init() after the FIFO error. */ + } else if (status & (T_MORE | T_ONE)) { + lp->stats.collisions++; + } else { + lp->stats.tx_packets++; + } + + if (depca_debug > 5) + printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n", + dev->name, dirty_tx, + tmdp[0], tmdp[1], tmdp[2], tmdp[3]); + } + /*mark_bh(INET_BH);*/ + return 0; +} + +static int +depca_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + + dev->start = 0; + dev->tbusy = 1; + + outw(CSR0, DEPCA_ADDR); + + if (depca_debug > 1) { + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inw(DEPCA_DATA)); + } + + /* + ** We stop the DEPCA here -- it occasionally polls + ** memory if we don't. + */ + outw(STOP, DEPCA_DATA); + + free_irq(dev->irq); + + irq2dev_map[dev->irq] = 0; + + return 0; +} + +static void LoadCSRs(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + int ioaddr = dev->base_addr; + + outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ + outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA); + outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */ + outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA); + outw(CSR3, DEPCA_ADDR); /* ALE control */ + outw(ACON, DEPCA_DATA); + outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ +} + +static int InitRestartDepca(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + int ioaddr = dev->base_addr; + int i, status=0; + + outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */ + outw(INIT, DEPCA_DATA); /* initialize DEPCA */ + + /* wait for lance to complete initialisation */ + for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); + + if (i!=100) { + /* clear IDON by writing a "1", enable interrupts and start lance */ + outw(IDON | INEA | STRT, DEPCA_DATA); + if (depca_debug > 2) { + printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n", + dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA)); + } + } else { + status = -1; + printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n", + dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA)); + } + + return status; +} + +static struct enet_statistics * +depca_get_stats(struct device *dev) +{ + struct depca_private *lp = (struct depca_private *)dev->priv; + + /* Null body since there is no framing error counter */ + + 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. +*/ +static void +set_multicast_list(struct device *dev, int num_addrs, void *addrs) +{ + short ioaddr = dev->base_addr; + struct depca_private *lp = (struct depca_private *)dev->priv; + + /* We take the simple way out and always enable promiscuous mode. */ + STOP_DEPCA; /* Temporarily stop the depca. */ + + lp->init_block.mode = PROM; /* Set promiscuous mode */ + if (num_addrs >= 0) { + short multicast_table[4]; + int i; + + SetMulticastFilter(num_addrs, (char *)addrs, (char *)multicast_table); + + /* 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++) { + lp->init_block.filter[i] = multicast_table[i]; + } + lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */ + } else { + lp->init_block.mode |= PROM; /* Set promiscuous mode */ + } + + outw(CSR0, DEPCA_ADDR); + outw(IDON|INEA|STRT, DEPCA_DATA); /* Resume normal operation. */ +} + +/* +** Calculate the hash code and update the logical address filter +** from a list of ethernet multicast addresses. +** Derived from a 'C' program in the AMD data book: +** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", +** Pub #17781, Rev. A, May 1993 +*/ +static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table) +{ + char j, ctrl, bit, octet, hashcode; + short int i; + long int CRC, poly = (long int) CRC_POLYNOMIAL; + + for (i=0;i> j) & 0x01; + ctrl = ((CRC < 0) ? 1 : 0); /* shift the control bit */ + CRC <<= 1; /* shift the CRC */ + if (bit ^ ctrl) { /* (bit) XOR (control bit) */ + CRC ^= poly; /* (CRC) XOR (polynomial) */ + } + } + } + hashcode = (CRC & 0x00000001); /* hashcode is 6 LSb of CRC ... */ + for (j=0;j<5;j++) { /* ... in reverse order. */ + hashcode <<= 1; + CRC >>= 1; + hashcode |= (CRC & 0x00000001); + } + octet = hashcode >> 3; /* bit[3-5] -> octet in filter */ + /* bit[0-2] -> bit in octet */ + multicast_table[octet] |= (1 << (hashcode & 0x07)); + } + } + return; +} + +#endif /* HAVE_MULTICAST */ + +/* +** Look for a particular board name in the on-board Remote Diagnostics +** and Boot (RDB) ROM. This will also give us a clue to the network RAM +** base address. +*/ +static char *DepcaSignature(unsigned long mem_addr) +{ + unsigned long i,j,k; + static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE; + static char thisName[DEPCA_NAME_LENGTH]; + char tmpstr[17]; + + for (i=0;i<16;i++) { /* copy the first 16 bytes of ROM to */ + tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */ + } + tmpstr[i]=(char)NULL; + + strcpy(thisName,""); + for (i=0;*signatures[i]!=(char)NULL && *thisName==(char)NULL;i++) { + for (j=0,k=0;j<16 && k=0) { + devSig[i]<<=4; + if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){ + devSig[j]=devSig[i]+devSig[i+1]; + } else { + status= -1; + } + } else { + status= -1; + } + } + sigLength=j; + fp = 0; + } + +/* +** Search the Ethernet address ROM for the signature. Since the ROM address +** counter can start at an arbitrary point, the search must include the entire +** probe sequence length plus the length of the (signature - 1). +** Stop the search IMMEDIATELY after the signature is found so that the +** PROM address counter is correctly positioned at the start of the +** ethernet address for later read out. +*/ + if (!status) { + for (i=0,j=0;j= 0) { + if (value > 9) { /* but may not be 10..15 */ + value &= 0x1f; /* make A..F & a..f be the same */ + value -= 0x07; /* normalise to 10..15 range */ + if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */ + value = -1; /* ...signal error */ + } + } + } else { /* outside 0..9 range... */ + value = -1; /* ...signal error */ + } + return value; /* return hex char or error */ +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c depca.c" + * End: + */ + + + diff -u +recursive +new-file 0.99pl15/linux/drivers/net/depca.h linux/drivers/net/depca.h --- 0.99pl15/linux/drivers/net/depca.h +++ linux/drivers/net/depca.h Tue Feb 22 08:35:15 1994 @@ -0,0 +1,128 @@ +/* + Written 1994 by David C. Davies. + + Copyright 1994 David C. Davies. This software may be used and distributed + according to the terms of the GNU Public License, incorporated herein by + reference. +*/ + +/* +** I/O addresses. Note that the 2k buffer option is not supported in +** this driver. +*/ +#define DEPCA_NICSR ioaddr+0x00 /* Network interface CSR */ +#define DEPCA_RBI ioaddr+0x02 /* RAM buffer index (2k buffer mode) */ +#define DEPCA_DATA ioaddr+0x04 /* LANCE registers' data port */ +#define DEPCA_ADDR ioaddr+0x06 /* LANCE registers' address port */ +#define DEPCA_PROM ioaddr+0x0c /* Ethernet address ROM data port */ +#define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */ + +/* +** These are LANCE registers addressable through DEPCA_ADDR +*/ +#define CSR0 0 +#define CSR1 1 +#define CSR2 2 +#define CSR3 3 + +/* +** NETWORK INTERFACE CSR (NI_CSR) bit definitions +*/ + +#define TO 0x0100 /* Time Out for remote boot */ +#define SHE 0x0080 /* SHadow memory Enable */ +#define BS 0x0040 /* Bank Select */ +#define BUF 0x0020 /* BUFfer size (1->32k, 0->64k) */ +#define RBE 0x0010 /* Remote Boot Enable (1->net boot) */ +#define AAC 0x0008 /* for DEPCA family compatability */ +#define IM 0x0004 /* Interrupt Mask (1->mask) */ +#define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */ +#define LED 0x0001 /* LED control */ + +/* +** Control and Status Register 0 (CSR0) bit definitions +*/ + +#define ERR 0x8000 /* Error summary */ +#define BABL 0x4000 /* Babble transmitter timeout error */ +#define CERR 0x2000 /* Collision Error */ +#define MISS 0x1000 /* Missed packet */ +#define MERR 0x0800 /* Memory Error */ +#define RINT 0x0400 /* Receiver Interrupt */ +#define TINT 0x0200 /* Transmit Interrupt */ +#define IDON 0x0100 /* Initialization Done */ +#define INTR 0x0080 /* Interrupt Flag */ +#define INEA 0x0040 /* Interrupt Enable */ +#define RXON 0x0020 /* Receiver on */ +#define TXON 0x0010 /* Transmitter on */ +#define TDMD 0x0008 /* Transmit Demand */ +#define STOP 0x0004 /* Stop */ +#define STRT 0x0002 /* Start */ +#define INIT 0x0001 /* Initialize */ + +/* +** CONTROL AND STATUS REGISTER 3 (CSR3) +*/ + +#define BSWP 0x0004 /* Byte SWaP */ +#define ACON 0x0002 /* ALE control */ +#define BCON 0x0001 /* Byte CONtrol */ + +/* +** Initialization Block Mode Register +*/ + +#define PROM 0x8000 /* Promiscuous Mode */ +#define EMBA 0x0080 /* Enable Modified Back-off Algorithm */ +#define INTL 0x0040 /* Internal Loopback */ +#define DRTY 0x0020 /* Disable Retry */ +#define COLL 0x0010 /* Force Collision */ +#define DTCR 0x0008 /* Disable Transmit CRC */ +#define LOOP 0x0004 /* Loopback */ +#define DTX 0x0002 /* Disable the Transmitter */ +#define DRX 0x0001 /* Disable the Receiver */ + +/* +** Receive Message Descriptor 1 (RMD1) bit definitions. +*/ + +#define R_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */ +#define R_ERR 0x4000 /* Error Summary */ +#define R_FRAM 0x2000 /* Framing Error */ +#define R_OFLO 0x1000 /* Overflow Error */ +#define R_CRC 0x0800 /* CRC Error */ +#define R_BUFF 0x0400 /* Buffer Error */ +#define R_STP 0x0200 /* Start of Packet */ +#define R_ENP 0x0100 /* End of Packet */ + +/* +** Transmit Message Descriptor 1 (TMD1) bit definitions. +*/ + +#define T_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */ +#define T_ERR 0x4000 /* Error Summary */ +#define T_ADD_FCS 0x2000 /* More the 1 retry needed to Xmit */ +#define T_MORE 0x1000 /* >1 retry to transmit packet */ +#define T_ONE 0x0800 /* 1 try needed to transmit the packet */ +#define T_DEF 0x0400 /* Deferred */ +#define T_STP 0x02000000 /* Start of Packet */ +#define T_ENP 0x01000000 /* End of Packet */ + +/* +** Transmit Message Descriptor 3 (TMD3) bit definitions. +*/ + +#define TMD3_BUFF 0x8000 /* BUFFer error */ +#define TMD3_UFLO 0x4000 /* UnderFLOw error */ +#define TMD3_RES 0x2000 /* REServed */ +#define TMD3_LCOL 0x1000 /* Late COLlision */ +#define TMD3_LCAR 0x0800 /* Loss of CARrier */ +#define TMD3_RTRY 0x0400 /* ReTRY error */ + +/* +** Miscellaneous +*/ + +#define MASK_INTERRUPTS 1 +#define UNMASK_INTERRUPTS 0 + diff -u +recursive +new-file 0.99pl15/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- 0.99pl15/linux/drivers/net/eexpress.c Wed Feb 2 17:30:04 1994 +++ linux/drivers/net/eexpress.c Sun Mar 6 16:12:05 1994 @@ -19,7 +19,7 @@ */ static char *version = - "eexpress.c:v0.06 10/27/93 Donald Becker (becker@super.org)\n"; + "eexpress.c:v0.07 1/19/94 Donald Becker (becker@super.org)\n"; #include @@ -154,7 +154,7 @@ #define ASIC_RESET 0x40 #define _586_RESET 0x80 -/* Offsets into the System Control Block structure. */ +/* Offsets to elements of the System Control Block structure. */ #define SCB_STATUS 0xc008 #define SCB_CMD 0xc00A #define CUC_START 0x0100 @@ -175,8 +175,8 @@ program space than initializing the individual tables, and I feel it's much cleaner. - The databook is particularly useless for the first two structures, I had - to use the Crynwr driver as an example. + The databook is particularly useless for the first two structures; they are + completely undocumented. I had to use the Crynwr driver as an example. The memory setup is as follows: */ @@ -194,17 +194,18 @@ #define TX_BUF_START 0x0100 #define NUM_TX_BUFS 4 -#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */ +#define TX_BUF_SIZE 0x0680 /* packet+header+TBD+extra (1518+14+20+16) */ +#define TX_BUF_END 0x2000 #define RX_BUF_START 0x2000 #define RX_BUF_SIZE (0x640) /* packet+header+RBD+extra */ -#define RX_BUF_END 0x8000 +#define RX_BUF_END 0x4000 /* That's it: only 86 bytes to set up the beast, including every extra command available. The 170 byte buffer at DUMP_DATA is shared between the Dump command (called only by the diagnostic program) and the SetMulticastList - command. + command. To complete the memory setup you only have to write the station address at SA_OFFSET and create the Tx & Rx buffer lists. @@ -277,7 +278,7 @@ #endif /* 0x0056: A continuous transmit command, only here for testing. */ - 0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x803ff, -1, DUMP_DATA, 0, + 0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x83ff, -1, DUMP_DATA, 0, }; /* Index to functions, as function prototypes. */ @@ -326,6 +327,7 @@ #ifdef notdef for (i = 16; i > 0; i--) sum += inb(id_addr); + printk("EtherExpress ID checksum is %04x.\n", sum); #else for (i = 4; i > 0; i--) { short id_val = inb(id_addr); @@ -353,7 +355,7 @@ station_addr[1] = read_eeprom(ioaddr, 3); station_addr[2] = read_eeprom(ioaddr, 4); - /* Check the first three octets of the S.A. for the manufactor's code. */ + /* Check the first three octets of the S.A. for the manufactor's code. */ if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) { printk(" rejected (invalid address %04x%04x%04x).\n", station_addr[2], station_addr[1], station_addr[0]); @@ -551,8 +553,8 @@ struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; int ioaddr, status, boguscount = 0; - short ack_cmd = 0; - + short ack_cmd; + if (dev == NULL) { printk ("net_interrupt(): irq %d for unknown device.\n", irq); return; @@ -595,7 +597,7 @@ if (net_debug > 5) printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); lp->tx_reap += TX_BUF_SIZE; - if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE) + if (lp->tx_reap > TX_BUF_END - TX_BUF_SIZE) lp->tx_reap = TX_BUF_START; if (++boguscount > 4) break; @@ -611,13 +613,22 @@ ack_cmd = status & 0xf000; if ((status & 0x0700) != 0x0200 && dev->start) { - if (net_debug) + short saved_write_ptr = inw(ioaddr + WRITE_PTR); + if (net_debug > 1) printk("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); - /* If this ever occurs we should really re-write the idle loop, reset - the Tx list, and do a complete restart of the command unit. - For now we rely on the Tx timeout if the resume doesn't work. */ - ack_cmd |= CUC_RESUME; + /* If this ever occurs we must re-write the idle loop, reset + the Tx list, and do a complete restart of the command unit. */ + outw(IDLELOOP, ioaddr + WRITE_PTR); + outw(0, ioaddr); + outw(CmdNOp, ioaddr); + outw(IDLELOOP, ioaddr); + outw(IDLELOOP, SCB_CBL); + lp->tx_cmd_link = IDLELOOP + 4; + lp->tx_head = lp->tx_reap = TX_BUF_START; + /* Restore the saved write pointer. */ + outw(saved_write_ptr, ioaddr + WRITE_PTR); + ack_cmd |= CUC_START; } if ((status & 0x0070) != 0x0040 && dev->start) { @@ -624,9 +635,21 @@ short saved_write_ptr = inw(ioaddr + WRITE_PTR); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ - if (net_debug) - printk("%s: Rx unit stopped, status %04x, restarting.\n", - dev->name, status); + lp->stats.rx_errors++; + if (net_debug > 1) { + int cur_rxbuf = RX_BUF_START; + printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n", + dev->name, status, lp->rx_head, lp->rx_tail); + while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) { + int i; + printk(" Rx buf at %04x:", cur_rxbuf); + outw(cur_rxbuf, ioaddr + READ_PTR); + for (i = 0; i < 0x20; i += 2) + printk(" %04x", inw(ioaddr)); + printk(".\n"); + cur_rxbuf += RX_BUF_SIZE; + } + } init_rx_bufs(dev); outw(RX_BUF_START, SCB_RFA); outw(saved_write_ptr, ioaddr + WRITE_PTR); @@ -813,8 +836,7 @@ } /* Initialize the Rx-block list. */ -static void -init_rx_bufs(struct device *dev) +static void init_rx_bufs(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; @@ -828,14 +850,14 @@ outw(0x0000, ioaddr); /* Command */ outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */ outw(cur_rxbuf + 22, ioaddr); /* Buffer offset */ - outw(0x0000, ioaddr); /* Pad for dest addr. */ - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); /* Pad for source addr. */ - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); /* Pad for protocol. */ - + outw(0xFeed, ioaddr); /* Pad for dest addr. */ + outw(0xF00d, ioaddr); + outw(0xF001, ioaddr); + outw(0x0505, ioaddr); /* Pad for source addr. */ + outw(0x2424, ioaddr); + outw(0x6565, ioaddr); + outw(0xdeaf, ioaddr); /* Pad for protocol. */ + outw(0x0000, ioaddr); /* Buffer: Actual count */ outw(-1, ioaddr); /* Buffer: Next (none). */ outw(cur_rxbuf + 0x20, ioaddr); /* Buffer: Address low */ @@ -890,7 +912,7 @@ /* Set the next free tx region. */ lp->tx_head = tx_block + TX_BUF_SIZE; - if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) + if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE) lp->tx_head = TX_BUF_START; if (net_debug > 4) { @@ -985,7 +1007,7 @@ printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name, rx_head, next_rx_frame, rx_head + RX_BUF_SIZE); next_rx_frame = rx_head + RX_BUF_SIZE; - if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) + if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) next_rx_frame = RX_BUF_START; } #endif diff -u +recursive +new-file 0.99pl15/linux/drivers/net/hp.c linux/drivers/net/hp.c --- 0.99pl15/linux/drivers/net/hp.c Mon Jan 3 08:31:18 1994 +++ linux/drivers/net/hp.c Sun Mar 6 16:12:05 1994 @@ -13,7 +13,7 @@ */ static char *version = - "hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n"; + "hp.c:v0.99.15k 3/3/94 Donald Becker (becker@super.org)\n"; #include #include @@ -56,7 +56,7 @@ static void hp_init_card(struct device *dev); /* The map from IRQ number to HP_CONFIGURE register setting. */ -/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */ +/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */ static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0}; @@ -86,24 +86,19 @@ int hpprobe1(struct device *dev, int ioaddr) { - int status, i, board_id, wordmode; + int i, board_id, wordmode; char *name; unsigned char *station_addr = dev->dev_addr; /* Check for the HP physical address, 08 00 09 xx xx xx. */ + /* This really isn't good enough: we may pick up HP LANCE boards + also! Avoid the lance 0x5757 signature. */ if (inb(ioaddr) != 0x08 || inb(ioaddr+1) != 0x00 - || inb(ioaddr+2) != 0x09) + || inb(ioaddr+2) != 0x09 + || inb(ioaddr+14) == 0x57) return ENODEV; - /* This really isn't good enough, we may pick up HP LANCE boards also! */ - /* Verify that there is a 8390 at the expected location. */ - outb(E8390_NODMA + E8390_STOP, ioaddr); - SLOW_DOWN_IO; - status = inb(ioaddr); - if (status != 0x21 && status != 0x23) - return ENODEV; - /* Set up the parameters based on the board ID. If you have additional mappings, please mail them to becker@super.org. */ if ((board_id = inb(ioaddr + HP_ID)) & 0x80) { @@ -182,31 +177,22 @@ { int hp_base = dev->base_addr - NIC_OFFSET; int saved_config = inb_p(hp_base + HP_CONFIGURE); - int reset_start_time = jiffies; - if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies); + if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies); outb_p(0x00, hp_base + HP_CONFIGURE); ei_status.txing = 0; - - sti(); - /* We shouldn't use the boguscount for timing, but this hasn't been - checked yet, and you could hang your machine if jiffies break... */ - { - int boguscount = 150000; - while(jiffies - reset_start_time < 2) - if (boguscount-- < 0) { - printk("jiffy failure (t=%d)...", jiffies); - break; - } - } + /* Pause just a few cycles for the hardware reset to take place. */ + SLOW_DOWN_IO; + SLOW_DOWN_IO; outb_p(saved_config, hp_base + HP_CONFIGURE); - while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2) { - printk("%s: hp_reset_8390() did not complete.\n", dev->name); - return; - } - if (ei_debug > 1) printk("8390 reset done (%d).", jiffies); + SLOW_DOWN_IO; SLOW_DOWN_IO; + + if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) + printk("%s: hp_reset_8390() did not complete.\n", dev->name); + + if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies); + return; } /* Block input and output, similar to the Crynwr packet driver. If you @@ -320,9 +306,10 @@ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * c-indent-level: 4 * End: */ diff -u +recursive +new-file 0.99pl15/linux/drivers/net/lance.c linux/drivers/net/lance.c --- 0.99pl15/linux/drivers/net/lance.c Wed Feb 2 17:41:54 1994 +++ linux/drivers/net/lance.c Fri Mar 4 09:16:19 1994 @@ -205,7 +205,7 @@ int pad0, pad1; /* Used for alignment */ }; -static unsigned long lance_probe1(short ioaddr, unsigned long mem_start); +unsigned long lance_probe1(short ioaddr, unsigned long mem_start); static int lance_open(struct device *dev); static void lance_init_ring(struct device *dev); static int lance_start_xmit(struct sk_buff *skb, struct device *dev); @@ -236,7 +236,7 @@ return mem_start; } -static unsigned long lance_probe1(short ioaddr, unsigned long mem_start) +unsigned long lance_probe1(short ioaddr, unsigned long mem_start) { struct device *dev; struct lance_private *lp; @@ -556,18 +556,18 @@ if ((int)(skb->data) + skb->len > 0x01000000) { if (lance_debug > 5) printk("%s: bouncing a high-memory packet (%#x).\n", - dev->name, (int)skb->data); + dev->name, (int)(skb->data)); memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); lp->tx_ring[entry].base = (int)(lp->tx_bounce_buffs + entry) | 0x83000000; if (skb->free) kfree_skb (skb, FREE_WRITE); - } else - { - /* Gimme!!! */ + } else { + /* We can't free the packet yet, so we inform the memory management + code that we are still using it. */ if(skb->free==0) skb_kept_by_device(skb); - lp->tx_ring[entry].base = (int)skb->data | 0x83000000; + lp->tx_ring[entry].base = (int)(skb->data) | 0x83000000; } lp->cur_tx++; @@ -638,11 +638,12 @@ if (err_status & 0x0800) lp->stats.tx_carrier_errors++; if (err_status & 0x1000) lp->stats.tx_window_errors++; if (err_status & 0x4000) lp->stats.tx_fifo_errors++; - /* We should re-init() after the FIFO error. */ - } else if (status & 0x18000000) - lp->stats.collisions++; - else + /* Perhaps we should re-init() after the FIFO error. */ + } else { + if (status & 0x18000000) + lp->stats.collisions++; lp->stats.tx_packets++; + } /* We don't free the skb if it's a data-only copy in the bounce buffer. The address checks here are sorted -- the first test @@ -654,7 +655,8 @@ kfree_skb(skb, FREE_WRITE); else skb_device_release(skb,FREE_WRITE); - /* Warning: skb may well vanish at the point you call device_release! */ + /* Warning: skb may well vanish at the point you call + device_release! */ } dirty_tx++; } @@ -704,8 +706,13 @@ while (lp->rx_ring[entry].base >= 0) { int status = lp->rx_ring[entry].base >> 24; - if (status & 0x40) { /* There was an error. */ - lp->stats.rx_errors++; + if (status != 0x03) { /* There was an error. */ + /* There is an tricky error noted by John Murphy, + to Russ Nelson: Even with full-sized + buffers it's possible for a jabber packet to use two + buffers, with only the last correctly noting the error. */ + if (status & 0x01) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet.*/ if (status & 0x20) lp->stats.rx_frame_errors++; if (status & 0x10) lp->stats.rx_over_errors++; if (status & 0x08) lp->stats.rx_crc_errors++; @@ -835,6 +842,12 @@ outw(0, ioaddr+LANCE_ADDR); outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */ } +#endif + +#ifdef HAVE_DEVLIST +static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0}; +struct netdev_entry lance_drv = +{"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist}; #endif /* diff -u +recursive +new-file 0.99pl15/linux/drivers/net/ne.c linux/drivers/net/ne.c --- 0.99pl15/linux/drivers/net/ne.c Fri Jan 28 09:50:24 1994 +++ linux/drivers/net/ne.c Sun Mar 6 16:12:04 1994 @@ -17,7 +17,7 @@ /* Routines for the NatSemi-based designs (NE[12]000). */ static char *version = - "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n"; + "ne.c:v0.99-15k 3/3/94 Donald Becker (becker@super.org)\n"; #include #include @@ -155,11 +155,10 @@ } if (wordlength == 2) { - /* We must set the 8390 for word mode, AND RESET IT. */ - int tmp; + /* We must set the 8390 for word mode. */ outb_p(0x49, ioaddr + EN0_DCFG); - tmp = inb_p(NE_BASE + NE_RESET); - outb(tmp, NE_BASE + NE_RESET); + /* We used to reset the ethercard here, but it doesn't seem + to be necessary. */ /* Un-double the SA_prom values. */ for (i = 0; i < 16; i++) SA_prom[i] = SA_prom[i+i]; @@ -265,7 +264,7 @@ int tmp = inb_p(NE_BASE + NE_RESET); int reset_start_time = jiffies; - if (ei_debug > 1) printk("resetting the 8390 t=%d...", jiffies); + if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); ei_status.txing = 0; outb_p(tmp, NE_BASE + NE_RESET); diff -u +recursive +new-file 0.99pl15/linux/drivers/net/slip.c linux/drivers/net/slip.c --- 0.99pl15/linux/drivers/net/slip.c Wed Feb 2 17:30:15 1994 +++ linux/drivers/net/slip.c Sun Mar 13 15:47:58 1994 @@ -19,6 +19,8 @@ * Alan Cox : Honours the old SL_COMPRESSED flag * Alan Cox : KISS AX.25 and AXUI IP support * Michael Riepe : Automatic CSLIP recognition added + * Charles Hedrick : CSLIP header length problem fix. + * Alan Cox : Corrected non-IP cases of the above. */ #include @@ -231,12 +233,19 @@ sl->mtu=dev->mtu; l=(dev->mtu *2); +/* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (l < (576 * 2)) + l = 576 * 2; DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n")); - tb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL); - rb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL); - cb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL); + tb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); + rb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); + cb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC); if(tb==NULL || rb==NULL || cb==NULL) { @@ -522,6 +531,7 @@ { struct tty_struct *tty; struct slip *sl; + int size; /* Find the correct SLIP channel to use. */ sl = &sl_ctrl[dev->base_addr]; @@ -543,26 +553,35 @@ /* We were not, so we are now... :-) */ if (skb != NULL) { #ifdef CONFIG_AX25 - if(sl->mode & SL_MODE_AX25) - { - if(!skb->arp && dev->rebuild_header(skb->data,dev)) - { - skb->dev=dev; - arp_queue(skb); - return 0; - } - skb->arp=1; - } + if(sl->mode & SL_MODE_AX25) + { + if(!skb->arp && dev->rebuild_header(skb->data,dev)) + { + skb->dev=dev; + arp_queue(skb); + return 0; + } + skb->arp=1; + } #endif sl_lock(sl); -/* sl_hex_dump(skb->data,skb->len);*/ - sl_encaps(sl, skb->data, skb->len); - if (skb->free) kfree_skb(skb, FREE_WRITE); + size = skb->len; + if (!(sl->mode & SL_MODE_AX25)) { + if (size < sizeof(struct iphdr)) { + printk("Runt IP frame fed to slip!\n"); + } else { + size = ((struct iphdr *)(skb->data))->tot_len; + size = ntohs(size); + } + } + /* sl_hex_dump(skb->data,skb->len);*/ + sl_encaps(sl, skb->data, size); + if (skb->free) + kfree_skb(skb, FREE_WRITE); } return(0); } - /* Return the frame type ID. This is normally IP but maybe be AX.25. */ static unsigned short sl_type_trans (struct sk_buff *skb, struct device *dev) @@ -642,6 +661,14 @@ * rmem_start Start of RECV frame buffer */ l = (dev->mtu * 2); +/* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (l < (576 * 2)) + l = 576 * 2; + p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); if (p == NULL) { DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP XMIT buffer!\n")); diff -u +recursive +new-file 0.99pl15/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- 0.99pl15/linux/drivers/net/smc-ultra.c Thu Dec 23 10:38:34 1993 +++ linux/drivers/net/smc-ultra.c Tue Mar 1 19:29:05 1994 @@ -14,7 +14,7 @@ */ static char *version = - "smc-ultra.c:v0.05 12/21/93 Donald Becker (becker@super.org)\n"; + "smc-ultra.c:v0.07 3/1/94 Donald Becker (becker@super.org)\n"; #include #include @@ -63,7 +63,7 @@ unsigned short ioaddr = dev->base_addr; if (ioaddr > 0x1ff) - return ! ultraprobe1(ioaddr, dev); + return ultraprobe1(ioaddr, dev); else if (ioaddr > 0) return ENXIO; /* Don't probe at all. */ @@ -139,7 +139,7 @@ dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; { - int addr_tbl[4] = {0x0C0000, 0x0D0000, 0xFC0000, 0xFD0000}; + int addr_tbl[4] = {0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000}; short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff}; dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ; @@ -158,7 +158,7 @@ dev->mem_end = dev->rmem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256; - printk(",%s IRQ %d memory %#x-%#x.\n", eeprom_irq ? "" : "assigned ", + printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ", dev->irq, dev->mem_start, dev->mem_end-1); if (ei_debug > 0) printk(version); @@ -193,7 +193,7 @@ int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */ outb(ULTRA_RESET, cmd_port); - if (ei_debug > 1) printk("resetting Ultra, t=%d...", jiffies); + if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies); ei_status.txing = 0; outb(ULTRA_MEMENB, cmd_port); diff -u +recursive +new-file 0.99pl15/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- 0.99pl15/linux/drivers/scsi/aha1542.c Mon Jan 24 09:23:20 1994 +++ linux/drivers/scsi/aha1542.c Mon Feb 14 22:06:26 1994 @@ -675,7 +675,7 @@ WAIT(INTRFLAGS(base),INTRMASK,HACC,0); aha1542_intr_reset(base); - if (mbenable_result[0] & 0x08) { + if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { mbenable_cmd[0]=CMD_MBENABLE; mbenable_cmd[1]=0; mbenable_cmd[2]=mbenable_result[1]; diff -u +recursive +new-file 0.99pl15/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c --- 0.99pl15/linux/drivers/scsi/constants.c Wed Dec 1 14:44:16 1993 +++ linux/drivers/scsi/constants.c Tue Feb 15 07:26:30 1994 @@ -18,7 +18,7 @@ #ifdef CONSTANTS #undef CONSTANTS #endif -#define CONSTANTS (CONST_CMD | CONST_STATUS | CONST_SENSE | CONST_XSENSE) +#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE) #endif #if (CONSTANTS & CONST_COMMAND) diff -u +recursive +new-file 0.99pl15/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- 0.99pl15/linux/drivers/scsi/scsi.c Thu Dec 30 11:39:04 1993 +++ linux/drivers/scsi/scsi.c Thu Mar 10 09:11:50 1994 @@ -127,15 +127,21 @@ static struct blist blacklist[] = { {"DENON","DRD-25X","V"}, /* A cdrom that locks up when probed at lun != 0 */ - {"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */ + {"IMS", "CDD521/10","2.06"}, /* Locks-up when LUN>0 polled. */ + {"MAXTOR","XT-3280","PR02"}, /* Locks-up when LUN>0 polled. */ + {"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */ {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */ - {"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */ + {"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */ + {"MAXTOR","XT-8760S","B7B"}, /* guess what? */ {"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */ + {"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */ {"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 for aha152x * controller, which causes SCSI code to reset bus.*/ {"SEAGATE", "ST296","921"}, /* Responds to all lun */ {"SONY","CD-ROM CDU-541","4.3d"}, {"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */ + {"TEAC","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 for seagate + * controller, which causes SCSI code to reset bus.*/ {"TEXEL","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 for seagate * controller, which causes SCSI code to reset bus.*/ {NULL, NULL, NULL}}; @@ -385,7 +391,7 @@ scsi_devices[NR_SCSI_DEVICES].tagged_queue = 0; - if ((scsi_devices[NR_SCSI_DEVICES].scsi_level == SCSI_2) && + if ((scsi_devices[NR_SCSI_DEVICES].scsi_level >= SCSI_2) && (scsi_result[7] & 2)) { scsi_devices[NR_SCSI_DEVICES].tagged_supported = 1; scsi_devices[NR_SCSI_DEVICES].current_tag = 0; @@ -449,6 +455,9 @@ /* Some scsi devices cannot be polled for lun != 0 due to firmware bugs */ if(blacklisted(scsi_result)) break; + /* Old drives like the MAXTOR XT-3280 say vers=0 */ + if ((scsi_result[2] & 0x07) == 0) + break; /* Some scsi-1 peripherals do not handle lun != 0. I am assuming that scsi-2 peripherals do better */ if((scsi_result[2] & 0x07) == 1 && diff -u +recursive +new-file 0.99pl15/linux/drivers/sound/os.h linux/drivers/sound/os.h --- 0.99pl15/linux/drivers/sound/os.h Tue Dec 21 10:24:00 1993 +++ linux/drivers/sound/os.h Fri Feb 11 13:07:33 1994 @@ -140,7 +140,7 @@ #define DEFINE_TIMER(name, proc) \ static struct timer_list name = \ - {NULL, 0, 0, proc} + {NULL, NULL, 0, 0, proc} /* * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks. diff -u +recursive +new-file 0.99pl15/linux/fs/binfmt_coff.c linux/fs/binfmt_coff.c --- 0.99pl15/linux/fs/binfmt_coff.c Thu Jan 20 14:36:30 1994 +++ linux/fs/binfmt_coff.c Mon Feb 14 18:41:55 1994 @@ -7,43 +7,12 @@ * This file is based upon code written by Eric Youndale for the ELF object * file format. * - * Revision information: - * 28 August 1993 - * Al Longyear (longyear@sii.com) - * initial release to alpha level testing. This version does not load - * shared libraries, but will identify them and log the file names. + * Author: Al Longyear (longyear@sii.com) * - * 4 September 1993 - * Al Longyear (longyear@sii.com) - * Added support for shared libraries. - * - * 9 September 1993 - * Al Longyear (longyear@sii.com) - * Load the FS register with the proper value prior to the call to - * sys_uselib(). - * - * Built the parameter and envionment strings before destroying the - * current executable. - * - * 10 September 1993 - * Al Longyear (longyear@sii.com) - * Added new parameter to the create_tables() function to allow the - * proper creation of the IBCS environment stack when the process is - * started. - * - * Added code to create_tables() which I mistakenly deleted in the - * last patch. - * - * 13 September 1993 - * Al Longyear (longyear@sii.com) - * Removed erroneous code which mistakenly folded .data with .bss for - * a shared library. - * - * 8 Janurary 1994 - * Al Longyear (longyear@sii.com) - * Corrected problem with read of library section returning the byte - * count rather than zero. This was a change between the pl12 and - * pl14 kernels which slipped by me. + * Latest Revision: + * 3 Feburary 1994 + * Al Longyear (longyear@sii.com) + * Cleared first page of bss section using put_fs_byte. */ #include @@ -105,6 +74,37 @@ } /* + * Clear the bytes in the last page of data. + */ + +static +int clear_memory (unsigned long addr, unsigned long size) +{ + int status; + + size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK; + if (size == 0) + status = 0; + else { + +#ifdef COFF_DEBUG + printk ("un-initialized storage in last page %d\n", size); +#endif + + status = verify_area (VERIFY_WRITE, + (void *) addr, size); +#ifdef COFF_DEBUG + printk ("result from verify_area = %d\n", status); +#endif + + if (status >= 0) + while (size-- != 0) + put_fs_byte (0, addr++); + } + return status; +} + +/* * Helper function to process the load operation. */ @@ -521,11 +521,13 @@ zeromap_page_range (PAGE_ALIGN (bss_vaddr), PAGE_ALIGN (bss_size), PAGE_COPY); + + status = clear_memory (bss_vaddr, bss_size); } /* * Load any shared library for the executable. */ - if (lib_ok && lib_count != 0) { + if (status >= 0 && lib_ok && lib_count != 0) { int nIndex; COFF_SCNHDR *sect_ptr = sect_bufr; /* diff -u +recursive +new-file 0.99pl15/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- 0.99pl15/linux/fs/binfmt_elf.c Thu Jan 20 14:36:30 1994 +++ linux/fs/binfmt_elf.c Thu Feb 17 09:07:27 1994 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -21,6 +22,8 @@ asmlinkage int sys_open(const char *, int, int); asmlinkage int sys_brk(unsigned long); +#define DLINFO_ITEMS 8 + #include /* We need to explicitly zero any fractional pages @@ -43,17 +46,220 @@ }; } +unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs) +{ + unsigned long *argv,*envp, *dlinfo; + unsigned long * sp; + struct vm_area_struct *mpnt; + + mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); + if (mpnt) { + mpnt->vm_task = current; + mpnt->vm_start = PAGE_MASK & (unsigned long) p; + mpnt->vm_end = TASK_SIZE; + mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY; + mpnt->vm_share = NULL; + mpnt->vm_inode = NULL; + mpnt->vm_offset = 0; + mpnt->vm_ops = NULL; + insert_vm_struct(current, mpnt); + current->stk_vma = mpnt; + } + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + if(exec) sp -= DLINFO_ITEMS*2; + dlinfo = sp; + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + if (!ibcs) { + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + } + + /* The constant numbers (0-9) that we are writing here are + described in the header file sys/auxv.h on at least + some versions of SVr4 */ + if(exec) { /* Put this here for an ELF program interpreter */ + struct elf_phdr * eppnt; + eppnt = (struct elf_phdr *) exec->e_phoff; + put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++); + put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++); + put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++); + put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++); + put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++); + put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++); + put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++); + put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++); + }; + + put_fs_long((unsigned long)argc,--sp); + current->arg_start = (unsigned long) p; + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + current->arg_end = current->env_start = (unsigned long) p; + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + current->env_end = (unsigned long) p; + return sp; +} + + +/* This is much more generalized than the library routine read function, + so we keep this separate. Techincally the library read function + is only provided so that we can read a.out libraries that have + an ELF header */ + +static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex, + struct inode * interpreter_inode) +{ + struct file * file; + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + unsigned int len; + unsigned int load_addr; + int elf_exec_fileno; + int elf_bss; + int old_fs, retval; + unsigned int last_bss; + int error; + int i, k; + + elf_bss = 0; + last_bss = 0; + error = load_addr = 0; + + /* First of all, some simple consistency checks */ + if((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) || + (!interpreter_inode->i_op || !interpreter_inode->i_op->bmap || + !interpreter_inode->i_op->default_file_ops->mmap)){ + return 0xffffffff; + }; + + /* Now read in all of the header information */ + + if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) + return 0xffffffff; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); + if(!elf_phdata) return 0xffffffff; + + old_fs = get_fs(); + set_fs(get_ds()); + retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + set_fs(old_fs); + + elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); + if (elf_exec_fileno < 0) return 0xffffffff; + file = current->filp[elf_exec_fileno]; + + eppnt = elf_phdata; + for(i=0; ie_phnum; i++, eppnt++) + if(eppnt->p_type == PT_LOAD) { + error = do_mmap(file, + eppnt->p_vaddr & 0xfffff000, + eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0), + eppnt->p_offset & 0xfffff000); + + if(!load_addr && interp_elf_ex->e_type == ET_DYN) + load_addr = error; + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if(k > elf_bss) elf_bss = k; + if(error < 0 && error > -1024) break; /* Real error */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if(k > last_bss) last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + + sys_close(elf_exec_fileno); + if(error < 0 && error > -1024) { + kfree(elf_phdata); + return 0xffffffff; + } + + padzero(elf_bss); + len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > len) + do_mmap(NULL, len, last_bss-len, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + kfree(elf_phdata); + + return ((unsigned int) interp_elf_ex->e_entry) + load_addr; +} + +static unsigned int load_aout_interp(struct exec * interp_ex, + struct inode * interpreter_inode) +{ + int retval; + unsigned int elf_entry; + + current->brk = interp_ex->a_bss + + (current->end_data = interp_ex->a_data + + (current->end_code = interp_ex->a_text)); + elf_entry = interp_ex->a_entry; + + + if (N_MAGIC(*interp_ex) == OMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, 32, (char *) 0, + interp_ex->a_text+interp_ex->a_data); + } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, + N_TXTOFF(*interp_ex) , + (char *) N_TXTADDR(*interp_ex), + interp_ex->a_text+interp_ex->a_data); + } else + retval = -1; + + if(retval >= 0) + do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & + 0xfffff000, interp_ex->a_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + if(retval < 0) return 0xffffffff; + return elf_entry; +} + /* * These are the functions used to load ELF style executables and shared * libraries. There is no binary dependent code anywhere else. */ +#define INTERPRETER_NONE 0 +#define INTERPRETER_AOUT 1 +#define INTERPRETER_ELF 2 + int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; struct file * file; - struct exec ex; + struct exec interp_ex; struct inode *interpreter_inode; + unsigned int load_addr; + unsigned int interpreter_type = INTERPRETER_NONE; int i; int old_fs; int error; @@ -69,6 +275,7 @@ char passed_fileno[6]; status = 0; + load_addr = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ if (elf_ex.e_ident[0] != 0x7f || @@ -141,12 +348,15 @@ retval = read_exec(interpreter_inode,0,bprm->buf,128); if(retval >= 0){ - ex = *((struct exec *) bprm->buf); /* exec-header */ + interp_ex = *((struct exec *) bprm->buf); /* exec-header */ + interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ -#if 0 - printk("Interpreter: %x %x %x\n",N_MAGIC(ex), ex.a_text,ex.a_data); -#endif }; + if(retval < 0) { + kfree (elf_phdata); + kfree(elf_interpreter); + return retval; + }; }; elf_ppnt++; }; @@ -155,16 +365,28 @@ /* Some simple consistency checks for the interpreter */ if(elf_interpreter){ + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; if(retval < 0) { kfree(elf_interpreter); kfree(elf_phdata); return -ELIBACC; }; - if((N_MAGIC(ex) != OMAGIC) && (N_MAGIC(ex) != ZMAGIC)) { - kfree(elf_interpreter); - kfree(elf_phdata); - return -ELIBBAD; - }; + /* Now figure out which format our binary is */ + if((N_MAGIC(interp_ex) != OMAGIC) && + (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) + interpreter_type = INTERPRETER_ELF; + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) + interpreter_type &= ~INTERPRETER_ELF; + + if(!interpreter_type) + { + kfree(elf_interpreter); + kfree(elf_phdata); + return -ELIBBAD; + }; } /* OK, we are done with that, now set up the arg stuff, @@ -173,12 +395,14 @@ if (!bprm->sh_bang) { char * passed_p; - sprintf(passed_fileno, "%d", elf_exec_fileno); - passed_p = passed_fileno; + if(interpreter_type == INTERPRETER_AOUT) { + sprintf(passed_fileno, "%d", elf_exec_fileno); + passed_p = passed_fileno; - if(elf_interpreter) { - bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); - bprm->argc++; + if(elf_interpreter) { + bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); + bprm->argc++; + }; }; if (!bprm->p) { if(elf_interpreter) { @@ -217,49 +441,27 @@ if(elf_ppnt->p_type == PT_INTERP) { /* Set these up so that we are able to load the interpreter */ - current->brk = ex.a_bss + - (current->end_data = ex.a_data + - (current->end_code = ex.a_text)); - elf_entry = ex.a_entry; - - /* Now load the interpreter into user address space */ - set_fs(old_fs); - - if (N_MAGIC(ex) == OMAGIC) { - do_mmap(NULL, 0, ex.a_text+ex.a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, 32, (char *) 0, - ex.a_text+ex.a_data); - iput(interpreter_inode); - } else if (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC) { - do_mmap(NULL, 0, ex.a_text+ex.a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, - N_TXTOFF(ex) , - (char *) N_TXTADDR(ex), - ex.a_text+ex.a_data); - iput(interpreter_inode); - } else - retval = -1; - - old_fs = get_fs(); - set_fs(get_ds()); - - if(retval >= 0) - do_mmap(NULL, (ex.a_text + ex.a_data + 0xfff) & - 0xfffff000, ex.a_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); + /* Now load the interpreter into user address space */ + set_fs(old_fs); - kfree(elf_interpreter); - - if(retval < 0) { - kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); - return 0; - }; + if(interpreter_type & 1) elf_entry = + load_aout_interp(&interp_ex, interpreter_inode); + + if(interpreter_type & 2) elf_entry = + load_elf_interp(&interp_elf_ex, interpreter_inode); + + old_fs = get_fs(); + set_fs(get_ds()); + + iput(interpreter_inode); + kfree(elf_interpreter); + + if(elf_entry == 0xffffffff) { + printk("Unable to load interpreter\n"); + kfree(elf_phdata); + send_sig(SIGSEGV, current, 0); + return 0; + }; }; @@ -276,6 +478,8 @@ elf_stack = elf_ppnt->p_vaddr & 0xfffff000; #endif + if(!load_addr) + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; k = elf_ppnt->p_vaddr; if(k > start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; @@ -285,14 +489,7 @@ if(end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if(k > elf_brk) elf_brk = k; - - if(status == 0xffffffff) { - set_fs(old_fs); - kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); - return 0; - }; - }; + }; elf_ppnt++; }; set_fs(old_fs); @@ -307,8 +504,15 @@ current->start_stack = p = elf_stack - 4; #endif bprm->p -= MAX_ARG_PAGES*PAGE_SIZE; - bprm->p = (unsigned long) create_tables((char *)bprm->p,bprm->argc,bprm->envc,0); - if(elf_interpreter) current->arg_start += strlen(passed_fileno) + 1; + bprm->p = (unsigned long) + create_elf_tables((char *)bprm->p, + bprm->argc, + bprm->envc, + (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + if(interpreter_type == INTERPRETER_AOUT) + current->arg_start += strlen(passed_fileno) + 1; current->start_brk = current->brk = elf_brk; current->end_code = end_code; current->start_code = start_code; @@ -324,6 +528,13 @@ padzero(elf_bss); + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + regs->eip = elf_entry; /* eip, magic happens :-) */ regs->esp = bprm->p; /* stack pointer */ if (current->flags & PF_PTRACED) @@ -331,8 +542,8 @@ return 0; } -/* This is really simpleminded and specialized - we are loading an a.out library that is given - an ELF header */ +/* This is really simpleminded and specialized - we are loading an + a.out library that is given an ELF header. */ int load_elf_library(int fd){ struct file * file; diff -u +recursive +new-file 0.99pl15/linux/fs/buffer.c linux/fs/buffer.c --- 0.99pl15/linux/fs/buffer.c Wed Dec 1 14:44:15 1993 +++ linux/fs/buffer.c Thu Mar 10 14:20:55 1994 @@ -484,17 +484,15 @@ #endif } - if (!bh && nr_free_pages > 5) { - if (grow_buffers(GFP_BUFFER, size)) - goto repeat; - } - -/* and repeat until we find something good */ if (!bh) { + if (nr_free_pages > 5) + if (grow_buffers(GFP_BUFFER, size)) + goto repeat; if (!grow_buffers(GFP_ATOMIC, size)) sleep_on(&buffer_wait); goto repeat; } + wait_on_buffer(bh); if (bh->b_count || bh->b_size != size) goto repeat; @@ -750,16 +748,14 @@ bh = create_buffers(address, size); if (!bh) return 0; + /* do any of the buffers already exist? punt if so.. */ p = b; for (offset = 0 ; offset < PAGE_SIZE ; offset += size) { block = *(p++); if (!block) goto not_aligned; - tmp = get_hash_table(dev, block, size); - if (tmp) { - brelse(tmp); + if (find_buffer(dev, block, size)) goto not_aligned; - } } tmp = bh; p = b; @@ -920,7 +916,7 @@ do { if (!tmp) return 0; - if (tmp->b_count || tmp->b_dirt || tmp->b_lock) + if (tmp->b_count || tmp->b_dirt || tmp->b_lock || tmp->b_wait) return 0; tmp = tmp->b_this_page; } while (tmp != bh); @@ -956,8 +952,14 @@ bh = free_list; i = nr_buffers >> priority; for ( ; i-- > 0 ; bh = bh->b_next_free) { - if (bh->b_count || !bh->b_this_page) + if (bh->b_count || + (priority >= 5 && + mem_map[MAP_NR((unsigned long) bh->b_data)] > 1)) { + put_last_free(bh); continue; + } + if (!bh->b_this_page) + continue; if (bh->b_lock) if (priority) continue; @@ -973,6 +975,29 @@ return 1; } return 0; +} + +void show_buffers(void) +{ + struct buffer_head * bh; + int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0; + + printk("Buffer memory: %6dkB\n",buffermem>>10); + printk("Buffer heads: %6d\n",nr_buffer_heads); + printk("Buffer blocks: %6d\n",nr_buffers); + bh = free_list; + do { + found++; + if (bh->b_lock) + locked++; + if (bh->b_dirt) + dirty++; + if (bh->b_count) + used++, lastused = found; + bh = bh->b_next_free; + } while (bh != free_list); + printk("Buffer mem: %d buffers, %d used (last=%d), %d locked, %d dirty\n", + found, used, lastused, locked, dirty); } /* diff -u +recursive +new-file 0.99pl15/linux/fs/exec.c linux/fs/exec.c --- 0.99pl15/linux/fs/exec.c Thu Jan 20 14:36:50 1994 +++ linux/fs/exec.c Fri Mar 4 14:10:38 1994 @@ -134,7 +134,11 @@ fs = get_fs(); set_fs(KERNEL_DS); memcpy(corefile,"core.",5); +#if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); +#else + corefile[4] = '\0'; +#endif if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { inode = NULL; goto end_coredump; @@ -688,6 +692,7 @@ retval = fn(&bprm, regs); if (retval == 0) { iput(bprm.inode); + current->did_exec = 1; return 0; } fmt++; diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/CHANGES linux/fs/ext2/CHANGES --- 0.99pl15/linux/fs/ext2/CHANGES Sun Jan 9 16:47:20 1994 +++ linux/fs/ext2/CHANGES Thu Mar 10 18:48:35 1994 @@ -1,3 +1,14 @@ +Changes from version 0.4b to version 0.5 +======================================== + - New superblock fields: s_lastcheck and s_checkinterval added + by Uwe Ohse to implement timedependent checks + of the file system + - Real random numbers for secure rm added by Pierre del Perugia + + - The mount warnings related to the state of a fs are not printed + if the fs is mounted read-only, idea by Nick Holloway + + Changes from version 0.4a to version 0.4b ========================================= - Copyrights changed to include the name of my laboratory. diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- 0.99pl15/linux/fs/ext2/balloc.c Thu Feb 3 13:22:23 1994 +++ linux/fs/ext2/balloc.c Tue Feb 22 08:15:49 1994 @@ -359,16 +359,13 @@ ext2_debug ("goal=%lu.\n", goal); - if (goal < es->s_first_data_block || goal >= es->s_blocks_count) { - ext2_warning (sb, "ext2_new_block", - "Goal out of bounds: %lu", goal); - goal = es->s_first_data_block; - } repeat: /* * First, test whether the goal block is free. */ - i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb)); + if (goal < es->s_first_data_block || goal >= es->s_blocks_count) + goal = es->s_first_data_block; + i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb); gdp = get_group_desc (sb, i, &bh2); if (gdp->bg_free_blocks_count > 0) { j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb)); @@ -608,6 +605,7 @@ struct buffer_head * bh; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; + unsigned long desc_blocks; int bitmap_nr; struct ext2_group_desc * gdp; int i, j; @@ -617,6 +615,8 @@ desc_count = 0; bitmap_count = 0; gdp = NULL; + desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / + EXT2_DESC_PER_BLOCK(sb); for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_blocks_count; @@ -623,6 +623,16 @@ bitmap_nr = load_block_bitmap (sb, i); bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + if (!test_bit (0, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Superblock in group %d is marked free", i); + + for (j = 0; j < desc_blocks; j++) + if (!test_bit (j + 1, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Descriptor block #%d in group " + "%d is marked free", j, i); + if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", "Block bitmap for group %d is marked free", @@ -635,9 +645,9 @@ for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++) if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data)) - ext2_error (sb, "ext2_check_blocks_bitmap", - "Block #%d of the inode table in group %d " - "is marked free", j, i); + ext2_error (sb, "ext2_check_blocks_bitmap", + "Block #%d of the inode table in " + "group %d is marked free", j, i); x = ext2_count_free (bh, sb->s_blocksize); if (gdp->bg_free_blocks_count != x) diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- 0.99pl15/linux/fs/ext2/inode.c Sat Jan 8 14:35:10 1994 +++ linux/fs/ext2/inode.c Mon Feb 7 15:32:00 1994 @@ -69,10 +69,11 @@ { #ifdef EXT2_PREALLOCATE if (inode->u.ext2_i.i_prealloc_count) { + int i = inode->u.ext2_i.i_prealloc_count; + inode->u.ext2_i.i_prealloc_count = 0; ext2_free_blocks (inode->i_sb, inode->u.ext2_i.i_prealloc_block, - inode->u.ext2_i.i_prealloc_count); - inode->u.ext2_i.i_prealloc_count = 0; + i); } #endif } diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- 0.99pl15/linux/fs/ext2/namei.c Fri Dec 31 11:59:50 1993 +++ linux/fs/ext2/namei.c Fri Feb 11 14:55:41 1994 @@ -653,15 +653,13 @@ retval = -ENOTDIR; goto end_rmdir; } - if (!empty_dir (inode)) { + down(&inode->i_sem); + if (!empty_dir (inode)) retval = -ENOTEMPTY; - goto end_rmdir; - } - if (de->inode != inode->i_ino) { + else if (de->inode != inode->i_ino) retval = -ENOENT; - goto end_rmdir; - } - if (inode->i_count > 1) { + else { + if (inode->i_count > 1) { /* * Are we deleting the last instance of a busy directory? * Better clean up if so. @@ -669,9 +667,11 @@ * Make directory empty (it will be truncated when finally * dereferenced). This also inhibits ext2_add_entry. */ - inode->i_size = 0; + inode->i_size = 0; + } + retval = ext2_delete_entry (de, bh); } - retval = ext2_delete_entry (de, bh); + up(&inode->i_sem); if (retval) goto end_rmdir; bh->b_dirt = 1; diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/super.c linux/fs/ext2/super.c --- 0.99pl15/linux/fs/ext2/super.c Sun Jan 9 16:47:21 1994 +++ linux/fs/ext2/super.c Thu Mar 10 18:48:35 1994 @@ -267,17 +267,21 @@ static void ext2_setup_super (struct super_block * sb, struct ext2_super_block * es) { - if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) - printk ("EXT2-fs warning: mounting unchecked fs, " - "running e2fsck is recommended\n"); - else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) - printk ("EXT2-fs warning: mounting fs with errors, " - "running e2fsck is recommended\n"); - else if (es->s_max_mnt_count >= 0 && - es->s_mnt_count >= (unsigned short) es->s_max_mnt_count) - printk ("EXT2-fs warning: maximal mount count reached, " - "running e2fsck is recommended\n"); if (!(sb->s_flags & MS_RDONLY)) { + if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + printk ("EXT2-fs warning: mounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) + printk ("EXT2-fs warning: mounting fs with errors, " + "running e2fsck is recommended\n"); + else if (es->s_max_mnt_count >= 0 && + es->s_mnt_count >= (unsigned short) es->s_max_mnt_count) + printk ("EXT2-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + else if (es->s_checkinterval && + (es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME)) + printk ("EXT2-fs warning: checktime reached, " + "running e2fsck is recommended\n"); es->s_state &= ~EXT2_VALID_FS; if (!es->s_max_mnt_count) es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c --- 0.99pl15/linux/fs/ext2/truncate.c Sat Jan 8 14:35:10 1994 +++ linux/fs/ext2/truncate.c Tue Feb 22 08:15:49 1994 @@ -12,6 +12,11 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +/* + * Real random numbers for secure rm added 94/02/18 + * Idea from Pierre del Perugia + */ + #include #include #include @@ -28,6 +33,10 @@ :"a" (value), "c" (size / 4), "D" ((long) (addr)) \ :"cx", "di") +static int ext2_secrm_seed = 152; /* Random generator base */ + +#define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1) + /* * Truncate has the most races in the whole filesystem: coding it is * a pain in the a**. Especially as I don't do any locking... @@ -80,7 +89,7 @@ inode->i_dirt = 1; if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { clear_block (bh->b_data, inode->i_sb->s_blocksize, - CURRENT_TIME); + RANDOM_INT); bh->b_dirt = 1; } brelse (bh); @@ -156,7 +165,7 @@ ind_bh->b_dirt = 1; if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { clear_block (bh->b_data, inode->i_sb->s_blocksize, - CURRENT_TIME); + RANDOM_INT); bh->b_dirt = 1; } brelse (bh); diff -u +recursive +new-file 0.99pl15/linux/fs/hpfs/README linux/fs/hpfs/README --- 0.99pl15/linux/fs/hpfs/README +++ linux/fs/hpfs/README Wed Feb 23 09:45:39 1994 @@ -0,0 +1,25 @@ +Linux can read, but not write, OS/2 HPFS partitions. + +Mount options are the same as for msdos partitions. + + uid=nnn All files in the partition will be owned by user id nnn. + gid=nnn All files in the partition will be in group nnn. + umask=nnn The permission mask (see umask(1)) for the partition. + conv=binary Data is returned exactly as is, with CRLF's. [default] + conv=text (Carriage return, line feed) is replaced with newline. + conv=auto Chooses, file by file, conv=binary or conv=text (by guessing) + +There is one mount option unique to HPFS. + + case=lower Convert file names to lower case. [default] + case=asis Return file names as is, in mixed case. + +Case is not significant in filename matching, like real HPFS. + + +Command line example + mkdir -p /os2/c + mount -t hpfs -o uid=100,gid=100 /dev/sda6 /os2/c + +/etc/fstab example + /dev/sdb5 /d/f hpfs ro,uid=402,gid=402,umask=002 diff -u +recursive +new-file 0.99pl15/linux/fs/hpfs/hpfs.h linux/fs/hpfs/hpfs.h --- 0.99pl15/linux/fs/hpfs/hpfs.h Wed Dec 1 14:44:15 1993 +++ linux/fs/hpfs/hpfs.h Wed Feb 23 09:45:39 1994 @@ -131,7 +131,7 @@ /* The code page info pointed to by the spare block consists of an index block and blocks containing character maps. The following is pretty - sketchy, but Linux is Latin-1 so it doesn't matter. */ + sketchy, but Linux doesn't use code pages so it doesn't matter. */ /* block pointed to by spareblock->code_page_dir */ diff -u +recursive +new-file 0.99pl15/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c --- 0.99pl15/linux/fs/hpfs/hpfs_fs.c Wed Dec 1 14:44:15 1993 +++ linux/fs/hpfs/hpfs_fs.c Wed Feb 23 09:45:40 1994 @@ -6,7 +6,7 @@ * Chris Smith 1993 * * Sources & references: - * Duncan, _Design ... of HPFS_, MSSJ 4(5) (C) 1989 Microsoft Corp + * Duncan, _Design ... of HPFS_, MSJ 4(5) (C) 1989 Microsoft Corp * linux/fs/minix Copyright (C) 1991, 1992, 1993 Linus Torvalds * linux/fs/msdos Written 1992, 1993 by Werner Almesberger * linux/fs/isofs Copyright (C) 1991 Eric Youngdale @@ -124,7 +124,7 @@ static void hpfs_read_inode(struct inode *); static void hpfs_put_super(struct super_block *); static void hpfs_statfs(struct super_block *, struct statfs *); -static int hpfs_remount_fs(struct super_block *, int *); +static int hpfs_remount_fs(struct super_block *, int *, char *); static const struct super_operations hpfs_sops = { @@ -752,7 +752,7 @@ * remount. Don't let read only be turned off. */ -static int hpfs_remount_fs(struct super_block *s, int *flags) +static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) { if (!(*flags & MS_RDONLY)) return -EINVAL; diff -u +recursive +new-file 0.99pl15/linux/fs/inode.c linux/fs/inode.c --- 0.99pl15/linux/fs/inode.c Wed Feb 2 08:45:07 1994 +++ linux/fs/inode.c Fri Feb 11 14:13:07 1994 @@ -384,6 +384,7 @@ clear_inode(inode); inode->i_count = 1; inode->i_nlink = 1; + inode->i_sem.count = 1; nr_free_inodes--; if (nr_free_inodes < 0) { printk ("VFS: get_empty_inode: bad free inode count.\n"); diff -u +recursive +new-file 0.99pl15/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- 0.99pl15/linux/fs/isofs/dir.c Sun Dec 12 12:26:43 1993 +++ linux/fs/isofs/dir.c Tue Mar 1 18:47:38 1994 @@ -191,6 +191,8 @@ for (i = 0; i < dlen && i < NAME_MAX; i++) { if (!(c = dpnt[i])) break; if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */ + if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1') + break; /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */ if (c == ';' && i == dlen-2 && de->name[i+1] == '1') break; /* Drop trailing ';1' */ if (c == ';') c = '.'; /* Convert remaining ';' to '.' */ diff -u +recursive +new-file 0.99pl15/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- 0.99pl15/linux/fs/isofs/inode.c Sat Jan 29 14:55:06 1994 +++ linux/fs/isofs/inode.c Sun Mar 13 20:39:14 1994 @@ -344,7 +344,7 @@ if (!(bh=bread(inode->i_dev,block, bufsize))) { printk("unable to read i-node block"); goto fail; - }; + } pnt = ((unsigned char *) bh->b_data + (inode->i_ino & (bufsize - 1))); @@ -353,18 +353,23 @@ if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){ cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL); + if (cpnt == NULL) { + printk(KERN_INFO "NoMem ISO inode %d\n",inode->i_ino); + brelse(bh); + goto fail; + } memcpy(cpnt, bh->b_data, bufsize); brelse(bh); if (!(bh = bread(inode->i_dev,++block, bufsize))) { - kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS); + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); printk("unable to read i-node block"); goto fail; - }; + } memcpy((char *)cpnt + bufsize, bh->b_data, bufsize); pnt = ((unsigned char *) cpnt + (inode->i_ino & (bufsize - 1))); raw_inode = ((struct iso_directory_record *) pnt); - }; + } inode->i_mode = S_IRUGO; /* Everybody gets to read the file. */ inode->i_nlink = 1; @@ -383,7 +388,7 @@ break; if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';') inode->i_mode |= S_IXUGO; /* execute permission */ - }; + } inode->i_uid = 0; inode->i_gid = 0; inode->i_size = isonum_733 (raw_inode->size); @@ -394,7 +399,7 @@ inode->i_sb->u.isofs_sb.s_cruft == 'n') { printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n"); inode->i_sb->u.isofs_sb.s_cruft = 'y'; - }; + } /* Some dipshit decided to store some other bit of information in the high byte of the file length. Catch this and holler. WARNING: this will make @@ -404,12 +409,12 @@ inode->i_size & 0xff000000){ /* printk("Illegal format on cdrom. Pester manufacturer.\n"); */ inode->i_size &= 0x00ffffff; - }; + } if (raw_inode->interleave[0]) { printk("Interleaved files not (yet) supported.\n"); inode->i_size = 0; - }; + } #ifdef DEBUG /* I have no idea what extended attributes are used for, so @@ -458,8 +463,7 @@ case 'm': inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT_M; /* File type */ break; - }; - + } /* Now test for possible Rock Ridge extensions which will override some of these numbers in the inode structure. */ @@ -472,11 +476,6 @@ #endif brelse(bh); - if (cpnt) { - kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS); - cpnt = NULL; - }; - inode->i_op = NULL; if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && isonum_723 (raw_inode->volume_sequence_number) != 1) { @@ -494,6 +493,10 @@ inode->i_op = &blkdev_inode_operations; else if (S_ISFIFO(inode->i_mode)) init_fifo(inode); + } + if (cpnt) { + kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS); + cpnt = NULL; } return; fail: diff -u +recursive +new-file 0.99pl15/linux/fs/isofs/rock.c linux/fs/isofs/rock.c --- 0.99pl15/linux/fs/isofs/rock.c Sat Jan 8 14:35:11 1994 +++ linux/fs/isofs/rock.c Tue Mar 1 18:45:15 1994 @@ -316,6 +316,7 @@ struct SL_component * slp; slen = rr->len - 5; slp = &rr->u.SL.link; + inode->i_size = 0; while (slen > 1){ rootflag = 0; switch(slp->flags &~1){ diff -u +recursive +new-file 0.99pl15/linux/fs/namei.c linux/fs/namei.c --- 0.99pl15/linux/fs/namei.c Wed Dec 1 14:44:15 1993 +++ linux/fs/namei.c Sun Feb 13 14:01:51 1994 @@ -275,7 +275,7 @@ struct inode ** res_inode, struct inode * base) { const char * basename; - int namelen,error,i; + int namelen,error; struct inode * dir, *inode; struct task_struct ** p; @@ -297,43 +297,35 @@ *res_inode=dir; return 0; } - for (i = 0; i < 5; i++) { /* races... */ - dir->i_count++; /* lookup eats the dir */ + dir->i_count++; /* lookup eats the dir */ + if (flag & O_CREAT) { + down(&dir->i_sem); error = lookup(dir,basename,namelen,&inode); - if (!error) - break; - if (!(flag & O_CREAT)) { - iput(dir); - return error; - } - if (!permission(dir,MAY_WRITE | MAY_EXEC)) { - iput(dir); - return -EACCES; - } - if (!dir->i_op || !dir->i_op->create) { - iput(dir); - return -EACCES; - } - if (IS_RDONLY(dir)) { - iput(dir); - return -EROFS; - } - dir->i_count++; /* create eats the dir */ - error = dir->i_op->create(dir,basename,namelen,mode,res_inode); - if (error != -EEXIST) { + if (!error) { + if (flag & O_EXCL) { + iput(inode); + error = -EEXIST; + } + } else if (!permission(dir,MAY_WRITE | MAY_EXEC)) + error = -EACCES; + else if (!dir->i_op || !dir->i_op->create) + error = -EACCES; + else if (IS_RDONLY(dir)) + error = -EROFS; + else { + dir->i_count++; /* create eats the dir */ + error = dir->i_op->create(dir,basename,namelen,mode,res_inode); + up(&dir->i_sem); iput(dir); return error; } - } + up(&dir->i_sem); + } else + error = lookup(dir,basename,namelen,&inode); if (error) { iput(dir); return error; } - if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { - iput(dir); - iput(inode); - return -EEXIST; - } error = follow_link(dir,inode,flag,mode,&inode); if (error) return error; @@ -415,7 +407,10 @@ iput(dir); return -EPERM; } - return dir->i_op->mknod(dir,basename,namelen,mode,dev); + down(&dir->i_sem); + error = dir->i_op->mknod(dir,basename,namelen,mode,dev); + up(&dir->i_sem); + return error; } asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev) @@ -467,7 +462,10 @@ iput(dir); return -EPERM; } - return dir->i_op->mkdir(dir,basename,namelen,mode); + down(&dir->i_sem); + error = dir->i_op->mkdir(dir,basename,namelen,mode); + up(&dir->i_sem); + return error; } asmlinkage int sys_mkdir(const char * pathname, int mode) @@ -590,7 +588,10 @@ iput(dir); return -EPERM; } - return dir->i_op->symlink(dir,basename,namelen,oldname); + down(&dir->i_sem); + error = dir->i_op->symlink(dir,basename,namelen,oldname); + up(&dir->i_sem); + return error; } asmlinkage int sys_symlink(const char * oldname, const char * newname) @@ -646,7 +647,10 @@ iput(oldinode); return -EPERM; } - return dir->i_op->link(oldinode, dir, basename, namelen); + down(&dir->i_sem); + error = dir->i_op->link(oldinode, dir, basename, namelen); + up(&dir->i_sem); + return error; } asmlinkage int sys_link(const char * oldname, const char * newname) @@ -719,8 +723,11 @@ iput(new_dir); return -EPERM; } - return old_dir->i_op->rename(old_dir, old_base, old_len, + down(&new_dir->i_sem); + error = old_dir->i_op->rename(old_dir, old_base, old_len, new_dir, new_base, new_len); + up(&new_dir->i_sem); + return error; } asmlinkage int sys_rename(const char * oldname, const char * newname) diff -u +recursive +new-file 0.99pl15/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- 0.99pl15/linux/fs/nfs/proc.c Wed Dec 29 06:52:29 1993 +++ linux/fs/nfs/proc.c Mon Feb 14 12:48:36 1994 @@ -1,7 +1,7 @@ /* * linux/fs/nfs/proc.c * - * Copyright (C) 1992 Rick Sladkey + * Copyright (C) 1992, 1993, 1994 Rick Sladkey * * OS-independent nfs remote procedure call functions */ @@ -41,7 +41,7 @@ #endif /* !NFS_PROC_DEBUG */ -static int *nfs_rpc_header(int *p, int procedure); +static int *nfs_rpc_header(int *p, int procedure, int ruid); static int *nfs_rpc_verify(int *p); static int nfs_stat_to_errno(int stat); @@ -192,11 +192,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call getattr\n"); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_GETATTR); +retry: + p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid); p = xdr_encode_fhandle(p, fhandle); if ((status = nfs_rpc_call(server, p0, p)) < 0) { nfs_rpc_free(p0); @@ -208,8 +210,13 @@ p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply getattr\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply getattr failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -219,11 +226,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call setattr\n"); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_SETATTR); +retry: + p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid); p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_sattr(p, sattr); if ((status = nfs_rpc_call(server, p0, p)) < 0) { @@ -236,8 +245,13 @@ p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply setattr\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply setattr failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -247,6 +261,7 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call lookup %s\n", name); #ifdef NFS_PROC_DEBUG @@ -255,7 +270,8 @@ #endif if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_LOOKUP); +retry: + p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); if ((status = nfs_rpc_call(server, p0, p)) < 0) { @@ -269,8 +285,13 @@ p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply lookup\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply lookup failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -280,11 +301,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call readlink\n"); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_READLINK); +retry: + p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid); p = xdr_encode_fhandle(p, fhandle); if ((status = nfs_rpc_call(server, p0, p)) < 0) { nfs_rpc_free(p0); @@ -300,8 +323,13 @@ else PRINTK("NFS reply readlink %s\n", res); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply readlink failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -311,12 +339,14 @@ { int *p, *p0; int status; + int ruid = 0; int len = 0; /* = 0 is for gcc */ PRINTK("NFS call read %d @ %d\n", count, offset); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_READ); +retry: + p = nfs_rpc_header(p0, NFSPROC_READ, ruid); p = xdr_encode_fhandle(p, fhandle); *p++ = htonl(offset); *p++ = htonl(count); @@ -336,8 +366,13 @@ else PRINTK("NFS reply read %d\n", len); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply read failed = %d\n", status); + } nfs_rpc_free(p0); return (status == NFS_OK) ? len : -nfs_stat_to_errno(status); } @@ -347,11 +382,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call write %d @ %d\n", count, offset); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_WRITE); +retry: + p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid); p = xdr_encode_fhandle(p, fhandle); *p++ = htonl(offset); /* traditional, could be any value */ *p++ = htonl(offset); @@ -367,8 +404,13 @@ p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply write\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply write failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -379,11 +421,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call create %s\n", name); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_CREATE); +retry: + p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_sattr(p, sattr); @@ -398,8 +442,13 @@ p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply create\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply create failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -408,11 +457,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call remove %s\n", name); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_REMOVE); +retry: + p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); if ((status = nfs_rpc_call(server, p0, p)) < 0) { @@ -424,8 +475,13 @@ else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply remove\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply remove failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -436,11 +492,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call rename %s -> %s\n", old_name, new_name); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_RENAME); +retry: + p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid); p = xdr_encode_fhandle(p, old_dir); p = xdr_encode_string(p, old_name); p = xdr_encode_fhandle(p, new_dir); @@ -454,8 +512,13 @@ else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply rename\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply rename failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -465,11 +528,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call link %s\n", name); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_LINK); +retry: + p = nfs_rpc_header(p0, NFSPROC_LINK, ruid); p = xdr_encode_fhandle(p, fhandle); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); @@ -482,8 +547,13 @@ else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply link\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply link failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -493,11 +563,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call symlink %s -> %s\n", name, path); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_SYMLINK); +retry: + p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_string(p, path); @@ -511,8 +583,13 @@ else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply symlink\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply symlink failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -523,11 +600,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call mkdir %s\n", name); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_MKDIR); +retry: + p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); p = xdr_encode_sattr(p, sattr); @@ -542,8 +621,13 @@ p = xdr_decode_fattr(p, fattr); PRINTK("NFS reply mkdir\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply mkdir failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -552,11 +636,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call rmdir %s\n", name); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_RMDIR); +retry: + p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid); p = xdr_encode_fhandle(p, dir); p = xdr_encode_string(p, name); if ((status = nfs_rpc_call(server, p0, p)) < 0) { @@ -568,8 +654,13 @@ else if ((status = ntohl(*p++)) == NFS_OK) { PRINTK("NFS reply rmdir\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply rmdir failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -579,6 +670,7 @@ { int *p, *p0; int status; + int ruid = 0; int i = 0; /* = 0 is for gcc */ int size; int eof; @@ -587,7 +679,8 @@ size = server->rsize; if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_READDIR); +retry: + p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid); p = xdr_encode_fhandle(p, fhandle); *p++ = htonl(cookie); *p++ = htonl(size); @@ -615,8 +708,13 @@ eof ? "eof" : ""); } } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply readdir failed = %d\n", status); + } nfs_rpc_free(p0); return (status == NFS_OK) ? i : -nfs_stat_to_errno(status); } @@ -626,11 +724,13 @@ { int *p, *p0; int status; + int ruid = 0; PRINTK("NFS call statfs\n"); if (!(p0 = nfs_rpc_alloc())) return -EIO; - p = nfs_rpc_header(p0, NFSPROC_STATFS); +retry: + p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid); p = xdr_encode_fhandle(p, fhandle); if ((status = nfs_rpc_call(server, p0, p)) < 0) { nfs_rpc_free(p0); @@ -642,8 +742,13 @@ p = xdr_decode_fsinfo(p, res); PRINTK("NFS reply statfs\n"); } - else + else { + if (!ruid && current->euid == 0 && current->uid != 0) { + ruid = 1; + goto retry; + } PRINTK("NFS reply statfs failed = %d\n", status); + } nfs_rpc_free(p0); return -nfs_stat_to_errno(status); } @@ -652,7 +757,7 @@ * Here are a few RPC-assist functions. */ -static int *nfs_rpc_header(int *p, int procedure) +static int *nfs_rpc_header(int *p, int procedure, int ruid) { int *p1, *p2; int i; @@ -673,7 +778,7 @@ p1 = p++; *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */ p = xdr_encode_string(p, (char *) sys); - *p++ = htonl(current->euid); + *p++ = htonl(ruid ? current->uid : current->euid); *p++ = htonl(current->egid); p2 = p++; for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++) diff -u +recursive +new-file 0.99pl15/linux/fs/nfs/sock.c linux/fs/nfs/sock.c --- 0.99pl15/linux/fs/nfs/sock.c Wed Dec 1 14:44:15 1993 +++ linux/fs/nfs/sock.c Tue Mar 1 08:03:41 1994 @@ -108,7 +108,7 @@ continue; if (server->flags & NFS_MOUNT_SOFT) { printk("NFS server %s not responding, " - "timed out", server_name); + "timed out\n", server_name); result = -EIO; break; } diff -u +recursive +new-file 0.99pl15/linux/fs/proc/array.c linux/fs/proc/array.c --- 0.99pl15/linux/fs/proc/array.c Thu Feb 3 13:18:45 1994 +++ linux/fs/proc/array.c Thu Feb 17 10:36:54 1994 @@ -42,10 +42,10 @@ if (count < 0) return -EINVAL; - if (p >= high_memory) + if (p >= high_memory + PAGE_SIZE) return 0; - if (count > high_memory - p) - count = high_memory - p; + if (count > high_memory + PAGE_SIZE - p) + count = high_memory + PAGE_SIZE - p; read = 0; if (p < sizeof(struct user) && count > 0) { @@ -441,7 +441,7 @@ return sz; } -asmlinkage int get_module_list( char *); +extern int get_module_list(char *); static int array_read(struct inode * inode, struct file * file,char * buf, int count) { diff -u +recursive +new-file 0.99pl15/linux/fs/proc/inode.c linux/fs/proc/inode.c --- 0.99pl15/linux/fs/proc/inode.c Wed Dec 1 14:44:15 1993 +++ linux/fs/proc/inode.c Wed Feb 23 09:47:59 1994 @@ -84,7 +84,8 @@ inode->i_nlink = 1; inode->i_size = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_blocks = inode->i_blksize = 0; + inode->i_blocks = 0; + inode->i_blksize = 1024; ino = inode->i_ino; pid = ino >> 16; p = task[0]; diff -u +recursive +new-file 0.99pl15/linux/fs/proc/link.c linux/fs/proc/link.c --- 0.99pl15/linux/fs/proc/link.c Thu Feb 3 14:47:55 1994 +++ linux/fs/proc/link.c Fri Mar 11 11:28:10 1994 @@ -111,6 +111,10 @@ unsigned int dev,ino; char buf[64]; + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } i = proc_follow_link(NULL, inode, 0, 0, &inode); if (i) return i; diff -u +recursive +new-file 0.99pl15/linux/fs/select.c linux/fs/select.c --- 0.99pl15/linux/fs/select.c Wed Dec 1 14:44:15 1993 +++ linux/fs/select.c Thu Feb 24 08:06:53 1994 @@ -223,11 +223,10 @@ i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); if (i) return i; - timeout = jiffies; - timeout += ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ)); + timeout = ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ)); timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ; - if (timeout <= jiffies) - timeout = 0; + if (timeout) + timeout += jiffies + 1; } current->timeout = timeout; i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex); diff -u +recursive +new-file 0.99pl15/linux/fs/super.c linux/fs/super.c --- 0.99pl15/linux/fs/super.c Tue Feb 1 07:58:24 1994 +++ linux/fs/super.c Tue Mar 1 08:27:32 1994 @@ -380,7 +380,7 @@ return retval; } -static int copy_mount_options (char * data, unsigned long *where) +static int copy_mount_options (const void * data, unsigned long *where) { int i; unsigned long page; diff -u +recursive +new-file 0.99pl15/linux/include/asm/bitops.h linux/include/asm/bitops.h --- 0.99pl15/linux/include/asm/bitops.h Wed Dec 1 14:44:15 1993 +++ linux/include/asm/bitops.h Fri Feb 11 09:25:54 1994 @@ -89,7 +89,7 @@ addr += nr >> 5; mask = 1 << (nr & 0x1f); cli(); - retval = (mask & *addr) == 0; + retval = (mask & *addr) != 0; *addr &= ~mask; sti(); return retval; diff -u +recursive +new-file 0.99pl15/linux/include/asm/io.h linux/include/asm/io.h --- 0.99pl15/linux/include/asm/io.h Wed Jan 5 07:41:12 1994 +++ linux/include/asm/io.h Fri Feb 4 09:59:16 1994 @@ -2,6 +2,19 @@ #define _ASM_IO_H /* + * This file contains the definitions for the x86 IO instructions + * inb/inw/inl/outb/outw/outl and the "string versions" of the same + * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" + * versions of the single-IO instructions (inb_p/inw_p/..). + * + * This file is not meant to be obfuscating: it's just complicated + * to (a) handle it all in a way that makes gcc able to optimize it + * as well as possible and (b) trying to avoid writing the same thing + * over and over again with slight variations and possibly making a + * mistake somewhere. + */ + +/* * Thanks to James van Artsdalen for a better timing-fix than * the two short jumps: using outb's to a nonexistent port seems * to guarantee better timings even on fast machines. diff -u +recursive +new-file 0.99pl15/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- 0.99pl15/linux/include/linux/ext2_fs.h Sun Jan 9 16:47:21 1994 +++ linux/include/linux/ext2_fs.h Thu Mar 10 18:48:36 1994 @@ -52,8 +52,8 @@ /* * The second extended file system version */ -#define EXT2FS_DATE "94/01/08" -#define EXT2FS_VERSION "0.4b" +#define EXT2FS_DATE "94/03/10" +#define EXT2FS_VERSION "0.5" /* * Debug code @@ -262,6 +262,7 @@ * Maximal mount counts between two filesystem checks */ #define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ /* * Behaviour when detecting errors @@ -294,7 +295,9 @@ unsigned short s_state; /* File system state */ unsigned short s_errors; /* Behaviour when detecting errors */ unsigned short s_pad; - unsigned long s_reserved[240]; /* Padding to the end of the block */ + unsigned long s_lastcheck; /* time of last check */ + unsigned long s_checkinterval; /* max. time between checks */ + unsigned long s_reserved[238]; /* Padding to the end of the block */ }; /* diff -u +recursive +new-file 0.99pl15/linux/include/linux/fs.h linux/include/linux/fs.h --- 0.99pl15/linux/include/linux/fs.h Mon Jan 3 09:45:26 1994 +++ linux/include/linux/fs.h Wed Feb 16 09:29:36 1994 @@ -171,6 +171,7 @@ time_t i_ctime; unsigned long i_blksize; unsigned long i_blocks; + struct semaphore i_sem; struct inode_operations * i_op; struct super_block * i_sb; struct wait_queue * i_wait; @@ -319,12 +320,13 @@ extern void putname(char * name); extern int register_blkdev(unsigned int, const char *, struct file_operations *); +extern int unregister_blkdev(unsigned int major, const char * name); extern int blkdev_open(struct inode * inode, struct file * filp); extern struct file_operations def_blk_fops; extern struct inode_operations blkdev_inode_operations; extern int register_chrdev(unsigned int, const char *, struct file_operations *); -extern int unregister_chrdev( unsigned int major, const char * name); +extern int unregister_chrdev(unsigned int major, const char * name); extern int chrdev_open(struct inode * inode, struct file * filp); extern struct file_operations def_chr_fops; extern struct inode_operations chrdev_inode_operations; @@ -392,6 +394,7 @@ extern void put_super(dev_t dev); extern dev_t ROOT_DEV; +extern void show_buffers(void); extern void mount_root(void); extern int char_read(struct inode *, struct file *, char *, int); diff -u +recursive +new-file 0.99pl15/linux/include/linux/if_ether.h linux/include/linux/if_ether.h --- 0.99pl15/linux/include/linux/if_ether.h Thu Feb 3 15:14:03 1994 +++ linux/include/linux/if_ether.h Fri Feb 18 11:20:46 1994 @@ -5,9 +5,10 @@ * * Global definitions for the Ethernet IEE 802.3 interface. * - * Version: @(#)if_ether.h 1.0.1 03/15/93 + * Version: @(#)if_ether.h 1.0.1a 02/08/94 * * Author: Fred N. van Kempen, + * Donald Becker, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,13 +19,15 @@ #define _LINUX_IF_ETHER_H -/* IEEE 802.3 Ethernet magic constants. */ -#define ETH_ALEN 6 /* #bytes in eth addr */ -#define ETH_HLEN 14 /* #bytes in eth header */ -#define ETH_ZLEN 64 /* min #bytes in frame */ -#define ETH_FLEN 1536 /* max #bytes in frame */ -#define ETH_DLEN (ETH_FLEN - ETH_HLEN) /* max #bytes of data */ +/* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble + and FCS/CRC (frame check sequence). */ +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_HLEN 14 /* Total octets in header. */ +#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ +#define ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ + /* These are the defined Ethernet Protocol ID's. */ #define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ #define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */ @@ -38,9 +41,6 @@ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ -/* Define the Ethernet Broadcast Address (48 bits set to "1"). */ -#define ETH_A_BCAST "\377\377\377\377\377\377" - /* This is an Ethernet frame header. */ struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ @@ -47,21 +47,6 @@ unsigned char h_source[ETH_ALEN]; /* source ether addr */ unsigned short h_proto; /* packet type ID field */ }; - -/* This is the complete Ethernet frame. */ -struct ethframe { - struct ethhdr f_hdr; /* frame header */ - char f_data[ETH_DLEN]; /* frame data (variable)*/ -}; - - -/* Receiver modes */ -#define ETH_MODE_MONITOR 1 /* Monitor mode - no receive */ -#define ETH_MODE_PHYS 2 /* Physical address receive only */ -#define ETH_MODE_BCAST 3 /* Broadcast receive + mode 2 */ -#define ETH_MODE_MCAST 4 /* Multicast receive + mode 3 */ -#define ETH_MODE_PROMISC 5 /* Promiscuous mode - receive all */ - /* Ethernet statistics collection data. */ struct enet_statistics{ diff -u +recursive +new-file 0.99pl15/linux/include/linux/in_systm.h linux/include/linux/in_systm.h --- 0.99pl15/linux/include/linux/in_systm.h +++ linux/include/linux/in_systm.h Mon Feb 14 18:51:45 1994 @@ -0,0 +1,32 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Miscellaneous internetwork definitions for kernel. + * + * Version: @(#)in_systm.h 1.0.0 12/17/93 + * + * Authors: Original taken from Berkeley BSD UNIX 4.3-RENO. + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IN_SYSTM_H +#define _LINUX_IN_SYSTM_H + +/* + * Network types. + * The n_ types are network-order variants of their natural + * equivalents. The Linux kernel NET-2 code does not use + * them (yet), but it might in the future. This is mostly + * there for compatibility with BSD user-level programs. + */ +typedef u_short n_short; /* short as received from the net */ +typedef u_long n_long; /* long as received from the net */ +typedef u_long n_time; /* ms since 00:00 GMT, byte rev */ + +#endif /* _LINUX_IN_SYSTM_H */ diff -u +recursive +new-file 0.99pl15/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- 0.99pl15/linux/include/linux/interrupt.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/interrupt.h Mon Mar 7 14:34:14 1994 @@ -24,17 +24,17 @@ extern inline void mark_bh(int nr) { - __asm__ __volatile__("btsl %1,%0":"=m" (bh_active):"ir" (nr)); + __asm__ __volatile__("orl %1,%0":"=m" (bh_active):"ir" (1<___eax) -#define EBX (info->___ebx) -#define ECX (info->___ecx) -#define EDX (info->___edx) -#define ESI (info->___esi) -#define EDI (info->___edi) -#define EBP (info->___ebp) -#define ESP (info->___esp) -#define EIP (info->___eip) -#define ORIG_EIP (info->___orig_eip) -#define EFLAGS (info->___eflags) -#define DS (*(unsigned short *) &(info->___ds)) -#define ES (*(unsigned short *) &(info->___es)) -#define FS (*(unsigned short *) &(info->___fs)) -#define CS (*(unsigned short *) &(info->___cs)) -#define SS (*(unsigned short *) &(info->___ss)) -#endif - -void __math_abort(struct info *, unsigned int); - -#define math_abort(x,y) \ -(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y))) #endif diff -u +recursive +new-file 0.99pl15/linux/include/linux/mm.h linux/include/linux/mm.h --- 0.99pl15/linux/include/linux/mm.h Tue Jan 25 11:56:54 1994 +++ linux/include/linux/mm.h Mon Feb 14 21:27:12 1994 @@ -11,7 +11,7 @@ int __verify_write(unsigned long addr, unsigned long count); -extern inline int verify_area(int type, void * addr, unsigned long size) +extern inline int verify_area(int type, const void * addr, unsigned long size) { if (TASK_SIZE <= (unsigned long) addr) return -EFAULT; @@ -81,7 +81,7 @@ extern int nr_secondary_pages; extern unsigned long secondary_page_list; -#define MAX_SECONDARY_PAGES 10 +#define MAX_SECONDARY_PAGES 20 /* * This is timing-critical - most of the time in getting a new page diff -u +recursive +new-file 0.99pl15/linux/include/linux/msg.h linux/include/linux/msg.h --- 0.99pl15/linux/include/linux/msg.h Thu Dec 23 13:28:50 1993 +++ linux/include/linux/msg.h Sun Mar 6 16:10:53 1994 @@ -52,7 +52,7 @@ }; #define MSGMNI 128 /* <= 1K */ /* max # of msg queue identifiers */ -#define MSGMAX 4080 /* <= 4080 */ /* max size of message (bytes) */ +#define MSGMAX 4056 /* <= 4056 */ /* max size of message (bytes) */ #define MSGMNB 16384 /* ? */ /* default max size of a message queue */ /* unused */ diff -u +recursive +new-file 0.99pl15/linux/include/linux/route.h linux/include/linux/route.h --- 0.99pl15/linux/include/linux/route.h Mon Jan 17 14:28:40 1994 +++ linux/include/linux/route.h Sun Feb 13 17:16:51 1994 @@ -21,21 +21,32 @@ #include +/* This structure gets passed by the SIOCADDRTOLD and SIOCDELRTOLD calls. */ +struct old_rtentry { + unsigned long rt_genmask; + struct sockaddr rt_dst; + struct sockaddr rt_gateway; + short rt_flags; + short rt_refcnt; + unsigned long rt_use; + char *rt_dev; +}; + /* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */ struct rtentry { - unsigned long rt_hash; /* hash key for lookups */ -#define rt_genmask rt_hash - struct sockaddr rt_dst; - struct sockaddr rt_gateway; - short rt_flags; - short rt_refcnt; - unsigned long rt_use; -#ifdef BSD_COMPATIBLE - struct ifnet *rt_ifp; -#else - void *rt_dev; -#endif + unsigned long rt_hash; /* hash key for lookups */ + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + short rt_flags; + short rt_refcnt; + unsigned long rt_use; + struct ifnet *rt_ifp; + short rt_metric; /* +1 for binary compatibility! */ + char *rt_dev; /* forcing the device at add */ }; + + #define RTF_UP 0x0001 /* route useable */ #define RTF_GATEWAY 0x0002 /* destination is a gateway */ #define RTF_HOST 0x0004 /* host entry (net otherwise) */ diff -u +recursive +new-file 0.99pl15/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h --- 0.99pl15/linux/include/linux/sbpcd.h Sat Jan 29 14:53:18 1994 +++ linux/include/linux/sbpcd.h Sun Mar 6 16:08:22 1994 @@ -35,12 +35,8 @@ * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ... * there are some soundcards on the market with 0x0630, 0x0650, ... * - * obey! changed against v0.4 !!! - * for SBPRO cards, specify the CDROM address - no longer the audio address! * example: if your SBPRO audio address is 0x220, specify 0x230. * - * a fill-in is not always necessary - the driver does auto-probing now, - * with the here specified address first... */ #define CDROM_PORT 0x0230 @@ -73,7 +69,9 @@ #define DBG_DID 16 /* drive ID test */ #define DBG_RES 17 /* drive reset info */ #define DBG_SPI 18 /* SpinUp test */ -#define DBG_000 19 /* unnecessary information */ +#define DBG_IOS 19 /* ioctl trace: "subchannel" */ +#define DBG_IO2 20 /* ioctl trace: general */ +#define DBG_000 21 /* unnecessary information */ /*==========================================================================*/ /*==========================================================================*/ @@ -420,12 +418,7 @@ /* * use "REP INSB" for strobing the data in: */ -#if PATCHLEVEL<15 -#define READ_DATA(port, buf, nr) \ -__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","dx","di") -#else #define READ_DATA(port, buf, nr) insb(port, buf, nr) -#endif /*==========================================================================*/ /* diff -u +recursive +new-file 0.99pl15/linux/include/linux/sched.h linux/include/linux/sched.h --- 0.99pl15/linux/include/linux/sched.h Tue Jan 25 11:47:13 1994 +++ linux/include/linux/sched.h Fri Mar 4 14:13:32 1994 @@ -166,7 +166,7 @@ struct task_struct { /* these are hardcoded - don't touch */ - long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ long counter; long priority; unsigned long signal; @@ -183,6 +183,7 @@ int elf_executable:1; int dumpable:1; int swappable:1; + int did_exec:1; unsigned long start_code,end_code,end_data,start_brk,brk,start_stack,start_mmap; unsigned long arg_start, arg_end, env_start, env_end; int pid,pgrp,session,leader; @@ -263,7 +264,7 @@ /* schedlink */ &init_task,&init_task, \ /* signals */ {{ 0, },}, \ /* stack */ 0,(unsigned long) &init_kernel_stack, \ -/* ec,brk... */ 0,0,0,0,0,0,0,0,0,0,0,0, \ +/* ec,brk... */ 0,0,0,0,0,0,0,0,0,0,0,0,0, \ /* argv.. */ 0,0,0,0, \ /* pid etc.. */ 0,0,0,0, \ /* suppl grps*/ {NOGROUP,}, \ @@ -302,6 +303,8 @@ extern struct task_struct *last_task_used_math; extern struct task_struct *current; extern unsigned long volatile jiffies; +extern unsigned long itimer_ticks; +extern unsigned long itimer_next; extern struct timeval xtime; extern int need_resched; @@ -478,6 +481,21 @@ add_wait_queue(wait_address,&entry->wait); p->nr++; } + +extern void __down(struct semaphore * sem); + +extern inline void down(struct semaphore * sem) +{ + if (sem->count <= 0) + __down(sem); + sem->count--; +} + +extern inline void up(struct semaphore * sem) +{ + sem->count++; + wake_up(&sem->wait); +} static inline unsigned long _get_base(char * addr) { diff -u +recursive +new-file 0.99pl15/linux/include/linux/sockios.h linux/include/linux/sockios.h --- 0.99pl15/linux/include/linux/sockios.h Thu Jan 13 20:50:55 1994 +++ linux/include/linux/sockios.h Sun Feb 13 16:44:20 1994 @@ -39,6 +39,10 @@ #define SIOCGPGRP 0x8904 #define SIOCATMARK 0x8905 +/* Routing table calls. */ +#define SIOCADDRT 0x890B /* add routing table entry */ +#define SIOCDELRT 0x890C /* delete routing table entry */ + /* Socket configuration controls. */ #define SIOCGIFNAME 0x8910 /* get iface name */ #define SIOCSIFLINK 0x8911 /* set iface channel */ @@ -64,9 +68,9 @@ #define SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */ #define SIOCSIFENCAP 0x8926 -/* Routing table calls. */ -#define SIOCADDRT 0x8940 /* add routing table entry */ -#define SIOCDELRT 0x8941 /* delete routing table entry */ +/* Routing table calls (oldrtent - don't use) */ +#define SIOCADDRTOLD 0x8940 /* add routing table entry */ +#define SIOCDELRTOLD 0x8941 /* delete routing table entry */ /* ARP cache control calls. */ #define SIOCDARP 0x8950 /* delete ARP table entry */ diff -u +recursive +new-file 0.99pl15/linux/include/linux/termios.h linux/include/linux/termios.h --- 0.99pl15/linux/include/linux/termios.h Wed Jan 26 11:17:56 1994 +++ linux/include/linux/termios.h Tue Mar 1 19:00:15 1994 @@ -150,9 +150,9 @@ #define VTDLY 0040000 #define VT0 0000000 #define VT1 0040000 -#define FFDLY 0040000 +#define FFDLY 0100000 #define FF0 0000000 -#define FF1 0040000 +#define FF1 0100000 /* c_cflag bit meaning */ #define CBAUD 0000017 diff -u +recursive +new-file 0.99pl15/linux/include/linux/timer.h linux/include/linux/timer.h --- 0.99pl15/linux/include/linux/timer.h Sat Jan 29 14:55:05 1994 +++ linux/include/linux/timer.h Fri Feb 11 12:59:42 1994 @@ -75,6 +75,7 @@ */ struct timer_list { struct timer_list *next; + struct timer_list *prev; unsigned long expires; unsigned long data; void (*function)(unsigned long); diff -u +recursive +new-file 0.99pl15/linux/include/linux/timex.h linux/include/linux/timex.h --- 0.99pl15/linux/include/linux/timex.h Mon Jan 31 09:01:36 1994 +++ linux/include/linux/timex.h Sun Mar 6 16:14:51 1994 @@ -25,8 +25,6 @@ #ifndef _LINUX_TIMEX_H #define _LINUX_TIMEX_H -#include - /* * The following defines establish the engineering parameters of the PLL * model. The HZ variable establishes the timer interrupt frequency, 100 Hz diff -u +recursive +new-file 0.99pl15/linux/include/linux/tty.h linux/include/linux/tty.h --- 0.99pl15/linux/include/linux/tty.h Sat Jan 29 13:15:25 1994 +++ linux/include/linux/tty.h Fri Feb 18 11:08:41 1994 @@ -399,7 +399,7 @@ extern void flush_input(struct tty_struct * tty); extern void flush_output(struct tty_struct * tty); -extern void wait_until_sent(struct tty_struct * tty); +extern void wait_until_sent(struct tty_struct * tty, int timeout); extern int check_change(struct tty_struct * tty, int channel); extern void stop_tty(struct tty_struct * tty); extern void start_tty(struct tty_struct * tty); diff -u +recursive +new-file 0.99pl15/linux/include/linux/wait.h linux/include/linux/wait.h --- 0.99pl15/linux/include/linux/wait.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/wait.h Fri Feb 11 09:57:58 1994 @@ -11,6 +11,13 @@ struct wait_queue * next; }; +struct semaphore { + int count; + struct wait_queue * wait; +}; + +#define MUTEX ((struct semaphore) { 1, NULL }) + struct select_table_entry { struct wait_queue wait; struct wait_queue ** wait_address; diff -u +recursive +new-file 0.99pl15/linux/include/linux/xd.h linux/include/linux/xd.h --- 0.99pl15/linux/include/linux/xd.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/xd.h Sat Feb 12 18:27:32 1994 @@ -131,6 +131,8 @@ static void xd_wd_init_drive (u_char drive); static void xd_seagate_init_controller (u_char *address); static void xd_seagate_init_drive (u_char drive); +static void xd_omti_init_controller (u_char *address); +static void xd_omti_init_drive (u_char drive); static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc); static void xd_override_init_drive (u_char drive); diff -u +recursive +new-file 0.99pl15/linux/init/main.c linux/init/main.c --- 0.99pl15/linux/init/main.c Sat Jan 29 14:55:05 1994 +++ linux/init/main.c Mon Feb 7 16:07:01 1994 @@ -326,6 +326,17 @@ envp_init[envs+1] = NULL; } +static void copy_options(char * to, char * from) +{ + char c = ' '; + + do { + if (c == ' ' && !memcmp("mem=", from, 4)) + memory_end = simple_strtoul(from+4, &from, 0); + c = *(to++) = *(from++); + } while (c); +} + static void copro_timeout(void) { fpu_error = 1; @@ -351,7 +362,7 @@ memory_end = (1<<20) + (EXT_MEM_K<<10); memory_end &= PAGE_MASK; ramdisk_size = RAMDISK_SIZE; - strcpy(command_line,COMMAND_LINE); + copy_options(command_line,COMMAND_LINE); #ifdef CONFIG_MAX_16M if (memory_end > 16*1024*1024) memory_end = 16*1024*1024; diff -u +recursive +new-file 0.99pl15/linux/ipc/shm.c linux/ipc/shm.c --- 0.99pl15/linux/ipc/shm.c Tue Jan 4 13:08:23 1994 +++ linux/ipc/shm.c Wed Mar 2 19:35:20 1994 @@ -391,6 +391,12 @@ if (shmid < 0) return -EINVAL; + if (raddr) { + err = verify_area(VERIFY_WRITE, raddr, sizeof(long)); + if (err) + return err; + } + shp = shm_segs[id = shmid % SHMMNI]; if (shp == IPC_UNUSED || shp == IPC_NOID) return -EINVAL; @@ -462,6 +468,8 @@ shp->attaches = shmd; shp->shm_lpid = current->pid; shp->shm_atime = CURRENT_TIME; + if (!raddr) + return addr; put_fs_long (addr, raddr); return 0; } diff -u +recursive +new-file 0.99pl15/linux/ipc/util.c linux/ipc/util.c --- 0.99pl15/linux/ipc/util.c Wed Dec 1 14:44:15 1993 +++ linux/ipc/util.c Fri Feb 18 16:20:22 1994 @@ -45,24 +45,19 @@ * to ipc resources. return 0 if allowed */ int ipcperms (struct ipc_perm *ipcp, short flag) -{ - int i; mode_t perm; uid_t euid; int egid; - +{ /* flag will most probably be 0 or S_...UGO from */ + int requested_mode, granted_mode; + if (suser()) return 0; - - perm = S_IRWXO; euid = current->euid; - - if (euid == ipcp->cuid || euid == ipcp->uid) - perm = S_IRWXU; - else { - for (i = 0; (egid = current->groups[i]) != NOGROUP; i++) - if ((egid == ipcp->cgid) || (egid == ipcp->gid)) { - perm = S_IRWXG; - break; - } - } - if (!(flag & perm) || flag & perm & ~ipcp->mode) + requested_mode = (flag >> 6) | (flag >> 3) | flag; + granted_mode = ipcp->mode; + if (current->euid == ipcp->cuid || current->euid == ipcp->uid) + granted_mode >>= 6; + else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) + granted_mode >>= 3; + /* is there some bit set in requested_mode but not in granted_mode? */ + if (requested_mode & ~granted_mode & 0007) return -1; return 0; } diff -u +recursive +new-file 0.99pl15/linux/kernel/fork.c linux/kernel/fork.c --- 0.99pl15/linux/kernel/fork.c Wed Jan 26 11:17:56 1994 +++ linux/kernel/fork.c Fri Mar 4 14:11:01 1994 @@ -136,6 +136,7 @@ goto bad_fork_free; task[nr] = p; *p = *current; + p->did_exec = 0; p->kernel_stack_page = 0; p->state = TASK_UNINTERRUPTIBLE; p->flags &= ~(PF_PTRACED|PF_TRACESYS); diff -u +recursive +new-file 0.99pl15/linux/kernel/itimer.c linux/kernel/itimer.c --- 0.99pl15/linux/kernel/itimer.c Wed Dec 1 14:44:15 1993 +++ linux/kernel/itimer.c Tue Feb 22 09:05:46 1994 @@ -81,14 +81,23 @@ return k; switch (which) { case ITIMER_REAL: + if (j) { + j += 1+itimer_ticks; + if (j < itimer_next) + itimer_next = j; + } current->it_real_value = j; current->it_real_incr = i; break; case ITIMER_VIRTUAL: + if (j) + j++; current->it_virt_value = j; current->it_virt_incr = i; break; case ITIMER_PROF: + if (j) + j++; current->it_prof_value = j; current->it_prof_incr = i; break; diff -u +recursive +new-file 0.99pl15/linux/kernel/ksyms.S linux/kernel/ksyms.S --- 0.99pl15/linux/kernel/ksyms.S Fri Jan 28 09:28:22 1994 +++ linux/kernel/ksyms.S Wed Feb 16 09:30:21 1994 @@ -9,6 +9,8 @@ _register_chrdev _unregister_chrdev +_register_blkdev +_unregister_blkdev _wake_up_interruptible _wp_works_ok diff -u +recursive +new-file 0.99pl15/linux/kernel/ksyms.sh linux/kernel/ksyms.sh --- 0.99pl15/linux/kernel/ksyms.sh Mon Jan 3 08:37:17 1994 +++ linux/kernel/ksyms.sh Fri Feb 18 16:54:02 1994 @@ -10,7 +10,7 @@ # # -trap "rm -f ksyms.tmp ksyms.lst" 1 2 +trap "rm -f ksyms.tmp ksyms.lst ; exit 1" 1 2 sed -e '/^#/d' -e '/^[ ]*$/d' ksyms.lst | sort > ksyms.tmp diff -u +recursive +new-file 0.99pl15/linux/kernel/module.c linux/kernel/module.c --- 0.99pl15/linux/kernel/module.c Sat Jan 8 14:35:12 1994 +++ linux/kernel/module.c Fri Feb 11 08:55:26 1994 @@ -233,8 +233,7 @@ /* * Called by the /proc file system to return a current list of modules. */ -int -get_module_list( char *buf) +int get_module_list(char *buf) { char *p; char *q; diff -u +recursive +new-file 0.99pl15/linux/kernel/sched.c linux/kernel/sched.c --- 0.99pl15/linux/kernel/sched.c Wed Feb 2 16:36:33 1994 +++ linux/kernel/sched.c Tue Feb 22 09:05:37 1994 @@ -192,8 +192,8 @@ #endif /* CONFIG_MATH_EMULATION */ -static unsigned long itimer_ticks = 0; -static unsigned long itimer_next = ~0; +unsigned long itimer_ticks = 0; +unsigned long itimer_next = ~0; static unsigned long lost_ticks = 0; /* @@ -359,6 +359,19 @@ } tmp = tmp->next; } while (tmp != *q); +} + +void __down(struct semaphore * sem) +{ + struct wait_queue wait = { current, NULL }; + add_wait_queue(&sem->wait, &wait); + current->state = TASK_UNINTERRUPTIBLE; + while (sem->count <= 0) { + schedule(); + current->state = TASK_UNINTERRUPTIBLE; + } + current->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); } static inline void __sleep_on(struct wait_queue **p, int state) diff -u +recursive +new-file 0.99pl15/linux/kernel/signal.c linux/kernel/signal.c --- 0.99pl15/linux/kernel/signal.c Fri Jan 21 09:19:01 1994 +++ linux/kernel/signal.c Tue Feb 15 10:50:23 1994 @@ -183,6 +183,9 @@ return -EINVAL; p = signum - 1 + current->sigaction; if (action) { + int err = verify_area(VERIFY_READ, action, sizeof(*action)); + if (err) + return err; memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); if (new_sa.sa_flags & SA_NOMASK) new_sa.sa_mask = 0; @@ -194,8 +197,10 @@ return -EFAULT; } if (oldaction) { - if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction))) - memcpy_tofs(oldaction, p, sizeof(struct sigaction)); + int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction)); + if (err) + return err; + memcpy_tofs(oldaction, p, sizeof(struct sigaction)); } if (action) { *p = new_sa; @@ -211,30 +216,36 @@ */ asmlinkage int sys_sigreturn(unsigned long __unused) { -#define CHECK_SEG(x) if (x) x |= 3 #define COPY(x) regs->x = context.x +#define COPY_SEG(x) \ +if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x); +#define COPY_SEG_STRICT(x) \ +if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); struct sigcontext_struct context; struct pt_regs * regs; regs = (struct pt_regs *) &__unused; + if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context))) + goto badframe; memcpy_fromfs(&context,(void *) regs->esp, sizeof(context)); current->blocked = context.oldmask & _BLOCKABLE; - CHECK_SEG(context.ss); - CHECK_SEG(context.cs); - CHECK_SEG(context.ds); - CHECK_SEG(context.es); - CHECK_SEG(context.fs); - CHECK_SEG(context.gs); - COPY(eip); COPY(eflags); + COPY_SEG(ds); + COPY_SEG(es); + COPY_SEG(fs); + COPY_SEG(gs); + COPY_SEG_STRICT(ss); + COPY_SEG_STRICT(cs); + COPY(eip); COPY(ecx); COPY(edx); COPY(ebx); COPY(esp); COPY(ebp); COPY(edi); COPY(esi); - COPY(cs); COPY(ss); - COPY(ds); COPY(es); - COPY(fs); COPY(gs); + regs->eflags &= ~0xCD5; + regs->eflags |= context.eflags & 0xCD5; regs->orig_eax = -1; /* disable syscall checks */ return context.eax; +badframe: + do_exit(SIGSEGV); } /* diff -u +recursive +new-file 0.99pl15/linux/kernel/sys.c linux/kernel/sys.c --- 0.99pl15/linux/kernel/sys.c Wed Jan 26 11:17:56 1994 +++ linux/kernel/sys.c Fri Mar 4 17:10:58 1994 @@ -461,32 +461,49 @@ * OK, I think I have the protection semantics right.... this is really * only important on a multi-user system anyway, to make sure one user * can't send a signal to a process owned by another. -TYT, 12/12/91 + * + * Auch. Had to add the 'did_exec' flag to conform completely to POSIX. + * LBT 04.03.94 */ asmlinkage int sys_setpgid(pid_t pid, pid_t pgid) { - int i; + struct task_struct * p; if (!pid) pid = current->pid; if (!pgid) - pgid = current->pid; + pgid = pid; if (pgid < 0) return -EINVAL; - for (i=0 ; ipid == pid) && - ((task[i]->p_pptr == current) || - (task[i]->p_opptr == current) || - (task[i] == current))) { - if (task[i]->leader) - return -EPERM; - if ((task[i]->session != current->session) || - ((pgid != pid) && - (session_of_pgrp(pgid) != current->session))) - return -EPERM; - task[i]->pgrp = pgid; - return 0; - } + for_each_task(p) { + if (p->pid == pid) + goto found_task; + } return -ESRCH; + +found_task: + if (p->p_pptr == current || p->p_opptr == current) { + if (p->session != current->session) + return -EPERM; + if (p->did_exec) + return -EACCES; + } else if (p != current) + return -ESRCH; + if (p->leader) + return -EPERM; + if (pgid != pid) { + struct task_struct * tmp; + for_each_task (tmp) { + if (tmp->pgrp == pgid && + tmp->session == current->session) + goto ok_pgid; + } + return -EPERM; + } + +ok_pgid: + p->pgrp = pgid; + return 0; } asmlinkage int sys_getpgid(pid_t pid) diff -u +recursive +new-file 0.99pl15/linux/kernel/traps.c linux/kernel/traps.c --- 0.99pl15/linux/kernel/traps.c Thu Feb 3 12:06:12 1994 +++ linux/kernel/traps.c Wed Mar 9 11:10:40 1994 @@ -80,21 +80,31 @@ /*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err) { int i; + unsigned long esp; + unsigned short ss; + esp = (unsigned long) ®s->esp; + ss = KERNEL_DS; if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3) return; - + if (regs->cs & 3) { + esp = regs->esp; + ss = regs->ss; + } console_verbose(); printk("%s: %04lx\n", str, err & 0xffff); printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); - printk("esi: %08lx edi: %08lx ebp: %08lx\n", - regs->esi, regs->edi, regs->ebp); - printk("ds: %04x es: %04x fs: %04x gs: %04x\n", - regs->ds, regs->es, regs->fs, regs->gs); + printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); + printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", + regs->ds, regs->es, regs->fs, regs->gs, ss); store_TR(i); - printk("Pid: %d, process nr: %d (%s)\n", current->pid, 0xffff & i, current->comm); + printk("Pid: %d, process nr: %d (%s)\nStack: ", current->pid, 0xffff & i, current->comm); + for(i=0;i<5;i++) + printk("%08lx ", get_seg_long(ss,(i+(unsigned long *)esp))); + printk("\nCode: "); for(i=0;i<20;i++) printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip))); printk("\n"); diff -u +recursive +new-file 0.99pl15/linux/mm/kmalloc.c linux/mm/kmalloc.c --- 0.99pl15/linux/mm/kmalloc.c Wed Dec 1 14:44:15 1993 +++ linux/mm/kmalloc.c Thu Mar 10 19:54:34 1994 @@ -151,8 +151,14 @@ int order,tries,i,sz; struct block_header *p; struct page_descriptor *page; + extern unsigned long intr_count; /* Sanity check... */ + if (intr_count && priority != GFP_ATOMIC) { + printk("kmalloc called nonatomically from interrupt %08lx\n", + ((unsigned long *)&size)[-1]); + priority = GFP_ATOMIC; + } if (size > MAX_KMALLOC_K * 1024) { printk ("kmalloc: I refuse to allocate %d bytes (for now max = %d).\n", diff -u +recursive +new-file 0.99pl15/linux/mm/memory.c linux/mm/memory.c --- 0.99pl15/linux/mm/memory.c Tue Jan 25 11:03:02 1994 +++ linux/mm/memory.c Wed Feb 23 10:36:51 1994 @@ -304,9 +304,9 @@ if ((page = *page_table) != 0) { *page_table = 0; if (1 & page) { - if (!(mem_map[MAP_NR(page)] - & MAP_PAGE_RESERVED)) - --current->rss; + if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)) + if (current->rss > 0) + --current->rss; free_page(PAGE_MASK & page); } else swap_free(page); @@ -364,9 +364,9 @@ if ((page = *page_table) != 0) { *page_table = 0; if (page & PAGE_PRESENT) { - if (!(mem_map[MAP_NR(page)] - & MAP_PAGE_RESERVED)) - --current->rss; + if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)) + if (current->rss > 0) + --current->rss; free_page(PAGE_MASK & page); } else swap_free(page); @@ -426,9 +426,9 @@ if ((page = *page_table) != 0) { *page_table = 0; if (PAGE_PRESENT & page) { - if (!(mem_map[MAP_NR(page)] - & MAP_PAGE_RESERVED)) - --current->rss; + if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)) + if (current->rss > 0) + --current->rss; free_page(PAGE_MASK & page); } else swap_free(page); @@ -981,9 +981,6 @@ printk("Free pages: %6dkB\n",nr_free_pages<<(PAGE_SHIFT-10)); printk("Secondary pages: %6dkB\n",nr_secondary_pages<<(PAGE_SHIFT-10)); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - printk("Buffer memory: %6dkB\n",buffermem>>10); - printk("Buffer heads: %6d\n",nr_buffer_heads); - printk("Buffer blocks: %6d\n",nr_buffers); i = high_memory >> PAGE_SHIFT; while (i-- > 0) { total++; @@ -998,6 +995,7 @@ printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); + show_buffers(); } /* diff -u +recursive +new-file 0.99pl15/linux/mm/mmap.c linux/mm/mmap.c --- 0.99pl15/linux/mm/mmap.c Tue Jan 18 10:44:25 1994 +++ linux/mm/mmap.c Fri Feb 4 11:59:35 1994 @@ -113,9 +113,9 @@ mask |= PAGE_READONLY; if (prot & PROT_WRITE) if ((flags & MAP_TYPE) == MAP_PRIVATE) - mask |= PAGE_COW; + mask |= PAGE_COPY; else - mask |= PAGE_RW; + mask |= PAGE_SHARED; if (!mask) return -EINVAL; diff -u +recursive +new-file 0.99pl15/linux/mm/swap.c linux/mm/swap.c --- 0.99pl15/linux/mm/swap.c Tue Feb 1 09:03:52 1994 +++ linux/mm/swap.c Thu Mar 10 19:54:09 1994 @@ -585,6 +585,7 @@ */ unsigned long __get_free_page(int priority) { + extern unsigned long intr_count; unsigned long result, flag; static unsigned long index = 0; @@ -593,6 +594,11 @@ sections of code have interrupts disabled. -RAB Is this code reentrant? */ + if (intr_count && priority != GFP_ATOMIC) { + printk("gfp called nonatomically from interrupt %08lx\n", + ((unsigned long *)&priority)[-1]); + priority = GFP_ATOMIC; + } save_flags(flag); repeat: REMOVE_FROM_MEM_QUEUE(free_page_list,nr_free_pages); diff -u +recursive +new-file 0.99pl15/linux/net/inet/arp.c linux/net/inet/arp.c --- 0.99pl15/linux/net/inet/arp.c Thu Feb 3 12:38:52 1994 +++ linux/net/inet/arp.c Wed Mar 2 10:03:40 1994 @@ -17,10 +17,10 @@ * * Authors: Ross Biro, * Fred N. van Kempen, - * Stephen A. Wood, * Arnt Gulbrandsen, * * Fixes: + * Stephen A. Wood : arp problems * 'Mr Linux' : arp problems. * Alan Cox : arp_ioctl now checks memory areas with verify_area. * Alan Cox : Non IP arp message now only appears with debugging on. @@ -39,6 +39,7 @@ * Dominik Kubla : Better checking * Tegge : Assorted corrections on cross port stuff * Alan Cox : ATF_PERM was backwards! - might be useful now (sigh) + * Alan Cox : Arp timer added. * * To Fix: * : arp response allocates an skbuff to send. However there is a perfectly @@ -60,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -250,6 +252,28 @@ } +static struct timer_list arp_timer; + +static void arp_queue_ticker(unsigned long data); + +static void arp_queue_kick(void) +{ + arp_timer.expires = 500; /* 5 seconds */ + arp_timer.data = 0; + arp_timer.function = arp_queue_ticker; + del_timer(&arp_timer); + add_timer(&arp_timer); +} + +static void arp_queue_ticker(unsigned long data/*UNUSED*/) +{ + arp_send_q(); + if (skb_peek(&arp_q)) + arp_queue_kick(); +} + + + /* Create and send our response to an ARP request. */ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype) @@ -753,6 +777,8 @@ printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic); return; } + if(arp_q==NULL) + arp_queue_kick(); skb_queue_tail(&arp_q,skb); skb->magic = ARP_QUEUE_MAGIC; sti(); diff -u +recursive +new-file 0.99pl15/linux/net/inet/datagram.c linux/net/inet/datagram.c --- 0.99pl15/linux/net/inet/datagram.c Thu Jan 13 20:56:24 1994 +++ linux/net/inet/datagram.c Fri Feb 11 09:14:40 1994 @@ -186,7 +186,7 @@ return(0); case SEL_OUT: - if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) + if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE) { return(1); } diff -u +recursive +new-file 0.99pl15/linux/net/inet/dev.c linux/net/inet/dev.c --- 0.99pl15/linux/net/inet/dev.c Fri Jan 21 15:31:25 1994 +++ linux/net/inet/dev.c Tue Feb 22 10:00:56 1994 @@ -193,81 +193,49 @@ /* Check the address for our address, broadcasts, etc. */ -int -chk_addr(unsigned long addr) +int chk_addr(unsigned long addr) { - struct device *dev; - unsigned long dst; - - DPRINTF((DBG_DEV, "chk_addr(%s) --> ", in_ntoa(addr))); - dst = ntohl(addr); - - /* Accept both `all ones' and `all zeros' as BROADCAST. */ - if (dst == INADDR_ANY || dst == INADDR_BROADCAST) { - DPRINTF((DBG_DEV, "BROADCAST\n")); - return(IS_BROADCAST); - } + struct device *dev; + unsigned long mask; - /* Accept all of the `loopback' class A net. */ - if ((dst & IN_CLASSA_NET) == 0x7F000000L) { - DPRINTF((DBG_DEV, "LOOPBACK\n")); + /* Accept both `all ones' and `all zeros' as BROADCAST. */ + if (addr == INADDR_ANY || addr == INADDR_BROADCAST) + return IS_BROADCAST; - /* - * We force `loopback' to be equal to MY_ADDR. - */ - return(IS_MYADDR); - /* return(IS_LOOPBACK); */ - } + mask = get_mask(addr); - /* OK, now check the interface addresses. */ - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (!(dev->flags&IFF_UP)) - continue; - if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/) - return(IS_MYADDR); - /* Is it the exact IP address? */ - if (addr == dev->pa_addr) { - DPRINTF((DBG_DEV, "MYADDR\n")); - return(IS_MYADDR); - } + /* Accept all of the `loopback' class A net. */ + if ((addr & mask) == htonl(0x7F000000L)) + return IS_MYADDR; - /* Nope. Check for a subnetwork broadcast. */ - if ((addr & dev->pa_mask) == (dev->pa_addr & dev->pa_mask)) { - if ((addr & ~dev->pa_mask) == 0) { - DPRINTF((DBG_DEV, "SUBBROADCAST-0\n")); - return(IS_BROADCAST); + /* OK, now check the interface addresses. */ + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (!(dev->flags & IFF_UP)) + continue; + if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/) + return IS_MYADDR; + /* Is it the exact IP address? */ + if (addr == dev->pa_addr) + return IS_MYADDR; + /* Is it our broadcast address? */ + if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr) + return IS_BROADCAST; + /* Nope. Check for a subnetwork broadcast. */ + if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) { + if ((addr & ~dev->pa_mask) == 0) + return IS_BROADCAST; + if ((addr & ~dev->pa_mask) == ~dev->pa_mask) + return IS_BROADCAST; } - if (((addr & ~dev->pa_mask) | dev->pa_mask) - == INADDR_BROADCAST) { - DPRINTF((DBG_DEV, "SUBBROADCAST-1\n")); - return(IS_BROADCAST); + /* Nope. Check for Network broadcast. */ + if (((addr ^ dev->pa_addr) & mask) == 0) { + if ((addr & ~mask) == 0) + return IS_BROADCAST; + if ((addr & ~mask) == ~mask) + return IS_BROADCAST; } } - - /* Nope. Check for Network broadcast. */ - if(IN_CLASSA(dst)) { - if( addr == (dev->pa_addr | 0xffffff00)) { - DPRINTF((DBG_DEV, "CLASS A BROADCAST-1\n")); - return(IS_BROADCAST); - } - } - else if(IN_CLASSB(dst)) { - if( addr == (dev->pa_addr | 0xffff0000)) { - DPRINTF((DBG_DEV, "CLASS B BROADCAST-1\n")); - return(IS_BROADCAST); - } - } - else { /* IN_CLASSC */ - if( addr == (dev->pa_addr | 0xff000000)) { - DPRINTF((DBG_DEV, "CLASS C BROADCAST-1\n")); - return(IS_BROADCAST); - } - } - } - - DPRINTF((DBG_DEV, "NONE\n")); - - return(0); /* no match at all */ + return 0; /* no match at all */ } @@ -998,52 +966,55 @@ { struct iflink iflink; struct ddi_device *dev; - int ret; switch(cmd) { - case IP_SET_DEV: - printk("Your network configuration program needs upgrading.\n"); - return -EINVAL; + case IP_SET_DEV: + printk("Your network configuration program needs upgrading.\n"); + return -EINVAL; + case SIOCGIFCONF: (void) dev_ifconf((char *) arg); - ret = 0; - break; + return 0; + case SIOCGIFFLAGS: - case SIOCSIFFLAGS: case SIOCGIFADDR: - case SIOCSIFADDR: case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: case SIOCGIFNETMASK: - case SIOCSIFNETMASK: case SIOCGIFMETRIC: - case SIOCSIFMETRIC: case SIOCGIFMTU: - case SIOCSIFMTU: case SIOCGIFMEM: - case SIOCSIFMEM: case SIOCGIFHWADDR: - if (!suser()) return(-EPERM); - ret = dev_ifsioc(arg, cmd); - break; + return dev_ifsioc(arg, cmd); + + case SIOCSIFFLAGS: + case SIOCSIFADDR: + case SIOCSIFDSTADDR: + case SIOCSIFBRDADDR: + case SIOCSIFNETMASK: + case SIOCSIFMETRIC: + case SIOCSIFMTU: + case SIOCSIFMEM: + if (!suser()) + return -EPERM; + return dev_ifsioc(arg, cmd); + case SIOCSIFLINK: - if (!suser()) return(-EPERM); + if (!suser()) + return -EPERM; memcpy_fromfs(&iflink, arg, sizeof(iflink)); dev = ddi_map(iflink.id); - if (dev == NULL) return(-EINVAL); + if (dev == NULL) + return -EINVAL; /* Now allocate an interface and connect it. */ printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n", dev->name, iflink.stream); - ret = 0; - break; + return 0; + default: - ret = -EINVAL; + return -EINVAL; } - - return(ret); } diff -u +recursive +new-file 0.99pl15/linux/net/inet/icmp.c linux/net/inet/icmp.c --- 0.99pl15/linux/net/inet/icmp.c Wed Jan 19 13:34:55 1994 +++ linux/net/inet/icmp.c Tue Mar 1 18:51:41 1994 @@ -210,9 +210,11 @@ ip = iph->daddr; switch(icmph->code & 7) { case ICMP_REDIR_NET: +#ifdef not_a_good_idea rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), ip, 0, icmph->un.gateway, dev); break; +#endif case ICMP_REDIR_HOST: rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), ip, 0, icmph->un.gateway, dev); diff -u +recursive +new-file 0.99pl15/linux/net/inet/ip.c linux/net/inet/ip.c --- 0.99pl15/linux/net/inet/ip.c Sat Jan 29 14:10:53 1994 +++ linux/net/inet/ip.c Thu Mar 10 21:28:17 1994 @@ -34,6 +34,12 @@ * Alan Cox : Save IP header pointer for later * Alan Cox : ip option setting * Alan Cox : Use ip_tos/ip_ttl settings + * Alan Cox : Fragmentation bogosity removed + * (Thanks to Mark.Bush@prg.ox.ac.uk) + * Dmitry Gorodchanin : Send of a raw packet crash fix. + * Alan Cox : Silly ip bug when an overlength + * fragment turns up. Now frees the + * queue. * * To Fix: * IP option processing is mostly not needed. ip_forward needs to know about routing rules @@ -764,7 +770,6 @@ skb->len = (len - qp->maclen); skb->h.raw = skb->data; skb->free = 1; - skb->lock = 1; /* Copy the original MAC and IP headers into the new buffer. */ ptr = (unsigned char *) skb->h.raw; @@ -786,6 +791,7 @@ if(count+fp->len>skb->len) { printk("Invalid fragment list: Fragment over size.\n"); + ip_free(qp); kfree_skb(skb,FREE_WRITE); return NULL; } @@ -971,7 +977,9 @@ /* Point into the IP datagram header. */ raw = skb->data; iph = (struct iphdr *) (raw + dev->hard_header_len); - + + skb->ip_hdr = iph; + /* Setup starting values. */ hlen = (iph->ihl * sizeof(unsigned long)); left = ntohs(iph->tot_len) - hlen; @@ -1009,6 +1017,7 @@ while(left > 0) { len = left; +#ifdef OLD if (len+8 > mtu) len = (dev->mtu - hlen - 8); if ((left - len) >= 8) @@ -1016,11 +1025,23 @@ len /= 8; len *= 8; } +#else + /* IF: it doesn't fit, use 'mtu' - the data space left */ + if (len > mtu) + len = mtu; + /* IF: we are not sending upto and including the packet end + then align the next start on an eight byte boundary */ + if (len < left) + { + len/=8; + len*=8; + } +#endif DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n", len, len + hlen)); /* Allocate buffer. */ - if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL) + if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_ATOMIC)) == NULL) { printk("IP: frag: no memory for new fragment!\n"); return; @@ -1369,6 +1390,7 @@ ptr = skb->data; ptr += dev->hard_header_len; iph = (struct iphdr *)ptr; + skb->ip_hdr = iph; iph->tot_len = ntohs(skb->len-dev->hard_header_len); if(skb->len > dev->mtu) diff -u +recursive +new-file 0.99pl15/linux/net/inet/ip.h linux/net/inet/ip.h --- 0.99pl15/linux/net/inet/ip.h Thu Jan 13 21:00:05 1994 +++ linux/net/inet/ip.h Sun Feb 6 12:17:40 1994 @@ -78,6 +78,7 @@ struct device *dev, struct sk_buff *skb, int free); extern void ip_retransmit(struct sock *sk, int all); +extern void ip_do_retransmit(struct sock *sk, int all); extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen); extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen); diff -u +recursive +new-file 0.99pl15/linux/net/inet/proc.c linux/net/inet/proc.c --- 0.99pl15/linux/net/inet/proc.c Tue Dec 14 12:12:07 1993 +++ linux/net/inet/proc.c Wed Mar 2 11:11:16 1994 @@ -88,7 +88,7 @@ sp->timer.expires = 0; pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n", i, src, srcp, dest, destp, sp->state, - format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc, + format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, timer_active, sp->timer.expires, (unsigned) sp->retransmits, SOCK_INODE(sp->socket)->i_uid); diff -u +recursive +new-file 0.99pl15/linux/net/inet/raw.c linux/net/inet/raw.c --- 0.99pl15/linux/net/inet/raw.c Tue Jan 25 08:52:22 1994 +++ linux/net/inet/raw.c Sun Feb 6 12:17:40 1994 @@ -115,7 +115,7 @@ /* Now we need to copy this into memory. */ skb->sk = sk; skb->len = len + skb->ip_hdr->ihl*sizeof(long); - skb->h.raw = skb->ip_hdr; + skb->h.raw = (unsigned char *) skb->ip_hdr; skb->dev = dev; skb->saddr = daddr; skb->daddr = saddr; diff -u +recursive +new-file 0.99pl15/linux/net/inet/route.c linux/net/inet/route.c --- 0.99pl15/linux/net/inet/route.c Tue Jan 25 08:26:20 1994 +++ linux/net/inet/route.c Sun Mar 13 16:20:59 1994 @@ -253,18 +253,51 @@ static int rt_new(struct rtentry *r) { - struct device *dev; + int err; + char * devname; + struct device * dev = NULL; unsigned long flags, daddr, mask, gw; + if ((devname = r->rt_dev) != NULL) { + err = getname(devname, &devname); + if (err) + return err; + dev = dev_get(devname); + putname(devname); + if (!dev) + return -EINVAL; + } + if (r->rt_dst.sa_family != AF_INET) return -EAFNOSUPPORT; flags = r->rt_flags; daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr; - mask = r->rt_genmask; + mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr; gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr; - dev = (struct device *) r->rt_dev; + +/* BSD emulation: Permits route add someroute gw one-of-my-addresses + to indicate which iface. Not as clean as the nice Linux dev technique + but people keep using it... */ + if (!dev && (flags & RTF_GATEWAY)) { + struct device *dev2; + for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) { + if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) { + flags &= ~RTF_GATEWAY; + dev = dev2; + break; + } + } + } + + if (bad_mask(mask, daddr)) + mask = 0; + if (flags & RTF_HOST) + mask = 0xffffffff; + else if (mask && r->rt_genmask.sa_family != AF_INET) + return -EAFNOSUPPORT; + if (flags & RTF_GATEWAY) { if (r->rt_gateway.sa_family != AF_INET) return -EAFNOSUPPORT; @@ -276,9 +309,6 @@ if (dev == NULL) return -ENETUNREACH; - if (bad_mask(mask, daddr)) - mask = 0; - rt_add(flags, daddr, mask, gw, dev); return 0; } @@ -343,19 +373,41 @@ return NULL; } +static int get_old_rtent(struct old_rtentry * src, struct rtentry * rt) +{ + int err; + struct old_rtentry tmp; + + err=verify_area(VERIFY_READ, src, sizeof(*src)); + if (err) + return err; + memcpy_fromfs(&tmp, src, sizeof(*src)); + memset(rt, 0, sizeof(*rt)); + rt->rt_dst = tmp.rt_dst; + rt->rt_gateway = tmp.rt_gateway; + rt->rt_genmask.sa_family = AF_INET; + ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask; + rt->rt_flags = tmp.rt_flags; + rt->rt_dev = tmp.rt_dev; + return 0; +} int rt_ioctl(unsigned int cmd, void *arg) { - struct device *dev; - struct rtentry rt; - char *devname; - int ret; int err; + struct rtentry rt; switch(cmd) { case DDIOCSDBG: - ret = dbg_ioctl(arg, DBG_RT); - break; + return dbg_ioctl(arg, DBG_RT); + case SIOCADDRTOLD: + case SIOCDELRTOLD: + if (!suser()) + return -EPERM; + err = get_old_rtent((struct old_rtentry *) arg, &rt); + if (err) + return err; + return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt); case SIOCADDRT: case SIOCDELRT: if (!suser()) @@ -364,21 +416,8 @@ if (err) return err; memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); - if ((devname = (char *) rt.rt_dev) != NULL) { - err = getname(devname, &devname); - if (err) - return err; - dev = dev_get(devname); - putname(devname); - if (!dev) - return -EINVAL; - rt.rt_dev = dev; - } - ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); - break; - default: - ret = -EINVAL; + return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); } - return ret; + return -EINVAL; } diff -u +recursive +new-file 0.99pl15/linux/net/inet/skbuff.c linux/net/inet/skbuff.c --- 0.99pl15/linux/net/inet/skbuff.c Thu Feb 3 12:44:45 1994 +++ linux/net/inet/skbuff.c Thu Mar 10 21:15:09 1994 @@ -394,8 +394,8 @@ skb->magic = 0; if (skb->sk) { - if(skb->sk->prot!=NULL) - { + if(skb->sk->prot!=NULL) + { if (rw) skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len); else @@ -425,7 +425,15 @@ struct sk_buff *alloc_skb(unsigned int size,int priority) { - struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority); + struct sk_buff *skb; + extern unsigned long intr_count; + + if (intr_count && priority != GFP_ATOMIC) { + printk("alloc_skb called nonatomically from interrupt %08lx\n", + ((unsigned long *)&size)[-1]); + priority = GFP_ATOMIC; + } + skb=(struct sk_buff *)kmalloc(size,priority); if(skb==NULL) return NULL; skb->free= 2; /* Invalid so we pick up forgetful users */ diff -u +recursive +new-file 0.99pl15/linux/net/inet/skbuff.h linux/net/inet/skbuff.h --- 0.99pl15/linux/net/inet/skbuff.h Wed Jan 26 12:44:20 1994 +++ linux/net/inet/skbuff.h Tue Mar 1 13:11:55 1994 @@ -72,8 +72,7 @@ volatile char acked, used, free, - arp, - urg_used; + arp; unsigned char tries,lock; /* Lock is now unused */ unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ unsigned long padding[0]; diff -u +recursive +new-file 0.99pl15/linux/net/inet/sock.c linux/net/inet/sock.c --- 0.99pl15/linux/net/inet/sock.c Wed Feb 2 17:07:01 1994 +++ linux/net/inet/sock.c Fri Mar 11 16:27:03 1994 @@ -119,8 +119,8 @@ printk(" daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr); printk(" num = %d", sk->num); printk(" next = %p\n", sk->next); - printk(" send_seq = %ld, acked_seq = %ld, copied_seq = %ld\n", - sk->send_seq, sk->acked_seq, sk->copied_seq); + printk(" write_seq = %ld, acked_seq = %ld, copied_seq = %ld\n", + sk->write_seq, sk->acked_seq, sk->copied_seq); printk(" rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n", sk->rcv_ack_seq, sk->window_seq, sk->fin_seq); printk(" prot = %p\n", sk->prot); @@ -130,7 +130,7 @@ printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout); printk(" cong_window = %d, packets_out = %d\n", sk->cong_window, sk->packets_out); - printk(" urg = %d shutdown=%d\n", sk->urg, sk->shutdown); + printk(" shutdown=%d\n", sk->shutdown); } @@ -497,7 +497,7 @@ static int inet_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { - struct sock *sk = sock->data; + struct sock *sk = (struct sock *) sock->data; if (level == SOL_SOCKET) return sock_getsockopt(sk,level,optname,optval,optlen); if(sk->prot->getsockopt==NULL) @@ -838,10 +838,12 @@ sk->rcvbuf = SK_RMEM_MAX; sk->pair = NULL; sk->opt = NULL; - sk->send_seq = 0; + sk->write_seq = 0; sk->acked_seq = 0; sk->copied_seq = 0; sk->fin_seq = 0; + sk->urg_seq = 0; + sk->urg_data = 0; sk->proc = 0; sk->rtt = TCP_WRITE_TIME << 3; sk->rto = TCP_WRITE_TIME; @@ -859,7 +861,6 @@ sk->priority = 1; sk->shutdown = 0; - sk->urg = 0; sk->keepopen = 0; sk->zapped = 0; sk->done = 0; @@ -981,9 +982,13 @@ while(sk->state != TCP_CLOSE && current->timeout>0) { interruptible_sleep_on(sk->sleep); if (current->signal & ~current->blocked) { + break; +#if 0 + /* not working now - closes can't be restarted */ sti(); current->timeout=0; return(-ERESTARTSYS); +#endif } } current->timeout=0; @@ -1531,8 +1536,8 @@ case DDIOCSDBG: return(dbg_ioctl((void *) arg, DBG_INET)); - case SIOCADDRT: - case SIOCDELRT: + case SIOCADDRT: case SIOCADDRTOLD: + case SIOCDELRT: case SIOCDELRTOLD: return(rt_ioctl(cmd,(void *) arg)); case SIOCDARP: @@ -1577,10 +1582,13 @@ { if (sk) { if (sk->wmem_alloc + size < sk->sndbuf || force) { - cli(); - sk->wmem_alloc+= size; - sti(); - return(alloc_skb(size, priority)); + struct sk_buff * c = alloc_skb(size, priority); + if (c) { + cli(); + sk->wmem_alloc+= size; + sti(); + } + return c; } DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n", sk, size, force, priority)); @@ -1595,10 +1603,12 @@ { if (sk) { if (sk->rmem_alloc + size < sk->rcvbuf || force) { - void *c = alloc_skb(size, priority); - cli(); - if (c) sk->rmem_alloc += size; - sti(); + struct sk_buff *c = alloc_skb(size, priority); + if (c) { + cli(); + sk->rmem_alloc += size; + sti(); + } return(c); } DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n", @@ -1849,7 +1859,7 @@ struct inet_protocol *p; int i; - printk("Swansea University Computer Society Net2Debugged [1.27]\n"); + printk("Swansea University Computer Society Net2Debugged [1.30]\n"); /* Set up our UNIX VFS major device. */ if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) { printk("%s: cannot register major device %d!\n", diff -u +recursive +new-file 0.99pl15/linux/net/inet/sock.h linux/net/inet/sock.h --- 0.99pl15/linux/net/inet/sock.h Wed Feb 2 17:06:44 1994 +++ linux/net/inet/sock.h Wed Mar 2 11:29:06 1994 @@ -55,12 +55,15 @@ struct options *opt; volatile unsigned long wmem_alloc; volatile unsigned long rmem_alloc; - unsigned long send_seq; + unsigned long write_seq; + unsigned long sent_seq; unsigned long acked_seq; unsigned long copied_seq; unsigned long rcv_ack_seq; unsigned long window_seq; unsigned long fin_seq; + unsigned long urg_seq; + unsigned long urg_data; /* * Not all are volatile, but some are, so we @@ -112,7 +115,6 @@ volatile unsigned short cong_count; volatile unsigned short ssthresh; volatile unsigned short packets_out; - volatile unsigned short urg; volatile unsigned short shutdown; volatile unsigned long rtt; volatile unsigned long mdev; diff -u +recursive +new-file 0.99pl15/linux/net/inet/tcp.c linux/net/inet/tcp.c --- 0.99pl15/linux/net/inet/tcp.c Thu Feb 3 12:55:16 1994 +++ linux/net/inet/tcp.c Sun Mar 13 16:03:36 1994 @@ -59,6 +59,10 @@ * Alan Cox : Added a couple of small NET2E timer fixes * Charles Hedrick : TCP fixes * Toomas Tamm : TCP window fixes + * Alan Cox : Small URG fix to rlogin ^C ack fight + * Charles Hedrick : Window fix + * Linus : Rewrote tcp_read() and URG handling + * completely * * * To Fix: @@ -113,28 +117,29 @@ } -void -print_th(struct tcphdr *th) +static void __print_th(struct tcphdr *th) { - unsigned char *ptr; - - if (inet_debug != DBG_TCP) return; + unsigned char *ptr; - printk("TCP header:\n"); - ptr =(unsigned char *)(th + 1); - printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n", - ntohs(th->source), ntohs(th->dest), - ntohl(th->seq), ntohl(th->ack_seq)); - printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n", - th->fin, th->syn, th->rst, th->psh, th->ack, - th->urg, th->res1, th->res2); - printk(" window = %d, check = %d urg_ptr = %d\n", - ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr)); - printk(" doff = %d\n", th->doff); - printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]); - } - + printk("TCP header:\n"); + printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n", + ntohs(th->source), ntohs(th->dest), + ntohl(th->seq), ntohl(th->ack_seq)); + printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n", + th->fin, th->syn, th->rst, th->psh, th->ack, + th->urg, th->res1, th->res2); + printk(" window = %d, check = %d urg_ptr = %d\n", + ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr)); + printk(" doff = %d\n", th->doff); + ptr =(unsigned char *)(th + 1); + printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]); +} +static inline void print_th(struct tcphdr *th) +{ + if (inet_debug == DBG_TCP) + __print_th(th); +} /* This routine grabs the first thing off of a rcv queue. */ static struct sk_buff * @@ -339,10 +344,8 @@ if (before(counted, skb->h.th->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) */ - if (skb->h.th->syn) sum++; - if (skb->h.th->urg) { - sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */ - } + if (skb->h.th->syn) + sum++; if (sum >= 0) { /* Add it up, move on */ amount += sum; if (skb->h.th->syn) amount--; @@ -351,6 +354,9 @@ if (amount && skb->h.th->psh) break; skb =(struct sk_buff *)skb->next; /* Move along */ } while(skb != sk->rqueue); + if (amount && !sk->urginline && sk->urg_data && + (sk->urg_seq - sk->copied_seq) <= (counted - sk->copied_seq)) + amount--; /* don't count urg data */ restore_flags(flags); DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount)); if(sk->debug) @@ -431,16 +437,16 @@ "tcp_select: sleeping on write sk->wmem_alloc = %d, " "sk->packets_out = %d\n" "sk->wback = %X, sk->wfront = %X\n" - "sk->send_seq = %u, sk->window_seq=%u\n", + "sk->write_seq = %u, sk->window_seq=%u\n", sk->wmem_alloc, sk->packets_out, sk->wback, sk->wfront, - sk->send_seq, sk->window_seq)); + sk->write_seq, sk->window_seq)); release_sock(sk); return(0); case SEL_EX: select_wait(sk->sleep,wait); - if (sk->err) { + if (sk->err || sk->urg_data) { release_sock(sk); return(1); } @@ -484,23 +490,11 @@ } case SIOCATMARK: { - struct sk_buff *skb; - int answ = 0; + int answ = sk->urg_data && sk->urg_seq == sk->copied_seq+1; - /* - * Try to figure out if we need to read - * some urgent data. - */ - sk->inuse = 1; - if ((skb=skb_peek(&sk->rqueue)) != NULL) - { - if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg) - answ = 1; - } - release_sock(sk); - err=verify_area(VERIFY_WRITE,(void *) arg, + err = verify_area(VERIFY_WRITE,(void *) arg, sizeof(unsigned long)); - if(err) + if (err) return err; put_fs_long(answ,(int *) arg); return(0); @@ -598,14 +592,15 @@ static void tcp_send_skb(struct sock *sk, struct sk_buff *skb) { int size; + struct tcphdr * th = skb->h.th; /* length of packet (not counting length of pre-tcp headers) */ - size = skb->len - ((unsigned char *) skb->h.th - skb->data); + size = skb->len - ((unsigned char *) th - skb->data); /* sanity check it.. */ if (size < sizeof(struct tcphdr) || size > skb->len) { printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n", - skb, skb->data, skb->h.th, skb->len); + skb, skb->data, th, skb->len); kfree_skb(skb, FREE_WRITE); return; } @@ -613,7 +608,7 @@ /* If we have queued a header size packet.. */ if (size == sizeof(struct tcphdr)) { /* If its got a syn or fin its notionally included in the size..*/ - if(!skb->h.th->syn && !skb->h.th->fin) { + if(!th->syn && !th->fin) { printk("tcp_send_skb: attempt to queue a bogon.\n"); kfree_skb(skb,FREE_WRITE); return; @@ -621,16 +616,16 @@ } /* We need to complete and send the packet. */ - tcp_send_check(skb->h.th, sk->saddr, sk->daddr, size, sk); + tcp_send_check(th, sk->saddr, sk->daddr, size, sk); - skb->h.seq = sk->send_seq; - if (after(sk->send_seq , sk->window_seq) || + skb->h.seq = ntohl(th->seq) + size - 4*th->doff; + if (after(skb->h.seq, sk->window_seq) || (sk->retransmits && sk->timeout == TIME_WRITE) || sk->packets_out >= sk->cong_window) { DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n", sk->cong_window, sk->packets_out)); - DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n", - sk->send_seq, sk->window_seq)); + DPRINTF((DBG_TCP, "sk->write_seq = %d, sk->window_seq = %d\n", + sk->write_seq, sk->window_seq)); skb->next = NULL; skb->magic = TCP_WRITE_QUEUE_MAGIC; if (sk->wback == NULL) { @@ -644,6 +639,7 @@ sk->ack_backlog == 0) reset_timer(sk, TIME_PROBE0, sk->rto); } else { + sk->sent_seq = sk->write_seq; sk->prot->queue_xmit(sk, skb->dev, skb, 0); } } @@ -786,7 +782,7 @@ /* FIXME: want to get rid of this. */ memcpy(th,(void *) &(sk->dummy_th), sizeof(*th)); - th->seq = htonl(sk->send_seq); + th->seq = htonl(sk->write_seq); th->psh =(push == 0) ? 1 : 0; th->doff = sizeof(*th)/4; th->ack = 1; @@ -927,7 +923,7 @@ from += copy; copied += copy; len -= copy; - sk->send_seq += copy; + sk->write_seq += copy; } if ((skb->len - hdrlen) >= sk->mss || (flags & MSG_OOB) || @@ -950,14 +946,11 @@ * be queued for later rather than sent. */ - copy = diff(sk->window_seq, sk->send_seq); - /* what if max_window == 1? In that case max_window >> 1 is 0. - * however in that case copy == max_window, so it's OK to use - * the window */ - if (copy < (sk->max_window >> 1)) - copy = sk->mss; - copy = min(copy, sk->mss); - copy = min(copy, len); + copy = sk->window_seq - sk->write_seq; + if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss) + copy = sk->mss; + if (copy > len) + copy = len; /* We should really check the window here also. */ send_tmp = NULL; @@ -1050,7 +1043,7 @@ len -= copy; skb->len += copy; skb->free = 0; - sk->send_seq += copy; + sk->write_seq += copy; if (send_tmp != NULL && sk->packets_out) { tcp_enqueue_partial(send_tmp, sk); @@ -1071,7 +1064,7 @@ if(sk->partial && ((!sk->packets_out) /* If not nagling we can send on the before case too.. */ - || (sk->nonagle && before(sk->send_seq , sk->window_seq)) + || (sk->nonagle && before(sk->write_seq , sk->window_seq)) )) tcp_send_partial(sk); /* -- */ @@ -1143,7 +1136,7 @@ t1 =(struct tcphdr *)(buff->data +tmp); memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); - t1->seq = ntohl(sk->send_seq); + t1->seq = htonl(sk->sent_seq); t1->ack = 1; t1->res1 = 0; t1->res2 = 0; @@ -1251,325 +1244,201 @@ tcp_read_urg(struct sock * sk, int nonblock, unsigned char *to, int len, unsigned flags) { - int copied = 0; - struct sk_buff *skb; + struct wait_queue wait = { current, NULL }; - DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n", - sk, to, len, flags)); + while (len > 0) { + if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ) + return -EINVAL; + if (sk->urg_data & URG_VALID) { + char c = sk->urg_data; + if (!(flags & MSG_PEEK)) + sk->urg_data = URG_READ; + put_fs_byte(c, to); + return 1; + } - while(len > 0) - { - sk->inuse = 1; - while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL) { if (sk->err) { - int tmp; - - release_sock(sk); - if (copied) return(copied); - tmp = -sk->err; + int tmp = -sk->err; sk->err = 0; - return(tmp); + return tmp; } if (sk->state == TCP_CLOSE || sk->done) { - release_sock(sk); - if (copied) return(copied); if (!sk->done) { sk->done = 1; - return(0); + return 0; } - return(-ENOTCONN); - } - - if (sk->shutdown & RCV_SHUTDOWN) { - release_sock(sk); - if (copied == 0) - sk->done = 1; - return(copied); - } - - if (nonblock || copied) { - release_sock(sk); - if (copied) return(copied); - return(-EAGAIN); + return -ENOTCONN; } - /* Now at this point, we may have gotten some data. */ - release_sock(sk); - cli(); - if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) && - sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) { - sti(); - if (copied) return(copied); - return(-ERESTARTSYS); - } + if (sk->shutdown & RCV_SHUTDOWN) { + sk->done = 1; + return 0; } - sk->inuse = 1; - sti(); - } - skb = skb_peek(&sk->rqueue); - do { - int amt; + if (nonblock) + return -EAGAIN; - if (skb->h.th->urg && !skb->urg_used) { - if (skb->h.th->urg_ptr == 0) { - skb->h.th->urg_ptr = ntohs(skb->len); - } - amt = min(ntohs(skb->h.th->urg_ptr),len); - if(amt) - { - memcpy_tofs(to,(unsigned char *)(skb->h.th) + - skb->h.th->doff*4, amt); - } + if (current->signal & ~current->blocked) + return -ERESTARTSYS; - if (!(flags & MSG_PEEK)) { - skb->urg_used = 1; - sk->urg--; - } - release_sock(sk); - copied += amt; - return(copied); - } - skb =(struct sk_buff *)skb->next; - } while(skb != sk->rqueue); - } -/*sk->urg = 0;*/ - release_sock(sk); - return(0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(sk->sleep, &wait); + if ((sk->urg_data & URG_NOTYET) && sk->err == 0 && + !(sk->shutdown & RCV_SHUTDOWN)) + schedule(); + remove_wait_queue(sk->sleep, &wait); + current->state = TASK_RUNNING; + } + return 0; } /* This routine copies from a sock struct into the user buffer. */ -static int -tcp_read(struct sock *sk, unsigned char *to, - int len, int nonblock, unsigned flags) +static int tcp_read(struct sock *sk, unsigned char *to, + int len, int nonblock, unsigned flags) { - int copied=0; /* will be used to say how much has been copied. */ - struct sk_buff *skb; - unsigned long offset; - unsigned long used; - int err; - - if (len == 0) return(0); - if (len < 0) { - return(-EINVAL); - } - - err=verify_area(VERIFY_WRITE,to,len); - if(err) - return err; - - /* This error should be checked. */ - if (sk->state == TCP_LISTEN) return(-ENOTCONN); + struct wait_queue wait = { current, NULL }; + int copied = 0; + unsigned long peek_seq; + unsigned long *seq; + unsigned long used; + int err; + + if (len == 0) + return 0; + + if (len < 0) + return -EINVAL; + + err = verify_area(VERIFY_WRITE, to, len); + if (err) + return err; + + /* This error should be checked. */ + if (sk->state == TCP_LISTEN) + return -ENOTCONN; + + /* Urgent data needs to be handled specially. */ + if (flags & MSG_OOB) + return tcp_read_urg(sk, nonblock, to, len, flags); + + peek_seq = sk->copied_seq; + seq = &sk->copied_seq; + if (flags & MSG_PEEK) + seq = &peek_seq; - /* Urgent data needs to be handled specially. */ - if ((flags & MSG_OOB)) - return(tcp_read_urg(sk, nonblock, to, len, flags)); + add_wait_queue(sk->sleep, &wait); + sk->inuse = 1; + while (len > 0) { + struct sk_buff * skb; + unsigned long offset; + + /* + * are we at urgent data? Stop if we have read anything. + */ + if (copied && sk->urg_data && sk->urg_seq == 1+*seq) + break; - /* So no-one else will use this socket. */ - sk->inuse = 1; - - skb=skb_peek(&sk->rqueue); + current->state = TASK_INTERRUPTIBLE; - DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n", - sk, to, len, nonblock, flags)); + skb = sk->rqueue; + do { + if (!skb) + break; + if (before(1+*seq, skb->h.th->seq)) + break; + offset = 1 + *seq - skb->h.th->seq; + if (skb->h.th->syn) + offset--; + if (offset < skb->len) + goto found_ok_skb; + if (!(flags & MSG_PEEK)) + skb->used = 1; + skb = (struct sk_buff *)skb->next; + } while (skb != sk->rqueue); - while(len > 0) { - /* skb->used just checks to see if we've gone all the way around. */ - - /* While no data, or first data indicates some is missing, or data is used */ - while(skb == NULL || - before(sk->copied_seq+1, skb->h.th->seq) || skb->used) { - DPRINTF((DBG_TCP, "skb = %X:\n", skb)); - cleanup_rbuf(sk); - if (sk->err) - { - int tmp; + if (copied) + break; - release_sock(sk); - if (copied) - { - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", - copied)); - return(copied); - } - tmp = -sk->err; + if (sk->err) { + copied = -sk->err; sk->err = 0; - return(tmp); + break; } - if (sk->state == TCP_CLOSE) - { - release_sock(sk); - if (copied) { - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", - copied)); - return(copied); - } + if (sk->state == TCP_CLOSE) { if (!sk->done) { sk->done = 1; - return(0); + break; } - return(-ENOTCONN); + copied = -ENOTCONN; + break; } - if (sk->shutdown & RCV_SHUTDOWN) - { - release_sock(sk); - if (copied == 0) sk->done = 1; - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); - return(copied); + if (sk->shutdown & RCV_SHUTDOWN) { + sk->done = 1; + break; } - if (nonblock || copied) - { - release_sock(sk); - if(sk->debug) - printk("read: EAGAIN\n"); - if (copied) - { - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", - copied)); - return(copied); - } - return(-EAGAIN); + if (nonblock) { + copied = -EAGAIN; + break; } - if ((flags & MSG_PEEK) && copied != 0) - { - release_sock(sk); - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); - return(copied); - } - - DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n", - sk->state)); + cleanup_rbuf(sk); release_sock(sk); - - /* - * Now we may have some data waiting or we could - * have changed state. - */ - cli(); - if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) { - sk->inuse = 1; - sti(); - continue; - } - - if (skb_peek(&sk->rqueue) == NULL || - before(sk->copied_seq+1, sk->rqueue->h.th->seq)) { - if(sk->debug) - printk("Read wait sleep\n"); - interruptible_sleep_on(sk->sleep); - if(sk->debug) - printk("Read wait wakes\n"); - if (current->signal & ~current->blocked) { - sti(); - if (copied) { - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", - copied)); - return(copied); - } - return(-ERESTARTSYS); - } - } + schedule(); sk->inuse = 1; - sti(); - DPRINTF((DBG_TCP, "tcp_read woke up. \n")); - - skb=skb_peek(&sk->rqueue); - /* That may have been null if we were beaten, if so we loop again */ - } + if (current->signal & ~current->blocked) { + copied = -ERESTARTSYS; + break; + } + continue; - /* - * Copy anything from the current block that needs - * to go into the user buffer. - */ - offset = sk->copied_seq+1 - skb->h.th->seq; - - if (skb->h.th->syn) offset--; - if (offset < skb->len) /* Some of the packet is useful */ - { - /* - * If there is urgent data we must either - * return or skip over it. - */ - if (skb->h.th->urg) - { - if (skb->urg_used) - { - sk->copied_seq += ntohs(skb->h.th->urg_ptr); - offset += ntohs(skb->h.th->urg_ptr); - if (offset >= skb->len) - { - skb->used = 1; - skb =(struct sk_buff *)skb->next; - continue; - } - } - else - { - release_sock(sk); - if (copied) - return(copied); - send_sig(SIGURG, current, 0); - return(-EINTR); + found_ok_skb: + /* Ok so how much can we use ? */ + used = skb->len - offset; + if (len < used) + used = len; + /* do we have urgent data here? */ + if (sk->urg_data) { + unsigned long urg_offset = sk->urg_seq - (1 + *seq); + if (urg_offset < used) { + if (!urg_offset) { + if (!sk->urginline) { + ++*seq; + offset++; + used--; + } + } else + used = urg_offset; } } - /* Ok so how much can we use ? */ - used = min(skb->len - offset, len); /* Copy it */ memcpy_tofs(to,((unsigned char *)skb->h.th) + - skb->h.th->doff*4 + offset, used); + skb->h.th->doff*4 + offset, used); copied += used; len -= used; to += used; - - /* If we were reading the data is 'eaten' */ - if (!(flags & MSG_PEEK)) - sk->copied_seq += used; - - /* - * Mark this data used if we are really reading it, - * and if it doesn't contain any urgent data. And we - * have used all the data. - */ - if (!(flags & MSG_PEEK) && - (!skb->h.th->urg || skb->urg_used) && - (used + offset >= skb->len)) - skb->used = 1; - - /* - * See if this is the end of a message or if the - * remaining data is urgent. - */ - if (/*skb->h.th->psh || */skb->h.th->urg) - { - break; - } - } - else - { /* already used this data, must be a retransmit */ - skb->used = 1; + *seq += used; + if (after(sk->copied_seq+1,sk->urg_seq)) + sk->urg_data = 0; + if (!(flags & MSG_PEEK) && (used + offset >= skb->len)) + skb->used = 1; } - /* Move along a packet */ - skb =(struct sk_buff *)skb->next; - } - /* Clean up data we have read: This will do ACK frames */ - cleanup_rbuf(sk); - release_sock(sk); - DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); - if (copied == 0 && nonblock) - return(-EAGAIN); - return(copied); + remove_wait_queue(sk->sleep, &wait); + current->state = TASK_RUNNING; + + /* Clean up data we have read: This will do ACK frames */ + cleanup_rbuf(sk); + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); + return copied; } - + /* * Send a FIN without closing the connection. * Not called at interrupt time. @@ -1629,9 +1498,9 @@ buff->len += tmp; buff->dev = dev; memcpy(t1, th, sizeof(*t1)); - t1->seq = ntohl(sk->send_seq); - sk->send_seq++; - buff->h.seq = sk->send_seq; + t1->seq = ntohl(sk->write_seq); + sk->write_seq++; + buff->h.seq = sk->write_seq; t1->ack = 1; t1->ack_seq = ntohl(sk->acked_seq); t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); @@ -1651,6 +1520,7 @@ sk->wback = buff; buff->magic = TCP_WRITE_QUEUE_MAGIC; } else { + sk->sent_seq = sk->write_seq; sk->prot->queue_xmit(sk, dev, buff, 0); } @@ -1744,13 +1614,13 @@ if(th->ack) { - t1->ack=0; - t1->seq=th->ack_seq; - t1->ack_seq=0; + t1->ack = 0; + t1->seq = th->ack_seq; + t1->ack_seq = 0; } else { - t1->ack=1; + t1->ack = 1; if(!th->syn) t1->ack_seq=htonl(th->seq); else @@ -1925,10 +1795,10 @@ newsk->copied_seq = skb->h.th->seq; newsk->state = TCP_SYN_RECV; newsk->timeout = 0; - newsk->send_seq = jiffies * SEQ_TICK - seq_offset; - newsk->window_seq = newsk->send_seq; - newsk->rcv_ack_seq = newsk->send_seq; - newsk->urg =0; + newsk->write_seq = jiffies * SEQ_TICK - seq_offset; + newsk->window_seq = newsk->write_seq; + newsk->rcv_ack_seq = newsk->write_seq; + newsk->urg_data = 0; newsk->retransmits = 0; newsk->destroy = 0; newsk->timer.data = (unsigned long)newsk; @@ -2013,14 +1883,15 @@ t1 =(struct tcphdr *)((char *)t1 +tmp); memcpy(t1, skb->h.th, sizeof(*t1)); - buff->h.seq = newsk->send_seq; + buff->h.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->send_seq++); + t1->seq = ntohl(newsk->write_seq++); t1->ack = 1; newsk->window = tcp_select_window(newsk);/*newsk->prot->rspace(newsk);*/ + newsk->sent_seq = newsk->write_seq; t1->window = ntohs(newsk->window); t1->res1 = 0; t1->res2 = 0; @@ -2162,9 +2033,9 @@ buff->len += tmp; buff->dev = dev; memcpy(t1, th, sizeof(*t1)); - t1->seq = ntohl(sk->send_seq); - sk->send_seq++; - buff->h.seq = sk->send_seq; + t1->seq = ntohl(sk->write_seq); + sk->write_seq++; + buff->h.seq = sk->write_seq; t1->ack = 1; /* Ack everything immediately from now on. */ @@ -2177,6 +2048,7 @@ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); if (sk->wfront == NULL) { + sk->sent_seq = sk->write_seq; prot->queue_xmit(sk, dev, buff, 0); } else { reset_timer(sk, TIME_WRITE, sk->rto); @@ -2243,6 +2115,7 @@ kfree_skb(skb, FREE_WRITE); if (!sk->dead) sk->write_space(sk); } else { + sk->sent_seq = skb->h.seq; sk->prot->queue_xmit(sk, skb->dev, skb, skb->free); } } @@ -2310,8 +2183,9 @@ if (sk->retransmits && sk->timeout == TIME_KEEPOPEN) sk->retransmits = 0; - if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1)) { - if (after(ack, sk->send_seq) || +/* not quite clear why the +1 and -1 here, and why not +1 in next line */ + if (after(ack, sk->sent_seq+1) || before(ack, sk->rcv_ack_seq-1)) { + if (after(ack, sk->sent_seq) || (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) { return(0); } @@ -2587,7 +2461,7 @@ if (sk->state == TCP_TIME_WAIT) { if (!sk->dead) sk->state_change(sk); - if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) { + if (sk->rcv_ack_seq == sk->write_seq && sk->acked_seq == sk->fin_seq) { flag |= 1; sk->state = TCP_CLOSE; sk->shutdown = SHUTDOWN_MASK; @@ -2596,13 +2470,13 @@ if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) { if (!sk->dead) sk->state_change(sk); - if (sk->rcv_ack_seq == sk->send_seq) { + if (sk->rcv_ack_seq == sk->write_seq) { flag |= 1; if (sk->acked_seq != sk->fin_seq) { tcp_time_wait(sk); } else { DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk)); - tcp_send_ack(sk->send_seq, sk->acked_seq, sk, + tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, sk->daddr); sk->shutdown = SHUTDOWN_MASK; sk->state = TCP_CLOSE; @@ -2673,7 +2547,7 @@ sk->bytes_rcv += skb->len; if (skb->len == 0 && !th->fin && !th->urg && !th->psh) { /* Don't want to keep passing ack's back and forth. */ - if (!th->ack) tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr); + if (!th->ack) tcp_send_ack(sk->sent_seq, sk->acked_seq,sk, th, saddr); kfree_skb(skb, FREE_READ); return(0); } @@ -2777,8 +2651,16 @@ /* Now figure out if we can ack anything. */ if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) { if (before(th->seq, sk->acked_seq+1)) { - if (after(th->ack_seq, sk->acked_seq)) - sk->acked_seq = th->ack_seq; + int newwindow; + + if (after(th->ack_seq, sk->acked_seq)) { + newwindow = sk->window - + (th->ack_seq - sk->acked_seq); + if (newwindow < 0) + newwindow = 0; + sk->window = newwindow; + sk->acked_seq = th->ack_seq; + } skb->acked = 1; /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */ @@ -2793,16 +2675,12 @@ if (before(skb2->h.th->seq, sk->acked_seq+1)) { if (after(skb2->h.th->ack_seq, sk->acked_seq)) { - long old_acked_seq = sk->acked_seq; + newwindow = sk->window - + (skb2->h.th->ack_seq - sk->acked_seq); + if (newwindow < 0) + newwindow = 0; + sk->window = newwindow; sk->acked_seq = skb2->h.th->ack_seq; - if((int)(sk->acked_seq - old_acked_seq) >0) - { - int new_window=sk->window-sk->acked_seq+ - old_acked_seq; - if(new_window<0) - new_window=0; - sk->window = new_window; - } } skb2->acked = 1; @@ -2829,7 +2707,7 @@ if (!sk->delay_acks || sk->ack_backlog >= sk->max_ack_backlog || sk->bytes_rcv > sk->max_unacked || th->fin) { -/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */ +/* tcp_send_ack(sk->sent_seq, sk->acked_seq,sk,th, saddr); */ } else { sk->ack_backlog++; if(sk->debug) @@ -2874,12 +2752,12 @@ #endif kfree_skb(skb1, FREE_READ); } - tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); + tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); sk->ack_backlog++; reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); } else { /* We missed a packet. Send an ack to try to resync things. */ - tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); + tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); } /* Now tell the user we may have some data. */ @@ -2892,10 +2770,10 @@ } if (sk->state == TCP_FIN_WAIT2 && - sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq) { + sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->write_seq) { DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk)); -/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */ +/* tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); */ sk->shutdown = SHUTDOWN_MASK; sk->state = TCP_LAST_ACK; if (!sk->dead) sk->state_change(sk); @@ -2905,23 +2783,23 @@ } -static int -tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr) +static void tcp_check_urg(struct sock * sk, struct tcphdr * th) { - extern int kill_pg(int pg, int sig, int priv); - extern int kill_proc(int pid, int sig, int priv); - - if (!sk->dead) - sk->data_ready(sk,0); - - if (sk->urginline) { - th->urg = 0; - th->psh = 1; - return(0); - } + unsigned long ptr = ntohs(th->urg_ptr); + + if (ptr) + ptr--; + ptr += th->seq; + + /* ignore urgent data that we've already seen and read */ + if (after(sk->copied_seq+1, ptr)) + return; - if (!sk->urg) { - /* So if we get more urgent data, we don't signal the user again. */ + /* do we already have a newer (or duplicate) urgent pointer? */ + if (sk->urg_data && !after(ptr, sk->urg_seq)) + return; + + /* tell the world about our new urgent pointer */ if (sk->proc != 0) { if (sk->proc > 0) { kill_proc(sk->proc, SIGURG, 1); @@ -2929,9 +2807,33 @@ kill_pg(-sk->proc, SIGURG, 1); } } - } - sk->urg++; - return(0); + sk->urg_data = URG_NOTYET; + sk->urg_seq = ptr; +} + +static inline int tcp_urg(struct sock *sk, struct tcphdr *th, + unsigned long saddr, unsigned long len) +{ + unsigned long ptr; + + /* check if we get a new urgent pointer */ + if (th->urg) + tcp_check_urg(sk,th); + + /* do we wait for any urgent data? */ + if (sk->urg_data != URG_NOTYET) + return 0; + + /* is the urgent pointer pointing into this packet? */ + ptr = sk->urg_seq - th->seq + th->doff*4; + if (ptr >= len) + return 0; + + /* ok, got the correct packet, update info */ + sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th); + if (!sk->dead) + wake_up_interruptible(sk->sleep); + return 0; } @@ -3069,9 +2971,9 @@ sk->inuse = 1; sk->daddr = sin.sin_addr.s_addr; - sk->send_seq = jiffies * SEQ_TICK - seq_offset; - sk->window_seq = sk->send_seq; - sk->rcv_ack_seq = sk->send_seq -1; + sk->write_seq = jiffies * SEQ_TICK - seq_offset; + sk->window_seq = sk->write_seq; + sk->rcv_ack_seq = sk->write_seq -1; sk->err = 0; sk->dummy_th.dest = sin.sin_port; release_sock(sk); @@ -3101,8 +3003,9 @@ t1 = (struct tcphdr *)((char *)t1 +tmp); memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1)); - t1->seq = ntohl(sk->send_seq++); - buff->h.seq = sk->send_seq; + t1->seq = ntohl(sk->write_seq++); + sk->sent_seq = sk->write_seq; + buff->h.seq = sk->write_seq; t1->ack = 0; t1->window = 2; t1->res1=0; @@ -3152,75 +3055,60 @@ } -/* This functions checks to see if the tcp header is actually acceptible. */ +/* This functions checks to see if the tcp header is actually acceptable. */ static int tcp_sequence(struct sock *sk, struct tcphdr *th, short len, struct options *opt, unsigned long saddr, struct device *dev) { - /* - * This isn't quite right. sk->acked_seq could be more recent - * than sk->window. This is however close enough. We will accept - * slightly more packets than we should, but it should not cause - * problems unless someone is trying to forge packets. - */ - DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n", - sk, th, len, opt, saddr)); + unsigned long next_seq; - if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)|| - between(th->seq + len-(th->doff*4), sk->acked_seq + 1, - sk->acked_seq + sk->window) || - (before(th->seq, sk->acked_seq) && - after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window))) { - return(1); - } - DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n")); + next_seq = len - 4*th->doff; + if (th->fin) + next_seq++; + /* 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; - /* - * Send a reset if we get something not ours and we are - * unsynchronized. Note: We don't do anything to our end. We - * are just killing the bogus remote connection then we will - * connect again and it will work (with luck). - */ - - if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV) - { - tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl); - return(1); - } + /* + * This isn't quite right. sk->acked_seq could be more recent + * than sk->window. This is however close enough. We will accept + * slightly more packets than we should, but it should not cause + * problems unless someone is trying to forge packets. + */ - /* - * If it's too far ahead, send an ack to let the - * other end know what we expect. - */ - if (after(th->seq, sk->acked_seq + sk->window)) { - if(!th->rst) - tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); - return(0); - } + /* have we already seen all of this packet? */ + 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)) + goto ignore_it; -#ifdef undef -/* - * if we do this, we won't respond to keepalive packets, since those - * are slightly out of window, and we have to generate an ack - * a late ack out still not to have a sequence number less than - * one we've seen before. Berkeley doesn't seem to do this, but it's - * always hard to be sure. - */ - /* In case it's just a late ack, let it through. */ - if (th->ack && len == (th->doff * 4) && - after(th->seq, sk->acked_seq - 32767) && - !th->fin && !th->syn) return(1); -#endif + /* ok, at least part of this packet would seem interesting.. */ + return 1; - if (!th->rst) { - /* Try to resync things. */ - tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); - } - return(0); -} +ignore_it: + DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n")); + /* + * Send a reset if we get something not ours and we are + * unsynchronized. Note: We don't do anything to our end. We + * are just killing the bogus remote connection then we will + * connect again and it will work (with luck). + */ + + if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) { + tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl); + return 1; + } + if (th->rst) + return 0; + /* Try to resync things. */ + tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); + return 0; +} int @@ -3278,14 +3166,12 @@ return(0); } + th->seq = ntohl(th->seq); + /* See if we know about the socket. */ if (sk == NULL) { - if (!th->rst) - { - th->seq = ntohl(th->seq); - /* So reset is always called with th->seq in host order */ + if (!th->rst) tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255); - } skb->sk = NULL; kfree_skb(skb, FREE_READ); return(0); @@ -3296,15 +3182,12 @@ skb->acked = 0; skb->used = 0; skb->free = 0; - skb->urg_used = 0; skb->saddr = daddr; skb->daddr = saddr; - th->seq = ntohl(th->seq); - - /* We may need to add it to the backlog here. */ - cli(); - if (sk->inuse) { + /* We may need to add it to the backlog here. */ + cli(); + if (sk->inuse) { if (sk->back_log == NULL) { sk->back_log = skb; skb->next = skb; @@ -3374,7 +3257,7 @@ #ifdef undef /* nice idea, but tcp_sequence already does this. Maybe it shouldn't?? */ if(!th->rst) - tcp_send_ack(sk->send_seq, sk->acked_seq, + tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); #endif kfree_skb(skb, FREE_READ); @@ -3421,19 +3304,17 @@ release_sock(sk); return(0); } - if (th->ack) { - if (!tcp_ack(sk, th, saddr, len)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } + + if (th->ack && !tcp_ack(sk, th, saddr, len)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); } - if (th->urg) { - if (tcp_urg(sk, th, saddr)) { - kfree_skb(skb, FREE_READ); - release_sock(sk); - return(0); - } + + if (tcp_urg(sk, th, saddr, len)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); } if (tcp_data(skb, sk, saddr, len)) { @@ -3573,7 +3454,7 @@ /* Ack the syn and fall through. */ sk->acked_seq = th->seq+1; sk->fin_seq = th->seq; - tcp_send_ack(sk->send_seq, th->seq+1, + tcp_send_ack(sk->sent_seq, th->seq+1, sk, th, sk->daddr); case TCP_SYN_RECV: @@ -3617,7 +3498,7 @@ * already in the established state. */ if (th->urg) { - if (tcp_urg(sk, th, saddr)) { + if (tcp_urg(sk, th, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3632,7 +3513,7 @@ } if (th->urg) { - if (tcp_urg(sk, th, saddr)) { + if (tcp_urg(sk, th, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3671,7 +3552,9 @@ if (sk->zapped) return; /* Afer a valid reset we can send no more */ - if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) return; + if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && + sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2) + return; buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); if (buff == NULL) return; @@ -3701,7 +3584,7 @@ * Use a previous sequence. * This should cause the other end to send an ack. */ - t1->seq = ntohl(sk->send_seq-1); + t1->seq = htonl(sk->sent_seq-1); t1->ack = 1; t1->res1= 0; t1->res2= 0; @@ -3721,101 +3604,25 @@ sk->prot->queue_xmit(sk, dev, buff, 1); } -/* - * This routine probes a zero window. It makes a copy of the first - * packet in the write queue, but with just one byte of data. - */ void tcp_send_probe0(struct sock *sk) { - unsigned char *raw; - struct iphdr *iph; - struct sk_buff *skb2, *skb; - int len, hlen, data; - struct tcphdr *t1; - struct device *dev; + if (sk->zapped) + return; /* Afer a valid reset we can send no more */ - if (sk->zapped) - return; /* Afer a valid reset we can send no more */ - - if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && - sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2) - return; + tcp_write_wakeup(sk); - skb = sk->wfront; - if (skb == NULL) - return; - - dev = skb->dev; - /* I know this can't happen but as it does.. */ - if(dev==NULL) - { - printk("tcp_send_probe0: NULL device bug!\n"); - return; - } - IS_SKB(skb); - - raw = skb->data; - iph = (struct iphdr *) (raw + dev->hard_header_len); - - hlen = (iph->ihl * sizeof(unsigned long)) + dev->hard_header_len; - data = skb->len - hlen - sizeof(struct tcphdr); - len = hlen + sizeof(struct tcphdr) + (data ? 1 : 0); - - /* Allocate buffer. */ - if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len, GFP_ATOMIC)) == NULL) { -/* printk("alloc failed raw %x th %x hlen %d data %d len %d\n", - raw, skb->h.th, hlen, data, len); */ - reset_timer (sk, TIME_PROBE0, 10); /* try again real soon */ - return; - } - - skb2->arp = skb->arp; - skb2->len = len; - skb2->h.raw = (char *)(skb2->data); - - sk->wmem_alloc += skb2->mem_len; - - /* Copy the packet header into the new buffer. */ - memcpy(skb2->h.raw, raw, len); - - skb2->h.raw += hlen; /* it's now h.th -- pointer to the tcp header */ - t1 = skb2->h.th; - -/* source, dest, seq, from existing packet */ - t1->ack_seq = ntohl(sk->acked_seq); - t1->res1 = 0; -/* doff, fin, from existing packet. Fin is safe because Linux always - * sends fin in a separate packet - * syn, rst, had better be zero in original */ - t1->ack = 1; - t1->urg = 0; /* urgent pointer might be beyond this fragment */ - t1->res2 = 0; - t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/); - t1->urg_ptr = 0; - tcp_send_check(t1, sk->saddr, sk->daddr, len - hlen, sk); - /* Send it and free it. - * This will prevent the timer from automatically being restarted. - */ - sk->prot->queue_xmit(sk, dev, skb2, 1); - sk->backoff++; - /* - * in the case of retransmissions, there's good reason to limit - * rto to 120 sec, as that's the maximum legal RTT on the Internet. - * For probes it could reasonably be longer. However making it - * much longer could cause unacceptable delays in some situation, - * so we might as well use the same value - */ - sk->rto = min(sk->rto << 1, 120*HZ); - reset_timer (sk, TIME_PROBE0, sk->rto); - sk->retransmits++; - sk->prot->retransmits ++; + sk->backoff++; + sk->rto = min(sk->rto << 1, 120*HZ); + reset_timer (sk, TIME_PROBE0, sk->rto); + sk->retransmits++; + sk->prot->retransmits ++; } + /* * Socket option code for TCP. - */ - + */ int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val,err; diff -u +recursive +new-file 0.99pl15/linux/net/inet/tcp.h linux/net/inet/tcp.h --- 0.99pl15/linux/net/inet/tcp.h Wed Feb 2 17:02:02 1994 +++ linux/net/inet/tcp.h Wed Mar 2 11:09:52 1994 @@ -30,6 +30,11 @@ #define MIN_WRITE_SPACE 2048 #define TCP_WINDOW_DIFF 2048 +/* urg_data states */ +#define URG_VALID 0x0100 +#define URG_NOTYET 0x0200 +#define URG_READ 0x0400 + #define TCP_RETR1 7 /* * This is howmany retries it does before it * tries to figure out if the gateway is @@ -75,16 +80,12 @@ */ static inline int before(unsigned long seq1, unsigned long seq2) { - /* this inequality is strict. */ - if (seq1 == seq2) - return 0; - seq2 -= seq1; - return (seq2 < 65536); + return (long)(seq1-seq2) < 0; } static inline int after(unsigned long seq1, unsigned long seq2) { - return before(seq2, seq1); + return (long)(seq1-seq2) > 0; } @@ -113,7 +114,6 @@ extern struct proto tcp_prot; -extern void print_th(struct tcphdr *); extern void tcp_err(int err, unsigned char *header, unsigned long daddr, unsigned long saddr, struct inet_protocol *protocol); extern void tcp_shutdown (struct sock *sk, int how); @@ -124,6 +124,7 @@ extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); +extern void tcp_send_probe0(struct sock *sk); extern void tcp_enqueue_partial(struct sk_buff *, struct sock *); extern struct sk_buff * tcp_dequeue_partial(struct sock *); diff -u +recursive +new-file 0.99pl15/linux/net/unix/proc.c linux/net/unix/proc.c --- 0.99pl15/linux/net/unix/proc.c Mon Jan 3 08:51:33 1994 +++ linux/net/unix/proc.c Fri Mar 4 09:25:21 1994 @@ -16,6 +16,7 @@ * Fred Baumgarten, * * Fixes: + * Dmitry Gorodchanin : /proc locking fix * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -43,7 +44,7 @@ pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n"); for(i = 0; i < NSOCKETS; i++) { - if (unix_datas[i].refcnt) { + if (unix_datas[i].refcnt>0) { pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i, unix_datas[i].refcnt, unix_datas[i].protocol, diff -u +recursive +new-file 0.99pl15/linux/net/unix/sock.c linux/net/unix/sock.c --- 0.99pl15/linux/net/unix/sock.c Mon Jan 31 16:48:28 1994 +++ linux/net/unix/sock.c Fri Mar 4 09:25:20 1994 @@ -13,13 +13,14 @@ * Fixes: * Alan Cox : Verify Area * NET2E Team : Page fault locks + * Dmitry Gorodchanin : /proc locking * * To Do: + * Some nice person is looking into Unix sockets done properly. NET3 + * will replace all of this and include datagram sockets and socket + * options - so please stop asking me for them 8-) * - * Change to the NET2E3 code for Unix domain sockets in general. The - * read/write logic is much better and cleaner. * - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -237,7 +238,7 @@ struct unix_proto_data *upd; for(upd = unix_datas; upd <= last_unix_data; ++upd) { - if (upd->refcnt && upd->socket && + if (upd->refcnt > 0 && upd->socket && upd->socket->state == SS_UNCONNECTED && upd->sockaddr_un.sun_family == sockun->sun_family && upd->inode == inode) return(upd); @@ -254,7 +255,7 @@ cli(); for(upd = unix_datas; upd <= last_unix_data; ++upd) { if (!upd->refcnt) { - upd->refcnt = 1; + upd->refcnt = -1; /* unix domain socket not yet initialised - bgm */ sti(); upd->socket = NULL; upd->sockaddr_len = 0; @@ -328,6 +329,7 @@ upd->protocol = protocol; upd->socket = sock; UN_DATA(sock) = upd; + upd->refcnt = 1; /* Now its complete - bgm */ dprintf(1, "UNIX: create: allocated data 0x%x\n", upd); return(0); } diff -u +recursive +new-file 0.99pl15/linux/net/unix/unix.h linux/net/unix/unix.h --- 0.99pl15/linux/net/unix/unix.h Thu Jan 13 22:56:02 1994 +++ linux/net/unix/unix.h Fri Mar 4 09:25:21 1994 @@ -15,6 +15,9 @@ * Ross Biro, * Fred N. van Kempen, * + * Fixes: + * Dmitry Gorodchanin - proc locking + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -27,6 +30,7 @@ struct unix_proto_data { int refcnt; /* cnt of reference 0=free */ + /* -1=not initialised -bgm */ struct socket *socket; /* socket we're bound to */ int protocol; struct sockaddr_un sockaddr_un; diff -u +recursive +new-file 0.99pl15/linux/zBoot/Makefile linux/zBoot/Makefile --- 0.99pl15/linux/zBoot/Makefile Wed Dec 1 14:44:15 1993 +++ linux/zBoot/Makefile Wed Mar 9 11:11:16 1994 @@ -6,7 +6,7 @@ zOBJECTS = $(HEAD) inflate.o unzip.o misc.o -CFLAGS = -O6 -DSTDC_HEADERS $(TEST) +CFLAGS = -O2 -DSTDC_HEADERS $(TEST) .c.s: $(CC) $(CFLAGS) -S -o $*.s $< @@ -18,7 +18,7 @@ all: zSystem zSystem: piggy.o $(zOBJECTS) - $(LD) $(LDFLAGS) -o zSystem -T 1000 $(zOBJECTS) piggy.o + $(LD) $(LDFLAGS) -o zSystem -Ttext 1000 $(zOBJECTS) piggy.o head.o: head.s