diff -urN linux-2.0.39/COPYING linux-2.0.40/COPYING --- linux-2.0.39/COPYING 1998-07-13 13:47:25.000000000 -0700 +++ linux-2.0.40/COPYING 2004-02-07 23:13:01.000000000 -0800 @@ -14,7 +14,7 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -67,7 +67,7 @@ The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -122,7 +122,7 @@ License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -180,7 +180,7 @@ access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -237,7 +237,7 @@ This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -290,8 +290,8 @@ POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -303,7 +303,7 @@ the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) 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 @@ -317,14 +317,14 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff -urN linux-2.0.39/CREDITS linux-2.0.40/CREDITS --- linux-2.0.39/CREDITS 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/CREDITS 2004-02-07 23:13:01.000000000 -0800 @@ -3,7 +3,7 @@ formatted in a format that allows for easy grepping and beautification by scripts. The fields are: name (N), email (E), web-address (W), PGP key ID and fingerprint (P), description (D) - and snail-mail address (S). + and snail-mail address (S). Thanks, Linus @@ -263,7 +263,7 @@ E: jjo@mendoza.gov.ar D: Network driver alias support D: IP masq hashing and app modules -D: IP ip_dynaddr bits +D: IP ip_dynaddr bits S: Las Cuevas 2385 - Bo Guemes S: Las Heras, Mendoza CP 5539 S: Argentina @@ -386,7 +386,7 @@ D: Extended support for loadable modules D: D-Link pocket adapter drivers S: Grevgatan 11 -S: S-114 53 Stockholm +S: SE-114 53 STOCKHOLM S: Sweden N: Fritz Elfert @@ -513,7 +513,7 @@ N: Paul Gortmaker E: p_gortmaker@yahoo.com D: Real Time Clock driver author. -D: 8390 net driver hacker (ne2000, wd8013, smc-ultra, 3c503, etc.) +D: 8390 net driver hacker (ne2000, wd8013, smc-ultra, 3c503, etc.) D: Ethernet-HowTo and BootPrompt-HowTo author. D: Added many new CONFIG options (modules, ramdisk, generic-serial, etc.) D: Implemented 1st "official" kernel thread (moved user bdflush to kflushd) @@ -540,7 +540,7 @@ W: http://www.torque.net/linux-pp.html D: Iomega PPA / ZIP driver S: 44 St. Joseph Street, Suite 506 -S: Toronto, Ontario, M4Y 2W4 +S: Toronto, Ontario, M4Y 2W4 S: Canada N: Danny ter Haar @@ -717,7 +717,7 @@ N: Bernhard Kaindl E: bkaindl@netway.at E: edv@bartelt.via.at -D: Author of a menu based configuration tool, kmenu, which +D: Author of a menu based configuration tool, kmenu, which D: is the predecessor of 'make menuconfig' and 'make xconfig'. S: Tallak 95 S: 8103 Rein @@ -781,7 +781,7 @@ D: IP transparent proxy support S: X/OS Experts in Open Systems BV S: Kruislaan 419 -S: 1098 VA Amsterdam +S: 1098 VA Amsterdam S: The Netherlands N: Gero Kuhlmann @@ -922,7 +922,7 @@ D: BOOTP support S: Kankovskeho 1241 S: 182 00 Praha 8 -S: Czech Republic +S: Czech Republic N: John A. Martin E: jam@acm.org @@ -970,7 +970,7 @@ P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03 AB AB 15 A3 AE AD 39 7D D: Kernel hacker. Software watchdog daemon. D: Maintainer of several Debian packages -S: Th.-Heuss-Str. 61 +S: Th.-Heuss-Str. 61 S: D-41812 Erkelenz S: Germany @@ -1085,7 +1085,7 @@ W: http://www.i-Connect.Net/~mike/ D: Developer and maintainer of the EATA-DMA SCSI driver D: Co-developer EATA-PIO SCSI driver -D: /proc/scsi and assorted other snippets +D: /proc/scsi and assorted other snippets S: Zum Schiersteiner Grund 2 S: 55127 Mainz S: Germany @@ -1131,23 +1131,23 @@ S: Russia N: Kai Petzke -E: wpp@marie.physik.tu-berlin.de -W: http://physik.tu-berlin.de/~wpp -P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 +E: petzke@teltarif.de +W: http://www.teltarif.de/ +P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 D: Driver for Laser Magnetic Storage CD-ROM D: Some kernel bug fixes D: Port of the database Postgres -D: "Unix fuer Jedermann" a German introduction to linux (see my web page) -S: M"ullerstr. 69 -S: 13349 Berlin +D: Book: "Linux verstehen und anwenden" (Hanser-Verlag) +S: Triftstraße 55 +S: 13353 Berlin S: Germany N: Ken Pizzini E: ken@halcyon.com D: CDROM driver "sonycd535" (Sony CDU-535/531) -N: Frederic Potter -E: Frederic.Potter@masi.ibp.fr +N: Frederic Potter +E: Frederic.Potter@masi.ibp.fr D: Some PCI kernel support N: Stefan Probst @@ -1257,7 +1257,7 @@ D: Network layer debugging. D: Dial on demand facility (diald). S: Dag Hammerskjolds v. 3E -S: S-226 64 LUND +S: SE-226 64 LUND S: Sweden N: Henning P. Schmiedehausen @@ -1327,7 +1327,7 @@ E: csmall@triode.apana.org.au E: vk2xlz@gonzo.vk2xlz.ampr.org (packet radio) D: Gracilis PackeTwin device driver -D: RSPF daemon +D: RSPF daemon S: 10 Stockalls Place S: Minto, NSW, 2566 S: Australia @@ -1440,7 +1440,7 @@ E: tsusheng@scf.usc.edu D: IGMP(Internet Group Management Protocol) version 2 S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD -S: Taipei +S: Taipei S: Taiwan 112 S: Republic of China S: 24335 Delta Drive @@ -1529,7 +1529,7 @@ D: patches for ghostscript, worked on color 'ls', etc. S: 301 15th Street S. S: Moorhead, Minnesota 56560 -S: USA +S: USA N: Jos Vos E: jos@xos.nl @@ -1537,7 +1537,7 @@ D: Various IP firewall updates, ipfwadm S: X/OS Experts in Open Systems BV S: Kruislaan 419 -S: 1098 VA Amsterdam +S: 1098 VA Amsterdam S: The Netherlands N: Juergen Weigert @@ -1547,10 +1547,12 @@ N: David Weinehall E: tao@acc.umu.se W: http://www.acc.umu.se/~tao/ +P: 1024D/DC47CA16 7ACE 0FB0 7A74 F994 9B36 E1D1 D14E 8526 DC47 CA16 +D: v2.0 kernel maintainer D: Miscellaneous fixes D: Cleanup of the Config-files -S: Axtorpsvagen 40:20 -S: S-903 37 UMEA +S: Västra Varmvattnet 63 +S: SE-922 67 TAVELSJÖ S: Sweden N: Matt Welsh @@ -1628,7 +1630,7 @@ E: R.E.Wolff@BitWizard.nl D: Written kmalloc/kfree D: Written Specialix IO8+ driver -S: Van Bronckhorststraat 12 +S: Van Bronckhorststraat 12 S: 2612 XV Delft S: The Netherlands @@ -1671,14 +1673,10 @@ S: Germany N: Leonard N. Zubkoff -E: lnz@dandelion.com -W: http://www.dandelion.com/Linux/ D: BusLogic SCSI driver D: Mylex DAC960 PCI RAID driver D: Miscellaneous kernel fixes -S: 3078 Sulphur Spring Court -S: San Jose, California 95148 -S: USA +D: Rest in peace N: Marc Zyngier E: maz@wild-wind.fr.eu.org @@ -1688,7 +1686,7 @@ S: France # Don't add your name here, unless you really _are_ after Marc -# alphabetically. Leonard used to be very proud of being the +# alphabetically. Leonard used to be very proud of being the # last entry, and he'll get positively pissed if he can't even # be second-to-last. (and this file really _is_ supposed to be -# in alphabetic order) +# in alphabetic order) diff -urN linux-2.0.39/Documentation/Changes linux-2.0.40/Documentation/Changes --- linux-2.0.39/Documentation/Changes 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/Documentation/Changes 2004-02-07 23:13:01.000000000 -0800 @@ -68,6 +68,10 @@ - Net-tools 1.32-alpha - Kbd 0.91 +Note that it is _very_ unlikely that you will be able to compile the +2.0 kernel with gcc-3.x or binutils 2.9.x, and even if it compiles, it +might not work properly. + Upgrade notes ************* @@ -107,7 +111,7 @@ use the new features you'll need to upgrade your bootloaders. Lilo can be found at ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz. LOADLIN is at -ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz. If +ftp://sunsite.unc.edu/pub/linux/system/boot/dualboot/lodlin16.tgz. If you're using more unusual loaders like SysLinux or etherboot, the latest versions are 1.3 and 2.0, respectively. @@ -169,7 +173,7 @@ in linux/fs/locks.c and recompile. If you're still running a.out, there's an unofficial libc-4.7.6 release out to which you can upgrade to fix this problem. Libc is available from -ftp://sunsite.unc.edu/pub/Linux/GCC/. +ftp://ftp.win.tue.nl/pub/linux-local/libc.archive/libc/. GCC Signal 11 error =================== @@ -198,7 +202,7 @@ upgrade procps to the latest release, currently 1.01. Otherwise, you'll get floating point errors with some ps commands or other similar surprises. Grab -ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz. +ftp://sunsite.unc.edu/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-29-1996/system/Status/ps/procps-1.01.tar.gz. Kernel Modules ============== @@ -206,8 +210,9 @@ Almost all drivers in 2.0.x can be modules, and kerneld is now incorporated into the kernel. To take advantage of this, you'll need the latest version of the module support apps. These are available at -http://www.pi.se/blox/modules/modules-2.0.0.tar.gz. Note: If you try to -load a module and get a message like +ftp://sunsite.unc.edu/pub/linux/kernel.org/pub/linux/kernel/v2.0/modules-2.0.0.tar.gz. + +Note: If you try to load a module and get a message like `gcc2_compiled, undefined Failed to load module! The symbols from kernel 1.3.foo don't match 1.3.foo' @@ -241,7 +246,7 @@ You need to be running a pppd from ppp-2.2.0.tar.gz or greater. The latest stable release is 2.2.0f and is available at -ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz. +ftp://sunsite.unc.edu/pub/historic-linux/distributions/slackware/3.1/source/n/ppp/ppp-2.2.0f.tar.gz Named pipes (SysVinit) ====================== @@ -253,7 +258,7 @@ your computer shuts down fine but "INIT: error reading initrequest" or words to that effect scroll across your screen hundreds of times. To fix, upgrade to -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz. +ftp://sunsite.unc.edu/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-29-1996/system/Daemons/init/sysvinit-2.64.tar.gz. If you're trying to run NCSA httpd, you might have problems with pre-spawning daemons. Upgrade to the latest release (1.5.2), available @@ -284,20 +289,20 @@ details. Among the programs this has impacted are older sendmails. If you get a message that sendmail cannot lock aliases.dir (or other files), you'll need to upgrade to at least 8.7.x. The latest sendmail -is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.8.7.tar.gz. +is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/. Uugetty ======= Older uugettys will not allow use of a bidirectional serial line. To fix this problem, upgrade to -ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7i.tar.gz. +ftp://tucows.belgium.eu.net/pub/linux/slackware/slackware-3.3/source/a/getty/getty_ps-2.0.7i.tar.gz. Kbd === For those of you needing non-ASCII character/font support, you should -upgrade to ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/kbd-0.91.tar.gz. +upgrade to ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/old-kbd/kbd-0.91.tar.gz. Mount ===== @@ -306,7 +311,7 @@ currently at release 2.5. Some may find, especially when using the loop or xiafs file system, NFS, or automounting, that they need to upgrade to the latest release of mount, available from -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5p.tar.gz. +ftp://ftp.win.tue.nl/pub/linux/utils/attic/mount/mount-2.5p.tar.gz. Console ======= @@ -321,14 +326,15 @@ ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console Better yet, just get the latest official Linux termcap from -ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz. If you -upgrade to this release read the `README' file contained into the -package to get some important information about the `tgetent' function -changes! Note that there is now a fixed version at -ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.fix. If some of your -apps complain that termcap entries are too long and you don't need some -of the more esoteric terms in the standard 2.0.8 termcap, just download -termcap-2.0.8.fix and move it to /etc/termcap. +ftp://sunsite.unc.edu/pub/historic-linux/distributions/slackware/3.1/source/d/libc/termcap-2.0.8.tar.gz. +If you upgrade to this release read the `README' file contained into +the package to get some important information about the `tgetent' +function changes! +Note that there is now a fixed version at +ftp://sunsite.unc.edu/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-19-1996/GCC/termcap-2.0.8.fix. +If some of your apps complain that termcap entries are too long and +you don't need some of the more esoteric terms in the standard 2.0.8 +termcap, just download termcap-2.0.8.fix and move it to /etc/termcap. Also, the console driver is now responsible for keeping track of correspondence between character codes and glyph bitmaps. If you @@ -340,7 +346,7 @@ Hdparm has been upgraded to take advantage of the latest features of the kernel drivers. The latest non-beta version can be found at -ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-3.1.tar.gz. +ftp://sunsite.unc.edu/pub/linux-historic/ftp-archives/sunsite.unc.edu/Sep-19-1996/kernel/patches/diskdrives/hdparm-3.1.tar.gz. IP Accounting ============= @@ -354,7 +360,8 @@ There also exists a possibility to match on device names and/or device addresses, so that only packets coming in/going out via that device (network interface) match with a rule. You'll need to get -ipfwadm from ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to +ipfwadm from +ftp://ftp.sunsite.auc.dk/disk2/slackware/slackware-8.0/pasture/pasture-sources/ipfwadm-2.3.0/ipfwadm-2.3.0.tar.gz to use this. IP Firewalls @@ -367,7 +374,8 @@ so that only packets coming in/going out via that device (network interface) match with a rule. This is especially useful to prevent spoofing. You'll need to get -ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. +ftp://ftp.sunsite.auc.dk/disk2/slackware/slackware-8.0/pasture/pasture-sources/ipfwadm-2.3.0/ipfwadm-2.3.0.tar.gz to +to use this. IP Masquerading =============== @@ -376,7 +384,8 @@ always need to load separate modules (ip_masq_ftp.o and/or ip_masq_irc.o) if you are going to use FTP or IRC in combination with masquerading. You'll need to get -ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. +ftp://ftp.sunsite.auc.dk/disk2/slackware/slackware-8.0/pasture/pasture-sources/ipfwadm-2.3.0/ipfwadm-2.3.0.tar.gz to +to use this. To enable IP forwarding, you may need to @@ -388,28 +397,28 @@ ============ The new kernels support ISDN. You'll need ISDN utils available from -ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz to try -this. +ftp://ftp.uni-jena.de/pub/fsu/rz/software/linux/internetworking/isdn/isdn4k-utils-2.0.tar.gz +to try this. Frame Relay =========== Frame relay support for Linux is now available as well. Currently, only Sangoma cards are supported, but the interface is such that others -will be as drivers become available. To use this, grab -ftp://linux.invlogic.com/pub/fr/frad-0.15.tgz (soon to be -frad-0.20.tgz). Another package of interest is -ftp://linux.invlogic.com/pub/routing/routing.tgz (which allows Linux to -make routing decisions based on packet source). +will be as drivers become available. To use this, grab +ftp://ftp.task.gda.pl/mirror/ftp.invlogic.com/pub/fr/frad-0.15.tgz +(soon to be frad-0.20.tgz). Another package of interest is +ftp://ftp.task.gda.pl/mirror/ftp.invlogic.com/pub/routing/routing-2.0.33.tgz +(which allows Linux to make routing decisions based on packet source). Networking ========== Some of the /proc/net entries have changed. You'll need to upgrade to the latest net-tools in -ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/, where the latest -is currently net-tools-1.32-alpha.tar.gz. See -http://www.inka.de/sites/lina/linux/NetTools/index_en.html for more +ftp://ftp.task.gda.pl/mirror/ftp.invlogic.com/pub/linux/routing/, +where the latest is currently net-tools-1.33.tar.gz. +See http://www.inka.de/sites/lina/linux/NetTools/index_en.html for more information. Note that there is currently no ipfw (which is part of net-tools) which works with 2.0.x kernels. If you need its functions, learn how to use ipfwadm or patch ipfw to get it to work (ipfw's current @@ -427,9 +436,10 @@ The sound driver was upgraded in the 2.0.x kernels, breaking vplay. To fix this problem, get a new version of the sndkit from -ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz. Some users -report that various other sound utils (cdd2wav-sbpcd, for example) need -to be recompiled before they will work with the new kernels. +ftp://sunsite.unc.edu/pub/historic-linux/distributions/slackware/3.1/source/extra-stuff/sound-utilities/snd-util-3.5.tar.gz. +Some users report that various other sound utils (cdd2wav-sbpcd, for +example) need to be recompiled before they will work with the new +kernels. Tcsh ==== @@ -459,8 +469,8 @@ file as a file system, which can allow for all sorts of cool things like encrypted file systems and such. To use it, you'll need a modified version of mount from -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz; preliminary work -on encrypted file system support can be found in +ftp://ftp.win.tue.nl/pub/linux-local/utils/attic/mount/mount-2.5k.tar.gz; +preliminary work on encrypted file system support can be found in ftp.funet.fi:/pub/Linux/BETA/loop/des.1.tar.gz. Multiple device diff -urN linux-2.0.39/Documentation/Configure.help linux-2.0.40/Documentation/Configure.help --- linux-2.0.39/Documentation/Configure.help 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/Documentation/Configure.help 2004-02-07 23:13:01.000000000 -0800 @@ -40,7 +40,7 @@ Prompt for development and/or incomplete code/drivers CONFIG_EXPERIMENTAL Some of the various things that Linux supports (such as network - drivers, filesystems, network protocols, etc.) can be in a state + drivers, file systems, network protocols, etc.) can be in a state of development where the functionality, stability, or the level of testing is not yet high enough for general use. This is usually known as the "alpha-test" phase amongst developers. If a feature is @@ -122,7 +122,7 @@ RAM disk support CONFIG_BLK_DEV_RAM Enabling this option will allow you to use a portion of your RAM - memory as a block device, so that you can make filesystems on it, + memory as a block device, so that you can make file systems on it, read and write to it and do all the other things that normal block devices (such as hard drives) can do. It is usually used to load and store a copy of a minimal root file system off of a floppy into RAM @@ -148,17 +148,17 @@ system. This is useful if you want to check an ISO9660 file system before burning the CD, or want to use floppy images without first writing them to floppy. This option also allows one to mount a - filesystem with encryption. To use these features, you need a + file system with encryption. To use these features, you need a recent version of mount (check the file Documentation/Changes for location and latest version). Note that this loop device has nothing to do with the loopback device used for network connections from the machine to itself. Most users will answer N here. -Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support +Enhanced IDE/MFM/RLL disk/CD-ROM/tape/floppy support CONFIG_BLK_DEV_IDE This will use the full-featured IDE driver to control up to four IDE interfaces, for a combination of up to eight IDE - disk/cdrom/tape/floppy drives. Useful information about large + disk/CD-ROM/tape/floppy drives. Useful information about large (>540MB) IDE disks, sound card IDE ports, and other topics, is all contained in Documentation/ide.txt. If you have one or more IDE drives, say Y here. If your system has no IDE drives, or if @@ -189,7 +189,7 @@ hard disk driver to control the primary IDE/disk interface in the system, leaving the new enhanced IDE driver take care of only the 2nd/3rd/4th IDE interfaces. Doing this will prevent you from having - an IDE/ATAPI CDROM or tape drive connected to the primary IDE + an IDE/ATAPI CD-ROM or tape drive connected to the primary IDE interface. Choosing this option may be useful for older systems which have MFM/RLL/ESDI controller+drives at the primary port address (0x1f0), along with IDE drives at the secondary/3rd/4th port @@ -205,21 +205,21 @@ If in doubt, say N. -Include IDE/ATAPI CDROM support +Include IDE/ATAPI CD-ROM support CONFIG_BLK_DEV_IDECD - If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is - a new protocol used by IDE CDROM and TAPE drives, similar to the - SCSI protocol. Most new CDROM drives use ATAPI, including the + If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is + a new protocol used by IDE CD-ROM and tape drives, similar to the + SCSI protocol. Most new CD-ROM drives use ATAPI, including the NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI double(2X), quad(4X), and six(6X) speed drives. At boot time, the - TAPE drive will be identified along with other IDE devices, as "hdb" + tape drive will be identified along with other IDE devices, as "hdb" or "hdc", or something similar. - If this is your only CDROM drive, you can say N to all other CDROM - options, but be sure to say Y to the ISO9660 filesystem. Read the + If this is your only CD-ROM drive, you can say N to all other CD-ROM + options, but be sure to say Y to the ISO9660 file system. Read the CDROM-HOWTO, available via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO and the file - Documentation/cdrom/ide-cd. Note that older versions of lilo (the - Linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so + Documentation/CD-ROM/ide-cd. Note that older versions of lilo (the + Linux boot loader) cannot properly deal with IDE/ATAPI CD-ROMs, so install lilo-16 or higher, available from sunsite.unc.edu:/pub/Linux/system/Linux-boot/lilo. @@ -236,7 +236,7 @@ Include IDE/ATAPI FLOPPY support (new) CONFIG_BLK_DEV_IDEFLOPPY If you have an IDE floppy which uses the ATAPI protocol, say Y. - ATAPI is a new protocol used by IDE cdrom/tape/floppy drives, + ATAPI is a new protocol used by IDE CD-ROM/tape/floppy drives, similar to the SCSI protocol. IDE floppy drives include the LS-120 and the ATAPI ZIP (ATAPI PD-CD drives are not supported by this driver; support for PD-CD drives is available through the SCSI @@ -347,7 +347,7 @@ boot parameter. It enables support for the secondary IDE interface of the chipset, and takes advantage of the caching features of the card. This driver is known to incur timeouts/retries during heavy - I/O to drives attached to the secondary interface. CDROM and TAPE + I/O to drives attached to the secondary interface. CD-ROM and TAPE devices are not supported yet. See the Documentation/ide.txt and promise.c files for more info. @@ -406,8 +406,8 @@ system. Among the devices supported by this driver are the MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If you have such a CD-ROM drive, you should also say Y to "ISO9660 - cdrom filesystem support" below, because that's the filesystem used - on CDROMs. + CD-ROM file system support" below, because that's the file system used + on CD-ROMs. Parallel port ATAPI disks CONFIG_PARIDE_PF @@ -1080,7 +1080,7 @@ Kernel daemon support CONFIG_KERNELD - Normally when you have selected some drivers and/or filesystems to + Normally when you have selected some drivers and/or file systems to be created as loadable modules, you also have the responsibility to load the corresponding module (via insmod/modprobe) before you can use it. If you select Y here, the kernel will take care of this all @@ -1212,7 +1212,7 @@ a router or a firewall for some local network, in which case you naturally should have said Y to IP forwarding/gatewaying resp. IP firewalling. The data is accessible with "cat /proc/net/ip_acct", so - you want to say Y to the /proc filesystem below, if you say Y here. + you want to say Y to the /proc file system below, if you say Y here. To specify what exactly should be recorded, you need the tool ipfwadm (check the file Documentation/Changes for location and latest version). @@ -1236,7 +1236,7 @@ IP: firewall packet logging CONFIG_IP_FIREWALL_VERBOSE This gives you information about what your firewall did with packets - it received. The information is handled by the klogd demon which is + it received. The information is handled by the klogd daemon which is responsible for kernel messages ("man klogd"). IP: transparent proxying (EXPERIMENTAL) @@ -1493,7 +1493,7 @@ sunsite.unc.edu:/pub/Linux/system/Filesystems/) or from within the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in sunsite.unc.edu:/pub/Linux/docs/HOWTO). In order to do the former, - you'll also have to say Y to "NCP filesystem support", below. To + you'll also have to say Y to "NCP file system support", below. To turn your Linux box into a fully featured NetWare file server and IPX router, say Y here and fetch either lwared from sunsite.unc.edu:/pub/Linux/system/Network/daemons/ or mars_nwe from @@ -1632,7 +1632,7 @@ SCSI support? CONFIG_SCSI - If you want to use a SCSI hard disk, SCSI tapedrive, SCSI CDROM or + If you want to use a SCSI hard disk, SCSI tapedrive, SCSI CD-ROM or any other SCSI device under Linux, say Y and make sure that you know the name of your SCSI host adapter (the card inside your computer that "speaks" the SCSI protocol), because you will be asked for it. @@ -1650,7 +1650,7 @@ If you want to use a SCSI hard disk or the SCSI or parallel port version of the IOMEGA ZIP drive under Linux, say Y and read the SCSI-HOWTO, available via FTP (user: anonymous) in sunsite.unc.edu: - /pub/Linux/docs/HOWTO. This is NOT for SCSI CDROMs. + /pub/Linux/docs/HOWTO. This is NOT for SCSI CD-ROMs. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read @@ -1661,18 +1661,18 @@ If you want to use a SCSI tapedrive under Linux, say Y and read the SCSI-HOWTO, available via FTP (user: anonymous) in sunsite.unc.edu: /pub/Linux/docs/HOWTO and drivers/scsi/README.st in the kernel - source. This is NOT for SCSI CDROMs. This driver is also available + source. This is NOT for SCSI CD-ROMs. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt and Documentation/scsi.txt. -SCSI CDROM support +SCSI CD-ROM support CONFIG_BLK_DEV_SR - If you want to use a SCSI CDROM under Linux, say Y and read the + If you want to use a SCSI CD-ROM under Linux, say Y and read the SCSI-HOWTO and the CDROM-HOWTO from sunsite.unc.edu: /pub/Linux/docs/HOWTO. Also make sure to enable the ISO9660 - filesystem later. This driver is also available as a module ( = code + file system later. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt and Documentation/scsi.txt. @@ -1681,7 +1681,7 @@ CONFIG_CHR_DEV_SG If you want to use SCSI scanners, synthesizers or CD-writers or just about anything having "SCSI" in its name other than hard disks, - CDROMs or tapes, say Y here. Those won't be supported by the kernel + CD-ROMs or tapes, say Y here. Those won't be supported by the kernel directly, so you need some additional software which knows how to talk to these devices using the SCSI protocol. For CD-writers, you would need the program cdwrite, available via FTP (user: anonymous) @@ -1708,7 +1708,7 @@ CONFIG_SCSI_CONSTANTS The error messages regarding your SCSI hardware will be easier to understand if you enable this; it will enlarge your kernel by about - 12KB. If in doubt, say Y. + 12kB. If in doubt, say Y. AdvanSys SCSI support CONFIG_SCSI_ADVANSYS @@ -1834,7 +1834,7 @@ small amount of overhead to each and every SCSI command the aic7xxx driver handles, so if you aren't really interested in this information, it is best to leave it disabled. This will only work if - you also say Y to "/proc filesystem support", below. + you also say Y to "/proc file system support", below. If unsure, say N. @@ -3392,31 +3392,31 @@ Support non-SCSI/IDE/ATAPI drives CONFIG_CD_NO_IDESCSI - If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y + If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y here, otherwise N. Read the CDROM-HOWTO, available via FTP (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all the questions - about these CDROM drives. If you are unsure what you have, say Y and + about these CD-ROM drives. If you are unsure what you have, say Y and find out whether you have one of the following drives. - For each of these drivers, a file Documentation/cdrom/ + For each of these drivers, a file Documentation/CD-ROM/ exists. Especially in cases where you do not know exactly which kind of drive you have you should read there. Most of these drivers use a file include/linux/.h where you can define your interface parameters and switch some internal goodies. - All these CDROM drivers are also usable as a module ( = code which + All these CD-ROM drivers are also usable as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile them as module, say M instead of Y and read Documentation/modules.txt. - If you want to use any of these CDROM drivers, you also have to say - Y to "ISO9660 cdrom filesystem support" below (this answer will get - "defaulted" for you if you enable any of the Linux CDROM drivers). + If you want to use any of these CD-ROM drivers, you also have to say + Y to "ISO9660 CD-ROM file system support" below (this answer will get + "defaulted" for you if you enable any of the Linux CD-ROM drivers). -Sony CDU31A/CDU33A CDROM support +Sony CDU31A/CDU33A CD-ROM support CONFIG_CDU31A - These CDROM drives have a spring-pop-out caddyless drawer, and a - rectangular green LED centered beneath it. NOTE: these CDROM drives + These CD-ROM drives have a spring-pop-out caddyless drawer, and a + rectangular green LED centered beneath it. NOTE: these CD-ROM drives will not be auto detected by the kernel at boot time; you have to provide the interface address as an option to the kernel at boot time as described in Documentation/cdrom/cdu31a or fill in your @@ -3424,14 +3424,14 @@ of your boot loader (lilo or loadlin) about how to pass options to the kernel. The lilo procedure is also explained in the SCSI-HOWTO. -Standard Mitsumi [no XA/Multisession] CDROM support +Standard Mitsumi [no XA/Multisession] CD-ROM support CONFIG_MCD This is the older of the two drivers for the older Mitsumi models LU-005, FX-001 and FX-001D. This is not the right driver for the FX-001DE and the triple or quad speed models (all these are IDE/ATAPI models). With the old LU-005 model, the whole drive chassis slides out for - cd insertion. The FX-xxx models use a motorized tray type mechanism. + CD insertion. The FX-xxx models use a motorized tray type mechanism. Note that this driver does not support XA or MultiSession CDs (PhotoCDs). There is a new driver (next question) which can do this. If you want that one, say N here. @@ -3442,12 +3442,12 @@ CONFIG_MCDX Use this driver if you want to be able to read XA or MultiSession CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005, - FX-001 or FX-001D CDROM drive. In addition, this driver uses much + FX-001 or FX-001D CD-ROM drive. In addition, this driver uses much less kernel memory than the old one, if that is a concern. This driver is able to support more than one drive, but each drive needs a separate interface card. Check out Documentation/cdrom/mcdx. -Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support +Matsushita/Panasonic/Creative, Longshine, TEAC CD-ROM support CONFIG_SBPCD This driver supports most of the drives which use the Panasonic or SoundBlaster interface. @@ -3467,76 +3467,76 @@ none of the supported drives gets found. Once your drive got found, you should enter the reported parameters into linux/include/linux/sbpcd.h and set "DISTRIBUTION 0" there. - This driver can support up to four CDROM interface cards, and each - card can support up to four CDROM drives; if you say Y here, you + This driver can support up to four CD-ROM interface cards, and each + card can support up to four CD-ROM drives; if you say Y here, you will be asked how many controllers you have. If compiled as a module, only one interface card (but with up to four drives) is usable. -Matsushita/Panasonic, ... second CDROM controller support +Matsushita/Panasonic, ... second CD-ROM controller support CONFIG_SBPCD2 - Say Y here only if you have two CDROM controller boards of this type + Say Y here only if you have two CD-ROM controller boards of this type (usually only if you have more than four drives). You should enter the parameters for the second, third and fourth interface card into linux/include/linux/sbpcd.h before compiling the new kernel. -Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support +Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CD-ROM support CONFIG_AZTCD This is your driver if you have an Aztech CDA268-01A, Orchid CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCDROM CR520 or - CR540 CDROM drive. This driver -- just like all these CDROM drivers - -- is NOT for CDROM drives with IDE/ATAPI interface, such as Aztech + CR540 CD-ROM drive. This driver -- just like all these CD-ROM drivers + -- is NOT for CD-ROM drives with IDE/ATAPI interface, such as Aztech CDA269-031SE. -Sony CDU535 CDROM support +Sony CDU535 CD-ROM support CONFIG_CDU535 - This is the driver for the older Sony CDU-535 and CDU-531 CDROM + This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM drives. -Goldstar R420 CDROM support +Goldstar R420 CD-ROM support CONFIG_GSCD - If this is your CDROM drive, say Y here. + If this is your CD-ROM drive, say Y here. As described in linux/Documentation/cdrom/gscd, you might have to change a setting in the file include/linux/gscd.h before compiling the kernel. -Philips/LMS CM206 CDROM support +Philips/LMS CM206 CD-ROM support CONFIG_CM206 - If you have a Philips/LMS CDROM drive cm206 in combination with a + If you have a Philips/LMS CD-ROM drive cm206 in combination with a cm260 host adapter card, say Y here. -Optics Storage DOLPHIN 8000AT CDROM support +Optics Storage DOLPHIN 8000AT CD-ROM support CONFIG_OPTCD This is the driver for the 'DOLPHIN' drive with a 34-pin Sony compatible interface. It also works with the Lasermate CR328A. If you have one of those, say Y. This driver does not work for the - Optics Storage 8001 drive; use the IDE-ATAPI CDROM driver for that + Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that one. -Sanyo CDR-H94A CDROM support +Sanyo CDR-H94A CD-ROM support CONFIG_SJCD - If this is your CDROM drive, say Y here. Command line option + If this is your CD-ROM drive, say Y here. Command line option (or 'append=' option in /etc/lilo.conf) is: sjcd= Here 'port' is the base i/o address used by the drive. It defaults to port=0x340. -Soft configurable cdrom interface card support +Soft configurable CD-ROM interface card support CONFIG_CDI_INIT - If you want to include boot-time initialization of any cdrom + If you want to include boot-time initialization of any CD-ROM interface card that is software configurable, say Y here. Currently only the ISP16/MAD16/Mozart cards are supported. -ISP16/MAD16/Mozart soft configurable cdrom interface support +ISP16/MAD16/Mozart soft configurable CD-ROM interface support CONFIG_ISP16_CDI - If you want any of these cdrom interface cards based on the + If you want any of these CD-ROM interface cards based on the OPTi 82C928 or 82C929 chips get detected and possibly configured at boot time, please say Y. Boot time command line options (or 'append=' options in /etc/lilo.conf) are: isp16=,,, Here 'port','irq' and 'dma' are the base i/o address, IRQ number and - DMA line assumed to be used by the attached cdrom - drive. 'drive_type' is the type of cdrom drive or its emulation + DMA line assumed to be used by the attached CD-ROM + drive. 'drive_type' is the type of CD-ROM drive or its emulation mode. Valid values for drive_type include: Sanyo, Panasonic (same as Sanyo), Sony and Mitsumi. Default values are: port=0x340, irq=0, dma=0, drive_type=Sanyo. @@ -3550,7 +3550,7 @@ CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk usage (also called diskquotas). Currently, it works only for the - ext2 filesystem. You need additional software in order to use quota + ext2 file system. You need additional software in order to use quota support; check the file Documentation/Changes for that. Probably the quota support is only useful for multi user systems. If unsure, say N. @@ -3570,9 +3570,9 @@ Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. - The minix filesystem ( = method to organize files on a hard disk - partition or a floppy disk) was the original filesystem for Linux, - has been superseded by the second extended filesystem ext2fs but is + The minix file system ( = method to organize files on a hard disk + partition or a floppy disk) was the original file system for Linux, + has been superseded by the second extended file system ext2fs but is still used for root/boot and other floppies or ram disks since it is leaner. You don't want to use it on your hard disk because of certain built-in restrictions. This option will enlarge your kernel @@ -3580,22 +3580,22 @@ read this common floppy format. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read - Documentation/modules.txt. Note that the filesystem of your root + Documentation/modules.txt. Note that the file system of your root partition cannot be compiled as a module. Extended fs support CONFIG_EXT_FS - This is the old Linux filesystem ( = method to organize files on a + This is the old Linux file system ( = method to organize files on a hard disk partition or a floppy disk) and not in use anymore. It enlarges your kernel by about 25 kB. Let's all kill this beast. Say N. Second extended fs support CONFIG_EXT2_FS - This is the de facto standard Linux filesystem ( = method to + This is the de facto standard Linux file system ( = method to organize files on a storage device) for hard disks. You want to say Y, unless you intend to use Linux exclusively from inside a DOS - partition using the umsdos filesystem. The advantage of the latter + partition using the umsdos file system. The advantage of the latter is that you can get away without repartitioning your hard drive (which often implies backing everything up and restoring afterwards); the disadvantage is that Linux becomes susceptible to @@ -3605,7 +3605,7 @@ facilitates the transition to a *real* Linux partition later. Another (rare) case which doesn't require ext2fs is a diskless Linux box which mounts all files over the network using NFS (in this case - it's sufficient to enable NFS filesystem support below; if you are + it's sufficient to enable NFS file system support below; if you are planning to do this, have a look at the netboot package in /pub/Linux/system/Linux-boot/, available via FTP (user: anonymous) from sunsite.unc.edu, extract with "tar xzvf filename"). There is a @@ -3613,31 +3613,31 @@ sunsite.unc.edu:/pub/Linux/docs/faqs. This option will enlarge your kernel by about 41 kB. Default is Y. -xiafs filesystem support +xiafs file system support CONFIG_XIA_FS - This is an old filesystem ( = method to organize files on a hard + This is an old file system ( = method to organize files on a hard disk partition or a floppy disk) and not in use anymore. This option would enlarge your kernel by about 28 kB. Let's all kill this beast: say N. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. Note that the - filesystem of your root partition cannot be compiled as a module. + file system of your root partition cannot be compiled as a module. -fat fs support +FAT fs support CONFIG_FAT_FS - If you want to use one of the FAT-based filesystems (the MS-DOS, - VFAT (Windows'95) and UMSDOS filesystems), then you must include - FAT support. This is not a filesystem in itself, but it provides - the foundation for the other filesystems. This option will enlarge + If you want to use one of the FAT-based file systems (the MS-DOS, + VFAT (Windows'95) and UMSDOS file systems), then you must include + FAT support. This is not a file system in itself, but it provides + the foundation for the other file systems. This option will enlarge your kernel about 24 kB. If unsure, say Y. If you want to compile this as a module however ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. Note that if you compile the FAT support as a module, you cannot compile any of the FAT-based - filesystems into the kernel -- they will have to be modules as well. - The filesystem of your root partition cannot be a module. + file systems into the kernel -- they will have to be modules as well. + The file system of your root partition cannot be a module. -msdos fs support +MSDOS fs support CONFIG_MSDOS_FS This allows you to mount MSDOS partitions of your hard drive (unless they are compressed; to access compressed MSDOS partitions under @@ -3650,29 +3650,29 @@ i.e. the MSDOS files look and behave just like all other Unix files. Another way to read and write MSDOS floppies from within Linux (but not transparently) is with the mtools ("man mtools") program suite, - which doesn't require the msdos filesystem support. If you want to - use umsdos, the Unix-like filesystem on top of DOS, which allows you + which doesn't require the MSDOS file system support. If you want to + use umsdos, the Unix-like file system on top of DOS, which allows you to run Linux from within a DOS partition without repartitioning, you'll have to say Y or M here. If your have Windows'95 or Windows NT installed on your MSDOS partitions, you should use the VFAT - filesystem instead, or you will not be able to see the long + file system instead, or you will not be able to see the long filenames generated by Windows'95 / Windows NT. This option will enlarge your kernel by about 7 kB. If unsure, say Y. This will only - work if you said Y to "fat fs support" as well. If you want to + work if you said Y to "FAT fs support" as well. If you want to compile this as a module however ( = code which can be inserted in and removed from the running kernel whenever you want), say M here - and read Documentation/modules.txt. Note that the filesystem of your + and read Documentation/modules.txt. Note that the file system of your root partition cannot be a module. -vfat fs support +VFAT fs support CONFIG_VFAT_FS This allows you to mount MSDOS partitions of your hard drive. It will let you use filenames in a way compatible with the long - filenames used by Windows'95 and Windows NT fat-based (not NTFS) - partitions. It does not support Windows'95 compressed filesystems. - You cannot use the VFAT filesystem for your root partition; use + filenames used by Windows'95 and Windows NT FAT-based (not NTFS) + partitions. It does not support Windows'95 compressed file systems. + You cannot use the VFAT file system for your root partition; use UMSDOS instead. This option enlarges your kernel by about 10 kB and - it only works if you enabled the "fat fs support" above. Please read + it only works if you enabled the "FAT fs support" above. Please read the file Documentation/filesystems/vfat.txt for details. If unsure, say N. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel @@ -3692,19 +3692,19 @@ MSDOS floppies. You will need a program called umssync in order to make use of umsdos. Read Documentation/filesystems/umsdos.txt. This option enlarges your kernel by about 25 kB and it only works if you - enabled both "fat fs support" and "msdos fs support" above. If + enabled both "FAT fs support" and "MSDOS fs support" above. If unsure, say N. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. - Note that the filesystem of your root partition cannot be a module. + Note that the file system of your root partition cannot be a module. nls: Native language codepages and Unicode support CONFIG_NLS - This is required by the FAT based filesystems and by the ISO9660 - filesystem with Joliet support. Joliet is a Microsoft extension - for CDROMs that supports Unicode. + This is required by the FAT based file systems and by the ISO9660 + file system with Joliet support. Joliet is a Microsoft extension + for CD-ROMs that supports Unicode. This allows translation between different character sets. When - dealing with the FAT based filesystems, there are two character + dealing with the FAT based file systems, there are two character sets that are important. The first is the codepage. Codepages are character sets that are used by DOS to allow filenames to have native language characters when character sets were limited to @@ -3850,13 +3850,13 @@ CONFIG_NLS_CODEPAGE_874 This is the DOS codepage that is used for Thai. -/proc filesystem support +/proc file system support CONFIG_PROC_FS - This is a virtual filesystem providing information about the status + This is a virtual file system providing information about the status of the system. "Virtual" means that it doesn't take up any space on your hard disk: the files are created on the fly when you access them. Also, you cannot read the files with less: you need to use - more or cat. The filesystem is explained in the Kernel Hacker's + more or cat. The file system is explained in the Kernel Hacker's Guide, available via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/LDP and also on the proc(8) manpage ("man 8 proc"). This option will enlarge your kernel by about 18 @@ -3868,7 +3868,14 @@ the same IRQ). Several programs depend on this, so everyone should say Y here. -NFS filesystem support +Enable mmap on /proc/*/mem (UNSECURE!) +CONFIG_UNSAFE_MMAP + As of linux-2.0.40, mmap on /proc/*/mem has been disabled due to + security problems. If you need this functionality, and have no + (potentially hostile) local users, you can enable this option to + restore the old functionality. If unsure, say N. + +NFS file system support CONFIG_NFS_FS If you are connected to some other (usually local) Unix computer (using SLIP, PLIP, PPP or Ethernet) and want to mount files @@ -3877,30 +3884,30 @@ can access the files with usual UNIX commands as if they were sitting on the client's hard disk. For this to work, the server must run the programs nfsd and mountd (but does not need to have NFS - filesystem support enabled). NFS is explained in the Network + file system support enabled). NFS is explained in the Network Administrator's Guide, available via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/LDP, and on its man page: "man nfs". There is also a NFS-FAQ in sunsite.unc.edu:/pub/Linux/docs/faqs which presumes that you know the basics of NFS already. If you say Y here, you should have said Y to TCP/IP networking also. This option - would enlarge your kernel by about 27 kB. This filesystem is also + would enlarge your kernel by about 27 kB. This file system is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. If you configure a diskless machine which will mount its root - filesystem over NFS, you cannot compile this driver as a module. + file system over NFS, you cannot compile this driver as a module. If you don't know what all this is about, say N. Root file system on NFS CONFIG_ROOT_NFS - If you want your Linux box to mount its whole root filesystem from + If you want your Linux box to mount its whole root file system from some other computer over the net via NFS (presumably because your box doesn't have a hard disk), say Y. Read Documentation/nfsroot.txt for details. Most people say N here. BOOTP support CONFIG_RNFS_BOOTP - If you want your Linux box to mount its whole root filesystem from + If you want your Linux box to mount its whole root file system from some other computer over the net via NFS and you want the IP address of your computer to be discovered automatically at boot time using the BOOTP protocol (a special protocol designed for doing this job), @@ -3913,7 +3920,7 @@ RARP support CONFIG_RNFS_RARP - If you want your Linux box to mount its whole root filesystem from + If you want your Linux box to mount its whole root file system from some other computer over the net via NFS and you want the IP address of your computer to be discovered automatically at boot time using the RARP protocol (an older protocol which is being obsoleted by @@ -3921,13 +3928,13 @@ server must be operating on your network. Read Documentation/nfsroot.txt for details. -ISO9660 cdrom filesystem support +ISO9660 CD-ROM file system support CONFIG_ISO9660_FS - This is the standard filesystem used on CDROMs. It was previously + This is the standard file system used on CD-ROMs. It was previously known as "High Sierra Filesystem" and is called "hsfs" on other Unix systems. The so-called Rock-Ridge extensions which allow for long Unix filenames are also supported by this driver. If you have a - CDROM drive and want to do more with it than just listen to audio + CD-ROM drive and want to do more with it than just listen to audio CDs and watch its LEDs, say Y (and read the CDROM-HOWTO, available via FTP (user: anonymous) from sunsite.unc.edu: /pub/Linux/docs/HOWTO), thereby enlarging your kernel by about @@ -3936,20 +3943,20 @@ kernel whenever you want), say M here and read Documentation/modules.txt. -OS/2 HPFS filesystem support (read only) +OS/2 HPFS file system support (read only) CONFIG_HPFS_FS OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS - is the filesystem used for organizing files on OS/2 hard disk + is the file system used for organizing files on OS/2 hard disk partitions. Say Y if you want to be able to read files from an OS/2 HPFS partition of your hard drive. OS/2 floppies however are in regular MSDOS format, so you don't need this option in order to be able to read them. Read Documentation/filesystems/hpfs.txt. This - filesystem is also available as a module ( = code which can be + file system is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -System V and Coherent filesystem support +System V and Coherent file system support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel machines. Enabling this option would allow you to read and write to @@ -3962,13 +3969,13 @@ and is often needed to run commercial software, most prominently WordPerfect. It's in tsx-11.mit.edu:/pub/linux/BETA). If you only intend to mount files from some other Unix over the network using - NFS, you don't need the System V filesystem support (but you need - NFS filesystem support obviously). Note that this option is + NFS, you don't need the System V file system support (but you need + NFS file system support obviously). Note that this option is generally not needed for floppies, since a good portable way to transport files and directories between unixes (and even other operating systems) is given by the tar program ("man tar"). Note also that this option has nothing whatsoever to do with the option - "System V IPC". Read about the System V filesystem in + "System V IPC". Read about the System V file system in Documentation/filesystems/sysv-fs.txt. This option will enlarge your kernel by about 34 kB. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel @@ -3977,7 +3984,7 @@ Kernel automounter support (EXPERIMENTAL) CONFIG_AUTOFS_FS - The automounter is a tool to automatically mount remote filesystems + The automounter is a tool to automatically mount remote file systems on demand. This implementation is partially kernel-based to reduce overhead in the already-mounted case; this is unlike the BSD automounter (amd), which is only in user space. To use the @@ -3986,15 +3993,15 @@ a fairly large, distributed network, you probably do not need an automounter, and can say N here. -BSD UFS filesystem support (read only) +BSD UFS file system support (read only) CONFIG_UFS_FS BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD - and NeXTstep) use a filesystem called UFS. Some System V Unixes can - create and mount partitions and diskettes using this filesystem + and NeXTstep) use a file system called UFS. Some System V Unixes can + create and mount partitions and diskettes using this file system as well. Enabling this option allows you to mount these partitions and diskettes read-only. If you only intend to mount files from some other Unix over the network using NFS, you don't need the - UFS filesystem support (but you need NFS filesystem support + UFS file system support (but you need NFS file system support obviously). Note that this option is generally not needed for floppies, since a good portable way to transport files and directories between unixes (and even other operating systems) @@ -4014,7 +4021,7 @@ similarly to DOS extended partitions, putting in its first sector a new partition table in disklabel format. Enabling this option allows you to read these disklabels and further mount FreeBSD partitions on - your Linux box if you also have configured BSD ufs filesystem + your Linux box if you also have configured BSD UFS file system support. If you don't know what all this is about, say N. SMD disklabel (Sun partition tables) support @@ -4022,21 +4029,21 @@ Like most systems, SunOS uses its own partition table format, incompatible with all others. Enabling this option allows you to read these partition tables and further mount SunOS disks on your - Linux box if you also have configured BSD ufs filesystem support. + Linux box if you also have configured BSD UFS file system support. This is mainly used to carry data from a SPARC under SunOS to your Linux box via a removable medium like magneto-optical or ZIP drives. If you don't know what all this is about, say N. -SMB filesystem support (to mount WfW shares etc...) +SMB file system support (to mount WfW shares etc...) CONFIG_SMB_FS SMB (Server Message Buffer) is the protocol Windows for Workgroups (WfW), Windows NT and Lan Manager use to talk to each other over an - Ethernet. Enabling this allows you to mount their filesystems and + Ethernet. Enabling this allows you to mount their file systems and access them just like any other unix directory. For details, read Documentation/filesystems/smbfs.txt. Note: if you just want your box to act as an SMB *server* and make files and printing services available to Windows clients (which need to have a TCP/IP stack), - you don't need to enable this filesystem support; you can use the + you don't need to enable this file system support; you can use the program samba (available via FTP (user: anonymous) in sunsite.unc.edu:/pub/Linux/system/Network/samba) for that. General information about how to connect Linux, Windows machines and Macs is @@ -4054,7 +4061,7 @@ directories unreliable. This option slows down the listing of directories. This makes the Windows 95 server a bit more stable. -NCP filesystem support (to mount NetWare volumes) +NCP file system support (to mount NetWare volumes) CONFIG_NCP_FS NCP (NetWare Core Protocol) is a protocol that runs over IPX and is used by Novell NetWare clients to talk to file servers. It is to IPX @@ -4113,9 +4120,9 @@ you count every byte. To utilize this feature you must use ncpfs-2.0.12 or newer. -Amiga FFS filesystem support (EXPERIMENTAL) +Amiga FFS file system support (EXPERIMENTAL) CONFIG_AFFS_FS - The Fast File System (FFS) is the common filesystem used on + The Fast File System (FFS) is the common file system used on hard disks by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also possible to mount diskfiles used by the Un*X Amiga Emulator by Bernd Schmidt @@ -4126,7 +4133,7 @@ however cannot be read with this driver due to an incompatibility of the floppy controller used in an Amiga and the standard floppy controller in PCs and workstations. Read - Documentation/filesystems/affs.txt. This filesystem is also + Documentation/filesystems/affs.txt. This file system is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -4697,7 +4704,7 @@ CONFIG_PROFILE This is for kernel hackers who want to know how much time the kernel spends in the various procedures. The information is stored in - /proc/profile (enable the /proc filesystem!) and in order to read + /proc/profile (enable the /proc file system!) and in order to read it, you need the readprofile package from sunsite.unc.edu. Its manpage gives information regarding the format of profiling data. To become a kernel hacker, you can start with the Kernel Hacker's @@ -4977,6 +4984,39 @@ split subject to kernel constraints. If you don't know how it works don't pick it. +Memory flooding +CONFIG_SADISTIC_KMALLOC + A common class of errors, both in user space programs and the kernel, + is accessing memory areas after freeing them. Programs with such + errors often work anyway most of the time, since the bug only bites + if something else happens to allocate the same area in a short time + window. + This option will cause the memory allocator to immediately destroy + any data that has been freed within the kernel, causing such bugs to + manifest consistently so they may be solved. Newly allocated memory + is also flooded, making failure-to-initialize bugs easier to detect. + This feature does not affect bugs in user space programs. + Non-kernel hackers should say N. If there are any such bugs in the + kernel, there is no point provoking them if you are not prepared to + fix them. And it will run slightly slower. + +Socket-buffer consistency checking +CONFIG_SKB_CHECK + The networking facilities of Linux use a special system of memory + management, known as socket buffers or SKBs. SKB structures are + moderately complicated and could be corrupted by kernel bugs, later + causing puzzling crashes. + This option causes SKBs to be rechecked almost every time they are + used, leading to earlier detection of such problems. This will + reduce performance -- however it does not affect the likelihood of + the kernel crashing. Non-kernel hackers should say N. + +Whole-queue checking +CONFIG_SKB_CHECK_WHOLE_QUEUE + This option is an extension of CONFIG_SKB_CHECK. Whenever a list + header is validated, this mode will traverse the entire list looking + for inconsistent pointers. + # need an empty line after last entry, for sed script in Configure. # @@ -4984,7 +5024,7 @@ # # LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp sunsite # LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz -# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide +# LocalWords: cdrom CD-ROM diskless netboot nfs xzvf ATAPI MB ide # LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI bios # LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt # LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB @@ -5032,7 +5072,7 @@ # LocalWords: PMAX MILO Alphas Multia Tseng linuxelf endian mipsel mips drv HT # LocalWords: KERNELD kerneld callouts AdvanSys advansys diskquotas Admin WDT # LocalWords: wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI -# LocalWords: QD qd UMC umc ALI ali lena fnet fr homepage azstarnet axplinux +# LocalWords: QD qd UMC umc ALI ali lena fnet fr azstarnet axplinux # LocalWords: Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC # LocalWords: AlphaPC uwaterloo cpbeaure mca AOUT OUTput PPro sipx gwdg lo nwe # LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT diff -urN linux-2.0.39/Documentation/cdrom/sbpcd linux-2.0.40/Documentation/cdrom/sbpcd --- linux-2.0.39/Documentation/cdrom/sbpcd 1996-02-06 22:17:49.000000000 -0800 +++ linux-2.0.40/Documentation/cdrom/sbpcd 2004-02-07 23:13:01.000000000 -0800 @@ -569,11 +569,11 @@ #ifdef AZT_PRIVATE_IOCTLS #include -#endif AZT_PRIVATE_IOCTLS +#endif /* AZT_PRIVATE_IOCTLS */ #ifdef SBP_PRIVATE_IOCTLS #include #include -#endif SBP_PRIVATE_IOCTLS +#endif /* SBP_PRIVATE_IOCTLS */ struct cdrom_tochdr hdr; struct cdrom_tochdr tocHdr; @@ -591,7 +591,7 @@ struct cdrom_msf msf; unsigned char buf[CD_FRAMESIZE_RAW]; } azt; -#endif AZT_PRIVATE_IOCTLS +#endif /* AZT_PRIVATE_IOCTLS */ int i, i1, i2, i3, j, k; unsigned char sequence=0; unsigned char command[80]; @@ -1053,7 +1053,7 @@ rc=ioctl(drive,CDROMAUDIOBUFSIZ,j); printf("%d frames granted.\n",rc); break; -#endif SBP_PRIVATE_IOCTLS +#endif /* SBP_PRIVATE_IOCTLS */ default: printf("unknown command: \"%s\".\n",command); break; diff -urN linux-2.0.39/Documentation/ioctl-number.txt linux-2.0.40/Documentation/ioctl-number.txt --- linux-2.0.39/Documentation/ioctl-number.txt 1996-08-10 00:03:14.000000000 -0700 +++ linux-2.0.40/Documentation/ioctl-number.txt 2004-02-07 23:13:01.000000000 -0800 @@ -20,7 +20,7 @@ The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter or number from the table below. If you are writing a driver for a new device and need a letter, pick an unused letter. You can register the -letter by patching this file and submitting the patch to Linus Torvalds. +letter by patching this file and submitting the patch to David Weinehall. Or you can e-mail me at and I'll register one for you. diff -urN linux-2.0.39/Documentation/magic-number.txt linux-2.0.40/Documentation/magic-number.txt --- linux-2.0.39/Documentation/magic-number.txt 1996-05-16 06:35:39.000000000 -0700 +++ linux-2.0.40/Documentation/magic-number.txt 2004-02-07 23:13:01.000000000 -0800 @@ -34,7 +34,12 @@ 6 May 1996 +Added SKB-debugging values. Note that they only appear under +CONFIG_SKB_CHECK, and are 12 bytes inside the structure. + Michael Deutschmann + + 2000-07-24 Magic Name Number Structure File =========================================================================== @@ -60,4 +65,7 @@ STL_PORTMAGIC 0x5a7182c9 stlport_t include/linux/stallion.h PCXX_MAGIC 0x5c6df104 struct channel drivers/char/pcxx.h BAYCOM_MAGIC 0x3105bac0 struct baycom_state drivers/char/baycom.c +SK_FREED_SKB 0x0de2code struct sk_buff include/linux/skbuff.h +SK_GOOD_SKB 0xdec0ded1 struct sk_buff include/linux/skbuff.h +SK_HEAD_SKB 0x12231298 struct sk_buff_head include/linux/skbuff.h diff -urN linux-2.0.39/Documentation/mandatory.txt linux-2.0.40/Documentation/mandatory.txt --- linux-2.0.39/Documentation/mandatory.txt 1997-08-03 13:59:07.000000000 -0700 +++ linux-2.0.40/Documentation/mandatory.txt 2004-02-07 23:13:01.000000000 -0800 @@ -140,7 +140,7 @@ Note 3: I may have overlooked some system calls that need mandatory lock checking in my eagerness to get this code out the door. Please let me know, or -better still fix the system calls yourself and submit a patch to me or Linus. +better still fix the system calls yourself and submit a patch to me or David. 6. Warning! ----------- diff -urN linux-2.0.39/Documentation/unicode.txt linux-2.0.40/Documentation/unicode.txt --- linux-2.0.39/Documentation/unicode.txt 1996-11-12 00:30:48.000000000 -0800 +++ linux-2.0.40/Documentation/unicode.txt 2004-02-07 23:13:01.000000000 -0800 @@ -50,6 +50,20 @@ character, and hence has been coded as U+2500 FORMS LIGHT HORIZONTAL. However, I left U+F802 blank should the need arise. +< +>> + Klingon language support ------------------------ diff -urN linux-2.0.39/MAINTAINERS linux-2.0.40/MAINTAINERS --- linux-2.0.39/MAINTAINERS 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/MAINTAINERS 2004-02-07 23:13:01.000000000 -0800 @@ -1,53 +1,46 @@ List of maintainers and how to submit kernel changes -Please try to follow the guidelines below. This will make things -easier on the maintainers. Not all of these guidelines matter for every -trivial patch so apply some common sense. - -1. Always _test_ your changes, however small, on at least 4 or - 5 people, preferably many more. - -2. Try to release a few ALPHA test versions to the net. Announce - them onto the kernel channel and await results. This is especially - important for device drivers, because often that's the only way - you will find things like the fact version 3 firmware needs - a magic fix you didn't know about, or some clown changed the - chips on a board and not its name. (Don't laugh! Look at the - SMC etherpower for that.) - -3. Make sure your changes compile correctly in multiple - configurations. In particular check that changes work both as a - module and built into the kernel. +Please try to follow the guidelines below. This will make things easier +on the maintainers. Not all of these guidelines matter for every trivial +patch so apply some common sense. + +1. Always _test_ your changes, however small, on at least 4 or 5 people, + preferably many more. + +2. Try to release a few ALPHA test versions to the net. Announce them + onto the kernel channel and await results. This is especially + important for device drivers, because often that's the only way you + will find things like the fact version 3 firmware needs a magic fix + you didn't know about, or some clown changed the chips on a board + and not its name. (Don't laugh! Look at the SMC etherpower for that.) + +3. Make sure your changes compile correctly in multiple configurations. + In particular check that changes work both as a module and built into + the kernel. 4. When you are happy with a change make it generally available for testing and await feedback. 5. Make a patch available to the relevant maintainer in the list. Use - 'diff -u' to make the patch easy to merge. Be prepared to get your - changes sent back with seemingly silly requests about formatting - and variable names. These aren't as silly as they seem. One - job the maintainers (and especially Linus) do is to keep things - looking the same. Sometimes this means that the clever hack in - your driver to get around a problem actual needs to become a - generalised kernel feature ready for next time. See - Documentation/CodingStyle for guidance here. - - PLEASE try to include any credit lines you want added with the - patch. It avoids people being missed off by mistake and makes - it easier to know who wants adding and who doesn't. - - PLEASE document known bugs. If it doesn't work for everything - or does something very odd once a month document it. - -6. Make sure you have the right to send any changes you make. If you - do changes at work you may find your employer owns the patch - not you. + 'diff -u5' to make the patch easy to merge. Be prepared to get your + changes sent back with seemingly silly requests about formatting and + variable names. These aren't as silly as they seem. One job the + maintainers (and especially Linus) do is to keep things looking the + same. Sometimes this means that the clever hack in your driver to get + around a problem actual needs to become a generalised kernel feature + ready for next time. See Documentation/CodingStyle for guidance here. + + PLEASE try to include any credit lines you want added with the patch. + It avoids people being missed off by mistake and makes it easier to + know who wants adding and who doesn't. -7. Happy hacking. + PLEASE document known bugs. If it doesn't work for everything or does + something very odd once a month document it. +6. Make sure you have the right to send any changes you make. If you do + changes at work you may find your employer owns the patch not you. -[This file is new: I've just put the existing network contacts in, other - people please add yourselves] -- AC +7. Happy hacking. ----------------------------------- @@ -60,7 +53,7 @@ S: Status, one of the following: Supported: Someone is actually paid to look after this (wildly - improbable). + improbable, but does occasionally happen). Maintained: Someone actually looks after it. Odd Fixes: It has a maintainer but they don't have time to do much other than throw the odd patch in. See below.. @@ -84,7 +77,7 @@ 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] P: Paul Gortmaker -M: gpg109@rsphy1.anu.edu.au +M: p_gortmaker@yahoo.com L: linux-net@vger.kernel.org S: Maintained @@ -97,21 +90,21 @@ AHA152X SCSI DRIVER P: Juergen E. Fischer -M: Juergen Fischer +M: Juergen Fischer L: linux-scsi@vger.kernel.org S: Maintained APM DRIVER P: Stephen Rothwell -M: apm@linuxcare.com.au +M: sfr@canb.auug.org.au L: linux-laptop@vger.kernel.org -W: http://linuxcare.com.au/apm/ -S: Maintained +W: http://www.canb.auug.org.au/~sfr/ +S: Supported APPLETALK NETWORK LAYER P: Jay Schulist -M: Jay.Schulist@spacs.k12.wi.us -L: linux-atalk@netspace.org +M: jschlst@samba.org +L: linux-atalk@lists.netspace.org S: Maintained ARPD SUPPORT @@ -120,27 +113,12 @@ L: linux-net@vger.kernel.org S: Maintained -AX.25 DAMA SLAVE -P: Joerg Reuter -M: jreuter@poboxes.com -W: http://poboxes.com/jreuter/ -W: http://qsl.net/dl1bke/ -L: linux-hams@vger.kernel.org -S: Maintained - AX.25 NETWORK LAYER P: Matthias Welwarsky M: dg2fef@afthd.tu-darmstadt.de L: linux-hams@vger.kernel.org S: Maintained -BUSLOGIC SCSI DRIVER -P: Leonard N. Zubkoff -M: Leonard N. Zubkoff -L: linux-scsi@vger.kernel.org -W: http://www.dandelion.com/Linux/ -S: Maintained - CREDITS FILE P: John A. Martin M: jam@acm.org @@ -148,14 +126,16 @@ CYCLADES ASYNC MUX DRIVER P: Ivan Passos -M: Ivan Passos +M: ivan@cyclades.com W: http://www.cyclades.com/ S: Supported -DAC960 RAID DRIVER -P: Leonard N. Zubkoff -M: Leonard N. Zubkoff -L: linux-raid@vger.kernel.org +DAMA SLAVE for AX.25 +P: Joerg Reuter +M: jreuter@yaina.de +W: http://yaina.de/jreuter/ +W: http://qsl.net/dl1bke/ +L: linux-hams@vger.kernel.org S: Maintained DC390/AM53C974 SCSI driver @@ -176,19 +156,20 @@ L: linux-kernel@vger.kernel.org S: Maintained -DIGIBOARD DRIVER -P: Christoph Lameter -M: clameter@fuller.edu -L: digiboard@list.fuller.edu -S: Maintained - DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson -M: rick@dgii.com +M: rick@remotepoint.com L: linux-net@vger.kernel.org W: http://www.dgii.com/linux/ S: Maintained +DIGIBOARD DRIVER +P: Christoph Lameter +M: christoph@lameter.com +W: http://www.dgii.com/linux,http://lameter.com/digi +L: digilnux@dgii.com +S: Maintained + EATA-DMA SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net @@ -197,7 +178,7 @@ EATA ISA/EISA/PCI SCSI DRIVER P: Dario Ballabio -M: dario@milano.europe.dg.com +M: ballabio_dario@emc.com L: linux-scsi@vger.kernel.org S: Maintained @@ -214,10 +195,8 @@ S: Maintained EXT2 FILE SYSTEM -P: Remy Card -M: Remy.Card@linux.org -L: linux-kernel@vger.kernel.org -S: Maintained +L: ext2-devel@lists.sourceforge.net +S: Odd fixes FILE LOCKING (flock() and fcntl()/lockf()) P: Andy Walker @@ -256,12 +235,21 @@ L: linux-kernel@vger.kernel.org S: Maintained +i386 BOOT CODE +P: Riley Williams +M: Riley@Williams.Name +L: linux-kernel@vger.kernel.org +S: Odd fixes + IDE DRIVER [GENERAL] P: Andre Hedrick M: andre@linux-ide.org +M: andre@linuxdiskcert.org L: linux-kernel@vger.kernel.org -W: http://linux.kernel.org/pub/linux/kernel/people/hedrick/ -S: Supported +W: http://www.kernel.org/pub/linux/kernel/people/hedrick/ +W: http://www.linux-ide.org/ +W: http://www.linuxdiskcert.org/ +S: Maintained IDE/ATAPI CDROM DRIVER P: Jens Axboe @@ -297,7 +285,9 @@ ISDN SUBSYSTEM HISAX P: Karsten Keil -M: keil@isdn4linux.de +M: kkeil@suse.de +P: Kai Germaschewski +M: kai.germaschewski@gmx.de L: isdn4linux@listserv.isdn4linux.de W: http://www.isdn4linux.de S: Maintained @@ -309,8 +299,8 @@ S: Maintained LANCE AND LANCE32 NETWORK DRIVER -P: Thomas Bogendoerfer -M: tsbogend@bigbug.franken.de +P: Thomas Bogendörfer +M: tsbogend@alpha.franken.de L: linux-net@vger.kernel.org S: Maintained @@ -423,20 +413,17 @@ SVGA HANDLING P: Martin Mares -M: mj@atrey.karlin.mff.cuni.cz +M: mj@ucw.cz L: linux-video@atrey.karlin.mff.cuni.cz S: Maintained -THE V2.0 KERNEL IN GENERAL -P: David Weinehall -M: tao@acc.umu.se -L: linux-kernel@vger.kernel.org -S: Maintained - TLAN NETWORK DRIVER P: Torben Mathiasen M: torben.mathiasen@compaq.com +M: torben@kernel.dk L: tlan@vuser.vu.union.edu +L: linux-net@vger.kernel.org +W: http://tlan.kernel.dk S: Maintained TOKEN-RING NETWORK DRIVER @@ -448,13 +435,13 @@ U14-34F SCSI DRIVER P: Dario Ballabio -M: dario@milano.europe.dg.com +M: ballabio_dario@emc.com L: linux-scsi@vger.kernel.org S: Maintained VFAT FILESYSTEM P: Gordon Chaffee -M: chaffee@plateau.cs.berkeley.edu +M: chaffee@cs.berkeley.edu L: linux-kernel@vger.kernel.org W: http://bmrc.berkeley.edu/people/chaffee S: Maintained @@ -473,12 +460,14 @@ Z8530 SCC DRIVER FOR AX.25 P: Joerg Reuter -M: jreuter@poboxes.com -W: http://poboxes.com/jreuter/ -W: http://qsl.net/dl1bke/ +M: jreuter@yaina.de +W: http://yaina.de/jreuter/ +W: http://www.qsl.net/dl1bke/ L: linux-hams@vger.kernel.org S: Maintained THE REST -P: Linus Torvalds -S: Buried alive in email +P: David Weinehall +M: tao@kernel.org +L: linux-kernel@vger.kernel.org +S: Maintained diff -urN linux-2.0.39/Makefile linux-2.0.40/Makefile --- linux-2.0.39/Makefile 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/Makefile 2004-02-07 23:13:01.000000000 -0800 @@ -1,6 +1,9 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 39 +SUBLEVEL = 40 +EXTRAVERSION = + +KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -31,14 +34,15 @@ CROSS_COMPILE = -AS =$(CROSS_COMPILE)as -LD =$(CROSS_COMPILE)ld -CC =$(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH) -CPP =$(CC) -E -AR =$(CROSS_COMPILE)ar -NM =$(CROSS_COMPILE)nm -STRIP =$(CROSS_COMPILE)strip -MAKE =make +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CC = $(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH) +CPP = $(CC) -E +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +MAKE = make +PERL = perl all: do-it-all @@ -185,6 +189,9 @@ symlinks: rm -f include/asm ( cd include ; ln -sf asm-$(ARCH) asm) + @if [ ! -d include/linux/modules ]; then \ + mkdir include/linux/modules; \ + fi oldconfig: symlinks $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in @@ -236,8 +243,9 @@ @mv -f .ver $@ include/linux/version.h: ./Makefile - @echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver + @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver + @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver @mv -f .ver $@ init/version.o: init/version.c include/linux/compile.h @@ -267,6 +275,18 @@ net: dummy $(MAKE) linuxsubdirs SUBDIRS=net +TAGS: dummy + etags `find include/asm-$(ARCH) -name '*.h'` + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a + find $(SUBDIRS) init -name '*.c' | xargs etags -a + +# Exuberant ctags works better with -I +tags: dummy + CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ + ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \ + find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ + find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a + MODFLAGS = -DMODULE ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS @@ -281,7 +301,7 @@ modules_install: @( \ - MODLIB=/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \ + MODLIB=/lib/modules/$(KERNELRELEASE); \ cd modules; \ MODULES=""; \ inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \ @@ -345,7 +365,7 @@ distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS tags backup: mrproper cd .. && tar cf - linux/ | gzip -9 > backup.gz @@ -377,7 +397,13 @@ depend dep: dep-files $(MODVERFILE) checkconfig: - perl -w scripts/checkconfig.pl `find * -name '*.[hcS]' -print | sort` + find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkconfig.pl + +checkhelp: + find * -name [cC]onfig.in -print | sort | xargs $(PERL) -w scripts/checkhelp.pl + +checkincludes: + find * -name '*.[hcS]' -type f -print | sort | xargs $(PERL) -w scripts/checkincludes.pl ifdef CONFIGURATION ..$(CONFIGURATION): diff -urN linux-2.0.39/README linux-2.0.40/README --- linux-2.0.39/README 1999-06-13 10:20:59.000000000 -0700 +++ linux-2.0.40/README 2004-02-07 23:13:01.000000000 -0800 @@ -50,17 +50,23 @@ latest kernel. If you use GNU tar, cd /usr/src - tar -xzvf linux-2.1.XX.tar.gz + tar -xzvf linux-2.0.XX.tar.gz is equivalent. - You can also upgrade between 2.0.xx releases by patching. Each patch that is released for 2.0.xx contains only bugfixes. No - new features will be added to the Linux kernel until the 2.1.xx - development effort begins. To install by patching, get all the - newer patch files and do + new features will be added to the Linux kernel 2.0 any more. If + you are interested in new kernel features, you may want to + help developing a more recent kernel. + + To patch to a newer 2.0 kernel version, get all the newer files + (you will find these patches at the kernel FTP servers: + , replace + xx with your two letter country code here, e.g. se for Sweden), + then do: - cd /usr/src + cd /usr/src/linux gzip -cd patchXX.gz | patch -p0 (repeat xx for all versions bigger than the version of your current @@ -96,7 +102,7 @@ - Alternate configuration commands are: "make menuconfig" Text based color menus, radiolists & dialogs. - "make xconfig" X windows based configuration tool. + "make xconfig" X window system based configuration tool. NOTES on "make config": - having unnecessary drivers will make the kernel bigger, and can @@ -160,7 +166,7 @@ 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.conf. The - kernel image file is usually /vmlinuz, or /zImage, or /etc/zImage. + kernel image file is usually /vmlinuz, /zImage, or /boot/vmlinuz. 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 @@ -187,10 +193,8 @@ the file MAINTAINERS to see if there is a particular person associated with the part of the kernel that you are having trouble with. If there isn't anyone listed there, then the second best thing is to mail - them to me (Linus.Torvalds@Helsinki.FI), and possibly to any other - relevant mailing-list or to the newsgroup. The mailing-lists are - useful especially for SCSI and NETworking problems, as I can't test - either of those personally anyway. + them to me (David Weinehall, tao@kernel.org), and possibly to any other + relevant mailing-list or to the newsgroup. - In all bug-reports, *please* tell what kernel you are talking about, how to duplicate the problem, and what your setup is (use your common diff -urN linux-2.0.39/arch/alpha/config.in linux-2.0.40/arch/alpha/config.in --- linux-2.0.39/arch/alpha/config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/arch/alpha/config.in 2004-02-07 23:13:01.000000000 -0800 @@ -227,6 +227,11 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Memory flooding' CONFIG_SADISTIC_KMALLOC +bool 'Socket-buffer consistency checking' CONFIG_SKB_CHECK +if [ "$CONFIG_SKB_CHECK" = "y" ]; then + bool ' Whole-queue checking' CONFIG_SKB_CHECK_WHOLE_QUEUE +fi endmenu if [ "$CONFIG_TGA_CONSOLE" = "n" ]; then diff -urN linux-2.0.39/arch/alpha/defconfig linux-2.0.40/arch/alpha/defconfig --- linux-2.0.39/arch/alpha/defconfig 1999-06-13 10:20:59.000000000 -0700 +++ linux-2.0.40/arch/alpha/defconfig 2004-02-07 23:13:01.000000000 -0800 @@ -193,6 +193,7 @@ # CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y +# CONFIG_UNSAFE_MMAP is not set CONFIG_NFS_FS=y # CONFIG_ROOT_NFS is not set # CONFIG_SMB_FS is not set diff -urN linux-2.0.39/arch/alpha/kernel/signal.c linux-2.0.40/arch/alpha/kernel/signal.c --- linux-2.0.39/arch/alpha/kernel/signal.c 1998-06-03 15:17:46.000000000 -0700 +++ linux-2.0.40/arch/alpha/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -320,7 +320,7 @@ if (current->pid == 1) continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN linux-2.0.39/arch/i386/config.in linux-2.0.40/arch/i386/config.in --- linux-2.0.39/arch/i386/config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/arch/i386/config.in 2004-02-07 23:13:01.000000000 -0800 @@ -141,4 +141,9 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Memory flooding' CONFIG_SADISTIC_KMALLOC +bool 'Socket-buffer consistency checking' CONFIG_SKB_CHECK +if [ "$CONFIG_SKB_CHECK" = "y" ]; then + bool ' Whole-queue checking' CONFIG_SKB_CHECK_WHOLE_QUEUE +fi endmenu diff -urN linux-2.0.39/arch/i386/defconfig linux-2.0.40/arch/i386/defconfig --- linux-2.0.39/arch/i386/defconfig 1999-06-13 10:20:59.000000000 -0700 +++ linux-2.0.40/arch/i386/defconfig 2004-02-07 23:13:01.000000000 -0800 @@ -178,6 +178,7 @@ # CONFIG_NLS_ISO8859_9 is not set # CONFIG_NLS_KOI8_R is not set CONFIG_PROC_FS=y +# CONFIG_UNSAFE_MMAP is not set CONFIG_NFS_FS=y # CONFIG_ROOT_NFS is not set # CONFIG_SMB_FS is not set diff -urN linux-2.0.39/arch/i386/kernel/entry.S linux-2.0.40/arch/i386/kernel/entry.S --- linux-2.0.39/arch/i386/kernel/entry.S 1998-11-15 10:32:46.000000000 -0800 +++ linux-2.0.40/arch/i386/kernel/entry.S 2004-02-07 23:13:01.000000000 -0800 @@ -65,7 +65,9 @@ OLDSS = 0x40 CF_MASK = 0x00000001 +TF_MASK = 0x00000100 IF_MASK = 0x00000200 +DF_MASK = 0x00000400 NT_MASK = 0x00004000 VM_MASK = 0x00020000 @@ -270,6 +272,9 @@ movl CS(%esp),%edx # this is eip.. movl EFLAGS(%esp),%ecx # and this is cs.. movl %eax,EFLAGS(%esp) # + andl $~(NT_MASK|TF_MASK|DF_MASK), %eax + pushl %eax + popfl movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # movl %esp,%eax @@ -401,6 +406,9 @@ pushl $ SYMBOL_NAME(do_divide_error) ALIGN error_code: + pushfl + andl $~(NT_MASK|TF_MASK|DF_MASK), (%esp) + popfl push %fs push %es push %ds @@ -413,7 +421,6 @@ decl %eax # eax = -1 pushl %ecx pushl %ebx - cld xorl %ebx,%ebx # zero ebx xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) mov %gs,%bx # get the lower order bits of gs diff -urN linux-2.0.39/arch/i386/kernel/head.S linux-2.0.40/arch/i386/kernel/head.S --- linux-2.0.39/arch/i386/kernel/head.S 1999-08-25 15:08:27.000000000 -0700 +++ linux-2.0.40/arch/i386/kernel/head.S 2004-02-07 23:13:01.000000000 -0800 @@ -51,7 +51,7 @@ jmp checkCPUtype 1: lss stack_start,%esp -#endif __SMP__ +#endif /* __SMP__ */ /* * Clear BSS first so that there are no surprises... */ diff -urN linux-2.0.39/arch/i386/kernel/process.c linux-2.0.40/arch/i386/kernel/process.c --- linux-2.0.39/arch/i386/kernel/process.c 1999-06-13 10:21:00.000000000 -0700 +++ linux-2.0.40/arch/i386/kernel/process.c 2004-02-07 23:13:01.000000000 -0800 @@ -520,35 +520,8 @@ /* We dump the emulator state here. We convert it into standard 387 format first.. */ #ifdef CONFIG_MATH_EMULATION - int i; - unsigned long top; - char (*hardreg)[10]; - struct i387_soft_struct *soft_fpu = ¤t->tss.i387.soft; - struct fpu_reg* softreg; - long int control_word = soft_fpu->cwd; - - fpu->cwd = soft_fpu->cwd; - fpu->swd = soft_fpu->swd; - fpu->twd = soft_fpu->twd; - fpu->fip = soft_fpu->fip; - fpu->fcs = soft_fpu->fcs; - fpu->foo = soft_fpu->foo; - fpu->fos = soft_fpu->fos; - hardreg = (char (*)[10]) &fpu->st_space[0]; - top = (unsigned long) soft_fpu->top % 8; - softreg = &soft_fpu->regs[top]; - for (i = top ; i < 8; i ++) { - softreg_to_hardreg(softreg, *hardreg, control_word); - hardreg++; - softreg++; - } - softreg = &soft_fpu->regs[0]; - for (i = 0; i < top; i++) { - softreg_to_hardreg(softreg, *hardreg, control_word); - hardreg++; - softreg++; - } - fpvalid = 1; + fpvalid = save_i387_soft(¤t->tss.i387.soft, + (struct _fpstate *)fpu); #else /* defined(CONFIG_MATH_EMULATION) */ fpvalid = 0; #endif /* !defined(CONFIG_MATH_EMULATION) */ diff -urN linux-2.0.39/arch/i386/kernel/ptrace.c linux-2.0.40/arch/i386/kernel/ptrace.c --- linux-2.0.39/arch/i386/kernel/ptrace.c 1998-07-13 13:47:27.000000000 -0700 +++ linux-2.0.40/arch/i386/kernel/ptrace.c 2004-02-07 23:13:01.000000000 -0800 @@ -295,68 +295,12 @@ put_long(tsk, vma, addr, data); return 0; } -#ifdef CONFIG_MATH_EMULATION -static void write_emulator_word(struct task_struct *child, - unsigned long register_offset, - long data) -{ - int i, j; - struct i387_soft_struct *soft_fpu; - struct fpu_reg *this_fpreg, *next_fpreg; - char hard_reg[2][10]; - int control_word; - unsigned long top; - i = register_offset / 10; - j = register_offset % 10; - soft_fpu = &child->tss.i387.soft; - top = i + (unsigned long) soft_fpu->top; - control_word = soft_fpu->cwd; - this_fpreg = &soft_fpu->regs[(top + i) % 8]; - next_fpreg = &soft_fpu->regs[(top + i + 1) % 8]; - softreg_to_hardreg(this_fpreg, hard_reg[0], control_word); - if (j > 6) - softreg_to_hardreg(next_fpreg, hard_reg[1], control_word); - *(long *) &hard_reg[0][j] = data; - hardreg_to_softreg(hard_reg[0], this_fpreg); - if (j > 6) - hardreg_to_softreg(hard_reg[1], next_fpreg); -} -#endif /* defined(CONFIG_MATH_EMULATION) */ /* * Floating point support added to ptrace by Ramon Garcia, * ramon@juguete.quim.ucm.es */ -#ifdef CONFIG_MATH_EMULATION - -static unsigned long get_emulator_word(struct task_struct *child, - unsigned long register_offset) -{ - char hard_reg[2][10]; - int i, j; - struct fpu_reg *this_fpreg, *next_fpreg; - struct i387_soft_struct *soft_fpu; - long int control_word; - unsigned long top; - unsigned long tmp; - i = register_offset / 10; - j = register_offset % 10; - soft_fpu = &child->tss.i387.soft; - top = (unsigned long) soft_fpu->top; - this_fpreg = &soft_fpu->regs[(top + i) % 8]; - next_fpreg = &soft_fpu->regs[(top + i + 1) % 8]; - control_word = soft_fpu->cwd; - softreg_to_hardreg(this_fpreg, hard_reg[0], control_word); - if (j > 6) - softreg_to_hardreg(next_fpreg, hard_reg[1], control_word); - tmp = *(long *) - &hard_reg[0][j]; - return tmp; -} - -#endif /* defined(CONFIG_MATH_EMULATION) */ - static int putreg(struct task_struct *child, unsigned long regno, unsigned long value) { diff -urN linux-2.0.39/arch/i386/kernel/setup.c linux-2.0.40/arch/i386/kernel/setup.c --- linux-2.0.39/arch/i386/kernel/setup.c 1999-06-13 10:21:00.000000000 -0700 +++ linux-2.0.40/arch/i386/kernel/setup.c 2004-02-07 23:13:01.000000000 -0800 @@ -50,17 +50,17 @@ char x86_vendor_id[13] = "GenuineIntel";/* default */ -static char *Cx86_step = "unknown"; /* stepping info for Cyrix CPUs */ +static char Cx86_step[8] = "unknown"; /* stepping info for Cyrix CPUs */ static unsigned char Cx86_mult = 0; /* clock multiplier for Cyrix CPUs */ static const char *x86_clkmult[] = { - "unknown", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5", - "6", "6.5", "7", "7.5", "8" - }; + "unknown", "1x", "1.5x", "2x", "2.5x", "3x", "3.5x", "4x", + "4.5x", "5x", "5.5x", "6x", "6.5x", "7x", "7.5x", "8x" +}; char ignore_irq13 = 0; /* set if exception 16 works */ -char wp_works_ok = -1; /* set if paging hardware honours WP */ +char wp_works_ok = -1; /* set if paging hardware honours WP */ char hlt_works_ok = 1; /* set if the "hlt" instruction works */ /* @@ -112,9 +112,9 @@ #define COMMAND_LINE ((char *) (PARAM+2048)) #define COMMAND_LINE_SIZE 256 -#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 +#define RAMDISK_LOAD_FLAG 0x4000 static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; @@ -136,9 +136,9 @@ } smptrap=1; - ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); - drive_info = DRIVE_INFO; - screen_info = SCREEN_INFO; + ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); + drive_info = DRIVE_INFO; + screen_info = SCREEN_INFO; #ifdef CONFIG_APM apm_bios_info = APM_BIOS_INFO; #endif @@ -167,14 +167,14 @@ /* * The CONFIG_MAX_MEMSIZE sanity checker. */ - + if (memory_end > (CONFIG_MAX_MEMSIZE-128)*1024*1024) { memory_end = (CONFIG_MAX_MEMSIZE-128)*1024*1024; printk(KERN_WARNING "ONLY %dMB RAM will be used, see Documentation/more-than-900MB-RAM.txt!.\n", CONFIG_MAX_MEMSIZE-128); udelay(3*1000*1000); } - + if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; memory_start = (unsigned long) &_end; @@ -263,12 +263,12 @@ unsigned char nr6x86 = 0; unsigned char cx_dir0 = 0; /* Model and bus clock multiplier */ unsigned char cx_dir1 = 0; /* Stepping info */ - unsigned int flags; + unsigned long flags; static const char *model[] = { "unknown", "Cx486", "5x86", "MediaGX", "6x86", "6x86L", "6x86MX", "M II" }; - + if (x86_model == -1) { /* is this an old Cx486 without DIR0/DIR1? */ nr6x86 = 1; /* Cx486 */ Cx86_mult = 0; /* unknown multiplier */ @@ -276,65 +276,65 @@ else { /* Get DIR0, DIR1 since all other Cyrix CPUs have them */ - + save_flags(flags); cli(); cx_dir0 = getCx86(CX86_DIR0); /* we use the access macros */ cx_dir1 = getCx86(CX86_DIR1); /* defined in processor.h */ restore_flags(flags); - + /* Now cook; the recipe is by Channing Corn, from Cyrix. * We do the same thing for each generation: we work out * the model, multiplier and stepping. */ - + if (cx_dir0 < 0x20) { nr6x86 = 1; /* Cx486 */ Cx86_mult = 0; /* unknown multiplier */ sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f); } - + if ((cx_dir0 > 0x20) && (cx_dir0 < 0x30)) { nr6x86 = 2; /* 5x86 */ Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */ sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f); } - + if ((cx_dir0 >= 0x30) && (cx_dir0 < 0x38)) { nr6x86 = ((x86_capability & (1 << 8)) ? 5 : 4); /* 6x86(L) */ Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */ sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 3), cx_dir1 & 0x0f); } - + if ((cx_dir0 >= 0x40) && (cx_dir0 < 0x50)) { if (x86 == 4) { /* MediaGX */ nr6x86 = 3; Cx86_mult = ((cx_dir0 & 0x01) ? 5 : 7); /* either 3x or 4x */ - switch (cx_dir1 >> 4) { - case (0) : - case (1) : - sprintf(Cx86_step, "2.%d", cx_dir1 & 0x0f); - break; - case (2) : - sprintf(Cx86_step, "1.%d", cx_dir1 & 0x0f); - break; + switch (cx_dir1 >> 4) { + case (0) : + case (1) : + sprintf(Cx86_step, "2.%d", cx_dir1 & 0x0f); + break; + case (2) : + sprintf(Cx86_step, "1.%d", cx_dir1 & 0x0f); + break; default : - break; + break; } } /* endif MediaGX */ - if (x86 == 5) { /* GXm */ - char GXm_mult[8] = {7,11,7,11,13,15,13,9}; /* 4 to 8 */ - ext_cpuid = 0x80000005; /* available */ - Cx86_mult = GXm_mult[cx_dir0 & 0x0f]; - sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) - 1, cx_dir1 & 0x0f); - } /* endif GXm */ + if (x86 == 5) { /* GXm */ + char GXm_mult[8] = {7,11,7,11,13,15,13,9}; /* 4 to 8 */ + ext_cpuid = 0x80000005; /* available */ + Cx86_mult = GXm_mult[cx_dir0 & 0x0f]; + sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) - 1, cx_dir1 & 0x0f); + } /* endif GXm */ } - + if ((cx_dir0 >= 0x50) && (cx_dir0 < 0x60)) { nr6x86 = ((cx_dir1 > 7) ? 7 : 6); /* 6x86Mx or M II */ Cx86_mult = (cx_dir0 & 0x07) + 2; /* 2 to 5 in 0.5 steps */ - if (((cx_dir1 & 0x0f) > 4) || ((cx_dir1 >> 4) == 2)) cx_dir1 += 0x10; - sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f); + if (((cx_dir1 & 0x0f) > 4) || ((cx_dir1 >> 4) == 2)) cx_dir1 += 0x10; + sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f); } } x86_mask = 1; /* we don't use it, but has to be set to something */ @@ -358,7 +358,7 @@ { const char *p=NULL; int i; - + if ((x86_model == 0) || (x86 == 4)) { for (i=0; i= 6)) { - len += sprintf(buffer+len, - "stepping\t: %c\n", - x86_mask + 'A'); + if ((strncmp(x86_vendor_id, "Au", 2) == 0) + && (x86_model >= 6)) { + len += sprintf(buffer+len, + "stepping\t: %c\n", + x86_mask + 'A'); } else if (strncmp(x86_vendor_id, "Cy", 2) == 0) { - len += sprintf(buffer+len, - "stepping\t: %s, core/bus clock ratio: %sx\n", - Cx86_step, x86_clkmult[Cx86_mult]); + len += sprintf(buffer+len, + "stepping\t: %s, core/bus clock ratio: %s\n", + Cx86_step, x86_clkmult[Cx86_mult]); } - else { - len += sprintf(buffer+len, - "stepping\t: %d\n", - CD(x86_mask)); + else { + len += sprintf(buffer+len, + "stepping\t: %d\n", + CD(x86_mask)); } else - len += sprintf(buffer+len, + len += sprintf(buffer+len, "stepping\t: unknown\n"); - + len += sprintf(buffer+len, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" @@ -530,7 +529,7 @@ ? "yes" : "no", CD(have_cpuid) ? "yes" : "no", CD(wp_works_ok) ? "yes" : "no"); - + for ( i = 0 ; i < 32 ; i++ ) { if ( CD(x86_capability) & (1 << i) ) { len += sprintf(buffer+len, " %s", diff -urN linux-2.0.39/arch/i386/kernel/signal.c linux-2.0.40/arch/i386/kernel/signal.c --- linux-2.0.39/arch/i386/kernel/signal.c 1997-08-04 12:12:51.000000000 -0700 +++ linux-2.0.40/arch/i386/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -69,7 +69,7 @@ restore_i387_hard(buf); return; } - restore_i387_soft(buf); + restore_i387_soft(¤t->tss.i387.soft, buf); #endif } @@ -152,7 +152,8 @@ #else if (hard_math) return save_i387_hard(buf); - return save_i387_soft(buf); + save_i387_soft(¤t->tss.i387.soft, buf); + return buf; #endif } @@ -311,7 +312,7 @@ if (current->pid == 1) continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN linux-2.0.39/arch/i386/kernel/smp.c linux-2.0.40/arch/i386/kernel/smp.c --- linux-2.0.39/arch/i386/kernel/smp.c 1998-11-15 10:32:46.000000000 -0800 +++ linux-2.0.40/arch/i386/kernel/smp.c 2004-02-07 23:13:01.000000000 -0800 @@ -22,6 +22,7 @@ */ #include +#include #include #include #include diff -urN linux-2.0.39/arch/i386/kernel/traps.c linux-2.0.40/arch/i386/kernel/traps.c --- linux-2.0.39/arch/i386/kernel/traps.c 1998-11-15 10:32:46.000000000 -0800 +++ linux-2.0.40/arch/i386/kernel/traps.c 2004-02-07 23:13:01.000000000 -0800 @@ -61,19 +61,23 @@ #define get_seg_byte(seg,addr) ({ \ register unsigned char __res; \ -__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ - :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__asm__("push %%fs; mov %%ax, %%fs; movb %%fs:%2, %%al; pop %%fs" \ + : "=a" (__res) \ + : "0" (seg), "m" (*(addr))); \ __res;}) #define get_seg_long(seg,addr) ({ \ register unsigned long __res; \ -__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ - :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__asm__("push %%fs; mov %%ax, %%fs; movl %%fs:%2, %%eax; pop %%fs" \ + : "=a" (__res) \ + : "0" (seg), "m" (*(addr))); \ __res;}) #define _fs() ({ \ register unsigned short __res; \ -__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__asm__("mov %%fs, %%ax" \ + : "=a" (__res) \ + :); \ __res;}) void page_exception(void); @@ -203,7 +207,7 @@ return; } - /* + /* * HACK HACK HACK :) Fixing the segment invalid on syscall return * barfage for 2.0 has been put into the too-hard basket but having * a user producing endless GPFs is unacceptable as well. - Paul G. @@ -219,25 +223,25 @@ } do_exit(SIGSEGV); } - else + else die_if_kernel("general protection",regs,error_code); } current->tss.error_code = error_code; current->tss.trap_no = 13; - force_sig(SIGSEGV, current); + force_sig(SIGSEGV, current); } asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { #ifdef CONFIG_SMP_NMI_INVAL smp_flush_tlb_rcv(); -#else +#else /* CONFIG_SMP_NMI_INVAL */ #ifndef CONFIG_IGNORE_NMI printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); printk("You probably have a hardware problem with your RAM chips or a\n"); printk("power saving mode enabled.\n"); -#endif -#endif +#endif /* !CONFIG_IGNORE_NMI */ +#endif /* !CONFIG_SMP_NMI_INVAL */ } asmlinkage void do_debug(struct pt_regs * regs, long error_code) @@ -251,7 +255,7 @@ current->tss.error_code = error_code; if ((regs->cs & 3) == 0) { /* If this is a kernel mode trap, then reset db7 and allow us to continue */ - __asm__("movl %0,%%db7" + __asm__("movl %0, %%db7" : /* no output */ : "r" (0)); return; @@ -282,7 +286,8 @@ /* * Save the info for the exception handler */ - __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard)); + __asm__ __volatile__("fnsave %0" + : "=m" (task->tss.i387.hard)); task->flags&=~PF_USEDFPU; stts(); @@ -329,16 +334,18 @@ if (last_task_used_math == current) return; if (last_task_used_math) - __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387)); + __asm__("fnsave %0" + : "=m" (last_task_used_math->tss.i387)); else __asm__("fnclex"); last_task_used_math = current; #endif if(current->used_math) - __asm__("frstor %0": :"m" (current->tss.i387)); - else - { + __asm__("frstor %0" + : + : "m" (current->tss.i387)); + else { /* * Our first FPU usage, clean the chip. */ @@ -398,7 +405,8 @@ flush_tlb_all(); /* now we have the mapping ok, we can do LIDT */ - __asm__ __volatile__("\tlidt %0": "=m" (idt_descriptor)); + __asm__ __volatile__("\tlidt %0" + : "=m" (idt_descriptor)); printk(" ... done\n"); } @@ -409,10 +417,9 @@ int i; struct desc_struct * p; static int smptrap=0; - - if(smptrap) - { - __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + + if(smptrap) { + __asm__("pushfl; andl $0xffffbfff, (%esp); popfl"); load_ldt(0); return; } @@ -454,7 +461,7 @@ p++; } /* Clear NT, so that we won't have troubles with that later on */ - __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + __asm__("pushfl; andl $0xffffbfff, (%esp); popfl"); load_TR(0); load_ldt(0); } diff -urN linux-2.0.39/arch/i386/math-emu/Makefile linux-2.0.40/arch/i386/math-emu/Makefile --- linux-2.0.39/arch/i386/math-emu/Makefile 1997-11-07 09:11:42.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/Makefile 2004-02-07 23:13:01.000000000 -0800 @@ -13,17 +13,17 @@ $(CC) -D__ASSEMBLY__ $(PARANOID) -c $< L_OBJS =fpu_entry.o div_small.o errors.o \ - fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \ + fpu_arith.o fpu_aux.o fpu_etc.o fpu_tags.o fpu_trig.o \ load_store.o get_address.o \ poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \ - reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o \ - reg_div.o reg_mul.o reg_norm.o \ + reg_add_sub.o reg_compare.o reg_constant.o reg_convert.o \ + reg_ld_str.o \ + reg_divide.o reg_mul.o reg_norm.o \ reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \ reg_round.o \ wm_shrx.o wm_sqrt.o \ div_Xsig.o polynom_Xsig.o round_Xsig.o \ - shr_Xsig.o mul_Xsig.o \ - fpu_debug.o + shr_Xsig.o mul_Xsig.o include $(TOPDIR)/Rules.make diff -urN linux-2.0.39/arch/i386/math-emu/README linux-2.0.40/arch/i386/math-emu/README --- linux-2.0.39/arch/i386/math-emu/README 1996-10-29 05:17:25.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/README 2004-02-07 23:13:01.000000000 -0800 @@ -1,9 +1,9 @@ +---------------------------------------------------------------------------+ | wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | | | - | Copyright (C) 1992,1993,1994,1995,1996 | + | Copyright (C) 1992,1993,1994,1995,1996,1997,1999,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@suburbia.net | + | Australia. E-mail billm@melbpc.org.au | | | | This program is free software; you can redistribute it and/or modify | | it under the terms of the GNU General Public License version 2 as | @@ -42,11 +42,14 @@ some differences. Please report bugs, etc to me at: - billm@suburbia.net + billm@melbpc.org.au + +For more information on the emulator and on floating point topics, see +my web pages, currently at http://floatingpoint.sourceforge.net/ --Bill Metzenthen - October 1996 + August 2001 ----------------------- Internals of wm-FPU-emu ----------------------- @@ -95,8 +98,9 @@ ----------------------- Limitations of wm-FPU-emu ----------------------- There are a number of differences between the current wm-FPU-emu -(version 1.20) and the 80486 FPU (apart from bugs). Some of the more -important differences are listed below: +(version 2.01) and the 80486 FPU (apart from bugs). The differences +are fewer than those which applied to the 1.xx series of the emulator. +Some of the more important differences are listed below: The Roundup flag does not have much meaning for the transcendental functions and its 80486 value with these functions is likely to differ @@ -122,24 +126,12 @@ emulator. Do not use them. The emulator treats them differently in detail from the way an 80486 does. -The emulator treats PseudoDenormals differently from an 80486. These -numbers are in fact properly normalised numbers with the exponent -offset by 1, and the emulator treats them as such. Unlike the 80486, -the emulator does not generate a Denormal Operand exception for these -numbers. The arithmetical results produced when using such a number as -an operand are the same for the emulator and a real 80486 (apart from -any slight precision difference for the transcendental functions). -Neither the emulator nor an 80486 produces one of these numbers as the -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 +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 @@ -171,7 +163,7 @@ The speed of floating point computation with the emulator will depend upon instruction mix. Relative performance is best for the instructions which require most computation. The simple instructions are adversely -affected by the fpu instruction trap overhead. +affected by the FPU instruction trap overhead. Timing: Some simple timing tests have been made on the emulator functions. diff -urN linux-2.0.39/arch/i386/math-emu/control_w.h linux-2.0.40/arch/i386/math-emu/control_w.h --- linux-2.0.39/arch/i386/math-emu/control_w.h 1995-06-29 08:25:27.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/control_w.h 2004-02-07 23:13:01.000000000 -0800 @@ -42,4 +42,4 @@ /* FULL_PRECISION simulates all exceptions masked */ #define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) -#endif _CONTROLW_H_ +#endif /* _CONTROLW_H_ */ diff -urN linux-2.0.39/arch/i386/math-emu/div_Xsig.S linux-2.0.40/arch/i386/math-emu/div_Xsig.S --- linux-2.0.39/arch/i386/math-emu/div_Xsig.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/div_Xsig.S 2004-02-07 23:13:01.000000000 -0800 @@ -55,7 +55,7 @@ Local storage in a static area: Accumulator: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 */ - .align 2,0 + .align 4,0 FPU_accum_3: .long 0 FPU_accum_2: @@ -70,7 +70,7 @@ .long 0 FPU_result_1: .long 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -91,7 +91,7 @@ #ifdef PARANOID testl $0x80000000, XsigH(%ebx) /* Divisor */ je L_bugged -#endif PARANOID +#endif /* PARANOID */ /*---------------------------------------------------------------------------+ @@ -164,7 +164,7 @@ #ifdef PARANOID jb L_bugged_1 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ incl FPU_result_3 /* Correct the answer */ @@ -177,7 +177,7 @@ #ifdef PARANOID sbbl $0,FPU_accum_3 jne L_bugged_1 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* Half of the main problem is done, there is just a reduced numerator @@ -207,7 +207,7 @@ #ifdef PARANOID je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif PARANOID +#endif /* PARANOID */ LDo_2nd_div: cmpl $0,%ecx /* augmented denom msw */ @@ -230,7 +230,7 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ movl FPU_result_2,%eax /* Get the result back */ mull XsigL(%ebx) /* now mul the ls dw of the denom */ @@ -241,14 +241,14 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ jz LDo_3rd_32_bits #ifdef PARANOID cmpl $1,FPU_accum_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ movl XsigL(%ebx),%eax @@ -260,14 +260,14 @@ #ifdef PARANOID jc L_bugged_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ addl $1,FPU_result_2 /* Correct the answer */ adcl $0,FPU_result_3 #ifdef PARANOID jc L_bugged_2 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* The division is essentially finished here, we just need to perform @@ -362,4 +362,4 @@ call EXCEPTION pop %ebx jmp L_exit -#endif PARANOID +#endif /* PARANOID */ diff -urN linux-2.0.39/arch/i386/math-emu/div_small.S linux-2.0.40/arch/i386/math-emu/div_small.S --- linux-2.0.39/arch/i386/math-emu/div_small.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/div_small.S 2004-02-07 23:13:01.000000000 -0800 @@ -12,13 +12,13 @@ +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ - | unsigned long div_small(unsigned long long *x, unsigned long y) | + | unsigned long FPU_div_small(unsigned long long *x, unsigned long y) | +---------------------------------------------------------------------------*/ #include "fpu_emu.h" .text -ENTRY(div_small) +ENTRY(FPU_div_small) pushl %ebp movl %esp,%ebp diff -urN linux-2.0.39/arch/i386/math-emu/errors.c linux-2.0.40/arch/i386/math-emu/errors.c --- linux-2.0.39/arch/i386/math-emu/errors.c 1996-05-06 06:31:17.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/errors.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | The error handling functions for wm-FPU-emu | | | - | Copyright (C) 1992,1993,1994,1996 | + | Copyright (C) 1992,1993,1994,1996,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | + | E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -19,11 +19,9 @@ #include -#include - +#include "fpu_emu.h" #include "fpu_system.h" #include "exception.h" -#include "fpu_emu.h" #include "status_w.h" #include "control_w.h" #include "reg_constant.h" @@ -36,23 +34,23 @@ void Un_impl(void) { - unsigned char byte1, FPU_modrm; + u_char byte1, FPU_modrm; unsigned long address = FPU_ORIG_EIP; RE_ENTRANT_CHECK_OFF; /* No need to verify_area(), we have previously fetched these bytes. */ printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address); - if ( FPU_CS == USER_CS ) + if ( FPU_CS == FPU_USER_CS ) { while ( 1 ) { - byte1 = get_fs_byte((unsigned char *) address); + FPU_get_user(byte1, (u_char *) address); if ( (byte1 & 0xf8) == 0xd8 ) break; printk("[%02x]", byte1); address++; } printk("%02x ", byte1); - FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + FPU_get_user(FPU_modrm, 1 + (u_char *) address); if (FPU_modrm >= 0300) printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); @@ -77,28 +75,28 @@ */ void FPU_illegal(void) { - math_abort(FPU_info,SIGILL); + math_abort(SIGILL); } -void emu_printall(void) +void FPU_printall(void) { int i; - static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR", - "DeNorm", "Inf", "NaN", "Empty" }; - unsigned char byte1, FPU_modrm; + static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty", + "DeNorm", "Inf", "NaN" }; + u_char byte1, FPU_modrm; unsigned long address = FPU_ORIG_EIP; RE_ENTRANT_CHECK_OFF; /* No need to verify_area(), we have previously fetched these bytes. */ printk("At %p:", (void *) address); - if ( FPU_CS == USER_CS ) + if ( FPU_CS == FPU_USER_CS ) { #define MAX_PRINTED_BYTES 20 for ( i = 0; i < MAX_PRINTED_BYTES; i++ ) { - byte1 = get_fs_byte((unsigned char *) address); + FPU_get_user(byte1, (u_char *) address); if ( (byte1 & 0xf8) == 0xd8 ) { printk(" %02x", byte1); @@ -111,7 +109,7 @@ printk(" [more..]\n"); else { - FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + FPU_get_user(FPU_modrm, 1 + (u_char *) address); if (FPU_modrm >= 0300) printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); @@ -122,7 +120,7 @@ } else { - printk("%04x\n", FPU_CS); + printk("%04x (Not USER_CS)\n", FPU_CS); } partial_status = status_word(); @@ -141,7 +139,7 @@ if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n"); if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n"); -#endif DEBUGGING +#endif /* DEBUGGING */ 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 */ @@ -166,29 +164,23 @@ for ( i = 0; i < 8; i++ ) { FPU_REG *r = &st(i); - char tagi = r->tag; + u_char tagi = FPU_gettagi(i); switch (tagi) { - case TW_Empty: + case TAG_Empty: continue; break; - case TW_Zero: -#if 0 - printk("st(%d) %c .0000 0000 0000 0000 ", - i, r->sign ? '-' : '+'); - break; -#endif - case TW_Valid: - case TW_NaN: -/* case TW_Denormal: */ - case TW_Infinity: - printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6ld ", i, - r->sign ? '-' : '+', + case TAG_Zero: + case TAG_Special: + tagi = FPU_Special(r); + case TAG_Valid: + printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i, + getsign(r) ? '-' : '+', (long)(r->sigh >> 16), (long)(r->sigh & 0xFFFF), (long)(r->sigl >> 16), (long)(r->sigl & 0xFFFF), - r->exp - EXP_BIAS + 1); + exponent(r) - EXP_BIAS + 1); break; default: printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi); @@ -262,6 +254,11 @@ 0x161 in reg_ld_str.c 0x162 in reg_ld_str.c 0x163 in reg_ld_str.c + 0x164 in reg_ld_str.c + 0x170 in fpu_tags.c + 0x171 in fpu_tags.c + 0x172 in fpu_tags.c + 0x180 in reg_convert.c 0x2nn in an *.S file: 0x201 in reg_u_add.S 0x202 in reg_u_div.S @@ -292,7 +289,7 @@ 0x242 in div_Xsig.S */ -void exception(int n) +void FPU_exception(int n) { int i, int_type; @@ -328,7 +325,7 @@ #ifdef PRINT_MESSAGES /* My message from the sponsor */ printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n"); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ /* Get a name string for error reporting */ for (i=0; exception_names[i].type; i++) @@ -339,7 +336,7 @@ { #ifdef PRINT_MESSAGES printk("FP Exception: %s!\n", exception_names[i].name); -#endif PRINT_MESSAGES +#endif /* PRINT_MESSAGES */ } else printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); @@ -347,12 +344,12 @@ if ( n == EX_INTERNAL ) { printk("FPU emulator: Internal error type 0x%04x\n", int_type); - emu_printall(); + FPU_printall(); } #ifdef PRINT_MESSAGES else - emu_printall(); -#endif PRINT_MESSAGES + FPU_printall(); +#endif /* PRINT_MESSAGES */ /* * The 80486 generates an interrupt on the next non-control FPU @@ -363,30 +360,103 @@ RE_ENTRANT_CHECK_ON; #ifdef __DEBUG__ - math_abort(FPU_info,SIGFPE); -#endif __DEBUG__ + math_abort(SIGFPE); +#endif /* __DEBUG__ */ } -/* Real operation attempted on two operands, one a NaN. */ -/* Returns nz if the exception is unmasked */ -asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest) +/* Real operation attempted on a NaN. */ +/* Returns < 0 if the exception is unmasked */ +int real_1op_NaN(FPU_REG *a) { - FPU_REG const *x; - int signalling; + int signalling, isNaN; + + isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000); /* The default result for the case of two "equal" NaNs (signs may differ) is chosen to reproduce 80486 behaviour */ - x = a; - if (a->tag == TW_NaN) + signalling = isNaN && !(a->sigh & 0x40000000); + + if ( !signalling ) + { + if ( !isNaN ) /* pseudo-NaN, or other unsupported? */ + { + if ( control_word & CW_Invalid ) + { + /* Masked response */ + reg_copy(&CONST_QNaN, a); + } + EXCEPTION(EX_Invalid); + return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; + } + return TAG_Special; + } + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + if ( !(a->sigh & 0x80000000) ) /* pseudo-NaN ? */ + { + reg_copy(&CONST_QNaN, a); + } + /* ensure a Quiet NaN */ + a->sigh |= 0x40000000; + } + + EXCEPTION(EX_Invalid); + + return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; +} + + +/* Real operation attempted on two operands, one a NaN. */ +/* Returns < 0 if the exception is unmasked */ +int real_2op_NaN(FPU_REG const *b, u_char tagb, + int deststnr, + FPU_REG const *defaultNaN) +{ + FPU_REG *dest = &st(deststnr); + FPU_REG const *a = dest; + u_char taga = FPU_gettagi(deststnr); + FPU_REG const *x; + int signalling, unsupported; + + if ( taga == TAG_Special ) + taga = FPU_Special(a); + if ( tagb == TAG_Special ) + tagb = FPU_Special(b); + + /* TW_NaN is also used for unsupported data types. */ + unsupported = ((taga == TW_NaN) + && !((exponent(a) == EXP_OVER) && (a->sigh & 0x80000000))) + || ((tagb == TW_NaN) + && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000))); + if ( unsupported ) + { + if ( control_word & CW_Invalid ) + { + /* Masked response */ + FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); + } + EXCEPTION(EX_Invalid); + return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; + } + + if (taga == TW_NaN) { - if (b->tag == TW_NaN) + x = a; + if (tagb == TW_NaN) { signalling = !(a->sigh & b->sigh & 0x40000000); - /* find the "larger" */ - if ( significand(a) < significand(b) ) + if ( significand(b) > significand(a) ) x = b; + else if ( significand(b) == significand(a) ) + { + /* The default result for the case of two "equal" NaNs (signs may + differ) is chosen to reproduce 80486 behaviour */ + x = defaultNaN; + } } else { @@ -396,8 +466,8 @@ } else #ifdef PARANOID - if (b->tag == TW_NaN) -#endif PARANOID + if (tagb == TW_NaN) +#endif /* PARANOID */ { signalling = !(b->sigh & 0x40000000); x = b; @@ -409,35 +479,34 @@ EXCEPTION(EX_INTERNAL|0x113); x = &CONST_QNaN; } -#endif PARANOID +#endif /* PARANOID */ - if ( !signalling ) + if ( (!signalling) || (control_word & CW_Invalid) ) { - if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */ - x = &CONST_QNaN; - reg_move(x, dest); - return 0; - } + if ( ! x ) + x = b; - if ( control_word & CW_Invalid ) - { - /* The masked response */ if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */ x = &CONST_QNaN; - reg_move(x, dest); + + FPU_copy_to_regi(x, TAG_Special, deststnr); + + if ( !signalling ) + return TAG_Special; + /* ensure a Quiet NaN */ dest->sigh |= 0x40000000; } EXCEPTION(EX_Invalid); - - return !(control_word & CW_Invalid); + + return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; } /* Invalid arith operation on Valid registers */ -/* Returns nz if the exception is unmasked */ -asmlinkage int arith_invalid(FPU_REG *dest) +/* Returns < 0 if the exception is unmasked */ +asmlinkage int arith_invalid(int deststnr) { EXCEPTION(EX_Invalid); @@ -445,28 +514,31 @@ if ( control_word & CW_Invalid ) { /* The masked response */ - reg_move(&CONST_QNaN, dest); + FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); } - return !(control_word & CW_Invalid); + return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid; } /* Divide a finite number by zero */ -asmlinkage int divide_by_zero(int sign, FPU_REG *dest) +asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign) { + FPU_REG *dest = &st(deststnr); + int tag = TAG_Valid; if ( control_word & CW_ZeroDiv ) { /* The masked response */ - reg_move(&CONST_INF, dest); - dest->sign = (unsigned char)sign; + FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr); + setsign(dest, sign); + tag = TAG_Special; } EXCEPTION(EX_ZeroDiv); - return !(control_word & CW_ZeroDiv); + return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag; } @@ -482,7 +554,7 @@ } else { - exception(flags); + EXCEPTION(flags); return 1; } } @@ -494,8 +566,7 @@ if ( control_word & CW_Precision ) partial_status |= (SW_Precision | SW_C1); /* The masked response */ else - exception(EX_Precision | SW_C1); - + EXCEPTION(EX_Precision | SW_C1); } @@ -508,7 +579,7 @@ partial_status |= SW_Precision; } else - exception(EX_Precision); + EXCEPTION(EX_Precision); } @@ -517,32 +588,69 @@ if ( control_word & CW_Denormal ) { /* The masked response */ partial_status |= SW_Denorm_Op; - return 0; + return TAG_Special; } else { - exception(EX_Denormal); - return 1; + EXCEPTION(EX_Denormal); + return TAG_Special | FPU_Exception; } } -asmlinkage int arith_overflow(FPU_REG *dest) +asmlinkage int arith_overflow(FPU_REG *dest, int negative) { + int tag = TAG_Valid; + int big_real = 0; if ( control_word & CW_Overflow ) { - char sign; /* The masked response */ -/* ###### The response here depends upon the rounding mode */ - sign = dest->sign; - reg_move(&CONST_INF, dest); - dest->sign = sign; + /* The response here depends upon the rounding mode */ + switch ( control_word & CW_RC ) + { + case RC_UP: + big_real = negative; + break; + case RC_DOWN: + big_real = ! negative; + break; + case RC_CHOP: + big_real = 1; + break; + default: + } + if ( big_real ) + { + switch ( control_word & CW_PC ) + { + case PR_24_BITS: + significand(dest) = 0xffffff0000000000LL; + exponent16(dest) = 0x7ffe; + break; + case PR_53_BITS: + significand(dest) = 0xfffffffffffff800LL; + exponent16(dest) = 0x7ffe; + break; + case PR_64_BITS: + significand(dest) = 0xffffffffffffffffLL; + exponent16(dest) = 0x7ffe; + break; + } + EXCEPTION(EX_Overflow); + EXCEPTION(EX_Precision); + return tag; + } + else + { + reg_copy(&CONST_INF, dest); + tag = TAG_Special; + } } else { /* Subtract the magic number from the exponent */ - dest->exp -= (3 * (1 << 13)); + addexponent(dest, (-3 * (1 << 13))); } EXCEPTION(EX_Overflow); @@ -553,30 +661,36 @@ The roundup bit (C1) is also set because we have "rounded" upwards to Infinity. */ EXCEPTION(EX_Precision | SW_C1); - return !(control_word & CW_Precision); + return tag; } - return 0; + return tag; } asmlinkage int arith_underflow(FPU_REG *dest) { + int tag = TAG_Valid; if ( control_word & CW_Underflow ) { /* The masked response */ - if ( dest->exp <= EXP_UNDER - 63 ) + if ( exponent16(dest) <= EXP_UNDER - 63 ) { - reg_move(&CONST_Z, dest); + reg_copy(&CONST_Z, dest); partial_status &= ~SW_C1; /* Round down. */ + tag = TAG_Zero; + } + else + { + stdexp(dest); } } else { /* Add the magic number to the exponent. */ - dest->exp += (3 * (1 << 13)); + addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias); } EXCEPTION(EX_Underflow); @@ -584,22 +698,22 @@ { /* The underflow exception is masked. */ EXCEPTION(EX_Precision); - return !(control_word & CW_Precision); + return tag; } - return 0; + return tag; } -void stack_overflow(void) +void FPU_stack_overflow(void) { if ( control_word & CW_Invalid ) { /* The masked response */ - top--; - reg_move(&CONST_QNaN, &st(0)); + FPU_top--; + FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); } EXCEPTION(EX_StackOver); @@ -609,13 +723,13 @@ } -void stack_underflow(void) +void FPU_stack_underflow(void) { if ( control_word & CW_Invalid ) { /* The masked response */ - reg_move(&CONST_QNaN, &st(0)); + FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); } EXCEPTION(EX_StackUnder); @@ -625,13 +739,13 @@ } -void stack_underflow_i(int i) +void FPU_stack_underflow_i(int i) { if ( control_word & CW_Invalid ) { /* The masked response */ - reg_move(&CONST_QNaN, &(st(i))); + FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); } EXCEPTION(EX_StackUnder); @@ -641,14 +755,14 @@ } -void stack_underflow_pop(int i) +void FPU_stack_underflow_pop(int i) { if ( control_word & CW_Invalid ) { /* The masked response */ - reg_move(&CONST_QNaN, &(st(i))); - pop(); + FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); + FPU_pop(); } EXCEPTION(EX_StackUnder); diff -urN linux-2.0.39/arch/i386/math-emu/exception.h linux-2.0.40/arch/i386/math-emu/exception.h --- linux-2.0.39/arch/i386/math-emu/exception.h 1997-03-28 16:12:25.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/exception.h 2004-02-07 23:13:01.000000000 -0800 @@ -18,7 +18,7 @@ #ifndef SW_C1 #include "fpu_emu.h" -#endif SW_C1 +#endif /* SW_C1 */ #define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ #define EX_ErrorSummary Const_(0x0080) /* Error summary status */ @@ -43,11 +43,11 @@ #ifdef DEBUG #define EXCEPTION(x) { printk("exception in %s at line %d\n", \ - __FILE__, __LINE__); exception(x); } + __FILE__, __LINE__); FPU_exception(x); } #else -#define EXCEPTION(x) exception(x) +#define EXCEPTION(x) FPU_exception(x) #endif -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _EXCEPTION_H_ +#endif /* _EXCEPTION_H_ */ diff -urN linux-2.0.39/arch/i386/math-emu/fpu_arith.c linux-2.0.40/arch/i386/math-emu/fpu_arith.c --- linux-2.0.39/arch/i386/math-emu/fpu_arith.c 1994-06-02 00:28:23.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_arith.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Code to implement the FPU register/register arithmetic instructions | | | - | Copyright (C) 1992,1993 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -19,16 +19,18 @@ void fadd__() { /* fadd st,st(i) */ + int i = FPU_rm; clear_C1(); - reg_add(&st(0), &st(FPU_rm), &st(0), control_word); + FPU_add(&st(i), FPU_gettagi(i), 0, control_word); } void fmul__() { /* fmul st,st(i) */ + int i = FPU_rm; clear_C1(); - reg_mul(&st(0), &st(FPU_rm), &st(0), control_word); + FPU_mul(&st(i), FPU_gettagi(i), 0, control_word); } @@ -37,7 +39,7 @@ { /* fsub st,st(i) */ clear_C1(); - reg_sub(&st(0), &st(FPU_rm), &st(0), control_word); + FPU_sub(0, FPU_rm, control_word); } @@ -45,7 +47,7 @@ { /* fsubr st,st(i) */ clear_C1(); - reg_sub(&st(FPU_rm), &st(0), &st(0), control_word); + FPU_sub(REV, FPU_rm, control_word); } @@ -53,7 +55,7 @@ { /* fdiv st,st(i) */ clear_C1(); - reg_div(&st(0), &st(FPU_rm), &st(0), control_word); + FPU_div(0, FPU_rm, control_word); } @@ -61,7 +63,7 @@ { /* fdivr st,st(i) */ clear_C1(); - reg_div(&st(FPU_rm), &st(0), &st(0), control_word); + FPU_div(REV, FPU_rm, control_word); } @@ -69,8 +71,9 @@ void fadd_i() { /* fadd st(i),st */ + int i = FPU_rm; clear_C1(); - reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); + FPU_add(&st(i), FPU_gettagi(i), i, control_word); } @@ -78,27 +81,23 @@ { /* fmul st(i),st */ clear_C1(); - reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); + FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word); } void fsubri() { /* fsubr st(i),st */ - /* This is the sense of the 80486 manual - reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */ clear_C1(); - reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); + FPU_sub(DEST_RM, FPU_rm, control_word); } void fsub_i() { /* fsub st(i),st */ - /* This is the sense of the 80486 manual - reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */ clear_C1(); - reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); + FPU_sub(REV|DEST_RM, FPU_rm, control_word); } @@ -106,7 +105,7 @@ { /* fdivr st(i),st */ clear_C1(); - reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); + FPU_div(DEST_RM, FPU_rm, control_word); } @@ -114,7 +113,7 @@ { /* fdiv st(i),st */ clear_C1(); - reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); + FPU_div(REV|DEST_RM, FPU_rm, control_word); } @@ -122,9 +121,10 @@ void faddp_() { /* faddp st(i),st */ + int i = FPU_rm; clear_C1(); - if ( !reg_add(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) - pop(); + if ( FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0 ) + FPU_pop(); } @@ -132,8 +132,8 @@ { /* fmulp st(i),st */ clear_C1(); - if ( !reg_mul(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) - pop(); + if ( FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0 ) + FPU_pop(); } @@ -141,22 +141,18 @@ void fsubrp() { /* fsubrp st(i),st */ - /* This is the sense of the 80486 manual - reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word); */ clear_C1(); - if ( !reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) - pop(); + if ( FPU_sub(DEST_RM, FPU_rm, control_word) >= 0 ) + FPU_pop(); } void fsubp_() { /* fsubp st(i),st */ - /* This is the sense of the 80486 manual - reg_sub(&st(0), &st(FPU_rm), &st(FPU_rm), control_word); */ clear_C1(); - if ( !reg_sub(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) ) - pop(); + if ( FPU_sub(REV|DEST_RM, FPU_rm, control_word) >= 0 ) + FPU_pop(); } @@ -164,8 +160,8 @@ { /* fdivrp st(i),st */ clear_C1(); - if ( !reg_div(&st(0), &st(FPU_rm), &st(FPU_rm), control_word) ) - pop(); + if ( FPU_div(DEST_RM, FPU_rm, control_word) >= 0 ) + FPU_pop(); } @@ -173,7 +169,6 @@ { /* fdivp st(i),st */ clear_C1(); - if ( !reg_div(&st(FPU_rm), &st(0), &st(FPU_rm), control_word) ) - pop(); + if ( FPU_div(REV|DEST_RM, FPU_rm, control_word) >= 0 ) + FPU_pop(); } - diff -urN linux-2.0.39/arch/i386/math-emu/fpu_asm.h linux-2.0.40/arch/i386/math-emu/fpu_asm.h --- linux-2.0.39/arch/i386/math-emu/fpu_asm.h 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_asm.h 2004-02-07 23:13:01.000000000 -0800 @@ -1,9 +1,9 @@ /*---------------------------------------------------------------------------+ | fpu_asm.h | | | - | Copyright (C) 1992,1995 | + | Copyright (C) 1992,1995,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | +---------------------------------------------------------------------------*/ @@ -12,20 +12,21 @@ #include -#define EXCEPTION SYMBOL_NAME(exception) +#define EXCEPTION SYMBOL_NAME(FPU_exception) #define PARAM1 8(%ebp) #define PARAM2 12(%ebp) #define PARAM3 16(%ebp) #define PARAM4 20(%ebp) +#define PARAM5 24(%ebp) +#define PARAM6 28(%ebp) +#define PARAM7 32(%ebp) -#define SIGL_OFFSET 8 -#define SIGN(x) (x) -#define TAG(x) 1(x) -#define EXP(x) 4(x) +#define SIGL_OFFSET 0 +#define EXP(x) 8(x) #define SIG(x) SIGL_OFFSET##(x) #define SIGL(x) SIGL_OFFSET##(x) -#define SIGH(x) 12(x) +#define SIGH(x) 4(x) -#endif _FPU_ASM_H_ +#endif /* _FPU_ASM_H_ */ diff -urN linux-2.0.39/arch/i386/math-emu/fpu_aux.c linux-2.0.40/arch/i386/math-emu/fpu_aux.c --- linux-2.0.39/arch/i386/math-emu/fpu_aux.c 1994-06-02 00:28:23.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_aux.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Code to implement some of the FPU auxiliary instructions. | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1997,2001 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -32,15 +32,11 @@ /* Needs to be externally visible */ void finit() { - int r; control_word = 0x037f; partial_status = 0; - top = 0; /* We don't keep top in the status word internally. */ - for (r = 0; r < 8; r++) - { - regs[r].tag = TW_Empty; - } - /* The behaviour is different to that detailed in + FPU_top = 0; /* We don't keep top in the status word internally. */ + fpu_tag_word = 0xffff; + /* The behaviour is different from that detailed in Section 15.1.6 of the Intel manual */ operand_address.offset = 0; operand_address.selector = 0; @@ -99,19 +95,27 @@ void fld_i_() { FPU_REG *st_new_ptr; + int i; + u_char tag; if ( STACK_OVERFLOW ) - { stack_overflow(); return; } + { FPU_stack_overflow(); return; } /* fld st(i) */ - if ( NOT_EMPTY(FPU_rm) ) - { reg_move(&st(FPU_rm), st_new_ptr); push(); } + i = FPU_rm; + if ( NOT_EMPTY(i) ) + { + reg_copy(&st(i), st_new_ptr); + tag = FPU_gettagi(i); + push(); + FPU_settag0(tag); + } else { if ( control_word & CW_Invalid ) { /* The masked response */ - stack_underflow(); + FPU_stack_underflow(); } else EXCEPTION(EX_StackUnder); @@ -124,61 +128,155 @@ { /* fxch st(i) */ FPU_REG t; - register FPU_REG *sti_ptr = &st(FPU_rm), *st0_ptr = &st(0); + int i = FPU_rm; + FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i); + long tag_word = fpu_tag_word; + int regnr = FPU_top & 7, regnri = ((regnr + i) & 7); + u_char st0_tag = (tag_word >> (regnr*2)) & 3; + u_char sti_tag = (tag_word >> (regnri*2)) & 3; - if ( st0_ptr->tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { - if ( sti_ptr->tag == TW_Empty ) + if ( sti_tag == TAG_Empty ) { - stack_underflow(); - stack_underflow_i(FPU_rm); + FPU_stack_underflow(); + FPU_stack_underflow_i(i); return; } if ( control_word & CW_Invalid ) - reg_move(sti_ptr, st0_ptr); /* Masked response */ - stack_underflow_i(FPU_rm); + { + /* Masked response */ + FPU_copy_to_reg0(sti_ptr, sti_tag); + } + FPU_stack_underflow_i(i); return; } - if ( sti_ptr->tag == TW_Empty ) + if ( sti_tag == TAG_Empty ) { if ( control_word & CW_Invalid ) - reg_move(st0_ptr, sti_ptr); /* Masked response */ - stack_underflow(); + { + /* Masked response */ + FPU_copy_to_regi(st0_ptr, st0_tag, i); + } + FPU_stack_underflow(); return; } clear_C1(); - reg_move(st0_ptr, &t); - reg_move(sti_ptr, st0_ptr); - reg_move(&t, sti_ptr); + + reg_copy(st0_ptr, &t); + reg_copy(sti_ptr, st0_ptr); + reg_copy(&t, sti_ptr); + + tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2)); + tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2)); + fpu_tag_word = tag_word; } void ffree_() { /* ffree st(i) */ - st(FPU_rm).tag = TW_Empty; + FPU_settagi(FPU_rm, TAG_Empty); } void ffreep() { /* ffree st(i) + pop - unofficial code */ - st(FPU_rm).tag = TW_Empty; - pop(); + FPU_settagi(FPU_rm, TAG_Empty); + FPU_pop(); } void fst_i_() { /* fst st(i) */ - reg_move(&st(0), &st(FPU_rm)); + FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); } void fstp_i() { /* fstp st(i) */ - reg_move(&st(0), &st(FPU_rm)); - pop(); + FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); + FPU_pop(); +} + + +#ifndef ONLY_486_FPU +static void fmov_i(void) +{ + int i; + u_char tag; + + /* for the fcmovxx instructions */ + i = FPU_rm; + if ( NOT_EMPTY(i) ) + { + reg_copy(&st(i), &st(0)); + tag = FPU_gettagi(i); + FPU_settag0(tag); + } + else + { + if ( control_word & CW_Invalid ) + { + /* The masked response */ + FPU_stack_underflow(); + } + else + EXCEPTION(EX_StackUnder); + } + +} + + +void fcmovnb(void) +{ + if ( ! (FPU_EFLAGS & CFLAG) ) + fmov_i(); +} + +void fcmovne(void) +{ + if ( ! (FPU_EFLAGS & ZFLAG) ) + fmov_i(); +} + +void fcmovnbe(void) +{ + if ( ! (FPU_EFLAGS & (CFLAG | ZFLAG)) ) + fmov_i(); +} + +void fcmovnu(void) +{ + if ( ! (FPU_EFLAGS & PFLAG) ) + fmov_i(); +} + +void fcmovb (void) +{ + if ( (FPU_EFLAGS & CFLAG) ) + fmov_i(); +} + +void fcmove (void) +{ + if ( (FPU_EFLAGS & ZFLAG) ) + fmov_i(); +} + +void fcmovbe(void) +{ + if ( (FPU_EFLAGS & (CFLAG | ZFLAG)) ) + fmov_i(); +} + +void fcmovu (void) +{ + if ( (FPU_EFLAGS & PFLAG) ) + fmov_i(); } +#endif /* ONLY_486_FPU */ diff -urN linux-2.0.39/arch/i386/math-emu/fpu_debug.c linux-2.0.40/arch/i386/math-emu/fpu_debug.c --- linux-2.0.39/arch/i386/math-emu/fpu_debug.c 1997-11-07 09:11:42.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/fpu_debug.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,230 +0,0 @@ -/* Interface with ptrace and core-dumping routines */ - - -#include "fpu_system.h" -#include "exception.h" -#include "reg_constant.h" -#include "fpu_emu.h" -#include "control_w.h" -#include "status_w.h" - - -#define EXTENDED_Ebias 0x3fff -#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ - -#define DOUBLE_Emax 1023 /* largest valid exponent */ -#define DOUBLE_Ebias 1023 -#define DOUBLE_Emin (-1022) /* smallest valid exponent */ - -#define SINGLE_Emax 127 /* largest valid exponent */ -#define SINGLE_Ebias 127 -#define SINGLE_Emin (-126) /* smallest valid exponent */ - - -/* Copy and paste from round_to_int. Original comments maintained */ -/*===========================================================================*/ - -/* r gets mangled such that sig is int, sign: - it is NOT normalized */ -/* The return value (in eax) is zero if the result is exact, - if bits are changed due to rounding, truncation, etc, then - a non-zero value is returned */ -/* Overflow is signalled by a non-zero return value (in eax). - In the case of overflow, the returned significand always has the - largest possible value */ - -static int round_to_int_cwd(FPU_REG *r, long int user_control_word) -{ - char very_big; - unsigned eax; - - if (r->tag == TW_Zero) - { - /* Make sure that zero is returned */ - significand(r) = 0; - return 0; /* o.k. */ - } - - if (r->exp > EXP_BIAS + 63) - { - r->sigl = r->sigh = ~0; /* The largest representable number */ - return 1; /* overflow */ - } - - eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp); - very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */ -#define half_or_more (eax & 0x80000000) -#define frac_part (eax) -#define more_than_half ((eax & 0x80000001) == 0x80000001) - switch (user_control_word & CW_RC) - { - case RC_RND: - if ( more_than_half /* nearest */ - || (half_or_more && (r->sigl & 1)) ) /* odd -> even */ - { - if ( very_big ) return 1; /* overflow */ - significand(r) ++; - return PRECISION_LOST_UP; - } - break; - case RC_DOWN: - if (frac_part && r->sign) - { - if ( very_big ) return 1; /* overflow */ - significand(r) ++; - return PRECISION_LOST_UP; - } - break; - case RC_UP: - if (frac_part && !r->sign) - { - if ( very_big ) return 1; /* overflow */ - significand(r) ++; - return PRECISION_LOST_UP; - } - break; - case RC_CHOP: - break; - } - - return eax ? PRECISION_LOST_DOWN : 0; - -} - - - -/* Conver a number in the emulator format to the - * hardware format. - * Taken from the emulator sources, function reg_load_extended - */ - -/* Get a long double from the debugger */ -void hardreg_to_softreg(const char hardreg[10], - FPU_REG *soft_reg) - -{ - unsigned long sigl, sigh, exp; - - sigl = *((unsigned long *) hardreg); - sigh = *(1 + (unsigned long *) hardreg); - exp = *(4 + (unsigned short *) hardreg); - - soft_reg->tag = TW_Valid; /* Default */ - soft_reg->sigl = sigl; - soft_reg->sigh = sigh; - if (exp & 0x8000) - soft_reg->sign = SIGN_NEG; - else - soft_reg->sign = SIGN_POS; - exp &= 0x7fff; - soft_reg->exp = exp - EXTENDED_Ebias + EXP_BIAS; - - if ( exp == 0 ) - { - if ( !(sigh | sigl) ) - { - soft_reg->tag = TW_Zero; - return; - } - /* The number is a de-normal or pseudodenormal. */ - if (sigh & 0x80000000) - { - /* Is a pseudodenormal. */ - /* Convert it for internal use. */ - /* This is non-80486 behaviour because the number - loses its 'denormal' identity. */ - soft_reg->exp++; - return; - } - else - { - /* Is a denormal. */ - /* Convert it for internal use. */ - soft_reg->exp++; - normalize_nuo(soft_reg); - return; - } - } - else if ( exp == 0x7fff ) - { - if ( !((sigh ^ 0x80000000) | sigl) ) - { - /* Matches the bit pattern for Infinity. */ - soft_reg->exp = EXP_Infinity; - soft_reg->tag = TW_Infinity; - return; - } - - soft_reg->exp = EXP_NaN; - soft_reg->tag = TW_NaN; - if ( !(sigh & 0x80000000) ) - { - /* NaNs have the ms bit set to 1. */ - /* This is therefore an Unsupported NaN data type. */ - /* This is non 80486 behaviour */ - /* This should generate an Invalid Operand exception - later, so we convert it to a SNaN */ - soft_reg->sigh = 0x80000000; - soft_reg->sigl = 0x00000001; - soft_reg->sign = SIGN_NEG; - return; - } - return; - } - - if ( !(sigh & 0x80000000) ) - { - /* Unsupported data type. */ - /* Valid numbers have the ms bit set to 1. */ - /* Unnormal. */ - /* Convert it for internal use. */ - /* This is non-80486 behaviour */ - /* This should generate an Invalid Operand exception - later, so we convert it to a SNaN */ - soft_reg->sigh = 0x80000000; - soft_reg->sigl = 0x00000001; - soft_reg->sign = SIGN_NEG; - soft_reg->exp = EXP_NaN; - soft_reg->tag = TW_NaN; - return; - } - return; -} - -/* Conver a number in the emulator format to the - * hardware format. - * Adapted from function write_to_extended - */ - - -void softreg_to_hardreg(const FPU_REG *rp, char d[10], long int user_control_word) -{ - long e; - FPU_REG tmp; - e = rp->exp - EXP_BIAS + EXTENDED_Ebias; - - /* - All numbers except denormals are stored internally in a - format which is compatible with the extended real number - format. - */ - if (e > 0) { - *(unsigned long *) d = rp->sigl; - *(unsigned long *) (d + 4) = rp->sigh; - } else { - /* - The number is a de-normal stored as a normal using our - extra exponent range, or is Zero. - Convert it back to a de-normal, or leave it as Zero. - */ - reg_move(rp, &tmp); - tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 63 */ - round_to_int_cwd(&tmp, user_control_word); - e = 0; - *(unsigned long *) d= tmp.sigl; - *(unsigned long *) (d + 4) = tmp.sigh; - } - e |= rp->sign == SIGN_POS ? 0 : 0x8000; - *(unsigned short *) (d + 8) = e; -} - diff -urN linux-2.0.39/arch/i386/math-emu/fpu_emu.h linux-2.0.40/arch/i386/math-emu/fpu_emu.h --- linux-2.0.39/arch/i386/math-emu/fpu_emu.h 1996-09-22 00:13:54.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_emu.h 2004-02-07 23:13:01.000000000 -0800 @@ -1,9 +1,9 @@ /*---------------------------------------------------------------------------+ | fpu_emu.h | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1997,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | +---------------------------------------------------------------------------*/ @@ -12,14 +12,6 @@ #define _FPU_EMU_H_ /* - * Define DENORM_OPERAND to make the emulator detect denormals - * and use the denormal flag of the status word. Note: this only - * affects the flag and corresponding interrupt, the emulator - * will always generate denormals and operate upon them as required. - */ -#define DENORM_OPERAND - -/* * Define PECULIAR_486 to get a closer approximation to 80486 behaviour, * rather than behaviour which appears to be cleaner. * This is a matter of opinion: for all I know, the 80486 may simply @@ -38,28 +30,51 @@ #define EXP_BIAS Const(0) #define EXP_OVER Const(0x4000) /* smallest invalid large exponent */ #define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */ +#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but + still a 16 bit nr. */ #define EXP_Infinity EXP_OVER #define EXP_NaN EXP_OVER +#define EXTENDED_Ebias Const(0x3fff) +#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ + #define SIGN_POS Const(0) -#define SIGN_NEG Const(1) +#define SIGN_NEG Const(0x80) -/* Keep the order TW_Valid, TW_Zero, TW_Denormal */ -#define TW_Valid Const(0) /* valid */ -#define TW_Zero Const(1) /* zero */ +#define SIGN_Positive Const(0) +#define SIGN_Negative Const(0x8000) + + +/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */ /* The following fold to 2 (Special) in the Tag Word */ -/* #define TW_Denormal Const(4) */ /* De-normal */ +#define TW_Denormal Const(4) /* De-normal */ #define TW_Infinity Const(5) /* + or - infinity */ #define TW_NaN Const(6) /* Not a Number */ +#define TW_Unsupported Const(7) /* Not supported by an 80486 */ + +#define TAG_Valid Const(0) /* valid */ +#define TAG_Zero Const(1) /* zero */ +#define TAG_Special Const(2) /* De-normal, + or - infinity, + or Not a Number */ +#define TAG_Empty Const(3) /* empty */ + +#define LOADED_DATA Const(10101) /* Special st() number to identify + loaded data (not on stack). */ + +/* A few flags (must be >= 0x10). */ +#define REV 0x10 +#define DEST_RM 0x20 +#define LOADED 0x40 -#define TW_Empty Const(7) /* empty */ +#define FPU_Exception Const(0x80000000) /* Added to tag returns. */ #ifndef __ASSEMBLY__ -#include /* for struct _fpstate */ -#include +#include "fpu_system.h" +#include /* for struct _fpstate */ +#include #include /* @@ -67,13 +82,13 @@ */ #ifdef RE_ENTRANT_CHECKING -extern char emulating; +extern u_char emulating; # define RE_ENTRANT_CHECK_OFF emulating = 0 # define RE_ENTRANT_CHECK_ON emulating = 1 #else # define RE_ENTRANT_CHECK_OFF # define RE_ENTRANT_CHECK_ON -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ #define FWAIT_OPCODE 0x9b #define OP_SIZE_PREFIX 0x66 @@ -97,18 +112,24 @@ struct address { unsigned int offset; - unsigned short selector; - unsigned short opcode:11, - empty:5; + unsigned int selector:16; + unsigned int opcode:11; + unsigned int empty:5; +}; +struct fpu__reg { + unsigned sigl; + unsigned sigh; + short exp; }; + typedef void (*FUNC)(void); -typedef struct fpu_reg FPU_REG; -typedef void (*FUNC_ST0)(FPU_REG *st0_ptr); -typedef struct { unsigned char address_size, operand_size, segment; } +typedef struct fpu__reg FPU_REG; +typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag); +typedef struct { u_char address_size, operand_size, segment; } overrides; /* This structure is 32 bits: */ typedef struct { overrides override; - unsigned char default_mode; } fpu_addr_modes; + u_char default_mode; } fpu_addr_modes; /* PROTECTED has a restricted meaning in the emulator; it is used to signal that the emulator needs to do special things to ensure that protection is respected in a segmented model. */ @@ -117,27 +138,48 @@ #define VM86 SIXTEEN #define PM16 (SIXTEEN | PROTECTED) #define SEG32 PROTECTED -extern unsigned char const data_sizes_16[32]; +extern u_char const data_sizes_16[32]; + +#define register_base ((u_char *) registers ) +#define fpu_register(x) ( * ((FPU_REG *)( register_base + 10 * (x & 7) )) ) +#define st(x) ( * ((FPU_REG *)( register_base + 10 * ((FPU_top+x) & 7) )) ) + +#define STACK_OVERFLOW (FPU_stackoverflow(&st_new_ptr)) +#define NOT_EMPTY(i) (!FPU_empty_i(i)) -#define st(x) ( regs[((top+x) &7 )] ) +#define NOT_EMPTY_ST0 (st0_tag ^ TAG_Empty) -#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty) -#define NOT_EMPTY(i) (st(i).tag != TW_Empty) -#define NOT_EMPTY_ST0 (st0_tag ^ TW_Empty) - -#define pop() { regs[(top++ & 7 )].tag = TW_Empty; } -#define poppop() { regs[((top + 1) & 7 )].tag \ - = regs[(top & 7 )].tag = TW_Empty; \ - top += 2; } +#define poppop() { FPU_pop(); FPU_pop(); } /* push() does not affect the tags */ -#define push() { top--; } +#define push() { FPU_top--; } +#define signbyte(a) (((u_char *)(a))[9]) +#define getsign(a) (signbyte(a) & 0x80) +#define setsign(a,b) { if (b) signbyte(a) |= 0x80; else signbyte(a) &= 0x7f; } +#define copysign(a,b) { if (getsign(a)) signbyte(b) |= 0x80; \ + else signbyte(b) &= 0x7f; } +#define changesign(a) { signbyte(a) ^= 0x80; } +#define setpositive(a) { signbyte(a) &= 0x7f; } +#define setnegative(a) { signbyte(a) |= 0x80; } +#define signpositive(a) ( (signbyte(a) & 0x80) == 0 ) +#define signnegative(a) (signbyte(a) & 0x80) + +static inline void reg_copy(FPU_REG const *x, FPU_REG *y) +{ + *(short *)&(y->exp) = *(const short *)&(x->exp); + *(long long *)&(y->sigl) = *(const long long *)&(x->sigl); +} + +#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias) +#define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \ + ((y) + EXTENDED_Ebias) & 0x7fff; } +#define exponent16(x) (*(short *)&((x)->exp)) +#define setexponent16(x,y) { (*(short *)&((x)->exp)) = (y); } +#define addexponent(x,y) { (*(short *)&((x)->exp)) += (y); } +#define stdexp(x) { (*(short *)&((x)->exp)) += EXTENDED_Ebias; } -#define reg_move(x, y) { \ - *(short *)&((y)->sign) = *(const short *)&((x)->sign); \ - *(long *)&((y)->exp) = *(const long *)&((x)->exp); \ - *(long long *)&((y)->sigl) = *(const long long *)&((x)->sigl); } +#define isdenormal(ptr) (exponent(ptr) == EXP_BIAS+EXP_UNDER) #define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] ) @@ -145,29 +187,31 @@ /*----- Prototypes for functions written in assembler -----*/ /* extern void reg_move(FPU_REG *a, FPU_REG *b); */ -asmlinkage void normalize(FPU_REG *x); -asmlinkage void normalize_nuo(FPU_REG *x); -asmlinkage int reg_div(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG *answ, unsigned int control_w); -asmlinkage int reg_u_sub(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG *answ, unsigned int control_w); -asmlinkage int reg_u_mul(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG *answ, unsigned int control_w); -asmlinkage int reg_u_div(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG *answ, unsigned int control_w); -asmlinkage int reg_u_add(FPU_REG const *arg1, FPU_REG const *arg2, - FPU_REG *answ, unsigned int control_w); -asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w); -asmlinkage unsigned shrx(void *l, unsigned x); -asmlinkage unsigned shrxs(void *v, unsigned x); -asmlinkage unsigned long div_small(unsigned long long *x, unsigned long y); -asmlinkage void round_reg(FPU_REG *arg, unsigned int extent, - unsigned int control_w); +asmlinkage int FPU_normalize(FPU_REG *x, int sign); +asmlinkage int FPU_normalize_nuo(FPU_REG *x); +asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w, u_char sign, + int expa, int expb); +asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w, u_char sign, + int expon); +asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w, u_char sign); +asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w, u_char sign, + int expa, int expb); +asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2, + unsigned int control_w, u_char sign); +asmlinkage unsigned FPU_shrx(void *l, unsigned x); +asmlinkage unsigned FPU_shrxs(void *v, unsigned x); +asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y); +asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy, + unsigned int control_w, u_char sign); #ifndef MAKING_PROTO #include "fpu_proto.h" #endif -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _FPU_EMU_H_ +#endif /* _FPU_EMU_H_ */ diff -urN linux-2.0.39/arch/i386/math-emu/fpu_entry.c linux-2.0.40/arch/i386/math-emu/fpu_entry.c --- linux-2.0.39/arch/i386/math-emu/fpu_entry.c 1996-05-06 06:31:17.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_entry.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | The entry functions for wm-FPU-emu | | | - | Copyright (C) 1992,1993,1994,1996 | + | Copyright (C) 1992,1993,1994,1996,1997,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | + | E-mail billm@suburbia.net | | | | See the files "README" and "COPYING" for further copyright and warranty | | information. | @@ -26,8 +26,6 @@ #include -#include - #include "fpu_system.h" #include "fpu_emu.h" #include "exception.h" @@ -36,6 +34,19 @@ #define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */ +#ifdef ONLY_486_FPU +#define fcmovnb __BAD__ /* Not present on 80486 */ +#define fcmovne __BAD__ /* Not present on 80486 */ +#define fcmovnbe __BAD__ /* Not present on 80486 */ +#define fcmovnu __BAD__ /* Not present on 80486 */ +#define fcmovb __BAD__ /* Not present on 80486 */ +#define fcmove __BAD__ /* Not present on 80486 */ +#define fcmovbe __BAD__ /* Not present on 80486 */ +#define fcmovu __BAD__ /* Not present on 80486 */ +#define fucomi __BAD__ /* Not present on 80486 */ +#define fcomi __BAD__ /* Not present on 80486 */ +#endif + #ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */ /* WARNING: These codes are not documented by Intel in their 80486 manual @@ -54,30 +65,30 @@ #define _df_d8_ fstp_i /* unofficial code (1f) */ static FUNC const st_instr_table[64] = { - fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_, - fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_, - fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_, - fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_, - fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, - fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, - fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, - fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, + fadd__, fld_i_, fcmovb, fcmovnb, fadd_i, ffree_, faddp_, _df_c0_, + fmul__, fxch_i, fcmove, fcmovne, fmul_i, _dd_c8_, fmulp_, _df_c8_, + fcom_st, fp_nop, fcmovbe, fcmovnbe, _dc_d0_, fst_i_, _de_d0_, _df_d0_, + fcompst, _d9_d8_, fcmovu, fcmovnu, _dc_d8_, fstp_i, fcompp, _df_d8_, + fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, + fsubr_, fconst, fucompp, fucomi, fsub_i, fucomp, fsubp_, __BAD__, + fdiv__, FPU_triga, __BAD__, fcomi, fdivri, __BAD__, fdivrp, __BAD__, + fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, }; #else /* Support only documented FPU op-codes */ static FUNC const st_instr_table[64] = { - fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__, - fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__, - fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__, - fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__, - fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, - fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, - fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, - fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, + fadd__, fld_i_, fcmovb, fcmovnb, fadd_i, ffree_, faddp_, __BAD__, + fmul__, fxch_i, fcmove, fcmovne, fmul_i, __BAD__, fmulp_, __BAD__, + fcom_st, fp_nop, fcmovbe, fcmovnbe, __BAD__, fst_i_, __BAD__, __BAD__, + fcompst, __BAD__, fcmovu, fcmovnu, __BAD__, fstp_i, fcompp, __BAD__, + fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, + fsubr_, fconst, fucompp, fucomi, fsub_i, fucomp, fsubp_, __BAD__, + fdiv__, FPU_triga, __BAD__, fcomi, fdivri, __BAD__, fdivrp, __BAD__, + fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, }; -#endif NO_UNDOC_CODE +#endif /* NO_UNDOC_CODE */ #define _NONE_ 0 /* Take no special action */ @@ -95,54 +106,54 @@ /* Un-documented FPU op-codes supported by default. (see above) */ -static unsigned char const type_table[64] = { - _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_, - _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_, - _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, - _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, +static u_char const type_table[64] = { + _REGI_, _NONE_, _REGi_, _REGi_, _REGIi, _REGi_, _REGIp, _REGi_, + _REGI_, _REGIn, _REGi_, _REGi_, _REGIi, _REGI_, _REGIp, _REGI_, + _REGIc, _NONE_, _REGi_, _REGi_, _REGIc, _REG0_, _REGIc, _REG0_, + _REGIc, _REG0_, _REGi_, _REGi_, _REGIc, _REG0_, _REGIc, _REG0_, _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, - _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, - _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, + _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _null_, + _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _null_, _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ }; #else /* Support only documented FPU op-codes */ -static unsigned char const type_table[64] = { - _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_, - _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_, - _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_, - _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_, +static u_char const type_table[64] = { + _REGI_, _NONE_, _REGi_, _REGi_, _REGIi, _REGi_, _REGIp, _null_, + _REGI_, _REGIn, _REGi_, _REGi_, _REGIi, _null_, _REGIp, _null_, + _REGIc, _NONE_, _REGi_, _REGi_, _null_, _REG0_, _null_, _null_, + _REGIc, _null_, _REGi_, _REGi_, _null_, _REG0_, _REGIc, _null_, _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, - _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, - _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, + _REGI_, _NONE_, _REGIc, _REGIc, _REGIi, _REGIc, _REGIp, _null_, + _REGI_, _NONE_, _null_, _REGIc, _REGIi, _null_, _REGIp, _null_, _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ }; -#endif NO_UNDOC_CODE +#endif /* NO_UNDOC_CODE */ #ifdef RE_ENTRANT_CHECKING -char emulating=0; -#endif RE_ENTRANT_CHECKING +u_char emulating=0; +#endif /* RE_ENTRANT_CHECKING */ -static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip, +static int valid_prefix(u_char *Byte, u_char **fpu_eip, overrides *override); asmlinkage void math_emulate(long arg) { - unsigned char FPU_modrm, byte1; + u_char FPU_modrm, byte1; unsigned short code; fpu_addr_modes addr_modes; int unmasked; FPU_REG loaded_data; + FPU_REG *st0_ptr; + u_char loaded_tag, st0_tag; void *data_address; struct address data_sel_off; struct address entry_sel_off; unsigned long code_base = 0; unsigned long code_limit = 0; /* Initialized to stop compiler warnings */ - char st0_tag; - FPU_REG *st0_ptr; struct desc_struct code_descriptor; #ifdef RE_ENTRANT_CHECKING @@ -151,21 +162,12 @@ printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); } RE_ENTRANT_CHECK_ON; -#endif RE_ENTRANT_CHECKING +#endif /* RE_ENTRANT_CHECKING */ - if (!current->used_math) + if (!FPU_current->used_math) { - int i; - for ( i = 0; i < 8; i++ ) - { - /* Make sure that the registers are compatible - with the assumptions of the emulator. */ - if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0) - && (regs[i].sigl == 0)) ) - regs[i].sigh |= 0x80000000; - } finit(); - current->used_math = 1; + FPU_current->used_math = 1; } SETUP_DATA_AREA(arg); @@ -179,11 +181,11 @@ FPU_EIP += code_base = FPU_CS << 4; code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */ } - else if ( FPU_CS == USER_CS && FPU_DS == USER_DS ) + else if ( FPU_CS == FPU_USER_CS && FPU_DS == FPU_USER_DS ) { addr_modes.default_mode = 0; } - else if ( FPU_CS == KERNEL_CS ) + else if ( FPU_CS == FPU_KERNEL_CS ) { printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP); panic("Math emulation needed in kernel"); @@ -196,7 +198,7 @@ /* Can only handle segmented addressing via the LDT for now, and it must be 16 bit */ printk("FPU emulator: Unsupported addressing mode\n"); - math_abort(FPU_info, SIGILL); + math_abort(SIGILL); } if ( SEG_D_SIZE(code_descriptor = LDT_DESCRIPTOR(FPU_CS)) ) @@ -218,10 +220,10 @@ } FPU_lookahead = 1; - if (current->flags & PF_PTRACED) + if ( FPU_TRACING ) FPU_lookahead = 0; - if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP, + if ( !valid_prefix(&byte1, (u_char **)&FPU_EIP, &addr_modes.override) ) { RE_ENTRANT_CHECK_OFF; @@ -230,7 +232,7 @@ byte1); RE_ENTRANT_CHECK_ON; EXCEPTION(EX_INTERNAL|0x126); - math_abort(FPU_info,SIGILL); + math_abort(SIGILL); } do_another_FPU_instruction: @@ -244,7 +246,7 @@ /* This checks for the minimum instruction bytes. We also need to check any extra (address mode) code access. */ if ( FPU_EIP > code_limit ) - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } if ( (byte1 & 0xf8) != 0xd8 ) @@ -258,13 +260,13 @@ } #ifdef PARANOID EXCEPTION(EX_INTERNAL|0x128); - math_abort(FPU_info,SIGILL); -#endif PARANOID + math_abort(SIGILL); +#endif /* PARANOID */ } RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - FPU_modrm = get_fs_byte((unsigned char *) FPU_EIP); + FPU_get_user(FPU_modrm, (u_char *) FPU_EIP); RE_ENTRANT_CHECK_ON; FPU_EIP++; @@ -287,12 +289,11 @@ * interrupts here. */ do_the_FPU_interrupt: + FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */ RE_ENTRANT_CHECK_OFF; - current->tss.trap_no = 16; - current->tss.error_code = 0; - send_sig(SIGFPE, current, 1); + FPU_SEND_SIGNAL(SIGFPE); return; } } @@ -309,16 +310,16 @@ if ( (addr_modes.default_mode & SIXTEEN) ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) ) - data_address = get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off, - addr_modes); + data_address = FPU_get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off, + addr_modes); else - data_address = get_address(FPU_modrm, &FPU_EIP, &data_sel_off, - addr_modes); + data_address = FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off, + addr_modes); if ( addr_modes.default_mode ) { if ( FPU_EIP-1 > code_limit ) - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } if ( !(byte1 & 1) ) @@ -326,7 +327,7 @@ unsigned short status1 = partial_status; st0_ptr = &st(0); - st0_tag = st0_ptr->tag; + st0_tag = FPU_gettag0(); /* Stack underflow has priority */ if ( NOT_EMPTY_ST0 ) @@ -335,36 +336,41 @@ { /* This table works for 16 and 32 bit protected mode */ if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] ) - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } unmasked = 0; /* Do this here to stop compiler warnings. */ switch ( (byte1 >> 1) & 3 ) { case 0: - unmasked = reg_load_single((float *)data_address, + unmasked = FPU_load_single((float *)data_address, &loaded_data); + loaded_tag = unmasked & 0xff; + unmasked &= ~0xff; break; case 1: - reg_load_int32((long *)data_address, &loaded_data); + loaded_tag = FPU_load_int32((long *)data_address, &loaded_data); break; case 2: - unmasked = reg_load_double((double *)data_address, + unmasked = FPU_load_double((double *)data_address, &loaded_data); + loaded_tag = unmasked & 0xff; + unmasked &= ~0xff; break; case 3: - reg_load_int16((short *)data_address, &loaded_data); + default: /* Used here to suppress gcc warnings. */ + loaded_tag = FPU_load_int16((short *)data_address, &loaded_data); break; } - + /* No more access to user memory, it is safe to use static data now */ /* NaN operands have the next priority. */ /* We have to delay looking at st(0) until after loading the data, because that data might contain an SNaN */ - if ( (st0_tag == TW_NaN) || - (loaded_data.tag == TW_NaN) ) + if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) || + ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) ) { /* Restore the status word; we might have loaded a denormal. */ @@ -375,22 +381,22 @@ EXCEPTION(EX_Invalid); setcc(SW_C3 | SW_C2 | SW_C0); if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) ) - pop(); /* fcomp, masked, so we pop. */ + FPU_pop(); /* fcomp, masked, so we pop. */ } else { + if ( loaded_tag == TAG_Special ) + loaded_tag = FPU_Special(&loaded_data); #ifdef PECULIAR_486 /* This is not really needed, but gives behaviour identical to an 80486 */ if ( (FPU_modrm & 0x28) == 0x20 ) /* fdiv or fsub */ - real_2op_NaN(&loaded_data, st0_ptr, - st0_ptr); + real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data); else -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ /* fadd, fdivr, fmul, or fsubr */ - real_2op_NaN(st0_ptr, &loaded_data, - st0_ptr); + real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr); } goto reg_mem_instr_done; } @@ -401,11 +407,13 @@ if ( (FPU_modrm & 0x38) == 0x38 ) { /* fdivr */ - if ( (st0_tag == TW_Zero) && - (loaded_data.tag == TW_Valid) ) + if ( (st0_tag == TAG_Zero) && + ((loaded_tag == TAG_Valid) + || (loaded_tag == TAG_Special + && isdenormal(&loaded_data))) ) { - if ( divide_by_zero(loaded_data.sign, - st0_ptr) ) + if ( FPU_divide_by_zero(0, getsign(&loaded_data)) + < 0 ) { /* We use the fact here that the unmasked exception in the loaded data was for a @@ -414,6 +422,8 @@ partial_status &= ~SW_Denorm_Op; partial_status |= status1 & SW_Denorm_Op; } + else + setsign(st0_ptr, getsign(&loaded_data)); } } goto reg_mem_instr_done; @@ -423,43 +433,38 @@ { case 0: /* fadd */ clear_C1(); - reg_add(st0_ptr, &loaded_data, st0_ptr, - control_word); + FPU_add(&loaded_data, loaded_tag, 0, control_word); break; case 1: /* fmul */ clear_C1(); - reg_mul(st0_ptr, &loaded_data, st0_ptr, - control_word); + FPU_mul(&loaded_data, loaded_tag, 0, control_word); break; case 2: /* fcom */ - compare_st_data(&loaded_data); + FPU_compare_st_data(&loaded_data, loaded_tag); break; case 3: /* fcomp */ - if ( !compare_st_data(&loaded_data) && !unmasked ) - pop(); + if ( !FPU_compare_st_data(&loaded_data, loaded_tag) + && !unmasked ) + FPU_pop(); break; case 4: /* fsub */ clear_C1(); - reg_sub(st0_ptr, &loaded_data, st0_ptr, - control_word); + FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word); break; case 5: /* fsubr */ clear_C1(); - reg_sub(&loaded_data, st0_ptr, st0_ptr, - control_word); + FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word); break; case 6: /* fdiv */ clear_C1(); - reg_div(st0_ptr, &loaded_data, st0_ptr, - control_word); + FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word); break; case 7: /* fdivr */ clear_C1(); - if ( st0_tag == TW_Zero ) + if ( st0_tag == TAG_Zero ) partial_status = status1; /* Undo any denorm tag, - zero-divide has priority. */ - reg_div(&loaded_data, st0_ptr, st0_ptr, - control_word); + zero-divide has priority. */ + FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word); break; } } @@ -471,10 +476,10 @@ EXCEPTION(EX_StackUnder); setcc(SW_C3 | SW_C2 | SW_C0); if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) ) - pop(); /* fcomp */ + FPU_pop(); /* fcomp */ } else - stack_underflow(); + FPU_stack_underflow(); } reg_mem_instr_done: operand_address = data_sel_off; @@ -482,8 +487,8 @@ else { if ( !(no_ip_update = - load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, - addr_modes, data_address)) ) + FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, + addr_modes, data_address)) ) { operand_address = data_sel_off; } @@ -493,17 +498,17 @@ else { /* None of these instructions access user memory */ - unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7); + u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7); #ifdef PECULIAR_486 /* This is supposed to be undefined, but a real 80486 seems to do this: */ operand_address.offset = 0; operand_address.selector = FPU_DS; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ st0_ptr = &st(0); - st0_tag = st0_ptr->tag; + st0_tag = FPU_gettag0(); switch ( type_table[(int) instr_index] ) { case _NONE_: /* also _REGIc: _REGIn */ @@ -511,28 +516,28 @@ case _REG0_: if ( !NOT_EMPTY_ST0 ) { - stack_underflow(); + FPU_stack_underflow(); goto FPU_instruction_done; } break; case _REGIi: if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) { - stack_underflow_i(FPU_rm); + FPU_stack_underflow_i(FPU_rm); goto FPU_instruction_done; } break; case _REGIp: if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) { - stack_underflow_pop(FPU_rm); + FPU_stack_underflow_pop(FPU_rm); goto FPU_instruction_done; } break; case _REGI_: if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) { - stack_underflow(); + FPU_stack_underflow(); goto FPU_instruction_done; } break; @@ -558,14 +563,14 @@ #ifdef DEBUG RE_ENTRANT_CHECK_OFF; - emu_printall(); + FPU_printall(); RE_ENTRANT_CHECK_ON; -#endif DEBUG +#endif /* DEBUG */ - if (FPU_lookahead && !need_resched) + if (FPU_lookahead && !FPU_need_resched) { FPU_ORIG_EIP = FPU_EIP - code_base; - if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP, + if ( valid_prefix(&byte1, (u_char **)&FPU_EIP, &addr_modes.override) ) goto do_another_FPU_instruction; } @@ -581,17 +586,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, unsigned char **fpu_eip, +static int valid_prefix(u_char *Byte, u_char **fpu_eip, overrides *override) { - unsigned char byte; - unsigned char *ip = *fpu_eip; + u_char byte; + u_char *ip = *fpu_eip; *override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */ RE_ENTRANT_CHECK_OFF; - FPU_code_verify_area(1); - byte = get_fs_byte(ip); + FPU_verify_area(VERIFY_READ,ip,1); + FPU_get_user(byte, ip); RE_ENTRANT_CHECK_ON; while ( 1 ) @@ -636,8 +641,8 @@ do_next_byte: ip++; RE_ENTRANT_CHECK_OFF; - FPU_code_verify_area(1); - byte = get_fs_byte(ip); + FPU_verify_area(VERIFY_READ,ip,1); + FPU_get_user(byte, ip); RE_ENTRANT_CHECK_ON; break; case FWAIT_OPCODE: @@ -662,34 +667,100 @@ } -void math_abort(struct info * info, unsigned int signal) +void math_abort(unsigned int signal) { - FPU_EIP = FPU_ORIG_EIP; - current->tss.trap_no = 16; - current->tss.error_code = 0; - send_sig(signal,current,1); - RE_ENTRANT_CHECK_OFF; - __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); + FPU_EIP = FPU_ORIG_EIP; + FPU_SEND_SIGNAL(signal); + RE_ENTRANT_CHECK_OFF; + FPU_EXIT; #ifdef PARANOID - printk("ERROR: wm-FPU-emu math_abort failed!\n"); -#endif PARANOID + printk("ERROR: wm-FPU-emu math_abort failed!\n"); +#endif /* PARANOID */ } -void restore_i387_soft(struct _fpstate *buf) +#define S387 ((struct i387_soft_struct *)s387) +#define FPU_s_top S387->ftop +#define FPU_s_regs S387->st_space +#define sstatus_word() \ + ((S387->swd & ~SW_Top & 0xffff) | ((FPU_s_top << SW_Top_Shift) & SW_Top)) + +int restore_i387_soft(void *s387, struct _fpstate *buf) { - fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0}; + u_char *d = (u_char *)buf; + int offset, other, i, tags, regnr, tag, newtop; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10); + if (FPU_copy_from_user(&S387->cwd, d, 7*4)) + return -1; + RE_ENTRANT_CHECK_ON; - frstor(addr_modes, (char *)buf); + d += 7*4; + + FPU_s_top = (S387->swd >> SW_Top_Shift) & 7; + offset = (FPU_s_top & 7) * 10; + other = 80 - offset; + + RE_ENTRANT_CHECK_OFF; + /* Copy all registers in stack order. */ + if (FPU_copy_from_user(((u_char *)&FPU_s_regs)+offset, d, other)) + return -1; + if ( offset ) + if (FPU_copy_from_user((u_char *)&FPU_s_regs, d+other, offset)) + return -1; + RE_ENTRANT_CHECK_ON; + + /* The tags may need to be corrected now. */ + tags = S387->twd; + newtop = FPU_s_top; + for ( i = 0; i < 8; i++ ) + { + regnr = (i+newtop) & 7; + if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty ) + { + /* The loaded data over-rides all other cases. */ + tag = FPU_tagof((FPU_REG *)((u_char *)FPU_s_regs + 10*regnr)); + tags &= ~(3 << (regnr*2)); + tags |= (tag & 3) << (regnr*2); + } + } + S387->twd = tags; + + return 0; } -struct _fpstate * save_i387_soft(struct _fpstate * buf) +int save_i387_soft(void *s387, struct _fpstate * buf) { - fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0}; + u_char *d = (u_char *)buf; + int offset = (FPU_s_top & 7) * 10, other = 80 - offset; - fsave(addr_modes, (char *)buf); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10); +#ifdef PECULIAR_486 + S387->cwd &= ~0xe080; + /* An 80486 sets nearly all of the reserved bits to 1. */ + S387->cwd |= 0xffff0040; + S387->swd = sstatus_word() | 0xffff0000; + S387->twd |= 0xffff0000; + S387->fcs &= ~0xf8000000; + S387->fos |= 0xffff0000; +#endif /* PECULIAR_486 */ + FPU_copy_to_user(d, &S387->cwd, 7*4); + RE_ENTRANT_CHECK_ON; + + d += 7*4; + + RE_ENTRANT_CHECK_OFF; + /* Copy all registers in stack order. */ + if (FPU_copy_to_user(d, ((u_char *)&FPU_s_regs)+offset, other)) + return -1; + if ( offset ) + if (FPU_copy_to_user(d+other, (u_char *)&FPU_s_regs, offset)) + return -1 + RE_ENTRANT_CHECK_ON; - return buf; + return 1; } diff -urN linux-2.0.39/arch/i386/math-emu/fpu_etc.c linux-2.0.40/arch/i386/math-emu/fpu_etc.c --- linux-2.0.39/arch/i386/math-emu/fpu_etc.c 1994-08-18 22:54:01.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_etc.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Implement a few FPU instructions. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -17,102 +17,116 @@ #include "reg_constant.h" -static void fchs(FPU_REG *st0_ptr) +static void fchs(FPU_REG *st0_ptr, u_char st0tag) { - if ( st0_ptr->tag ^ TW_Empty ) + if ( st0tag ^ TAG_Empty ) { - st0_ptr->sign ^= SIGN_POS^SIGN_NEG; + signbyte(st0_ptr) ^= SIGN_NEG; clear_C1(); } else - stack_underflow(); + FPU_stack_underflow(); } -static void fabs(FPU_REG *st0_ptr) + +static void fabs(FPU_REG *st0_ptr, u_char st0tag) { - if ( st0_ptr->tag ^ TW_Empty ) + if ( st0tag ^ TAG_Empty ) { - st0_ptr->sign = SIGN_POS; + setpositive(st0_ptr); clear_C1(); } else - stack_underflow(); + FPU_stack_underflow(); } -static void ftst_(FPU_REG *st0_ptr) +static void ftst_(FPU_REG *st0_ptr, u_char st0tag) { - switch (st0_ptr->tag) + switch (st0tag) { - case TW_Zero: + case TAG_Zero: setcc(SW_C3); break; - case TW_Valid: - if (st0_ptr->sign == SIGN_POS) + case TAG_Valid: + if (getsign(st0_ptr) == SIGN_POS) setcc(0); else setcc(SW_C0); - -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + break; + case TAG_Special: + switch ( FPU_Special(st0_ptr) ) { + case TW_Denormal: + if (getsign(st0_ptr) == SIGN_POS) + setcc(0); + else + setcc(SW_C0); + if ( denormal_operand() < 0 ) + { #ifdef PECULIAR_486 - /* This is weird! */ - if (st0_ptr->sign == SIGN_POS) - setcc(SW_C3); -#endif PECULIAR_486 - return; + /* This is weird! */ + if (getsign(st0_ptr) == SIGN_POS) + setcc(SW_C3); +#endif /* PECULIAR_486 */ + return; + } + break; + case TW_NaN: + setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ + EXCEPTION(EX_Invalid); + break; + case TW_Infinity: + if (getsign(st0_ptr) == SIGN_POS) + setcc(0); + else + setcc(SW_C0); + break; + default: + setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ + EXCEPTION(EX_INTERNAL|0x14); + break; } -#endif DENORM_OPERAND - - break; - case TW_NaN: - setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ - EXCEPTION(EX_Invalid); - break; - case TW_Infinity: - if (st0_ptr->sign == SIGN_POS) - setcc(0); - else - setcc(SW_C0); break; - case TW_Empty: + case TAG_Empty: setcc(SW_C0|SW_C2|SW_C3); EXCEPTION(EX_StackUnder); break; - default: - setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ - EXCEPTION(EX_INTERNAL|0x14); - break; } } -static void fxam(FPU_REG *st0_ptr) + +static void fxam(FPU_REG *st0_ptr, u_char st0tag) { - int c=0; - switch (st0_ptr->tag) + int c = 0; + switch (st0tag) { - case TW_Empty: + case TAG_Empty: c = SW_C3|SW_C0; break; - case TW_Zero: + case TAG_Zero: c = SW_C3; break; - case TW_Valid: - /* This will need to be changed if TW_Denormal is ever used. */ - if ( st0_ptr->exp <= EXP_UNDER ) - c = SW_C2|SW_C3; /* Denormal */ - else - c = SW_C2; - break; - case TW_NaN: - c = SW_C0; - break; - case TW_Infinity: - c = SW_C2|SW_C0; + case TAG_Valid: + c = SW_C2; break; + case TAG_Special: + switch ( FPU_Special(st0_ptr) ) + { + case TW_Denormal: + c = SW_C2|SW_C3; /* Denormal */ + break; + case TW_NaN: + /* We also use NaN for unsupported types. */ + if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) ) + c = SW_C0; + break; + case TW_Infinity: + c = SW_C2|SW_C0; + break; + } } - if (st0_ptr->sign == SIGN_NEG) + if ( getsign(st0_ptr) == SIGN_NEG ) c |= SW_C1; setcc(c); } @@ -123,7 +137,7 @@ ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal }; -void fp_etc() +void FPU_etc() { - (fp_etc_table[FPU_rm])(&st(0)); + (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0()); } diff -urN linux-2.0.39/arch/i386/math-emu/fpu_proto.h linux-2.0.40/arch/i386/math-emu/fpu_proto.h --- linux-2.0.39/arch/i386/math-emu/fpu_proto.h 1994-07-31 22:19:13.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_proto.h 2004-02-07 23:13:01.000000000 -0800 @@ -1,22 +1,26 @@ +#ifndef _FPU_PROTO_H +#define _FPU_PROTO_H + /* errors.c */ extern void Un_impl(void); extern void FPU_illegal(void); -extern void emu_printall(void); -extern void stack_overflow(void); -extern void stack_underflow(void); -extern void stack_underflow_i(int i); -extern void stack_underflow_pop(int i); +extern void FPU_printall(void); +asmlinkage void FPU_exception(int n); +extern int real_1op_NaN(FPU_REG *a); +extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr, + FPU_REG const *defaultNaN); +extern int arith_invalid(int deststnr); +extern int FPU_divide_by_zero(int deststnr, u_char sign); extern int set_precision_flag(int flags); -asmlinkage void exception(int n); -asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest); -asmlinkage int arith_invalid(FPU_REG *dest); -asmlinkage int divide_by_zero(int sign, FPU_REG *dest); -asmlinkage void set_precision_flag_up(void); -asmlinkage void set_precision_flag_down(void); -asmlinkage int denormal_operand(void); -asmlinkage int arith_overflow(FPU_REG *dest); -asmlinkage int arith_underflow(FPU_REG *dest); - +extern void set_precision_flag_up(void); +extern void set_precision_flag_down(void); +extern int denormal_operand(void); +extern int arith_overflow(FPU_REG *dest, int sign); +extern int arith_underflow(FPU_REG *dest); +extern void FPU_stack_overflow(void); +extern void FPU_stack_underflow(void); +extern void FPU_stack_underflow_i(int i); +extern void FPU_stack_underflow_pop(int i); /* fpu_arith.c */ extern void fadd__(void); extern void fmul__(void); @@ -36,7 +40,6 @@ extern void fsubp_(void); extern void fdivrp(void); extern void fdivp_(void); - /* fpu_aux.c */ extern void fclex(void); extern void finit(void); @@ -50,56 +53,66 @@ extern void fst_i_(void); extern void fstp_i(void); -/* fpu_entry.c */ -asmlinkage void math_emulate(long arg); -extern void math_abort(struct info *info, unsigned int signal); +extern void fcmovnb(void); +extern void fcmovne(void); +extern void fcmovnbe(void); +extern void fcmovnu(void); +extern void fcmovb(void); +extern void fcmove(void); +extern void fcmovbe(void); +extern void fcmovu(void); +/* fpu_entry.c */ +extern void math_emulate(long arg); +extern void math_abort(unsigned int signal); /* fpu_etc.c */ -extern void fp_etc(void); - +extern void FPU_etc(void); +/* fpu_tags.c */ +extern int FPU_gettag0(void); +extern int FPU_gettagi(int stnr); +extern int FPU_gettag(int regnr); +extern void FPU_settag0(int tag); +extern void FPU_settagi(int stnr, int tag); +extern void FPU_settag(int regnr, int tag); +extern int FPU_Special(FPU_REG const *ptr); +extern int isNaN(FPU_REG const *ptr); +extern void FPU_pop(void); +extern int FPU_empty_i(int stnr); +extern int FPU_stackoverflow(FPU_REG **st_new_ptr); +extern void FPU_sync_tags(void); +extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); +extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); +extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); /* fpu_trig.c */ -extern void convert_l2reg(long const *arg, FPU_REG *dest); -extern void trig_a(void); -extern void trig_b(void); - +extern void FPU_triga(void); +extern void FPU_trigb(void); /* get_address.c */ -extern void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, - struct address *addr, - fpu_addr_modes); -extern void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, - struct address *addr, - fpu_addr_modes); - +extern void *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, + struct address *addr, fpu_addr_modes addr_modes); +extern void *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, + struct address *addr, fpu_addr_modes addr_modes); /* load_store.c */ -extern int load_store_instr(unsigned char type, fpu_addr_modes addr_modes, - void *address); - +extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes, + void *data_address); /* poly_2xm1.c */ -extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result); - +extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result); /* poly_atan.c */ -extern void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result); - +extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr, + u_char st1_tag); /* poly_l2.c */ -extern void poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result); -extern int poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result); - +extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign); +extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1, + FPU_REG *d); /* poly_sin.c */ -extern void poly_sine(FPU_REG const *arg, FPU_REG *result); -extern void poly_cos(FPU_REG const *arg, FPU_REG *result); - +extern void poly_sine(FPU_REG *st0_ptr); +extern void poly_cos(FPU_REG *st0_ptr); /* poly_tan.c */ -extern void poly_tan(FPU_REG const *arg, FPU_REG *result); - +extern void poly_tan(FPU_REG *st0_ptr); /* reg_add_sub.c */ -extern int reg_add(FPU_REG const *a, FPU_REG const *b, - FPU_REG *dest, int control_w); -extern int reg_sub(FPU_REG const *a, FPU_REG const *b, - FPU_REG *dest, int control_w); - +extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w); +extern int FPU_sub(int flags, int rm, int control_w); /* reg_compare.c */ -extern int compare(FPU_REG const *b); -extern int compare_st_data(FPU_REG const *b); +extern int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag); extern void fcom_st(void); extern void fcompst(void); extern void fcompp(void); @@ -107,31 +120,37 @@ extern void fucomp(void); extern void fucompp(void); +extern void fucomi(void); +extern void fcomi(void); /* reg_constant.c */ extern void fconst(void); - /* reg_ld_str.c */ -extern int reg_load_extended(long double *addr, FPU_REG *loaded_data); -extern int reg_load_double(double *dfloat, FPU_REG *loaded_data); -extern int reg_load_single(float *single, FPU_REG *loaded_data); -extern void reg_load_int64(long long *_s, FPU_REG *loaded_data); -extern void reg_load_int32(long *_s, FPU_REG *loaded_data); -extern void reg_load_int16(short *_s, FPU_REG *loaded_data); -extern void reg_load_bcd(char *s, FPU_REG *loaded_data); -extern int reg_store_extended(long double *d, FPU_REG *st0_ptr); -extern int reg_store_double(double *dfloat, FPU_REG *st0_ptr); -extern int reg_store_single(float *single, FPU_REG *st0_ptr); -extern int reg_store_int64(long long *d, FPU_REG *st0_ptr); -extern int reg_store_int32(long *d, FPU_REG *st0_ptr); -extern int reg_store_int16(short *d, FPU_REG *st0_ptr); -extern int reg_store_bcd(char *d, FPU_REG *st0_ptr); -extern int round_to_int(FPU_REG *r); -extern char *fldenv(fpu_addr_modes addr_modes, char *address); -extern void frstor(fpu_addr_modes addr_modes, char *address); -extern unsigned short tag_word(void); -extern char *fstenv(fpu_addr_modes addr_modes, char *address); -extern void fsave(fpu_addr_modes addr_modes, char *address); - +extern int FPU_load_extended(long double *s, int stnr); +extern int FPU_load_double(double *dfloat, FPU_REG *loaded_data); +extern int FPU_load_single(float *single, FPU_REG *loaded_data); +extern int FPU_load_int64(long long *_s); +extern int FPU_load_int32(long *_s, FPU_REG *loaded_data); +extern int FPU_load_int16(short *_s, FPU_REG *loaded_data); +extern int FPU_load_bcd(u_char *s); +extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, + long double *d); +extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat); +extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single); +extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d); +extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d); +extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d); +extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d); +extern int FPU_round_to_int(FPU_REG *r, u_char tag); +extern u_char *fldenv(fpu_addr_modes addr_modes, u_char *s); +extern void frstor(fpu_addr_modes addr_modes, u_char *data_address); +extern u_char *fstenv(fpu_addr_modes addr_modes, u_char *d); +extern void fsave(fpu_addr_modes addr_modes, u_char *data_address); +extern int FPU_tagof(FPU_REG *ptr); /* reg_mul.c */ -extern int reg_mul(FPU_REG const *a, FPU_REG const *b, - FPU_REG *dest, unsigned int control_w); +extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w); + +extern int FPU_div(int flags, int regrm, int control_w); +/* reg_convert.c */ +extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x); +#endif /* _FPU_PROTO_H */ + diff -urN linux-2.0.39/arch/i386/math-emu/fpu_system.h linux-2.0.40/arch/i386/math-emu/fpu_system.h --- linux-2.0.39/arch/i386/math-emu/fpu_system.h 1997-10-15 15:27:56.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_system.h 2004-02-07 23:13:01.000000000 -0800 @@ -1,9 +1,9 @@ /*---------------------------------------------------------------------------+ | fpu_system.h | | | - | Copyright (C) 1992,1994 | + | Copyright (C) 1992,1994,1997,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | +---------------------------------------------------------------------------*/ @@ -12,28 +12,38 @@ /* system dependent definitions */ +#include + +#include /* for copy to and from user */ + #include #include #include +#ifdef FPU_current +extern struct task_struct * FPU_current; +#else +#define FPU_current current +#endif + /* This sets the pointer FPU_info to point to the argument part of the stack frame of math_emulate() */ -#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg +#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg -#define LDT_DESCRIPTOR(s) (current->ldt[(s) >> 3]) -#define SEG_D_SIZE(x) ((x).b & (3 << 21)) -#define SEG_G_BIT(x) ((x).b & (1 << 23)) -#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) -#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23))) -#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \ +#define LDT_DESCRIPTOR(s) (FPU_current->ldt[(s) >> 3]) +#define SEG_D_SIZE(x) ((x).b & (3 << 21)) +#define SEG_G_BIT(x) ((x).b & (1 << 23)) +#define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) +#define SEG_286_MODE(x) ((x).b & ( 0xff000000 | 0xf0000 | (1 << 23))) +#define SEG_BASE_ADDR(s) (((s).b & 0xff000000) \ | (((s).b & 0xff) << 16) | ((s).a >> 16)) -#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff)) -#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11)) -#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9)) -#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \ +#define SEG_LIMIT(s) (((s).b & 0xff0000) | ((s).a & 0xffff)) +#define SEG_EXECUTE_ONLY(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 11)) +#define SEG_WRITE_PERM(s) (((s).b & ((1 << 11) | (1 << 9))) == (1 << 9)) +#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \ == (1 << 10)) -#define I387 (current->tss.i387) +#define I387 (FPU_current->tss.i387) #define FPU_info (I387.soft.info) #define FPU_CS (*(unsigned short *) &(FPU_info->___cs)) @@ -44,27 +54,39 @@ #define FPU_EIP (FPU_info->___eip) #define FPU_ORIG_EIP (FPU_info->___orig_eip) +#define FPU_USER_CS USER_CS +#define FPU_USER_DS USER_DS +#define FPU_KERNEL_CS KERNEL_CS + +#define FPU_TRACING (FPU_current->flags & PF_PTRACED) + +#define FPU_SEND_SIGNAL(signal) FPU_current->tss.trap_no = 16; \ + FPU_current->tss.error_code = 0; \ + send_sig(signal,FPU_current,1); + #define FPU_lookahead (I387.soft.lookahead) +#define FPU_need_resched need_resched + /* nz if ip_offset and cs_selector are not to be set for the current instruction. */ -#define no_ip_update (((char *)&(I387.soft.twd))[0]) -#define FPU_rm (((unsigned char *)&(I387.soft.twd))[1]) +#define no_ip_update (*(u_char *)&(I387.soft.no_update)) +#define FPU_rm (*(u_char *)&(I387.soft.rm)) /* Number of bytes of data which can be legally accessed by the current instruction. This only needs to hold a number <= 108, so a byte will do. */ -#define access_limit (((unsigned char *)&(I387.soft.twd))[2]) +#define access_limit (*(u_char *)&(I387.soft.alimit)) -#define partial_status (I387.soft.swd) +#define partial_status (I387.soft.swd) #define control_word (I387.soft.cwd) -#define regs (I387.soft.regs) -#define top (I387.soft.top) +#define fpu_tag_word (I387.soft.twd) +#define registers (I387.soft.st_space) +#define FPU_top (I387.soft.ftop) -#define instruction_address (*(struct address *)&I387.soft.fip) -#define operand_address (*(struct address *)&I387.soft.foo) +#define instruction_address (*(struct address *)&I387.soft.fip) +#define operand_address (*(struct address *)&I387.soft.foo) -#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \ - math_abort(FPU_info,SIGSEGV) +#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) math_abort(SIGSEGV) #undef FPU_IGNORE_CODE_SEGV #ifdef FPU_IGNORE_CODE_SEGV @@ -80,4 +102,22 @@ #define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z) #endif +#ifndef FPU_get_user +#define FPU_get_user(x,y) (x) = get_user(y) +#define FPU_put_user(x,y) put_user((x),(y)) +#define FPU_copy_from_user(x,y,z) copy_from_user((x),(y),(z)) +#define FPU_copy_to_user(x,y,z) copy_to_user((x),(y),(z)) +#else +int get_user_n(void *dst, void *ptr, int n); +#define FPU_get_user(x,y) { unsigned long int v; \ + get_user_n(&v, (y),sizeof(*(y))); (x) = v; } +int put_user_n(void *src, void *ptr, int n); +#define FPU_put_user(x,y) { unsigned long int v = (x); \ + put_user_n(&v,(y),sizeof(*(y))); } +#define FPU_copy_from_user(x,y,n) get_user_n((x),(y),n) +#define FPU_copy_to_user(x,y,n) put_user_n((x),(y),n) +#endif + +#define FPU_EXIT __asm__("movl %0,%%esp ; ret": :"g" (((long) FPU_info)-4)) + #endif diff -urN linux-2.0.39/arch/i386/math-emu/fpu_tags.c linux-2.0.40/arch/i386/math-emu/fpu_tags.c --- linux-2.0.39/arch/i386/math-emu/fpu_tags.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/fpu_tags.c 2004-02-07 23:13:01.000000000 -0800 @@ -0,0 +1,127 @@ +/*---------------------------------------------------------------------------+ + | fpu_tags.c | + | | + | Set FPU register tags. | + | | + | Copyright (C) 1997,2001 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@melbpc.org.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_emu.h" +#include "fpu_system.h" +#include "exception.h" + + +void FPU_pop(void) +{ + fpu_tag_word |= 3 << ((FPU_top & 7)*2); + FPU_top++; +} + + +int FPU_gettag0(void) +{ + return (fpu_tag_word >> ((FPU_top & 7)*2)) & 3; +} + + +int FPU_gettagi(int stnr) +{ + return (fpu_tag_word >> (((FPU_top+stnr) & 7)*2)) & 3; +} + + +int FPU_gettag(int regnr) +{ + return (fpu_tag_word >> ((regnr & 7)*2)) & 3; +} + + +void FPU_settag0(int tag) +{ + int regnr = FPU_top; + regnr &= 7; + fpu_tag_word &= ~(3 << (regnr*2)); + fpu_tag_word |= (tag & 3) << (regnr*2); +} + + +void FPU_settagi(int stnr, int tag) +{ + int regnr = stnr+FPU_top; + regnr &= 7; + fpu_tag_word &= ~(3 << (regnr*2)); + fpu_tag_word |= (tag & 3) << (regnr*2); +} + + +void FPU_settag(int regnr, int tag) +{ + regnr &= 7; + fpu_tag_word &= ~(3 << (regnr*2)); + fpu_tag_word |= (tag & 3) << (regnr*2); +} + + +int FPU_Special(FPU_REG const *ptr) +{ + int exp = exponent(ptr); + + if ( exp == EXP_BIAS+EXP_UNDER ) + return TW_Denormal; + else if ( exp != EXP_BIAS+EXP_OVER ) + return TW_NaN; + else if ( (ptr->sigh == 0x80000000) && (ptr->sigl == 0) ) + return TW_Infinity; + return TW_NaN; +} + + +int isNaN(FPU_REG const *ptr) +{ + return ( (exponent(ptr) == EXP_BIAS+EXP_OVER) + && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) ); +} + + +int FPU_empty_i(int stnr) +{ + int regnr = (FPU_top+stnr) & 7; + + return ((fpu_tag_word >> (regnr*2)) & 3) == TAG_Empty; +} + + +int FPU_stackoverflow(FPU_REG **st_new_ptr) +{ + *st_new_ptr = &st(-1); + + return ((fpu_tag_word >> (((FPU_top - 1) & 7)*2)) & 3) != TAG_Empty; +} + + +void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr) +{ + reg_copy(r, &st(stnr)); + FPU_settagi(stnr, tag); +} + +void FPU_copy_to_reg1(FPU_REG const *r, u_char tag) +{ + reg_copy(r, &st(1)); + FPU_settagi(1, tag); +} + +void FPU_copy_to_reg0(FPU_REG const *r, u_char tag) +{ + int regnr = FPU_top; + regnr &= 7; + + reg_copy(r, &st(0)); + + fpu_tag_word &= ~(3 << (regnr*2)); + fpu_tag_word |= (tag & 3) << (regnr*2); +} diff -urN linux-2.0.39/arch/i386/math-emu/fpu_trig.c linux-2.0.40/arch/i386/math-emu/fpu_trig.c --- linux-2.0.39/arch/i386/math-emu/fpu_trig.c 1994-07-31 22:19:13.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/fpu_trig.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Implementation of the FPU "transcendental" functions. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1997,1999,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -17,7 +17,6 @@ #include "control_w.h" #include "reg_constant.h" - static void rem_kernel(unsigned long long st0, unsigned long long *y, unsigned long long st1, unsigned long long q, int n); @@ -25,9 +24,6 @@ #define BETTER_THAN_486 #define FCOS 4 -/* Not needed now with new code -#define FPTAN 1 - */ /* Used only by fptan, fsin, fcos, and fsincos. */ /* This routine produces very accurate results, similar to @@ -35,13 +31,15 @@ /* Limited measurements show no results worse than 64 bit precision except for the results for arguments close to 2^63, where the precision of the result sometimes degrades to about 63.9 bits */ -static int trig_arg(FPU_REG *X, int even) +static int trig_arg(FPU_REG *st0_ptr, int even) { FPU_REG tmp; + u_char tmptag; unsigned long long q; int old_cw = control_word, saved_status = partial_status; + int tag, st0_tag = TAG_Valid; - if ( X->exp >= EXP_BIAS + 63 ) + if ( exponent(st0_ptr) >= 63 ) { partial_status |= SW_C2; /* Reduction incomplete. */ return -1; @@ -50,62 +48,57 @@ control_word &= ~CW_RC; control_word |= RC_CHOP; - reg_div(X, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f); - round_to_int(&tmp); /* Fortunately, this can't overflow - to 2^64 */ + setpositive(st0_ptr); + tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f, + SIGN_POS); + + FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow + to 2^64 */ q = significand(&tmp); if ( q ) { - rem_kernel(significand(X), + rem_kernel(significand(st0_ptr), &significand(&tmp), significand(&CONST_PI2), - q, X->exp - CONST_PI2.exp); - tmp.exp = CONST_PI2.exp; - normalize(&tmp); - reg_move(&tmp, X); + q, exponent(st0_ptr) - exponent(&CONST_PI2)); + setexponent16(&tmp, exponent(&CONST_PI2)); + st0_tag = FPU_normalize(&tmp, 0); /* Can't overflow */ + FPU_copy_to_reg0(&tmp, st0_tag); } -#ifdef FPTAN - if ( even == FPTAN ) - { - if ( ((X->exp >= EXP_BIAS) || - ((X->exp == EXP_BIAS-1) - && (X->sigh >= 0xc90fdaa2))) ^ (q & 1) ) - even = FCOS; - else - even = 0; - } -#endif FPTAN - if ( (even && !(q & 1)) || (!even && (q & 1)) ) { - reg_sub(&CONST_PI2, X, X, FULL_PRECISION); + st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2, FULL_PRECISION); + #ifdef BETTER_THAN_486 /* So far, the results are exact but based upon a 64 bit precision approximation to pi/2. The technique used now is equivalent to using an approximation to pi/2 which is accurate to about 128 bits. */ - if ( (X->exp <= CONST_PI2extra.exp + 64) || (q > 1) ) + if ( (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64) || (q > 1) ) { - /* This code gives the effect of having p/2 to better than + /* This code gives the effect of having pi/2 to better than 128 bits precision. */ + significand(&tmp) = q + 1; - tmp.exp = EXP_BIAS + 63; - tmp.tag = TW_Valid; - normalize(&tmp); - reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION); - reg_add(X, &tmp, X, FULL_PRECISION); - if ( X->sign == SIGN_NEG ) + setexponent16(&tmp, 63); + FPU_normalize(&tmp, 0); /* Can't overflow */ + tmptag = + FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, SIGN_POS, + exponent(&CONST_PI2extra) + exponent(&tmp)); + setsign(&tmp, getsign(&CONST_PI2extra)); + st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION); + if ( signnegative(st0_ptr) ) { /* CONST_PI2extra is negative, so the result of the addition can be negative. This means that the argument is actually in a different quadrant. The correction is always < pi/2, so it can't overflow into yet another quadrant. */ - X->sign = SIGN_POS; + setpositive(st0_ptr); q++; } } -#endif BETTER_THAN_486 +#endif /* BETTER_THAN_486 */ } #ifdef BETTER_THAN_486 else @@ -114,33 +107,40 @@ precision approximation to pi/2. The technique used now is equivalent to using an approximation to pi/2 which is accurate to about 128 bits. */ - if ( ((q > 0) && (X->exp <= CONST_PI2extra.exp + 64)) || (q > 1) ) + if ( ((q > 0) && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)) + || (q > 1) ) { /* This code gives the effect of having p/2 to better than 128 bits precision. */ + significand(&tmp) = q; - tmp.exp = EXP_BIAS + 63; - tmp.tag = TW_Valid; - normalize(&tmp); - reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION); - reg_sub(X, &tmp, X, FULL_PRECISION); - if ( (X->exp == CONST_PI2.exp) && - ((X->sigh > CONST_PI2.sigh) - || ((X->sigh == CONST_PI2.sigh) - && (X->sigl > CONST_PI2.sigl))) ) + setexponent16(&tmp, 63); + FPU_normalize(&tmp, 0); /* This must return TAG_Valid */ + tmptag = FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, + SIGN_POS, + exponent(&CONST_PI2extra) + exponent(&tmp)); + setsign(&tmp, getsign(&CONST_PI2extra)); + st0_tag = FPU_sub(LOADED|(tmptag & 0x0f), (int)&tmp, + FULL_PRECISION); + if ( (exponent(st0_ptr) == exponent(&CONST_PI2)) && + ((st0_ptr->sigh > CONST_PI2.sigh) + || ((st0_ptr->sigh == CONST_PI2.sigh) + && (st0_ptr->sigl > CONST_PI2.sigl))) ) { /* CONST_PI2extra is negative, so the result of the subtraction can be larger than pi/2. This means that the argument is actually in a different quadrant. The correction is always < pi/2, so it can't overflow into yet another quadrant. */ - reg_sub(&CONST_PI, X, X, FULL_PRECISION); + st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2, + FULL_PRECISION); q++; } } } -#endif BETTER_THAN_486 +#endif /* BETTER_THAN_486 */ + FPU_settag0(st0_tag); control_word = old_cw; partial_status = saved_status & ~SW_C2; /* Reduction complete. */ @@ -149,57 +149,56 @@ /* Convert a long to register */ -void convert_l2reg(long const *arg, FPU_REG *dest) +static void convert_l2reg(long const *arg, int deststnr) { + int tag; long num = *arg; + u_char sign; + FPU_REG *dest = &st(deststnr); if (num == 0) - { reg_move(&CONST_Z, dest); return; } + { + FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); + return; + } if (num > 0) - dest->sign = SIGN_POS; + { sign = SIGN_POS; } else - { num = -num; dest->sign = SIGN_NEG; } + { num = -num; sign = SIGN_NEG; } dest->sigh = num; dest->sigl = 0; - dest->exp = EXP_BIAS + 31; - dest->tag = TW_Valid; - normalize(dest); + setexponent16(dest, 31); + tag = FPU_normalize(dest, sign); + FPU_settagi(deststnr, tag); + setsign(dest, sign); + return; } -static void single_arg_error(FPU_REG *st0_ptr) +static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag) { - switch ( st0_ptr->tag ) - { - case TW_NaN: - if ( !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ - { - EXCEPTION(EX_Invalid); - if ( control_word & CW_Invalid ) - st0_ptr->sigh |= 0x40000000; /* Convert to a QNaN */ - } - break; /* return with a NaN in st(0) */ - case TW_Empty: - stack_underflow(); /* Puts a QNaN in st(0) */ - break; + if ( st0_tag == TAG_Empty ) + FPU_stack_underflow(); /* Puts a QNaN in st(0) */ + else if ( st0_tag == TW_NaN ) + real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */ #ifdef PARANOID - default: - EXCEPTION(EX_INTERNAL|0x0112); -#endif PARANOID - } + else + EXCEPTION(EX_INTERNAL|0x0112); +#endif /* PARANOID */ } -static void single_arg_2_error(FPU_REG *st0_ptr) +static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag) { - FPU_REG *st_new_ptr; + int isNaN; - switch ( st0_ptr->tag ) + switch ( st0_tag ) { case TW_NaN: - if ( !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ + isNaN = (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000); + if ( isNaN && !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ { EXCEPTION(EX_Invalid); if ( control_word & CW_Invalid ) @@ -207,115 +206,121 @@ /* The masked response */ /* Convert to a QNaN */ st0_ptr->sigh |= 0x40000000; - st_new_ptr = &st(-1); push(); - reg_move(&st(1), st_new_ptr); + FPU_copy_to_reg0(st0_ptr, TAG_Special); } } - else + else if ( isNaN ) { /* A QNaN */ - st_new_ptr = &st(-1); push(); - reg_move(&st(1), st_new_ptr); + FPU_copy_to_reg0(st0_ptr, TAG_Special); + } + else + { + /* pseudoNaN or other unsupported */ + EXCEPTION(EX_Invalid); + if ( control_word & CW_Invalid ) + { + /* The masked response */ + FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); + push(); + FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); + } } break; /* return with a NaN in st(0) */ #ifdef PARANOID default: EXCEPTION(EX_INTERNAL|0x0112); -#endif PARANOID +#endif /* PARANOID */ } } /*---------------------------------------------------------------------------*/ -static void f2xm1(FPU_REG *st0_ptr) +static void f2xm1(FPU_REG *st0_ptr, u_char tag) { + FPU_REG a; + clear_C1(); - switch ( st0_ptr->tag ) + + if ( tag == TAG_Valid ) { - case TW_Valid: - { - if ( st0_ptr->exp >= 0 ) - { - /* For an 80486 FPU, the result is undefined. */ - } -#ifdef DENORM_OPERAND - else if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND - else - { - /* poly_2xm1(x) requires 0 < x < 1. */ - poly_2xm1(st0_ptr, st0_ptr); - } - if ( st0_ptr->exp <= EXP_UNDER ) - { - /* A denormal result has been produced. - Precision must have been lost, this is always - an underflow. */ - arith_underflow(st0_ptr); - } - set_precision_flag_up(); /* 80486 appears to always do this */ - return; - } - case TW_Zero: + /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */ + if ( exponent(st0_ptr) < 0 ) + { + denormal_arg: + + FPU_to_exp16(st0_ptr, &a); + + /* poly_2xm1(x) requires 0 < st(0) < 1. */ + poly_2xm1(getsign(st0_ptr), &a, st0_ptr); + } + set_precision_flag_up(); /* 80486 appears to always do this */ return; + } + + if ( tag == TAG_Zero ) + return; + + if ( tag == TAG_Special ) + tag = FPU_Special(st0_ptr); + + switch ( tag ) + { + case TW_Denormal: + if ( denormal_operand() < 0 ) + return; + goto denormal_arg; case TW_Infinity: - if ( st0_ptr->sign == SIGN_NEG ) + if ( signnegative(st0_ptr) ) { /* -infinity gives -1 (p16-10) */ - reg_move(&CONST_1, st0_ptr); - st0_ptr->sign = SIGN_NEG; + FPU_copy_to_reg0(&CONST_1, TAG_Valid); + setnegative(st0_ptr); } return; default: - single_arg_error(st0_ptr); + single_arg_error(st0_ptr, tag); } } -static void fptan(FPU_REG *st0_ptr) +static void fptan(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; FPU_REG *st_new_ptr; int q; - char arg_sign = st0_ptr->sign; + u_char arg_sign = getsign(st0_ptr); /* Stack underflow has higher priority */ - if ( st0_tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { - stack_underflow(); /* Puts a QNaN in st(0) */ + FPU_stack_underflow(); /* Puts a QNaN in st(0) */ if ( control_word & CW_Invalid ) { st_new_ptr = &st(-1); push(); - stack_underflow(); /* Puts a QNaN in the new st(0) */ + FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */ } return; } if ( STACK_OVERFLOW ) - { stack_overflow(); return; } + { FPU_stack_overflow(); return; } - switch ( st0_tag ) + if ( st0_tag == TAG_Valid ) { - case TW_Valid: - if ( st0_ptr->exp > EXP_BIAS - 40 ) + if ( exponent(st0_ptr) > -40 ) { - st0_ptr->sign = SIGN_POS; - if ( (q = trig_arg(st0_ptr, 0)) != -1 ) - { - poly_tan(st0_ptr, st0_ptr); - st0_ptr->sign = (q & 1) ^ arg_sign; - } - else + if ( (q = trig_arg(st0_ptr, 0)) == -1 ) { /* Operand is out of range */ - st0_ptr->sign = arg_sign; /* restore st(0) */ return; } + + poly_tan(st0_ptr); + setsign(st0_ptr, (q & 1) ^ (arg_sign != 0)); set_precision_flag_up(); /* We do not really know if up or down */ } else @@ -323,106 +328,134 @@ /* For a small arg, the result == the argument */ /* Underflow may happen */ - if ( st0_ptr->exp <= EXP_UNDER ) - { -#ifdef DENORM_OPERAND - if ( denormal_operand() ) - return; -#endif DENORM_OPERAND - /* A denormal result has been produced. - Precision must have been lost, this is always - an underflow. */ - if ( arith_underflow(st0_ptr) ) - return; - } - set_precision_flag_down(); /* Must be down. */ + denormal_arg: + + FPU_to_exp16(st0_ptr, st0_ptr); + + st0_tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign); + FPU_settag0(st0_tag); } push(); - reg_move(&CONST_1, st_new_ptr); + FPU_copy_to_reg0(&CONST_1, TAG_Valid); return; - break; - case TW_Infinity: + } + + if ( st0_tag == TAG_Zero ) + { + push(); + FPU_copy_to_reg0(&CONST_1, TAG_Valid); + setcc(0); + return; + } + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + + if ( st0_tag == TW_Denormal ) + { + if ( denormal_operand() < 0 ) + return; + + goto denormal_arg; + } + + if ( st0_tag == TW_Infinity ) + { /* The 80486 treats infinity as an invalid operand */ - arith_invalid(st0_ptr); - if ( control_word & CW_Invalid ) + if ( arith_invalid(0) >= 0 ) { st_new_ptr = &st(-1); push(); - arith_invalid(st_new_ptr); + arith_invalid(0); } return; - case TW_Zero: - push(); - reg_move(&CONST_1, st_new_ptr); - setcc(0); - break; - default: - single_arg_2_error(st0_ptr); - break; } + + single_arg_2_error(st0_ptr, st0_tag); } -static void fxtract(FPU_REG *st0_ptr) +static void fxtract(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; FPU_REG *st_new_ptr; + u_char sign; register FPU_REG *st1_ptr = st0_ptr; /* anticipate */ if ( STACK_OVERFLOW ) - { stack_overflow(); return; } + { FPU_stack_overflow(); return; } + clear_C1(); - if ( !(st0_tag ^ TW_Valid) ) + + if ( st0_tag == TAG_Valid ) { long e; -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND - push(); - reg_move(st1_ptr, st_new_ptr); - st_new_ptr->exp = EXP_BIAS; - e = st1_ptr->exp - EXP_BIAS; - convert_l2reg(&e, st1_ptr); + sign = getsign(st1_ptr); + reg_copy(st1_ptr, st_new_ptr); + setexponent16(st_new_ptr, exponent(st_new_ptr)); + + denormal_arg: + + e = exponent16(st_new_ptr); + convert_l2reg(&e, 1); + setexponentpos(st_new_ptr, 0); + setsign(st_new_ptr, sign); + FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */ return; } - else if ( st0_tag == TW_Zero ) + else if ( st0_tag == TAG_Zero ) { - char sign = st0_ptr->sign; - if ( divide_by_zero(SIGN_NEG, st0_ptr) ) + sign = getsign(st0_ptr); + + if ( FPU_divide_by_zero(0, SIGN_NEG) < 0 ) return; + push(); - reg_move(&CONST_Z, st_new_ptr); - st_new_ptr->sign = sign; + FPU_copy_to_reg0(&CONST_Z, TAG_Zero); + setsign(st_new_ptr, sign); return; } + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + + if ( st0_tag == TW_Denormal ) + { + if (denormal_operand() < 0 ) + return; + + push(); + sign = getsign(st1_ptr); + FPU_to_exp16(st1_ptr, st_new_ptr); + goto denormal_arg; + } else if ( st0_tag == TW_Infinity ) { - char sign = st0_ptr->sign; - st0_ptr->sign = SIGN_POS; + sign = getsign(st0_ptr); + setpositive(st0_ptr); push(); - reg_move(&CONST_INF, st_new_ptr); - st_new_ptr->sign = sign; + FPU_copy_to_reg0(&CONST_INF, TAG_Special); + setsign(st_new_ptr, sign); return; } else if ( st0_tag == TW_NaN ) { - if ( real_2op_NaN(st0_ptr, st0_ptr, st0_ptr) ) + if ( real_1op_NaN(st0_ptr) < 0 ) return; + push(); - reg_move(st1_ptr, st_new_ptr); + FPU_copy_to_reg0(st0_ptr, TAG_Special); return; } - else if ( st0_tag == TW_Empty ) + else if ( st0_tag == TAG_Empty ) { /* Is this the correct behaviour? */ if ( control_word & EX_Invalid ) { - stack_underflow(); + FPU_stack_underflow(); push(); - stack_underflow(); + FPU_stack_underflow(); } else EXCEPTION(EX_StackUnder); @@ -430,197 +463,237 @@ #ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x119); -#endif PARANOID +#endif /* PARANOID */ } -static void fdecstp(FPU_REG *st0_ptr) +static void fdecstp(void) { clear_C1(); - top--; /* st0_ptr will be fixed in math_emulate() before the next instr */ + FPU_top--; } -static void fincstp(FPU_REG *st0_ptr) +static void fincstp(void) { clear_C1(); - top++; /* st0_ptr will be fixed in math_emulate() before the next instr */ + FPU_top++; } -static void fsqrt_(FPU_REG *st0_ptr) +static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; + int expon; clear_C1(); - if ( !(st0_tag ^ TW_Valid) ) + + if ( st0_tag == TAG_Valid ) { - int expon; + u_char tag; - if (st0_ptr->sign == SIGN_NEG) + if (signnegative(st0_ptr)) { - arith_invalid(st0_ptr); /* sqrt(negative) is invalid */ + arith_invalid(0); /* sqrt(negative) is invalid */ return; } -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND + /* make st(0) in [1.0 .. 4.0) */ + expon = exponent(st0_ptr); - expon = st0_ptr->exp - EXP_BIAS; - st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */ - - wm_sqrt(st0_ptr, control_word); /* Do the computation */ - - st0_ptr->exp += expon >> 1; - st0_ptr->sign = SIGN_POS; + denormal_arg: + + setexponent16(st0_ptr, (expon & 1)); + + /* Do the computation, the sign of the result will be positive. */ + tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS); + addexponent(st0_ptr, expon >> 1); + FPU_settag0(tag); + return; } - else if ( st0_tag == TW_Zero ) + + if ( st0_tag == TAG_Zero ) return; - else if ( st0_tag == TW_Infinity ) + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + + if ( st0_tag == TW_Infinity ) { - if ( st0_ptr->sign == SIGN_NEG ) - arith_invalid(st0_ptr); /* sqrt(-Infinity) is invalid */ + if ( signnegative(st0_ptr) ) + arith_invalid(0); /* sqrt(-Infinity) is invalid */ return; } - else - { single_arg_error(st0_ptr); return; } + else if ( st0_tag == TW_Denormal ) + { + if (signnegative(st0_ptr)) + { + arith_invalid(0); /* sqrt(negative) is invalid */ + return; + } + + if ( denormal_operand() < 0 ) + return; + + FPU_to_exp16(st0_ptr, st0_ptr); + + expon = exponent16(st0_ptr); + + goto denormal_arg; + } + + single_arg_error(st0_ptr, st0_tag); } -static void frndint_(FPU_REG *st0_ptr) +static void frndint_(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; - int flags; + int flags, tag; - if ( !(st0_tag ^ TW_Valid) ) + if ( st0_tag == TAG_Valid ) { - if (st0_ptr->exp > EXP_BIAS+63) - return; + u_char sign; + + denormal_arg: + + sign = getsign(st0_ptr); -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if (exponent(st0_ptr) > 63) return; -#endif DENORM_OPERAND + + if ( st0_tag == TW_Denormal ) + { + if (denormal_operand() < 0 ) + return; + } /* Fortunately, this can't overflow to 2^64 */ - if ( (flags = round_to_int(st0_ptr)) ) + if ( (flags = FPU_round_to_int(st0_ptr, st0_tag)) ) set_precision_flag(flags); - st0_ptr->exp = EXP_BIAS + 63; - normalize(st0_ptr); + setexponent16(st0_ptr, 63); + tag = FPU_normalize(st0_ptr, sign); + setsign(st0_ptr, sign); + FPU_settag0(tag); return; } - else if ( (st0_tag == TW_Zero) || (st0_tag == TW_Infinity) ) + + if ( st0_tag == TAG_Zero ) + return; + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + + if ( st0_tag == TW_Denormal ) + goto denormal_arg; + else if ( st0_tag == TW_Infinity ) return; else - single_arg_error(st0_ptr); + single_arg_error(st0_ptr, st0_tag); } -static void fsin(FPU_REG *st0_ptr) +static int fsin(FPU_REG *st0_ptr, u_char tag) { - char st0_tag = st0_ptr->tag; - char arg_sign = st0_ptr->sign; + u_char arg_sign = getsign(st0_ptr); - if ( st0_tag == TW_Valid ) + if ( tag == TAG_Valid ) { - FPU_REG rv; int q; - if ( st0_ptr->exp > EXP_BIAS - 40 ) + if ( exponent(st0_ptr) > -40 ) { - st0_ptr->sign = SIGN_POS; - if ( (q = trig_arg(st0_ptr, 0)) != -1 ) + if ( (q = trig_arg(st0_ptr, 0)) == -1 ) { + /* Operand is out of range */ + return 1; + } - poly_sine(st0_ptr, &rv); + poly_sine(st0_ptr); + + if (q & 2) + changesign(st0_ptr); - if (q & 2) - rv.sign ^= SIGN_POS ^ SIGN_NEG; - rv.sign ^= arg_sign; - reg_move(&rv, st0_ptr); + setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign); - /* We do not really know if up or down */ - set_precision_flag_up(); - return; - } - else - { - /* Operand is out of range */ - st0_ptr->sign = arg_sign; /* restore st(0) */ - return; - } + /* We do not really know if up or down */ + set_precision_flag_up(); + return 0; } else { /* For a small arg, the result == the argument */ - /* Underflow may happen */ - - if ( st0_ptr->exp <= EXP_UNDER ) - { -#ifdef DENORM_OPERAND - if ( denormal_operand() ) - return; -#endif DENORM_OPERAND - /* A denormal result has been produced. - Precision must have been lost, this is always - an underflow. */ - arith_underflow(st0_ptr); - return; - } - set_precision_flag_up(); /* Must be up. */ + return 0; } } - else if ( st0_tag == TW_Zero ) + + if ( tag == TAG_Zero ) { setcc(0); - return; + return 0; } - else if ( st0_tag == TW_Infinity ) + + if ( tag == TAG_Special ) + tag = FPU_Special(st0_ptr); + + if ( tag == TW_Denormal ) + { + if ( denormal_operand() < 0 ) + return 1; + + /* For a small arg, the result == the argument */ + /* Underflow may happen */ + FPU_to_exp16(st0_ptr, st0_ptr); + + tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign); + + FPU_settag0(tag); + + return 0; + } + else if ( tag == TW_Infinity ) { /* The 80486 treats infinity as an invalid operand */ - arith_invalid(st0_ptr); - return; + arith_invalid(0); + return 1; } else - single_arg_error(st0_ptr); + { + single_arg_error(st0_ptr, tag); + return 1; + } } -static int f_cos(FPU_REG *arg) +static int f_cos(FPU_REG *st0_ptr, u_char tag) { - char arg_sign = arg->sign; + u_char st0_sign; + + st0_sign = getsign(st0_ptr); - if ( arg->tag == TW_Valid ) + if ( tag == TAG_Valid ) { - FPU_REG rv; int q; - if ( arg->exp > EXP_BIAS - 40 ) + if ( exponent(st0_ptr) > -40 ) { - arg->sign = SIGN_POS; - if ( (arg->exp < EXP_BIAS) - || ((arg->exp == EXP_BIAS) - && (significand(arg) <= 0xc90fdaa22168c234LL)) ) + if ( (exponent(st0_ptr) < 0) + || ((exponent(st0_ptr) == 0) + && (significand(st0_ptr) <= 0xc90fdaa22168c234LL)) ) { - poly_cos(arg, &rv); - reg_move(&rv, arg); + poly_cos(st0_ptr); /* We do not really know if up or down */ set_precision_flag_down(); return 0; } - else if ( (q = trig_arg(arg, FCOS)) != -1 ) + else if ( (q = trig_arg(st0_ptr, FCOS)) != -1 ) { - poly_sine(arg, &rv); + poly_sine(st0_ptr); if ((q+1) & 2) - rv.sign ^= SIGN_POS ^ SIGN_NEG; - reg_move(&rv, arg); + changesign(st0_ptr); /* We do not really know if up or down */ set_precision_flag_down(); @@ -630,100 +703,116 @@ else { /* Operand is out of range */ - arg->sign = arg_sign; /* restore st(0) */ return 1; } } else { -#ifdef DENORM_OPERAND - if ( (arg->exp <= EXP_UNDER) && (denormal_operand()) ) - return 1; -#endif DENORM_OPERAND + denormal_arg: setcc(0); - reg_move(&CONST_1, arg); + FPU_copy_to_reg0(&CONST_1, TAG_Valid); #ifdef PECULIAR_486 set_precision_flag_down(); /* 80486 appears to do this. */ #else set_precision_flag_up(); /* Must be up. */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return 0; } } - else if ( arg->tag == TW_Zero ) + else if ( tag == TAG_Zero ) { - reg_move(&CONST_1, arg); + FPU_copy_to_reg0(&CONST_1, TAG_Valid); setcc(0); return 0; } - else if ( arg->tag == TW_Infinity ) + + if ( tag == TAG_Special ) + tag = FPU_Special(st0_ptr); + + if ( tag == TW_Denormal ) + { + if ( denormal_operand() < 0 ) + return 1; + + goto denormal_arg; + } + else if ( tag == TW_Infinity ) { /* The 80486 treats infinity as an invalid operand */ - arith_invalid(arg); + arith_invalid(0); return 1; } else { - single_arg_error(arg); /* requires arg == &st(0) */ + single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */ return 1; } } -static void fcos(FPU_REG *st0_ptr) +static void fcos(FPU_REG *st0_ptr, u_char st0_tag) { - f_cos(st0_ptr); + f_cos(st0_ptr, st0_tag); } -static void fsincos(FPU_REG *st0_ptr) +static void fsincos(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; FPU_REG *st_new_ptr; FPU_REG arg; + u_char tag; /* Stack underflow has higher priority */ - if ( st0_tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { - stack_underflow(); /* Puts a QNaN in st(0) */ + FPU_stack_underflow(); /* Puts a QNaN in st(0) */ if ( control_word & CW_Invalid ) { st_new_ptr = &st(-1); push(); - stack_underflow(); /* Puts a QNaN in the new st(0) */ + FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */ } return; } if ( STACK_OVERFLOW ) - { stack_overflow(); return; } + { FPU_stack_overflow(); return; } - if ( st0_tag == TW_NaN ) + if ( st0_tag == TAG_Special ) + tag = FPU_Special(st0_ptr); + else + tag = st0_tag; + + if ( tag == TW_NaN ) { - single_arg_2_error(st0_ptr); + single_arg_2_error(st0_ptr, TW_NaN); return; } - else if ( st0_tag == TW_Infinity ) + else if ( tag == TW_Infinity ) { /* The 80486 treats infinity as an invalid operand */ - if ( !arith_invalid(st0_ptr) ) + if ( arith_invalid(0) >= 0 ) { - /* unmasked response */ + /* Masked response */ push(); - arith_invalid(st_new_ptr); + arith_invalid(0); } return; } - reg_move(st0_ptr,&arg); - if ( !f_cos(&arg) ) + reg_copy(st0_ptr, &arg); + if ( !fsin(st0_ptr, st0_tag) ) { - fsin(st0_ptr); push(); - reg_move(&arg,st_new_ptr); + FPU_copy_to_reg0(&arg, st0_tag); + f_cos(&st(0), st0_tag); + } + else + { + /* An error, so restore st(0) */ + FPU_copy_to_reg0(&arg, st0_tag); } - } @@ -740,18 +829,29 @@ unsigned long long st1, unsigned long long q, int n) { + int dummy; unsigned long long x; x = st0 << n; /* Do the required multiplication and subtraction in the one operation */ - asm volatile ("movl %2,%%eax; mull %4; subl %%eax,%0; sbbl %%edx,%1; - movl %3,%%eax; mull %4; subl %%eax,%1; - movl %2,%%eax; mull %5; subl %%eax,%1;" - :"=m" (x), "=m" (((unsigned *)&x)[1]) - :"m" (st1),"m" (((unsigned *)&st1)[1]), - "m" (q),"m" (((unsigned *)&q)[1]) - :"%ax","%dx"); + + /* lsw x -= lsw st1 * lsw q */ + asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1" + :"=m" (((unsigned *)&x)[0]), "=m" (((unsigned *)&x)[1]), + "=a" (dummy) + :"2" (((unsigned *)&st1)[0]), "m" (((unsigned *)&q)[0]) + :"%dx"); + /* msw x -= msw st1 * lsw q */ + asm volatile ("mull %3; subl %%eax,%0" + :"=m" (((unsigned *)&x)[1]), "=a" (dummy) + :"1" (((unsigned *)&st1)[1]), "m" (((unsigned *)&q)[0]) + :"%dx"); + /* msw x -= lsw st1 * msw q */ + asm volatile ("mull %3; subl %%eax,%0" + :"=m" (((unsigned *)&x)[1]), "=a" (dummy) + :"1" (((unsigned *)&st1)[0]), "m" (((unsigned *)&q)[1]) + :"%dx"); *y = x; } @@ -760,79 +860,86 @@ /* Remainder of st(0) / st(1) */ /* This routine produces exact results, i.e. there is never any rounding or truncation, etc of the result. */ -static void do_fprem(FPU_REG *st0_ptr, int round) +static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round) { FPU_REG *st1_ptr = &st(1); - char st1_tag = st1_ptr->tag; - char st0_tag = st0_ptr->tag; - char sign = st0_ptr->sign; + u_char st1_tag = FPU_gettagi(1); - if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { - FPU_REG tmp; - int old_cw = control_word; - int expdif = st0_ptr->exp - st1_ptr->exp; + FPU_REG tmp, st0, st1; + u_char st0_sign, st1_sign; + u_char tmptag; + int tag; + int old_cw; + int expdif; long long q; unsigned short saved_status; - int cc = 0; + int cc; + + fprem_valid: + /* Convert registers for internal use. */ + st0_sign = FPU_to_exp16(st0_ptr, &st0); + st1_sign = FPU_to_exp16(st1_ptr, &st1); + expdif = exponent16(&st0) - exponent16(&st1); + + old_cw = control_word; + cc = 0; -#ifdef DENORM_OPERAND - if ( ((st0_ptr->exp <= EXP_UNDER) || - (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND - /* We want the status following the denorm tests, but don't want the status changed by the arithmetic operations. */ saved_status = partial_status; control_word &= ~CW_RC; control_word |= RC_CHOP; - if (expdif < 64) + if ( expdif < 64 ) { /* This should be the most common case */ if ( expdif > -2 ) { - reg_div(st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f); + u_char sign = st0_sign ^ st1_sign; + tag = FPU_u_div(&st0, &st1, &tmp, + PR_64_BITS | RC_CHOP | 0x3f, + sign); + setsign(&tmp, sign); - if ( tmp.exp >= EXP_BIAS ) + if ( exponent(&tmp) >= 0 ) { - round_to_int(&tmp); /* Fortunately, this can't overflow - to 2^64 */ + FPU_round_to_int(&tmp, tag); /* Fortunately, this can't + overflow to 2^64 */ q = significand(&tmp); - rem_kernel(significand(st0_ptr), + rem_kernel(significand(&st0), &significand(&tmp), - significand(st1_ptr), + significand(&st1), q, expdif); - tmp.exp = st1_ptr->exp; + setexponent16(&tmp, exponent16(&st1)); } else { - reg_move(st0_ptr, &tmp); + reg_copy(&st0, &tmp); q = 0; } - tmp.sign = sign; if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) ) { /* We may need to subtract st(1) once more, to get a result <= 1/2 of st(1). */ unsigned long long x; - expdif = st1_ptr->exp - tmp.exp; + expdif = exponent16(&st1) - exponent16(&tmp); if ( expdif <= 1 ) { if ( expdif == 0 ) - x = significand(st1_ptr) - significand(&tmp); + x = significand(&st1) - significand(&tmp); else /* expdif is 1 */ - x = (significand(st1_ptr) << 1) - significand(&tmp); + x = (significand(&st1) << 1) - significand(&tmp); if ( (x < significand(&tmp)) || /* or equi-distant (from 0 & st(1)) and q is odd */ ((x == significand(&tmp)) && (q & 1) ) ) { - tmp.sign ^= (SIGN_POS^SIGN_NEG); + st0_sign = ! st0_sign; significand(&tmp) = x; q++; } @@ -855,28 +962,35 @@ /* There is a large exponent difference ( >= 64 ) */ /* To make much sense, the code in this section should be done at high precision. */ - int exp_1; + int exp_1, N; + u_char sign; /* prevent overflow here */ /* N is 'a number between 32 and 63' (p26-113) */ - reg_move(st0_ptr, &tmp); - tmp.exp = EXP_BIAS + 56; - exp_1 = st1_ptr->exp; st1_ptr->exp = EXP_BIAS; - expdif -= 56; - - reg_div(&tmp, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f); - st1_ptr->exp = exp_1; + reg_copy(&st0, &tmp); + tmptag = st0_tag; + N = (expdif & 0x0000001f) + 32; /* This choice gives results + identical to an AMD 486 */ + setexponent16(&tmp, N); + exp_1 = exponent16(&st1); + setexponent16(&st1, 0); + expdif -= N; + + sign = getsign(&tmp) ^ st1_sign; + tag = FPU_u_div(&tmp, &st1, &tmp, PR_64_BITS | RC_CHOP | 0x3f, + sign); + setsign(&tmp, sign); - round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */ + FPU_round_to_int(&tmp, tag); /* Fortunately, this can't + overflow to 2^64 */ - rem_kernel(significand(st0_ptr), + rem_kernel(significand(&st0), &significand(&tmp), - significand(st1_ptr), + significand(&st1), significand(&tmp), - tmp.exp - EXP_BIAS + exponent(&tmp) ); - tmp.exp = exp_1 + expdif; - tmp.sign = sign; + setexponent16(&tmp, exp_1 + expdif); /* It is possible for the operation to be complete here. What does the IEEE standard say? The Intel 80486 manual @@ -888,13 +1002,13 @@ /* The result is zero */ control_word = old_cw; partial_status = saved_status; - reg_move(&CONST_Z, st0_ptr); - st0_ptr->sign = sign; + FPU_copy_to_reg0(&CONST_Z, TAG_Zero); + setsign(&st0, st0_sign); #ifdef PECULIAR_486 setcc(SW_C2); #else setcc(0); -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return; } cc = SW_C2; @@ -902,52 +1016,82 @@ control_word = old_cw; partial_status = saved_status; - normalize_nuo(&tmp); - reg_move(&tmp, st0_ptr); - setcc(cc); + tag = FPU_normalize_nuo(&tmp); + reg_copy(&tmp, st0_ptr); /* The only condition to be looked for is underflow, and it can occur here only if underflow is unmasked. */ - if ( (st0_ptr->exp <= EXP_UNDER) && (st0_ptr->tag != TW_Zero) + if ( (exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero) && !(control_word & CW_Underflow) ) - arith_underflow(st0_ptr); + { + setcc(cc); + tag = arith_underflow(st0_ptr); + setsign(st0_ptr, st0_sign); + FPU_settag0(tag); + return; + } + else if ( (exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero) ) + { + stdexp(st0_ptr); + setsign(st0_ptr, st0_sign); + } + else + { + tag = FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign); + } + FPU_settag0(tag); + setcc(cc); return; } - else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + if ( st1_tag == TAG_Special ) + st1_tag = FPU_Special(st1_ptr); + + if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) + || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) + || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) + { + if ( denormal_operand() < 0 ) + return; + goto fprem_valid; + } + else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) ) { - stack_underflow(); + FPU_stack_underflow(); return; } - else if ( st0_tag == TW_Zero ) + else if ( st0_tag == TAG_Zero ) { - if ( st1_tag == TW_Valid ) + if ( st1_tag == TAG_Valid ) { -#ifdef DENORM_OPERAND - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + setcc(0); return; + } + else if ( st1_tag == TW_Denormal ) + { + if ( denormal_operand() < 0 ) return; -#endif DENORM_OPERAND - setcc(0); return; } - else if ( st1_tag == TW_Zero ) - { arith_invalid(st0_ptr); return; } /* fprem(?,0) always invalid */ + else if ( st1_tag == TAG_Zero ) + { arith_invalid(0); return; } /* fprem(?,0) always invalid */ else if ( st1_tag == TW_Infinity ) { setcc(0); return; } } - else if ( st0_tag == TW_Valid ) + else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) { - if ( st1_tag == TW_Zero ) + if ( st1_tag == TAG_Zero ) { - arith_invalid(st0_ptr); /* fprem(Valid,Zero) is invalid */ + arith_invalid(0); /* fprem(Valid,Zero) is invalid */ return; } else if ( st1_tag != TW_NaN ) { -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( ((st0_tag == TW_Denormal) || (st1_tag == TW_Denormal)) + && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND if ( st1_tag == TW_Infinity ) { @@ -960,729 +1104,715 @@ { if ( st1_tag != TW_NaN ) { - arith_invalid(st0_ptr); /* fprem(Infinity,?) is invalid */ + arith_invalid(0); /* fprem(Infinity,?) is invalid */ return; } } - /* One of the registers must contain a NaN is we got here. */ + /* One of the registers must contain a NaN if we got here. */ #ifdef PARANOID if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) EXCEPTION(EX_INTERNAL | 0x118); -#endif PARANOID +#endif /* PARANOID */ - real_2op_NaN(st1_ptr, st0_ptr, st0_ptr); + real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr); } /* ST(1) <- ST(1) * log ST; pop ST */ -static void fyl2x(FPU_REG *st0_ptr) +static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1), exponent; - char st1_tag = st1_ptr->tag; - int e; + u_char st1_tag = FPU_gettagi(1); + u_char sign; + int e, tag; clear_C1(); - if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + + if ( (st0_tag == TAG_Valid) && (st1_tag == TAG_Valid) ) { - if ( st0_ptr->sign == SIGN_POS ) + both_valid: + /* Both regs are Valid or Denormal */ + if ( signpositive(st0_ptr) ) { -#ifdef DENORM_OPERAND - if ( ((st0_ptr->exp <= EXP_UNDER) || - (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND + if ( st0_tag == TW_Denormal ) + FPU_to_exp16(st0_ptr, st0_ptr); + else + /* Convert st(0) for internal use. */ + setexponent16(st0_ptr, exponent(st0_ptr)); if ( (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) ) { /* Special case. The result can be precise. */ - e = st0_ptr->exp - EXP_BIAS; - if ( e > 0 ) + u_char esign; + e = exponent16(st0_ptr); + if ( e >= 0 ) { exponent.sigh = e; - exponent.sign = SIGN_POS; + esign = SIGN_POS; } else { exponent.sigh = -e; - exponent.sign = SIGN_NEG; + esign = SIGN_NEG; } exponent.sigl = 0; - exponent.exp = EXP_BIAS + 31; - exponent.tag = TW_Valid; - normalize_nuo(&exponent); - reg_mul(&exponent, st1_ptr, st1_ptr, FULL_PRECISION); + setexponent16(&exponent, 31); + tag = FPU_normalize_nuo(&exponent); + stdexp(&exponent); + setsign(&exponent, esign); + tag = FPU_mul(&exponent, tag, 1, FULL_PRECISION); + if ( tag >= 0 ) + FPU_settagi(1, tag); } else { /* The usual case */ - poly_l2(st0_ptr, st1_ptr, st1_ptr); - if ( st1_ptr->exp <= EXP_UNDER ) - { - /* A denormal result has been produced. - Precision must have been lost, this is always - an underflow. */ - arith_underflow(st1_ptr); - } + sign = getsign(st1_ptr); + if ( st1_tag == TW_Denormal ) + FPU_to_exp16(st1_ptr, st1_ptr); else - set_precision_flag_up(); /* 80486 appears to always do this */ + /* Convert st(1) for internal use. */ + setexponent16(st1_ptr, exponent(st1_ptr)); + poly_l2(st0_ptr, st1_ptr, sign); } - pop(); - return; } else { /* negative */ - if ( !arith_invalid(st1_ptr) ) - pop(); - return; + if ( arith_invalid(1) < 0 ) + return; } - } - else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) - { - stack_underflow_pop(1); + + FPU_pop(); + return; } - else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + if ( st1_tag == TAG_Special ) + st1_tag = FPU_Special(st1_ptr); + + if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) ) { - if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) - pop(); + FPU_stack_underflow_pop(1); return; } - else if ( (st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) ) + else if ( (st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal) ) { - /* one of the args is zero, the other valid, or both zero */ - if ( st0_tag == TW_Zero ) + if ( st0_tag == TAG_Zero ) { - if ( st1_tag == TW_Zero ) + if ( st1_tag == TAG_Zero ) { /* Both args zero is invalid */ - if ( !arith_invalid(st1_ptr) ) - pop(); - } -#ifdef PECULIAR_486 - /* This case is not specifically covered in the manual, - but divide-by-zero would seem to be the best response. - However, a real 80486 does it this way... */ - else if ( st0_ptr->tag == TW_Infinity ) - { - reg_move(&CONST_INF, st1_ptr); - pop(); + if ( arith_invalid(1) < 0 ) + return; } -#endif PECULIAR_486 else { - if ( !divide_by_zero(st1_ptr->sign^SIGN_NEG^SIGN_POS, st1_ptr) ) - pop(); + u_char sign; + sign = getsign(st1_ptr)^SIGN_NEG; + if ( FPU_divide_by_zero(1, sign) < 0 ) + return; + + setsign(st1_ptr, sign); } - return; } - else + else if ( st1_tag == TAG_Zero ) { /* st(1) contains zero, st(0) valid <> 0 */ /* Zero is the valid answer */ - char sign = st1_ptr->sign; - - if ( st0_ptr->sign == SIGN_NEG ) + sign = getsign(st1_ptr); + + if ( signnegative(st0_ptr) ) { /* log(negative) */ - if ( !arith_invalid(st1_ptr) ) - pop(); - return; + if ( arith_invalid(1) < 0 ) + return; } - -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND + else + { + if ( exponent(st0_ptr) < 0 ) + sign ^= SIGN_NEG; - if ( st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS; - pop(); st0_ptr = &st(0); - reg_move(&CONST_Z, st0_ptr); - st0_ptr->sign = sign; - return; + FPU_copy_to_reg1(&CONST_Z, TAG_Zero); + setsign(st1_ptr, sign); + } + } + else + { + /* One or both operands are denormals. */ + if ( denormal_operand() < 0 ) + return; + goto both_valid; } } + else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) + { + if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) + return; + } /* One or both arg must be an infinity */ else if ( st0_tag == TW_Infinity ) { - if ( (st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) ) + if ( (signnegative(st0_ptr)) || (st1_tag == TAG_Zero) ) { /* log(-infinity) or 0*log(infinity) */ - if ( !arith_invalid(st1_ptr) ) - pop(); - return; + if ( arith_invalid(1) < 0 ) + return; } else { - char sign = st1_ptr->sign; + u_char sign = getsign(st1_ptr); -#ifdef DENORM_OPERAND - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - pop(); st0_ptr = &st(0); - reg_move(&CONST_INF, st0_ptr); - st0_ptr->sign = sign; - return; + FPU_copy_to_reg1(&CONST_INF, TAG_Special); + setsign(st1_ptr, sign); } } /* st(1) must be infinity here */ - else if ( (st0_tag == TW_Valid) && (st0_ptr->sign == SIGN_POS) ) + else if ( ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) + && ( signpositive(st0_ptr) ) ) { - if ( st0_ptr->exp >= EXP_BIAS ) + if ( exponent(st0_ptr) >= 0 ) { - if ( (st0_ptr->exp == EXP_BIAS) && + if ( (exponent(st0_ptr) == 0) && (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) ) { /* st(0) holds 1.0 */ /* infinity*log(1) */ - if ( !arith_invalid(st1_ptr) ) - pop(); - return; + if ( arith_invalid(1) < 0 ) + return; } - /* st(0) is positive and > 1.0 */ - pop(); + /* else st(0) is positive and > 1.0 */ } else { /* st(0) is positive and < 1.0 */ -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - st1_ptr->sign ^= SIGN_NEG; - pop(); + changesign(st1_ptr); } - return; } else { /* st(0) must be zero or negative */ - if ( st0_ptr->tag == TW_Zero ) + if ( st0_tag == TAG_Zero ) { /* This should be invalid, but a real 80486 is happy with it. */ + #ifndef PECULIAR_486 - if ( !divide_by_zero(st1_ptr->sign, st1_ptr) ) -#endif PECULIAR_486 - { - st1_ptr->sign ^= SIGN_NEG^SIGN_POS; - pop(); - } - } - else - { - /* log(negative) */ - if ( !arith_invalid(st1_ptr) ) - pop(); + sign = getsign(st1_ptr); + if ( FPU_divide_by_zero(1, sign) < 0 ) + return; +#endif /* PECULIAR_486 */ + + changesign(st1_ptr); } - return; + else if ( arith_invalid(1) < 0 ) /* log(negative) */ + return; } + + FPU_pop(); } -static void fpatan(FPU_REG *st0_ptr) +static void fpatan(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1); - char st1_tag = st1_ptr->tag; + u_char st1_tag = FPU_gettagi(1); + int tag; clear_C1(); - if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { -#ifdef DENORM_OPERAND - if ( ((st0_ptr->exp <= EXP_UNDER) || - (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND + valid_atan: - poly_atan(st0_ptr, st1_ptr, st1_ptr); + poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag); - if ( st1_ptr->exp <= EXP_UNDER ) - { - /* A denormal result has been produced. - Precision must have been lost. - This is by definition an underflow. */ - arith_underflow(st1_ptr); - pop(); - return; - } + FPU_pop(); + + return; + } + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + if ( st1_tag == TAG_Special ) + st1_tag = FPU_Special(st1_ptr); + + if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) + || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) + || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) + { + if ( denormal_operand() < 0 ) + return; + + goto valid_atan; } - else if ( (st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) + else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) ) { - stack_underflow_pop(1); + FPU_stack_underflow_pop(1); return; } else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) { - if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) - pop(); + if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0 ) + FPU_pop(); return; } else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) ) { - char sign = st1_ptr->sign; + u_char sign = getsign(st1_ptr); if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_Infinity ) { - if ( st0_ptr->sign == SIGN_POS ) - { reg_move(&CONST_PI4, st1_ptr); } + if ( signpositive(st0_ptr) ) + { + FPU_copy_to_reg1(&CONST_PI4, TAG_Valid); + } else - reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION); + { + setpositive(st1_ptr); + tag = FPU_u_add(&CONST_PI4, &CONST_PI2, st1_ptr, + FULL_PRECISION, SIGN_POS, + exponent(&CONST_PI4), exponent(&CONST_PI2)); + if ( tag >= 0 ) + FPU_settagi(1, tag); + } } else { -#ifdef DENORM_OPERAND - if ( st1_tag != TW_Zero ) - { - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; - } -#endif DENORM_OPERAND + if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) + return; - if ( st0_ptr->sign == SIGN_POS ) + if ( signpositive(st0_ptr) ) { - reg_move(&CONST_Z, st1_ptr); - st1_ptr->sign = sign; /* An 80486 preserves the sign */ - pop(); + FPU_copy_to_reg1(&CONST_Z, TAG_Zero); + setsign(st1_ptr, sign); /* An 80486 preserves the sign */ + FPU_pop(); return; } else - reg_move(&CONST_PI, st1_ptr); + { + FPU_copy_to_reg1(&CONST_PI, TAG_Valid); + } } } else { /* st(1) is infinity, st(0) not infinity */ -#ifdef DENORM_OPERAND - if ( st0_tag != TW_Zero ) - { - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; - } -#endif DENORM_OPERAND + if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) + return; - reg_move(&CONST_PI2, st1_ptr); + FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); } - st1_ptr->sign = sign; + setsign(st1_ptr, sign); } - else if ( st1_tag == TW_Zero ) + else if ( st1_tag == TAG_Zero ) { /* st(0) must be valid or zero */ - char sign = st1_ptr->sign; + u_char sign = getsign(st1_ptr); + + if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) + return; -#ifdef DENORM_OPERAND - if ( st0_tag != TW_Zero ) + if ( signpositive(st0_ptr) ) { - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; + /* An 80486 preserves the sign */ + FPU_pop(); + return; } -#endif DENORM_OPERAND - if ( st0_ptr->sign == SIGN_POS ) - { /* An 80486 preserves the sign */ pop(); return; } - else - reg_move(&CONST_PI, st1_ptr); - st1_ptr->sign = sign; + FPU_copy_to_reg1(&CONST_PI, TAG_Valid); + setsign(st1_ptr, sign); } - else if ( st0_tag == TW_Zero ) + else if ( st0_tag == TAG_Zero ) { - /* st(1) must be TW_Valid here */ - char sign = st1_ptr->sign; + /* st(1) must be TAG_Valid here */ + u_char sign = getsign(st1_ptr); -#ifdef DENORM_OPERAND - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - reg_move(&CONST_PI2, st1_ptr); - st1_ptr->sign = sign; + FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); + setsign(st1_ptr, sign); } #ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x125); -#endif PARANOID +#endif /* PARANOID */ - pop(); + FPU_pop(); set_precision_flag_up(); /* We do not really know if up or down */ } -static void fprem(FPU_REG *st0_ptr) +static void fprem(FPU_REG *st0_ptr, u_char st0_tag) { - do_fprem(st0_ptr, RC_CHOP); + do_fprem(st0_ptr, st0_tag, RC_CHOP); } -static void fprem1(FPU_REG *st0_ptr) +static void fprem1(FPU_REG *st0_ptr, u_char st0_tag) { - do_fprem(st0_ptr, RC_RND); + do_fprem(st0_ptr, st0_tag, RC_RND); } -static void fyl2xp1(FPU_REG *st0_ptr) +static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag, sign; - FPU_REG *st1_ptr = &st(1); - char st1_tag = st1_ptr->tag; + u_char sign, sign1; + FPU_REG *st1_ptr = &st(1), a, b; + u_char st1_tag = FPU_gettagi(1); clear_C1(); - if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { -#ifdef DENORM_OPERAND - if ( ((st0_ptr->exp <= EXP_UNDER) || - (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() ) + valid_yl2xp1: + + sign = getsign(st0_ptr); + sign1 = getsign(st1_ptr); + + FPU_to_exp16(st0_ptr, &a); + FPU_to_exp16(st1_ptr, &b); + + if ( poly_l2p1(sign, sign1, &a, &b, st1_ptr) ) return; -#endif DENORM_OPERAND - if ( poly_l2p1(st0_ptr, st1_ptr, st1_ptr) ) - { -#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ - st1_ptr->sign ^= SIGN_POS^SIGN_NEG; -#else - if ( arith_invalid(st1_ptr) ) /* poly_l2p1() returned invalid */ - return; -#endif PECULIAR_486 - } - if ( st1_ptr->exp <= EXP_UNDER ) - { - /* A denormal result has been produced. - Precision must have been lost, this is always - an underflow. */ - sign = st1_ptr->sign; - arith_underflow(st1_ptr); - st1_ptr->sign = sign; - } - else - set_precision_flag_up(); /* 80486 appears to always do this */ - pop(); + FPU_pop(); return; } - else if ( (st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + if ( st1_tag == TAG_Special ) + st1_tag = FPU_Special(st1_ptr); + + if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) + || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) + || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) { - stack_underflow_pop(1); + if ( denormal_operand() < 0 ) + return; + + goto valid_yl2xp1; + } + else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) ) + { + FPU_stack_underflow_pop(1); return; } - else if ( st0_tag == TW_Zero ) + else if ( st0_tag == TAG_Zero ) { - if ( st1_tag <= TW_Zero ) + switch ( st1_tag ) { -#ifdef DENORM_OPERAND - if ( (st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) && - (denormal_operand()) ) + case TW_Denormal: + if ( denormal_operand() < 0 ) return; -#endif DENORM_OPERAND - - st0_ptr->sign ^= st1_ptr->sign; - reg_move(st0_ptr, st1_ptr); - } - else if ( st1_tag == TW_Infinity ) - { + + case TAG_Zero: + case TAG_Valid: + setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr)); + FPU_copy_to_reg1(st0_ptr, st0_tag); + break; + + case TW_Infinity: /* Infinity*log(1) */ - if ( !arith_invalid(st1_ptr) ) - pop(); - return; - } - else if ( st1_tag == TW_NaN ) - { - if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) - pop(); - return; - } + if ( arith_invalid(1) < 0 ) + return; + break; + + case TW_NaN: + if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) + return; + break; + + default: #ifdef PARANOID - else - { EXCEPTION(EX_INTERNAL | 0x116); return; +#endif /* PARANOID */ + break; } -#endif PARANOID - pop(); return; } - else if ( st0_tag == TW_Valid ) + else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) { - if ( st1_tag == TW_Zero ) + switch ( st1_tag ) { - if ( st0_ptr->sign == SIGN_NEG ) + case TAG_Zero: + if ( signnegative(st0_ptr) ) { - if ( st0_ptr->exp >= EXP_BIAS ) + if ( exponent(st0_ptr) >= 0 ) { /* st(0) holds <= -1.0 */ #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ - st1_ptr->sign ^= SIGN_POS^SIGN_NEG; + changesign(st1_ptr); #else - if ( arith_invalid(st1_ptr) ) return; -#endif PECULIAR_486 - pop(); return; + if ( arith_invalid(1) < 0 ) + return; +#endif /* PECULIAR_486 */ } -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - st1_ptr->sign ^= SIGN_POS^SIGN_NEG; - pop(); return; + else + changesign(st1_ptr); } -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - pop(); return; - } - if ( st1_tag == TW_Infinity ) - { - if ( st0_ptr->sign == SIGN_NEG ) + break; + + case TW_Infinity: + if ( signnegative(st0_ptr) ) { - if ( (st0_ptr->exp >= EXP_BIAS) && + if ( (exponent(st0_ptr) >= 0) && !((st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0)) ) { /* st(0) holds < -1.0 */ #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ - st1_ptr->sign ^= SIGN_POS^SIGN_NEG; + changesign(st1_ptr); #else - if ( arith_invalid(st1_ptr) ) return; -#endif PECULIAR_486 - pop(); return; + if ( arith_invalid(1) < 0 ) return; +#endif /* PECULIAR_486 */ } -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - st1_ptr->sign ^= SIGN_POS^SIGN_NEG; - pop(); return; + else + changesign(st1_ptr); } -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) + return; + break; + + case TW_NaN: + if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) return; -#endif DENORM_OPERAND - pop(); return; - } - if ( st1_tag == TW_NaN ) - { - if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) - pop(); - return; } + } else if ( st0_tag == TW_NaN ) { - if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) - pop(); - return; + if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) + return; } else if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_NaN ) { - if ( !real_2op_NaN(st0_ptr, st1_ptr, st1_ptr) ) - pop(); - return; + if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) + return; } - else if ( st0_ptr->sign == SIGN_NEG ) + else if ( signnegative(st0_ptr) ) { - int exponent = st1_ptr->exp; #ifndef PECULIAR_486 /* This should have higher priority than denormals, but... */ - if ( arith_invalid(st1_ptr) ) /* log(-infinity) */ + if ( arith_invalid(1) < 0 ) /* log(-infinity) */ + return; +#endif /* PECULIAR_486 */ + if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif PECULIAR_486 -#ifdef DENORM_OPERAND - if ( st1_tag != TW_Zero ) - { - if ( (exponent <= EXP_UNDER) && (denormal_operand()) ) - return; - } -#endif DENORM_OPERAND #ifdef PECULIAR_486 /* Denormal operands actually get higher priority */ - if ( arith_invalid(st1_ptr) ) /* log(-infinity) */ + if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return; -#endif PECULIAR_486 - pop(); - return; +#endif /* PECULIAR_486 */ } - else if ( st1_tag == TW_Zero ) + else if ( st1_tag == TAG_Zero ) { /* log(infinity) */ - if ( !arith_invalid(st1_ptr) ) - pop(); - return; + if ( arith_invalid(1) < 0 ) + return; } /* st(1) must be valid here. */ -#ifdef DENORM_OPERAND - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + else if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND /* The Manual says that log(Infinity) is invalid, but a real 80486 sensibly says that it is o.k. */ - { char sign = st1_ptr->sign; - reg_move(&CONST_INF, st1_ptr); - st1_ptr->sign = sign; - } - pop(); - return; + else + { + u_char sign = getsign(st1_ptr); + FPU_copy_to_reg1(&CONST_INF, TAG_Special); + setsign(st1_ptr, sign); + } } #ifdef PARANOID else { EXCEPTION(EX_INTERNAL | 0x117); + return; } -#endif PARANOID +#endif /* PARANOID */ + + FPU_pop(); + return; + } -static void fscale(FPU_REG *st0_ptr) +static void fscale(FPU_REG *st0_ptr, u_char st0_tag) { - char st0_tag = st0_ptr->tag; FPU_REG *st1_ptr = &st(1); - char st1_tag = st1_ptr->tag; + u_char st1_tag = FPU_gettagi(1); int old_cw = control_word; - char sign = st0_ptr->sign; + u_char sign = getsign(st0_ptr); clear_C1(); - if ( !((st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { long scale; FPU_REG tmp; -#ifdef DENORM_OPERAND - if ( ((st0_ptr->exp <= EXP_UNDER) || - (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND + /* Convert register for internal use. */ + setexponent16(st0_ptr, exponent(st0_ptr)); + + valid_scale: - if ( st1_ptr->exp > EXP_BIAS + 30 ) + if ( exponent(st1_ptr) > 18 ) { - /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */ - char sign; + /* 2^18 is far too large, would require 2^(2^17) or 2^(-2^17) */ - if ( st1_ptr->sign == SIGN_POS ) + outrange_scale: + if ( signpositive(st1_ptr) ) { EXCEPTION(EX_Overflow); - sign = st0_ptr->sign; - reg_move(&CONST_INF, st0_ptr); - st0_ptr->sign = sign; + FPU_copy_to_reg0(&CONST_INF, TAG_Special); } else { EXCEPTION(EX_Underflow); - sign = st0_ptr->sign; - reg_move(&CONST_Z, st0_ptr); - st0_ptr->sign = sign; + FPU_copy_to_reg0(&CONST_Z, TAG_Zero); } + setsign(st0_ptr, sign); return; } control_word &= ~CW_RC; control_word |= RC_CHOP; - reg_move(st1_ptr, &tmp); - round_to_int(&tmp); /* This can never overflow here */ + reg_copy(st1_ptr, &tmp); + FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */ control_word = old_cw; - scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl; - scale += st0_ptr->exp; - st0_ptr->exp = scale; + scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl; + scale += exponent16(st0_ptr); + if ( (scale > 0x7000) || (scale < -0x7000) ) + goto outrange_scale; - /* Use round_reg() to properly detect under/overflow etc */ - round_reg(st0_ptr, 0, control_word); + setexponent16(st0_ptr, scale); + + /* Use FPU_round() to properly detect remaining cases of + under/overflow etc */ + FPU_round(st0_ptr, 0, 0, control_word, sign); return; } - else if ( st0_tag == TW_Valid ) + + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); + if ( st1_tag == TAG_Special ) + st1_tag = FPU_Special(st1_ptr); + + if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) { - if ( st1_tag == TW_Zero ) + switch ( st1_tag ) { - -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + case TAG_Valid: + /* st(0) must be a denormal */ + if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND + FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */ + goto valid_scale; + + case TAG_Zero: + if ( st0_tag == TW_Denormal ) + denormal_operand(); return; - } - if ( st1_tag == TW_Infinity ) - { -#ifdef DENORM_OPERAND - if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + + case TW_Denormal: + denormal_operand(); + return; + + case TW_Infinity: + if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; -#endif DENORM_OPERAND - if ( st1_ptr->sign == SIGN_POS ) - { reg_move(&CONST_INF, st0_ptr); } + if ( signpositive(st1_ptr) ) + FPU_copy_to_reg0(&CONST_INF, TAG_Special); else - reg_move(&CONST_Z, st0_ptr); - st0_ptr->sign = sign; + FPU_copy_to_reg0(&CONST_Z, TAG_Zero); + setsign(st0_ptr, sign); + return; + + case TW_NaN: + real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } - if ( st1_tag == TW_NaN ) - { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } - else if ( st0_tag == TW_Zero ) + else if ( st0_tag == TAG_Zero ) { - if ( st1_tag == TW_Valid ) + switch ( st1_tag ) { + case TAG_Valid: + case TAG_Zero: + return; -#ifdef DENORM_OPERAND - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND + case TW_Denormal: + denormal_operand(); + return; + case TW_Infinity: + if ( signpositive(st1_ptr) ) + arith_invalid(0); /* Zero scaled by +Infinity */ + return; + + case TW_NaN: + real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } - else if ( st1_tag == TW_Zero ) { return; } - else if ( st1_tag == TW_Infinity ) - { - if ( st1_ptr->sign == SIGN_NEG ) - return; - else - { - arith_invalid(st0_ptr); /* Zero scaled by +Infinity */ - return; - } - } - else if ( st1_tag == TW_NaN ) - { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } else if ( st0_tag == TW_Infinity ) { - if ( st1_tag == TW_Valid ) + switch ( st1_tag ) { + case TAG_Valid: + case TAG_Zero: + return; -#ifdef DENORM_OPERAND - if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) - return; -#endif DENORM_OPERAND + case TW_Denormal: + denormal_operand(); + return; + case TW_Infinity: + if ( signnegative(st1_ptr) ) + arith_invalid(0); /* Infinity scaled by -Infinity */ return; - } - if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS)) - || (st1_tag == TW_Zero) ) - return; - else if ( st1_tag == TW_Infinity ) - { - arith_invalid(st0_ptr); /* Infinity scaled by -Infinity */ + + case TW_NaN: + real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } - else if ( st1_tag == TW_NaN ) - { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } } else if ( st0_tag == TW_NaN ) { - if ( st1_tag != TW_Empty ) - { real_2op_NaN(st0_ptr, st1_ptr, st0_ptr); return; } + if ( st1_tag != TAG_Empty ) + { real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } } #ifdef PARANOID - if ( !((st0_tag == TW_Empty) || (st1_tag == TW_Empty)) ) + if ( !((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) ) { EXCEPTION(EX_INTERNAL | 0x115); return; @@ -1690,7 +1820,7 @@ #endif /* At least one of st(0), st(1) must be empty */ - stack_underflow(); + FPU_stack_underflow(); } @@ -1698,21 +1828,22 @@ /*---------------------------------------------------------------------------*/ static FUNC_ST0 const trig_table_a[] = { - f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp + f2xm1, fyl2x, fptan, fpatan, + fxtract, fprem1, (FUNC_ST0)fdecstp, (FUNC_ST0)fincstp }; -void trig_a(void) +void FPU_triga(void) { - (trig_table_a[FPU_rm])(&st(0)); + (trig_table_a[FPU_rm])(&st(0), FPU_gettag0()); } static FUNC_ST0 const trig_table_b[] = { - fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos + fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0)fsin, fcos }; -void trig_b(void) +void FPU_trigb(void) { - (trig_table_b[FPU_rm])(&st(0)); + (trig_table_b[FPU_rm])(&st(0), FPU_gettag0()); } diff -urN linux-2.0.39/arch/i386/math-emu/get_address.c linux-2.0.40/arch/i386/math-emu/get_address.c --- linux-2.0.39/arch/i386/math-emu/get_address.c 1994-08-18 22:54:01.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/get_address.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Get the effective address from an FPU instruction. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -19,9 +19,6 @@ #include -#include - -#include #include "fpu_system.h" #include "exception.h" @@ -41,7 +38,7 @@ offsetof(struct info,___edi) }; -#define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info)) +#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info)) static int reg_offset_vm86[] = { offsetof(struct info,___cs), @@ -54,31 +51,35 @@ }; #define VM86_REG_(x) (*(unsigned short *) \ - (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info)) + (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info)) + +/* These are dummy, fs and gs are not saved on the stack. */ +#define ___FS ___ds +#define ___GS ___ds static int reg_offset_pm[] = { offsetof(struct info,___cs), offsetof(struct info,___ds), offsetof(struct info,___es), - offsetof(struct info,___fs), - offsetof(struct info,___gs), + offsetof(struct info,___FS), + offsetof(struct info,___GS), offsetof(struct info,___ss), offsetof(struct info,___ds) }; #define PM_REG_(x) (*(unsigned short *) \ - (reg_offset_pm[((unsigned)x)]+(char *) FPU_info)) + (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info)) /* Decode the SIB byte. This function assumes mod != 0 */ static int sib(int mod, unsigned long *fpu_eip) { - unsigned char ss,index,base; + u_char ss,index,base; long offset; RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - base = get_fs_byte((char *) (*fpu_eip)); /* The SIB byte */ + FPU_get_user(base, (u_char *) (*fpu_eip)); /* The SIB byte */ RE_ENTRANT_CHECK_ON; (*fpu_eip)++; ss = base >> 6; @@ -105,18 +106,22 @@ if (mod == 1) { /* 8 bit signed displacement */ + long displacement; RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - offset += (signed char) get_fs_byte((char *) (*fpu_eip)); + FPU_get_user(displacement, (signed char *) (*fpu_eip)); + offset += displacement; RE_ENTRANT_CHECK_ON; (*fpu_eip)++; } else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ { /* 32 bit displacement */ + long displacement; RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(4); - offset += (signed) get_fs_long((unsigned long *) (*fpu_eip)); + FPU_get_user(displacement, (long *) (*fpu_eip)); + offset += displacement; RE_ENTRANT_CHECK_ON; (*fpu_eip) += 4; } @@ -125,39 +130,61 @@ } -static unsigned long vm86_segment(unsigned char segment, - unsigned short *selector) -{ +static unsigned long vm86_segment(u_char segment, + struct address *addr) +{ segment--; #ifdef PARANOID if ( segment > PREFIX_SS_ ) { EXCEPTION(EX_INTERNAL|0x130); - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } -#endif PARANOID - *selector = VM86_REG_(segment); +#endif /* PARANOID */ + addr->selector = VM86_REG_(segment); return (unsigned long)VM86_REG_(segment) << 4; } /* This should work for 16 and 32 bit protected mode. */ -static long pm_address(unsigned char FPU_modrm, unsigned char segment, - unsigned short *selector, long offset) +static long pm_address(u_char FPU_modrm, u_char segment, + struct address *addr, long offset) { struct desc_struct descriptor; unsigned long base_address, limit, address, seg_top; + unsigned short selector; segment--; + #ifdef PARANOID + /* segment is unsigned, so this also detects if segment was 0: */ if ( segment > PREFIX_SS_ ) { EXCEPTION(EX_INTERNAL|0x132); - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } -#endif PARANOID +#endif /* PARANOID */ - *selector = PM_REG_(segment); + switch ( segment ) + { + /* fs and gs aren't used by the kernel, so they still have their + user-space values. */ + case PREFIX_FS_-1: + /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register + in the assembler statement. */ + + __asm__("mov %%fs,%0":"=r" (selector)); + addr->selector = selector; + break; + case PREFIX_GS_-1: + /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register + in the assembler statement. */ + __asm__("mov %%gs,%0":"=r" (selector)); + addr->selector = selector; + break; + default: + addr->selector = PM_REG_(segment); + } descriptor = LDT_DESCRIPTOR(PM_REG_(segment)); base_address = SEG_BASE_ADDR(descriptor); @@ -211,12 +238,11 @@ */ -void *get_address(unsigned char FPU_modrm, unsigned long *fpu_eip, +void *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, struct address *addr, -/* unsigned short *selector, unsigned long *offset, */ fpu_addr_modes addr_modes) { - unsigned char mod; + u_char mod; unsigned rm = FPU_modrm & 7; long *cpu_reg_ptr; int address = 0; /* Initialized just to stop compiler warnings. */ @@ -226,7 +252,7 @@ if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) && (addr_modes.override.segment == PREFIX_CS_) ) { - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ @@ -248,7 +274,7 @@ /* Special case: disp32 */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(4); - address = get_fs_long((unsigned long *) (*fpu_eip)); + FPU_get_user(address, (unsigned long *) (*fpu_eip)); (*fpu_eip) += 4; RE_ENTRANT_CHECK_ON; addr->offset = address; @@ -265,7 +291,7 @@ /* 8 bit signed displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - address = (signed char) get_fs_byte((char *) (*fpu_eip)); + FPU_get_user(address, (signed char *) (*fpu_eip)); RE_ENTRANT_CHECK_ON; (*fpu_eip)++; break; @@ -273,7 +299,7 @@ /* 32 bit displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(4); - address = (signed) get_fs_long((unsigned long *) (*fpu_eip)); + FPU_get_user(address, (long *) (*fpu_eip)); (*fpu_eip) += 4; RE_ENTRANT_CHECK_ON; break; @@ -291,13 +317,12 @@ case 0: break; case VM86: - address += vm86_segment(addr_modes.override.segment, - (unsigned short *)&(addr->selector)); + address += vm86_segment(addr_modes.override.segment, addr); break; case PM16: case SEG32: address = pm_address(FPU_modrm, addr_modes.override.segment, - (unsigned short *)&(addr->selector), address); + addr, address); break; default: EXCEPTION(EX_INTERNAL|0x133); @@ -307,12 +332,11 @@ } -void *get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip, +void *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, struct address *addr, -/* unsigned short *selector, unsigned long *offset, */ fpu_addr_modes addr_modes) { - unsigned char mod; + u_char mod; unsigned rm = FPU_modrm & 7; int address = 0; /* Default used for mod == 0 */ @@ -321,7 +345,7 @@ if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) && (addr_modes.override.segment == PREFIX_CS_) ) { - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ @@ -336,7 +360,7 @@ /* Special case: disp16 */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(2); - address = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip)); + FPU_get_user(address, (unsigned short *) (*fpu_eip)); (*fpu_eip) += 2; RE_ENTRANT_CHECK_ON; goto add_segment; @@ -346,7 +370,7 @@ /* 8 bit signed displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(1); - address = (signed char) get_fs_byte((signed char *) (*fpu_eip)); + FPU_get_user(address, (signed char *) (*fpu_eip)); RE_ENTRANT_CHECK_ON; (*fpu_eip)++; break; @@ -354,7 +378,7 @@ /* 16 bit displacement */ RE_ENTRANT_CHECK_OFF; FPU_code_verify_area(2); - address = (unsigned) get_fs_word((unsigned short *) (*fpu_eip)); + FPU_get_user(address, (unsigned short *) (*fpu_eip)); (*fpu_eip) += 2; RE_ENTRANT_CHECK_ON; break; @@ -407,13 +431,12 @@ case 0: break; case VM86: - address += vm86_segment(addr_modes.override.segment, - (unsigned short *)&(addr->selector)); + address += vm86_segment(addr_modes.override.segment, addr); break; case PM16: case SEG32: address = pm_address(FPU_modrm, addr_modes.override.segment, - (unsigned short *)&(addr->selector), address); + addr, address); break; default: EXCEPTION(EX_INTERNAL|0x131); diff -urN linux-2.0.39/arch/i386/math-emu/load_store.c linux-2.0.40/arch/i386/math-emu/load_store.c --- linux-2.0.39/arch/i386/math-emu/load_store.c 1994-06-02 00:28:26.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/load_store.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,9 +4,9 @@ | This file contains most of the code to interpret the FPU instructions | | which load and store from user memory. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1997,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -18,8 +18,6 @@ | other processes using the emulator while swapping is in progress. | +---------------------------------------------------------------------------*/ -#include - #include "fpu_system.h" #include "exception.h" #include "fpu_emu.h" @@ -32,10 +30,10 @@ #define _PUSH_ 3 /* Need to check for space to push onto stack */ #define _null_ 4 /* Function illegal or not implemented */ -#define pop_0() { st0_ptr->tag = TW_Empty; top++; } +#define pop_0() { FPU_settag0(TAG_Empty); FPU_top++; } -static unsigned char const type_table[32] = { +static u_char const type_table[32] = { _PUSH_, _PUSH_, _PUSH_, _PUSH_, _null_, _null_, _null_, _null_, _REG0_, _REG0_, _REG0_, _REG0_, @@ -46,25 +44,27 @@ _NONE_, _REG0_, _NONE_, _REG0_ }; -unsigned char const data_sizes_16[32] = { +u_char const data_sizes_16[32] = { 4, 4, 8, 2, 0, 0, 0, 0, 4, 4, 8, 2, 4, 4, 8, 2, 14, 0, 94, 10, 2, 10, 0, 8, 14, 0, 94, 10, 2, 10, 2, 8 }; -unsigned char const data_sizes_32[32] = { +u_char const data_sizes_32[32] = { 4, 4, 8, 2, 0, 0, 0, 0, 4, 4, 8, 2, 4, 4, 8, 2, 28, 0,108, 10, 2, 10, 0, 8, 28, 0,108, 10, 2, 10, 2, 8 }; -int load_store_instr(unsigned char type, fpu_addr_modes addr_modes, +int FPU_load_store(u_char type, fpu_addr_modes addr_modes, void *data_address) { FPU_REG loaded_data; FPU_REG *st0_ptr; + u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */ + u_char loaded_tag; st0_ptr = NULL; /* Initialized just to stop compiler warnings. */ @@ -73,17 +73,17 @@ if ( addr_modes.default_mode == SEG32 ) { if ( access_limit < data_sizes_32[type] ) - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } else if ( addr_modes.default_mode == PM16 ) { if ( access_limit < data_sizes_16[type] ) - math_abort(FPU_info,SIGSEGV); + math_abort(SIGSEGV); } #ifdef PARANOID else EXCEPTION(EX_INTERNAL|0x140); -#endif PARANOID +#endif /* PARANOID */ } switch ( type_table[type] ) @@ -93,13 +93,14 @@ case _REG0_: st0_ptr = &st(0); /* Some of these instructions pop after storing */ + st0_tag = FPU_gettag0(); break; case _PUSH_: { - st0_ptr = &st(-1); - if ( st0_ptr->tag != TW_Empty ) - { stack_overflow(); return 0; } - top--; + if ( FPU_gettagi(-1) != TAG_Empty ) + { FPU_stack_overflow(); return 0; } + FPU_top--; + st0_ptr = &st(0); } break; case _null_: @@ -109,99 +110,104 @@ default: EXCEPTION(EX_INTERNAL|0x141); return 0; -#endif PARANOID +#endif /* PARANOID */ } switch ( type ) { case 000: /* fld m32real */ clear_C1(); - reg_load_single((float *)data_address, &loaded_data); - if ( (loaded_data.tag == TW_NaN) && - real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) ) + loaded_tag = FPU_load_single((float *)data_address, &loaded_data); + if ( (loaded_tag == TAG_Special) + && isNaN(&loaded_data) + && (real_1op_NaN(&loaded_data) < 0) ) { - top++; + FPU_top++; break; } - reg_move(&loaded_data, st0_ptr); + FPU_copy_to_reg0(&loaded_data, loaded_tag); break; case 001: /* fild m32int */ clear_C1(); - reg_load_int32((long *)data_address, st0_ptr); + loaded_tag = FPU_load_int32((long *)data_address, &loaded_data); + FPU_copy_to_reg0(&loaded_data, loaded_tag); break; case 002: /* fld m64real */ clear_C1(); - reg_load_double((double *)data_address, &loaded_data); - if ( (loaded_data.tag == TW_NaN) && - real_2op_NaN(&loaded_data, &loaded_data, &loaded_data) ) + loaded_tag = FPU_load_double((double *)data_address, &loaded_data); + if ( (loaded_tag == TAG_Special) + && isNaN(&loaded_data) + && (real_1op_NaN(&loaded_data) < 0) ) { - top++; + FPU_top++; break; } - reg_move(&loaded_data, st0_ptr); + FPU_copy_to_reg0(&loaded_data, loaded_tag); break; case 003: /* fild m16int */ clear_C1(); - reg_load_int16((short *)data_address, st0_ptr); + loaded_tag = FPU_load_int16((short *)data_address, &loaded_data); + FPU_copy_to_reg0(&loaded_data, loaded_tag); break; case 010: /* fst m32real */ clear_C1(); - reg_store_single((float *)data_address, st0_ptr); + FPU_store_single(st0_ptr, st0_tag, (float *)data_address); break; case 011: /* fist m32int */ clear_C1(); - reg_store_int32((long *)data_address, st0_ptr); + FPU_store_int32(st0_ptr, st0_tag, (long *)data_address); break; case 012: /* fst m64real */ clear_C1(); - reg_store_double((double *)data_address, st0_ptr); + FPU_store_double(st0_ptr, st0_tag, (double *)data_address); break; case 013: /* fist m16int */ clear_C1(); - reg_store_int16((short *)data_address, st0_ptr); + FPU_store_int16(st0_ptr, st0_tag, (short *)data_address); break; case 014: /* fstp m32real */ clear_C1(); - if ( reg_store_single((float *)data_address, st0_ptr) ) + if ( FPU_store_single(st0_ptr, st0_tag, (float *)data_address) ) 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((long *)data_address, st0_ptr) ) + if ( FPU_store_int32(st0_ptr, st0_tag, (long *)data_address) ) 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((double *)data_address, st0_ptr) ) + if ( FPU_store_double(st0_ptr, st0_tag, (double *)data_address) ) 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((short *)data_address, st0_ptr) ) + if ( FPU_store_int16(st0_ptr, st0_tag, (short *)data_address) ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 020: /* fldenv m14/28byte */ - fldenv(addr_modes, (char *)data_address); + fldenv(addr_modes, (u_char *)data_address); /* Ensure that the values just loaded are not changed by fix-up operations. */ return 1; case 022: /* frstor m94/108byte */ - frstor(addr_modes, (char *)data_address); + frstor(addr_modes, (u_char *)data_address); /* Ensure that the values just loaded are not changed by fix-up operations. */ return 1; case 023: /* fbld m80dec */ clear_C1(); - reg_load_bcd((char *)data_address, st0_ptr); + loaded_tag = FPU_load_bcd((u_char *)data_address); + FPU_settag0(loaded_tag); break; case 024: /* fldcw */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, data_address, 2); - control_word = get_fs_word((unsigned short *) data_address); + FPU_get_user(control_word, (unsigned short *) data_address); RE_ENTRANT_CHECK_ON; if ( partial_status & ~control_word & CW_Exceptions ) partial_status |= (SW_Summary | SW_Backward); @@ -209,49 +215,51 @@ partial_status &= ~(SW_Summary | SW_Backward); #ifdef PECULIAR_486 control_word |= 0x40; /* An 80486 appears to always set this bit */ -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ return 1; case 025: /* fld m80real */ clear_C1(); - reg_load_extended((long double *)data_address, st0_ptr); + loaded_tag = FPU_load_extended((long double *)data_address, 0); + FPU_settag0(loaded_tag); break; case 027: /* fild m64int */ clear_C1(); - reg_load_int64((long long *)data_address, st0_ptr); + loaded_tag = FPU_load_int64((long long *)data_address); + FPU_settag0(loaded_tag); break; case 030: /* fstenv m14/28byte */ - fstenv(addr_modes, (char *)data_address); + fstenv(addr_modes, (u_char *)data_address); return 1; case 032: /* fsave */ - fsave(addr_modes, (char *)data_address); + fsave(addr_modes, (u_char *)data_address); return 1; case 033: /* fbstp m80dec */ clear_C1(); - if ( reg_store_bcd((char *)data_address, st0_ptr) ) + if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char *)data_address) ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 034: /* fstcw m16int */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,data_address,2); - put_fs_word(control_word, (short *) data_address); + FPU_put_user(control_word, (unsigned short *) data_address); RE_ENTRANT_CHECK_ON; return 1; case 035: /* fstp m80real */ clear_C1(); - if ( reg_store_extended((long double *)data_address, st0_ptr) ) + if ( FPU_store_extended(st0_ptr, st0_tag, (long double *)data_address) ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; case 036: /* fstsw m2byte */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,data_address,2); - put_fs_word(status_word(),(short *) data_address); + FPU_put_user(status_word(),(unsigned short *) data_address); RE_ENTRANT_CHECK_ON; return 1; case 037: /* fistp m64int */ clear_C1(); - if ( reg_store_int64((long long *)data_address, st0_ptr) ) + if ( FPU_store_int64(st0_ptr, st0_tag, (long long *)data_address) ) pop_0(); /* pop only if the number was actually stored (see the 80486 manual p16-28) */ break; diff -urN linux-2.0.39/arch/i386/math-emu/poly.h linux-2.0.40/arch/i386/math-emu/poly.h --- linux-2.0.39/arch/i386/math-emu/poly.h 1994-07-31 22:19:14.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/poly.h 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Header file for the FPU-emu poly*.c source files. | | | - | Copyright (C) 1994 | + | Copyright (C) 1994,1999 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | | Declarations and definitions for functions operating on Xsig (12-byte | | extended-significand) quantities. | @@ -55,15 +55,20 @@ actually be in-line. */ -/* Multiply two fixed-point 32 bit numbers. */ -extern inline void mul_32_32(const unsigned long arg1, - const unsigned long arg2, - unsigned long *out) +/* Multiply two fixed-point 32 bit numbers, producing a 32 bit result. + The answer is the ms word of the product. */ +/* Some versions of gcc make it difficult to stop eax from being clobbered. + Merely specifying that it is used doesn't work... + */ +extern inline unsigned long mul_32_32(const unsigned long arg1, + const unsigned long arg2) { - asm volatile ("movl %1,%%eax; mull %2; movl %%edx,%0" \ - :"=g" (*out) \ - :"g" (arg1), "g" (arg2) \ - :"ax","dx"); + int retval; + asm volatile ("mull %2; movl %%edx,%%eax" \ + :"=a" (retval) \ + :"0" (arg1), "g" (arg2) \ + :"dx"); + return retval; } @@ -83,7 +88,7 @@ /* Note: the constraints in the asm statement didn't always work properly with gcc 2.5.8. Changing from using edi to using ecx got around the problem, but keep fingers crossed! */ -extern inline int add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) +extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) { asm volatile ("movl %2,%%ecx; movl %3,%%esi; movl (%%esi),%%eax; addl %%eax,(%%ecx); @@ -113,4 +118,4 @@ :"=g" (*x):"g" (x):"si","ax","cx"); } -#endif _POLY_H +#endif /* _POLY_H */ diff -urN linux-2.0.39/arch/i386/math-emu/poly_2xm1.c linux-2.0.40/arch/i386/math-emu/poly_2xm1.c --- linux-2.0.39/arch/i386/math-emu/poly_2xm1.c 1994-07-31 22:19:14.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/poly_2xm1.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Function to compute 2^x-1 by a polynomial approximation. | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -13,6 +13,7 @@ #include "exception.h" #include "reg_constant.h" #include "fpu_emu.h" +#include "fpu_system.h" #include "control_w.h" #include "poly.h" @@ -48,26 +49,25 @@ /*--- poly_2xm1() -----------------------------------------------------------+ - | Requires an argument which is TW_Valid and < 1. | + | Requires st(0) which is TAG_Valid and < 1. | +---------------------------------------------------------------------------*/ -int poly_2xm1(FPU_REG const *arg, FPU_REG *result) +int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result) { - long int exponent, shift; - unsigned long long Xll; - Xsig accumulator, Denom, argSignif; + long int exponent, shift; + unsigned long long Xll; + Xsig accumulator, Denom, argSignif; + u_char tag; - - exponent = arg->exp - EXP_BIAS; + exponent = exponent16(arg); #ifdef PARANOID - if ( (exponent >= 0) /* Don't want a |number| >= 1.0 */ - || (arg->tag != TW_Valid) ) + if ( exponent >= 0 ) /* Don't want a |number| >= 1.0 */ { /* Number negative, too large, or not Valid. */ EXCEPTION(EX_INTERNAL|0x127); return 1; } -#endif PARANOID +#endif /* PARANOID */ argSignif.lsw = 0; XSIG_LL(argSignif) = Xll = significand(arg); @@ -94,7 +94,7 @@ if ( exponent < -2 ) { /* Shift the argument right by the required places. */ - if ( shrx(&Xll, -2-exponent) >= 0x80000000U ) + if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U ) Xll++; /* round up */ } @@ -118,7 +118,7 @@ exponent = 1; } - if ( arg->sign != SIGN_POS ) + if ( sign != SIGN_POS ) { /* The argument is negative, use the identity: f(-x) = -f(x) / (1 + f(x)) @@ -142,10 +142,14 @@ /* Convert to 64 bit signed-compatible */ exponent += round_Xsig(&accumulator); + result = &st(0); significand(result) = XSIG_LL(accumulator); - result->tag = TW_Valid; - result->exp = exponent + EXP_BIAS; - result->sign = arg->sign; + setexponent16(result, exponent); + + tag = FPU_round(result, 1, 0, FULL_PRECISION, sign); + + setsign(result, sign); + FPU_settag0(tag); return 0; diff -urN linux-2.0.39/arch/i386/math-emu/poly_atan.c linux-2.0.40/arch/i386/math-emu/poly_atan.c --- linux-2.0.39/arch/i386/math-emu/poly_atan.c 1994-07-31 22:19:14.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/poly_atan.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Compute the arctan of a FPU_REG, using a polynomial approximation. | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -13,6 +13,7 @@ #include "exception.h" #include "reg_constant.h" #include "fpu_emu.h" +#include "fpu_system.h" #include "status_w.h" #include "control_w.h" #include "poly.h" @@ -51,31 +52,57 @@ /*--- poly_atan() -----------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ -void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result) +void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, + FPU_REG *st1_ptr, u_char st1_tag) { - char transformed, inverted, - sign1 = arg1->sign, sign2 = arg2->sign; - long int exponent, dummy_exp; - Xsig accumulator, Numer, Denom, accumulatore, argSignif, - argSq, argSqSq; + u_char transformed, inverted, + sign1, sign2; + int exponent; + long int dummy_exp; + Xsig accumulator, Numer, Denom, accumulatore, argSignif, + argSq, argSqSq; + u_char tag; + sign1 = getsign(st0_ptr); + sign2 = getsign(st1_ptr); + if ( st0_tag == TAG_Valid ) + { + exponent = exponent(st0_ptr); + } + else + { + /* This gives non-compatible stack contents... */ + FPU_to_exp16(st0_ptr, st0_ptr); + exponent = exponent16(st0_ptr); + } + if ( st1_tag == TAG_Valid ) + { + exponent -= exponent(st1_ptr); + } + else + { + /* This gives non-compatible stack contents... */ + FPU_to_exp16(st1_ptr, st1_ptr); + exponent -= exponent16(st1_ptr); + } - arg1->sign = arg2->sign = SIGN_POS; - if ( (compare(arg2) & ~COMP_Denormal) == COMP_A_lt_B ) + if ( (exponent < 0) || ((exponent == 0) && + ((st0_ptr->sigh < st1_ptr->sigh) || + ((st0_ptr->sigh == st1_ptr->sigh) && + (st0_ptr->sigl < st1_ptr->sigl))) ) ) { inverted = 1; - exponent = arg1->exp - arg2->exp; Numer.lsw = Denom.lsw = 0; - XSIG_LL(Numer) = significand(arg1); - XSIG_LL(Denom) = significand(arg2); + XSIG_LL(Numer) = significand(st0_ptr); + XSIG_LL(Denom) = significand(st1_ptr); } else { inverted = 0; - exponent = arg2->exp - arg1->exp; + exponent = -exponent; Numer.lsw = Denom.lsw = 0; - XSIG_LL(Numer) = significand(arg2); - XSIG_LL(Denom) = significand(arg1); + XSIG_LL(Numer) = significand(st1_ptr); + XSIG_LL(Denom) = significand(st0_ptr); } div_Xsig(&Numer, &Denom, &argSignif); exponent += norm_Xsig(&argSignif); @@ -97,7 +124,7 @@ EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ return; } -#endif PARANOID +#endif /* PARANOID */ argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ } else @@ -189,9 +216,14 @@ } exponent += round_Xsig(&accumulator); - significand(result) = XSIG_LL(accumulator); - result->exp = exponent + EXP_BIAS; - result->tag = TW_Valid; - result->sign = sign2; + + significand(st1_ptr) = XSIG_LL(accumulator); + setexponent16(st1_ptr, exponent); + + tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2); + FPU_settagi(1, tag); + + set_precision_flag_up(); /* We do not really know if up or down, + use this as the default. */ } diff -urN linux-2.0.39/arch/i386/math-emu/poly_l2.c linux-2.0.40/arch/i386/math-emu/poly_l2.c --- linux-2.0.39/arch/i386/math-emu/poly_l2.c 1994-07-31 22:19:14.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/poly_l2.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Compute the base 2 log of a FPU_REG, using a polynomial approximation. | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -14,96 +14,101 @@ #include "exception.h" #include "reg_constant.h" #include "fpu_emu.h" +#include "fpu_system.h" #include "control_w.h" #include "poly.h" - -static void log2_kernel(FPU_REG const *arg, +static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result, long int *expon); /*--- poly_l2() -------------------------------------------------------------+ | Base 2 logarithm by a polynomial approximation. | +---------------------------------------------------------------------------*/ -void poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result) +void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign) { long int exponent, expon, expon_expon; Xsig accumulator, expon_accum, yaccum; - char sign; + u_char sign, argsign; FPU_REG x; + int tag; + exponent = exponent16(st0_ptr); - exponent = arg->exp - EXP_BIAS; - - /* From arg, make a number > sqrt(2)/2 and < sqrt(2) */ - if ( arg->sigh > (unsigned)0xb504f334 ) + /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */ + if ( st0_ptr->sigh > (unsigned)0xb504f334 ) { - /* Treat as sqrt(2)/2 < arg < 1 */ - significand(&x) = - significand(arg); - x.sign = SIGN_NEG; - x.tag = TW_Valid; - x.exp = EXP_BIAS-1; + /* Treat as sqrt(2)/2 < st0_ptr < 1 */ + significand(&x) = - significand(st0_ptr); + setexponent16(&x, -1); exponent++; - normalize(&x); + argsign = SIGN_NEG; } else { - /* Treat as 1 <= arg < sqrt(2) */ - x.sigh = arg->sigh - 0x80000000; - x.sigl = arg->sigl; - x.sign = SIGN_POS; - x.tag = TW_Valid; - x.exp = EXP_BIAS; - normalize(&x); + /* Treat as 1 <= st0_ptr < sqrt(2) */ + x.sigh = st0_ptr->sigh - 0x80000000; + x.sigl = st0_ptr->sigl; + setexponent16(&x, 0); + argsign = SIGN_POS; } + tag = FPU_normalize_nuo(&x); - if ( x.tag == TW_Zero ) + if ( tag == TAG_Zero ) { expon = 0; accumulator.msw = accumulator.midw = accumulator.lsw = 0; } else { - log2_kernel(&x, &accumulator, &expon); + log2_kernel(&x, argsign, &accumulator, &expon); } - sign = exponent < 0; - if ( sign ) exponent = -exponent; + if ( exponent < 0 ) + { + sign = SIGN_NEG; + exponent = -exponent; + } + else + sign = SIGN_POS; expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0; if ( exponent ) { expon_expon = 31 + norm_Xsig(&expon_accum); shr_Xsig(&accumulator, expon_expon - expon); - if ( sign ^ (x.sign == SIGN_NEG) ) + if ( sign ^ argsign ) negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &expon_accum); } else { expon_expon = expon; - sign = x.sign; + sign = argsign; } - yaccum.lsw = 0; XSIG_LL(yaccum) = significand(y); + yaccum.lsw = 0; XSIG_LL(yaccum) = significand(st1_ptr); mul_Xsig_Xsig(&accumulator, &yaccum); expon_expon += round_Xsig(&accumulator); if ( accumulator.msw == 0 ) { - reg_move(&CONST_Z, y); - } - else - { - result->exp = expon_expon + y->exp + 1; - significand(result) = XSIG_LL(accumulator); - result->tag = TW_Valid; /* set the tags to Valid */ - result->sign = sign ^ y->sign; + FPU_copy_to_reg1(&CONST_Z, TAG_Zero); + return; } + significand(st1_ptr) = XSIG_LL(accumulator); + setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1); + + tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign); + FPU_settagi(1, tag); + + set_precision_flag_up(); /* 80486 appears to always do this */ + return; + } @@ -111,47 +116,62 @@ | Base 2 logarithm by a polynomial approximation. | | log2(x+1) | +---------------------------------------------------------------------------*/ -int poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result) +int poly_l2p1(u_char sign0, u_char sign1, + FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest) { - char sign; - long int exponent; - Xsig accumulator, yaccum; + u_char tag; + long int exponent; + Xsig accumulator, yaccum; - - sign = arg->sign; - - if ( arg->exp < EXP_BIAS ) + if ( exponent16(st0_ptr) < 0 ) { - log2_kernel(arg, &accumulator, &exponent); + log2_kernel(st0_ptr, sign0, &accumulator, &exponent); yaccum.lsw = 0; - XSIG_LL(yaccum) = significand(y); + XSIG_LL(yaccum) = significand(st1_ptr); mul_Xsig_Xsig(&accumulator, &yaccum); exponent += round_Xsig(&accumulator); - result->exp = exponent + y->exp + 1; - significand(result) = XSIG_LL(accumulator); - result->tag = TW_Valid; /* set the tags to Valid */ - result->sign = sign ^ y->sign; + exponent += exponent16(st1_ptr) + 1; + if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER; + + significand(dest) = XSIG_LL(accumulator); + setexponent16(dest, exponent); - return 0; + tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1); + FPU_settagi(1, tag); + + if ( tag == TAG_Valid ) + set_precision_flag_up(); /* 80486 appears to always do this */ } else { - /* The magnitude of arg is far too large. */ - reg_move(y, result); - if ( sign != SIGN_POS ) + /* The magnitude of st0_ptr is far too large. */ + + if ( sign0 != SIGN_POS ) { /* Trying to get the log of a negative number. */ - return 1; +#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ + changesign(st1_ptr); +#else + if ( arith_invalid(1) < 0 ) + return 1; +#endif /* PECULIAR_486 */ } + + /* 80486 appears to do this */ + if ( sign0 == SIGN_NEG ) + set_precision_flag_down(); else - { - return 0; - } + set_precision_flag_up(); } + if ( exponent(dest) <= EXP_UNDER ) + EXCEPTION(EX_Underflow); + + return 0; + } @@ -180,20 +200,17 @@ | Base 2 logarithm by a polynomial approximation. | | log2(x+1) | +---------------------------------------------------------------------------*/ -static void log2_kernel(FPU_REG const *arg, Xsig *accum_result, +static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result, long int *expon) { - char sign; long int exponent, adj; unsigned long long Xsq; Xsig accumulator, Numer, Denom, argSignif, arg_signif; - sign = arg->sign; - - exponent = arg->exp - EXP_BIAS; + exponent = exponent16(arg); Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg); - if ( sign == SIGN_POS ) + if ( argsign == SIGN_POS ) { shr_Xsig(&Denom, 2 - (1 + exponent)); Denom.msw |= 0x80000000; @@ -226,7 +243,7 @@ /* The argument is too large */ } } -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif); adj = norm_Xsig(&argSignif); diff -urN linux-2.0.39/arch/i386/math-emu/poly_sin.c linux-2.0.40/arch/i386/math-emu/poly_sin.c --- linux-2.0.39/arch/i386/math-emu/poly_sin.c 1994-07-31 22:19:15.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/poly_sin.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,9 +4,9 @@ | Computation of an approximation of the sin function and the cosine | | function by a polynomial. | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1997,1999 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -15,6 +15,7 @@ #include "exception.h" #include "reg_constant.h" #include "fpu_emu.h" +#include "fpu_system.h" #include "control_w.h" #include "poly.h" @@ -62,35 +63,26 @@ /*--- poly_sine() -----------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ -void poly_sine(FPU_REG const *arg, FPU_REG *result) +void poly_sine(FPU_REG *st0_ptr) { int exponent, echange; Xsig accumulator, argSqrd, argTo4; unsigned long fix_up, adj; unsigned long long fixed_arg; + FPU_REG result; - -#ifdef PARANOID - if ( arg->tag == TW_Zero ) - { - /* Return 0.0 */ - reg_move(&CONST_Z, result); - return; - } -#endif PARANOID - - exponent = arg->exp - EXP_BIAS; + exponent = exponent(st0_ptr); accumulator.lsw = accumulator.midw = accumulator.msw = 0; /* Split into two ranges, for arguments below and above 1.0 */ /* The boundary between upper and lower is approx 0.88309101259 */ - if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xe21240aa)) ) + if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) ) { /* The argument is <= 0.88309101259 */ - argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0; - mul64_Xsig(&argSqrd, &significand(arg)); + argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0; + mul64_Xsig(&argSqrd, &significand(st0_ptr)); shr_Xsig(&argSqrd, 2*(-1-exponent)); argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; @@ -107,29 +99,29 @@ shr_Xsig(&accumulator, 2); /* Divide by four */ accumulator.msw |= 0x80000000; /* Add 1.0 */ - mul64_Xsig(&accumulator, &significand(arg)); - mul64_Xsig(&accumulator, &significand(arg)); - mul64_Xsig(&accumulator, &significand(arg)); + mul64_Xsig(&accumulator, &significand(st0_ptr)); + mul64_Xsig(&accumulator, &significand(st0_ptr)); + mul64_Xsig(&accumulator, &significand(st0_ptr)); /* Divide by four, FPU_REG compatible, etc */ - exponent = 3*exponent + EXP_BIAS; + exponent = 3*exponent; /* The minimum exponent difference is 3 */ - shr_Xsig(&accumulator, arg->exp - exponent); + shr_Xsig(&accumulator, exponent(st0_ptr) - exponent); negate_Xsig(&accumulator); - XSIG_LL(accumulator) += significand(arg); + XSIG_LL(accumulator) += significand(st0_ptr); echange = round_Xsig(&accumulator); - result->exp = arg->exp + echange; + setexponentpos(&result, exponent(st0_ptr) + echange); } else { /* The argument is > 0.88309101259 */ - /* We use sin(arg) = cos(pi/2-arg) */ + /* We use sin(st(0)) = cos(pi/2-st(0)) */ - fixed_arg = significand(arg); + fixed_arg = significand(st0_ptr); if ( exponent == 0 ) { @@ -140,6 +132,9 @@ } /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ fixed_arg = 0x921fb54442d18469LL - fixed_arg; + /* There is a special case which arises due to rounding, to fix here. */ + if ( fixed_arg == 0xffffffffffffffffLL ) + fixed_arg = 0; XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &fixed_arg); @@ -180,10 +175,9 @@ if ( argSqrd.msw & 0xffc00000 ) { /* Get about 32 bit precision in these: */ - mul_32_32(0x898cc517, argSqrd.msw, &adj); - fix_up -= adj/6; + fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6; } - mul_32_32(fix_up, LL_MSW(fixed_arg), &fix_up); + fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg)); adj = accumulator.lsw; /* temp save */ accumulator.lsw -= fix_up; @@ -192,20 +186,20 @@ echange = round_Xsig(&accumulator); - result->exp = EXP_BIAS - 1 + echange; + setexponentpos(&result, echange - 1); } - significand(result) = XSIG_LL(accumulator); - result->tag = TW_Valid; - result->sign = arg->sign; + significand(&result) = XSIG_LL(accumulator); + setsign(&result, getsign(st0_ptr)); + FPU_copy_to_reg0(&result, TAG_Valid); #ifdef PARANOID - if ( (result->exp >= EXP_BIAS) - && (significand(result) > 0x8000000000000000LL) ) + if ( (exponent(&result) >= 0) + && (significand(&result) > 0x8000000000000000LL) ) { EXCEPTION(EX_INTERNAL|0x150); } -#endif PARANOID +#endif /* PARANOID */ } @@ -214,42 +208,35 @@ /*--- poly_cos() ------------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ -void poly_cos(FPU_REG const *arg, FPU_REG *result) +void poly_cos(FPU_REG *st0_ptr) { + FPU_REG result; long int exponent, exp2, echange; Xsig accumulator, argSqrd, fix_up, argTo4; - unsigned long adj; unsigned long long fixed_arg; - #ifdef PARANOID - if ( arg->tag == TW_Zero ) - { - /* Return 1.0 */ - reg_move(&CONST_1, result); - return; - } - - if ( (arg->exp > EXP_BIAS) - || ((arg->exp == EXP_BIAS) - && (significand(arg) > 0xc90fdaa22168c234LL)) ) + if ( (exponent(st0_ptr) > 0) + || ((exponent(st0_ptr) == 0) + && (significand(st0_ptr) > 0xc90fdaa22168c234LL)) ) { EXCEPTION(EX_Invalid); - reg_move(&CONST_QNaN, result); + FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); return; } -#endif PARANOID +#endif /* PARANOID */ - exponent = arg->exp - EXP_BIAS; + exponent = exponent(st0_ptr); accumulator.lsw = accumulator.midw = accumulator.msw = 0; - if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xb00d6f54)) ) + if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) ) { /* arg is < 0.687705 */ - argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0; - mul64_Xsig(&argSqrd, &significand(arg)); + argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; + argSqrd.lsw = 0; + mul64_Xsig(&argSqrd, &significand(st0_ptr)); if ( exponent < -1 ) { @@ -270,8 +257,8 @@ N_COEFF_PH-1); negate_Xsig(&accumulator); - mul64_Xsig(&accumulator, &significand(arg)); - mul64_Xsig(&accumulator, &significand(arg)); + mul64_Xsig(&accumulator, &significand(st0_ptr)); + mul64_Xsig(&accumulator, &significand(st0_ptr)); shr_Xsig(&accumulator, -2*(1+exponent)); shr_Xsig(&accumulator, 3); @@ -290,20 +277,20 @@ if ( accumulator.msw == 0 ) { /* The result is 1.0 */ - reg_move(&CONST_1, result); + FPU_copy_to_reg0(&CONST_1, TAG_Valid); + return; } else { - significand(result) = XSIG_LL(accumulator); + significand(&result) = XSIG_LL(accumulator); /* will be a valid positive nr with expon = -1 */ - *(short *)&(result->sign) = 0; - result->exp = EXP_BIAS - 1; + setexponentpos(&result, -1); } } else { - fixed_arg = significand(arg); + fixed_arg = significand(st0_ptr); if ( exponent == 0 ) { @@ -314,6 +301,9 @@ } /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ fixed_arg = 0x921fb54442d18469LL - fixed_arg; + /* There is a special case which arises due to rounding, to fix here. */ + if ( fixed_arg == 0xffffffffffffffffLL ) + fixed_arg = 0; exponent = -1; exp2 = -1; @@ -377,10 +367,8 @@ if ( argSqrd.msw & 0xffc00000 ) { /* Get about 32 bit precision in these: */ - mul_32_32(0x898cc517, argSqrd.msw, &adj); - fix_up.msw -= adj/2; - mul_32_32(0x898cc517, argTo4.msw, &adj); - fix_up.msw += adj/24; + fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2; + fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24; } exp2 += norm_Xsig(&accumulator); @@ -392,17 +380,18 @@ echange = round_Xsig(&accumulator); - result->exp = exp2 + EXP_BIAS + echange; - *(short *)&(result->sign) = 0; /* Is a valid positive nr */ - significand(result) = XSIG_LL(accumulator); + setexponentpos(&result, exp2 + echange); + significand(&result) = XSIG_LL(accumulator); } + FPU_copy_to_reg0(&result, TAG_Valid); + #ifdef PARANOID - if ( (result->exp >= EXP_BIAS) - && (significand(result) > 0x8000000000000000LL) ) + if ( (exponent(&result) >= 0) + && (significand(&result) > 0x8000000000000000LL) ) { EXCEPTION(EX_INTERNAL|0x151); } -#endif PARANOID +#endif /* PARANOID */ } diff -urN linux-2.0.39/arch/i386/math-emu/poly_tan.c linux-2.0.40/arch/i386/math-emu/poly_tan.c --- linux-2.0.39/arch/i386/math-emu/poly_tan.c 1994-08-18 22:54:01.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/poly_tan.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Compute the tan of a FPU_REG, using a polynomial approximation. | | | - | Copyright (C) 1992,1993,1994 | + | Copyright (C) 1992,1993,1994,1997,1999 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -13,6 +13,7 @@ #include "exception.h" #include "reg_constant.h" #include "fpu_emu.h" +#include "fpu_system.h" #include "control_w.h" #include "poly.h" @@ -52,7 +53,7 @@ /*--- poly_tan() ------------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ -void poly_tan(FPU_REG const *arg, FPU_REG *result) +void poly_tan(FPU_REG *st0_ptr) { long int exponent; int invert; @@ -60,20 +61,20 @@ argSignif, fix_up; unsigned long adj; - exponent = arg->exp - EXP_BIAS; + exponent = exponent(st0_ptr); #ifdef PARANOID - if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */ - { arith_invalid(result); return; } /* Need a positive number */ -#endif PARANOID + if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */ + { arith_invalid(0); return; } /* Need a positive number */ +#endif /* PARANOID */ /* Split the problem into two domains, smaller and larger than pi/4 */ - if ( (exponent == 0) || ((exponent == -1) && (arg->sigh > 0xc90fdaa2)) ) + if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) ) { /* The argument is greater than (approx) pi/4 */ invert = 1; accum.lsw = 0; - XSIG_LL(accum) = significand(arg); + XSIG_LL(accum) = significand(st0_ptr); if ( exponent == 0 ) { @@ -83,6 +84,14 @@ } /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum); + /* This is a special case which arises due to rounding. */ + if ( XSIG_LL(accum) == 0xffffffffffffffffLL ) + { + FPU_settag0(TAG_Valid); + significand(st0_ptr) = 0x8a51e04daabda360LL; + setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative); + return; + } argSignif.lsw = accum.lsw; XSIG_LL(argSignif) = XSIG_LL(accum); @@ -92,12 +101,12 @@ { invert = 0; argSignif.lsw = 0; - XSIG_LL(accum) = XSIG_LL(argSignif) = significand(arg); + XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr); if ( exponent < -1 ) { /* shift the argument right by the required places */ - if ( shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U ) + if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U ) XSIG_LL(accum) ++; /* round up */ } } @@ -176,11 +185,11 @@ else if ( exponent > -30 ) { adj = accum.msw >> -(exponent+1); /* tan */ - mul_32_32(adj, adj, &adj); /* tan^2 */ + adj = mul_32_32(adj, adj); /* tan^2 */ } else adj = 0; - mul_32_32(0x898cc517, adj, &adj); /* delta * tan^2 */ + adj = mul_32_32(0x898cc517, adj); /* delta * tan^2 */ fix_up.msw += adj; if ( !(fix_up.msw & 0x80000000) ) /* did fix_up overflow ? */ @@ -206,8 +215,8 @@ /* Transfer the result */ round_Xsig(&accum); - *(short *)&(result->sign) = 0; - significand(result) = XSIG_LL(accum); - result->exp = EXP_BIAS + exponent; + FPU_settag0(TAG_Valid); + significand(st0_ptr) = XSIG_LL(accum); + setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */ } diff -urN linux-2.0.39/arch/i386/math-emu/reg_add_sub.c linux-2.0.40/arch/i386/math-emu/reg_add_sub.c --- linux-2.0.39/arch/i386/math-emu/reg_add_sub.c 1993-12-01 04:44:16.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_add_sub.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,16 +3,19 @@ | | | Functions to add or subtract two registers and put the result in a third. | | | - | Copyright (C) 1992,1993 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ - | For each function, the destination may be any FPU_REG, including one of | + | For each function, the destination may be any FPU_REG, including one of | | the source FPU_REGs. | + | Each function returns 0 if the answer is o.k., otherwise a non-zero | + | value is returned, indicating either an exception condition or an | + | internal error. | +---------------------------------------------------------------------------*/ #include "exception.h" @@ -21,156 +24,164 @@ #include "control_w.h" #include "fpu_system.h" +static +int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, + FPU_REG const *b, u_char tagb, u_char signb, + FPU_REG *dest, int deststnr, int control_w); -int reg_add(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w) +/* + Operates on st(0) and st(n), or on st(0) and temporary data. + The destination must be one of the source st(x). + */ +int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w) { - char saved_sign = dest->sign; - int diff; + FPU_REG *a = &st(0); + FPU_REG *dest = &st(deststnr); + u_char signb = getsign(b); + u_char taga = FPU_gettag0(); + u_char signa = getsign(a); + u_char saved_sign = getsign(dest); + int diff, tag, expa, expb; - if ( !(a->tag | b->tag) ) + if ( !(taga | tagb) ) { + expa = exponent(a); + expb = exponent(b); + + valid_add: /* Both registers are valid */ - if (!(a->sign ^ b->sign)) + if (!(signa ^ signb)) { /* signs are the same */ - dest->sign = a->sign; - if ( reg_u_add(a, b, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } - return 0; + tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb); } - - /* The signs are different, so do a subtraction */ - diff = a->exp - b->exp; - if (!diff) + else { - diff = a->sigh - b->sigh; /* Works only if ms bits are identical */ + /* The signs are different, so do a subtraction */ + diff = expa - expb; if (!diff) { - diff = a->sigl > b->sigl; + diff = a->sigh - b->sigh; /* This works only if the ms bits + are identical. */ if (!diff) - diff = -(a->sigl < b->sigl); - } - } - - if (diff > 0) - { - dest->sign = a->sign; - if ( reg_u_sub(a, b, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } - } - else if ( diff == 0 ) - { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(&CONST_Z, dest); - /* sign depends upon rounding mode */ - dest->sign = ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG; - } - else - { - dest->sign = b->sign; - if ( reg_u_sub(b, a, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } - } - return 0; - } - else - { - if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) ) - { return real_2op_NaN(a, b, dest); } - else if (a->tag == TW_Zero) - { - if (b->tag == TW_Zero) - { - char different_signs = a->sign ^ b->sign; - /* Both are zero, result will be zero. */ - reg_move(a, dest); - if (different_signs) { - /* Signs are different. */ - /* Sign of answer depends upon rounding mode. */ - dest->sign = ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG; + diff = a->sigl > b->sigl; + if (!diff) + diff = -(a->sigl < b->sigl); } } - else + + if (diff > 0) { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(b, dest); + tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb); } - return 0; - } - else if (b->tag == TW_Zero) - { -#ifdef DENORM_OPERAND - if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(a, dest); return 0; - } - else if (a->tag == TW_Infinity) - { - if (b->tag != TW_Infinity) + else if ( diff < 0 ) { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(a, dest); return 0; + tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa); } - if (a->sign == b->sign) + else { - /* They are both + or - infinity */ - reg_move(a, dest); return 0; + FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); + /* sign depends upon rounding mode */ + setsign(dest, ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG); + return TAG_Zero; } - return arith_invalid(dest); /* Infinity-Infinity is undefined. */ } - else if (b->tag == TW_Infinity) + + if ( tag < 0 ) { -#ifdef DENORM_OPERAND - if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(b, dest); return 0; + setsign(dest, saved_sign); + return tag; } + FPU_settagi(deststnr, tag); + return tag; } -#ifdef PARANOID - EXCEPTION(EX_INTERNAL|0x101); -#endif - return 1; + + if ( taga == TAG_Special ) + taga = FPU_Special(a); + if ( tagb == TAG_Special ) + tagb = FPU_Special(b); + + if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) + || ((taga == TW_Denormal) && (tagb == TAG_Valid)) + || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) + { + FPU_REG x, y; + + if ( denormal_operand() < 0 ) + return FPU_Exception; + + FPU_to_exp16(a, &x); + FPU_to_exp16(b, &y); + a = &x; + b = &y; + expa = exponent16(a); + expb = exponent16(b); + goto valid_add; + } + + if ( (taga == TW_NaN) || (tagb == TW_NaN) ) + { + if ( deststnr == 0 ) + return real_2op_NaN(b, tagb, deststnr, a); + else + return real_2op_NaN(a, taga, deststnr, a); + } + + return add_sub_specials(a, taga, signa, b, tagb, signb, + dest, deststnr, control_w); } /* Subtract b from a. (a-b) -> dest */ -int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w) +int FPU_sub(int flags, int rm, int control_w) { - char saved_sign = dest->sign; - int diff; + FPU_REG const *a, *b; + FPU_REG *dest; + u_char taga, tagb, signa, signb, saved_sign, sign; + int diff, tag, expa, expb, deststnr; + + a = &st(0); + taga = FPU_gettag0(); + + deststnr = 0; + if ( flags & LOADED ) + { + b = (FPU_REG *)rm; + tagb = flags & 0x0f; + } + else + { + b = &st(rm); + tagb = FPU_gettagi(rm); + + if ( flags & DEST_RM ) + deststnr = rm; + } + + signa = getsign(a); + signb = getsign(b); + + if ( flags & REV ) + { + signa ^= SIGN_NEG; + signb ^= SIGN_NEG; + } - if ( !(a->tag | b->tag) ) + dest = &st(deststnr); + saved_sign = getsign(dest); + + if ( !(taga | tagb) ) { + expa = exponent(a); + expb = exponent(b); + + valid_subtract: /* Both registers are valid */ - diff = a->exp - b->exp; + + diff = expa - expb; + if (!diff) { diff = a->sigh - b->sigh; /* Works only if ms bits are identical */ @@ -182,137 +193,182 @@ } } - switch (a->sign*2 + b->sign) + switch ( (((int)signa)*2 + signb) / SIGN_NEG ) { case 0: /* P - P */ case 3: /* N - N */ if (diff > 0) { /* |a| > |b| */ - dest->sign = a->sign; - if ( reg_u_sub(a, b, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } - return 0; + tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb); } else if ( diff == 0 ) { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(&CONST_Z, dest); + FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); + /* sign depends upon rounding mode */ - dest->sign = ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG; + setsign(dest, ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG); + return TAG_Zero; } else { - dest->sign = a->sign ^ SIGN_POS^SIGN_NEG; - if ( reg_u_sub(b, a, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } + sign = signa ^ SIGN_NEG; + tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa); } break; case 1: /* P - N */ - dest->sign = SIGN_POS; - if ( reg_u_add(a, b, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } + tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb); break; case 2: /* N - P */ - dest->sign = SIGN_NEG; - if ( reg_u_add(a, b, dest, control_w) ) - { - dest->sign = saved_sign; - return 1; - } + tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb); break; +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL|0x111); + return -1; +#endif + } + if ( tag < 0 ) + { + setsign(dest, saved_sign); + return tag; } - return 0; + FPU_settagi(deststnr, tag); + return tag; } - else + + if ( taga == TAG_Special ) + taga = FPU_Special(a); + if ( tagb == TAG_Special ) + tagb = FPU_Special(b); + + if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) + || ((taga == TW_Denormal) && (tagb == TAG_Valid)) + || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) { - if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) ) - { return real_2op_NaN(b, a, dest); } - else if (b->tag == TW_Zero) - { - if (a->tag == TW_Zero) - { - char same_signs = !(a->sign ^ b->sign); - /* Both are zero, result will be zero. */ - reg_move(a, dest); /* Answer for different signs. */ - if (same_signs) - { - /* Sign depends upon rounding mode */ - dest->sign = ((control_w & CW_RC) != RC_DOWN) - ? SIGN_POS : SIGN_NEG; - } - } - else - { -#ifdef DENORM_OPERAND - if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(a, dest); - } - return 0; + FPU_REG x, y; + + if ( denormal_operand() < 0 ) + return FPU_Exception; + + FPU_to_exp16(a, &x); + FPU_to_exp16(b, &y); + a = &x; + b = &y; + expa = exponent16(a); + expb = exponent16(b); + + goto valid_subtract; + } + + if ( (taga == TW_NaN) || (tagb == TW_NaN) ) + { + FPU_REG const *d1, *d2; + if ( flags & REV ) + { + d1 = b; + d2 = a; } - else if (a->tag == TW_Zero) + else { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(b, dest); - dest->sign ^= SIGN_POS^SIGN_NEG; - return 0; + d1 = a; + d2 = b; } - else if (a->tag == TW_Infinity) + if ( flags & LOADED ) + return real_2op_NaN(b, tagb, deststnr, d1); + if ( flags & DEST_RM ) + return real_2op_NaN(a, taga, deststnr, d2); + else + return real_2op_NaN(b, tagb, deststnr, d2); + } + + return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG, + dest, deststnr, control_w); +} + + +static +int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, + FPU_REG const *b, u_char tagb, u_char signb, + FPU_REG *dest, int deststnr, int control_w) +{ + if ( ((taga == TW_Denormal) || (tagb == TW_Denormal)) + && (denormal_operand() < 0) ) + return FPU_Exception; + + if (taga == TAG_Zero) + { + if (tagb == TAG_Zero) { - if (b->tag != TW_Infinity) + /* Both are zero, result will be zero. */ + u_char different_signs = signa ^ signb; + + FPU_copy_to_regi(a, TAG_Zero, deststnr); + if ( different_signs ) { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(a, dest); return 0; + /* Signs are different. */ + /* Sign of answer depends upon rounding mode. */ + setsign(dest, ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG); } - /* Both args are Infinity */ - if (a->sign == b->sign) + else + setsign(dest, signa); /* signa may differ from the sign of a. */ + return TAG_Zero; + } + else + { + reg_copy(b, dest); + if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) ) { - /* Infinity-Infinity is undefined. */ - return arith_invalid(dest); - } - reg_move(a, dest); - return 0; + /* A pseudoDenormal, convert it. */ + addexponent(dest, 1); + tagb = TAG_Valid; + } + else if ( tagb > TAG_Empty ) + tagb = TAG_Special; + setsign(dest, signb); /* signb may differ from the sign of b. */ + FPU_settagi(deststnr, tagb); + return tagb; } - else if (b->tag == TW_Infinity) + } + else if (tagb == TAG_Zero) + { + reg_copy(a, dest); + if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) ) { -#ifdef DENORM_OPERAND - if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(b, dest); - dest->sign ^= SIGN_POS^SIGN_NEG; - return 0; + /* A pseudoDenormal */ + addexponent(dest, 1); + taga = TAG_Valid; + } + else if ( taga > TAG_Empty ) + taga = TAG_Special; + setsign(dest, signa); /* signa may differ from the sign of a. */ + FPU_settagi(deststnr, taga); + return taga; + } + else if (taga == TW_Infinity) + { + if ( (tagb != TW_Infinity) || (signa == signb) ) + { + FPU_copy_to_regi(a, TAG_Special, deststnr); + setsign(dest, signa); /* signa may differ from the sign of a. */ + return taga; } + /* Infinity-Infinity is undefined. */ + return arith_invalid(deststnr); + } + else if (tagb == TW_Infinity) + { + FPU_copy_to_regi(b, TAG_Special, deststnr); + setsign(dest, signb); /* signb may differ from the sign of b. */ + return tagb; } + #ifdef PARANOID - EXCEPTION(EX_INTERNAL|0x110); + EXCEPTION(EX_INTERNAL|0x101); #endif - return 1; + + return FPU_Exception; } diff -urN linux-2.0.39/arch/i386/math-emu/reg_compare.c linux-2.0.40/arch/i386/math-emu/reg_compare.c --- linux-2.0.39/arch/i386/math-emu/reg_compare.c 1994-06-02 00:28:27.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_compare.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | Compare two floating point registers | | | - | Copyright (C) 1992,1993,1994 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1994,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -21,86 +21,94 @@ #include "status_w.h" -int compare(FPU_REG const *b) +static void setflags(unsigned char flags) { - int diff; - char st0_tag; - FPU_REG *st0_ptr; + *(unsigned char *)&FPU_EFLAGS &= ~SFLAGS; + *(unsigned char *)&FPU_EFLAGS |= (flags & SFLAGS); +} + + +static int compare(FPU_REG const *b, int tagb) +{ + int diff, exp0, expb; + u_char st0_tag; + FPU_REG *st0_ptr; + FPU_REG x, y; + u_char st0_sign, signb = getsign(b); st0_ptr = &st(0); - st0_tag = st0_ptr->tag; + st0_tag = FPU_gettag0(); + st0_sign = getsign(st0_ptr); + + if ( tagb == TAG_Special ) + tagb = FPU_Special(b); + if ( st0_tag == TAG_Special ) + st0_tag = FPU_Special(st0_ptr); - if ( st0_tag | b->tag ) + if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal)) + || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) ) { - if ( st0_tag == TW_Zero ) + if ( st0_tag == TAG_Zero ) { - if ( b->tag == TW_Zero ) return COMP_A_eq_B; - if ( b->tag == TW_Valid ) - { - return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) -#ifdef DENORM_OPERAND - | ((b->exp <= EXP_UNDER) ? - COMP_Denormal : 0) -#endif DENORM_OPERAND - ; - } + if ( tagb == TAG_Zero ) return COMP_A_eq_B; + if ( tagb == TAG_Valid ) + return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); + if ( tagb == TW_Denormal ) + return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) + | COMP_Denormal; } - else if ( b->tag == TW_Zero ) + else if ( tagb == TAG_Zero ) { - if ( st0_tag == TW_Valid ) - { - return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B - : COMP_A_lt_B) -#ifdef DENORM_OPERAND - | ((st0_ptr->exp <= EXP_UNDER ) - ? COMP_Denormal : 0 ) -#endif DENORM_OPERAND - ; - } + if ( st0_tag == TAG_Valid ) + return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); + if ( st0_tag == TW_Denormal ) + return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) + | COMP_Denormal; } if ( st0_tag == TW_Infinity ) { - if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) ) - { - return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B - : COMP_A_lt_B) -#ifdef DENORM_OPERAND - | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ? - COMP_Denormal : 0 ) -#endif DENORM_OPERAND -; - } - else if ( b->tag == TW_Infinity ) + if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) ) + return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); + else if ( tagb == TW_Denormal ) + return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) + | COMP_Denormal; + else if ( tagb == TW_Infinity ) { /* The 80486 book says that infinities can be equal! */ - return (st0_ptr->sign == b->sign) ? COMP_A_eq_B : - ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); + return (st0_sign == signb) ? COMP_A_eq_B : + ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); } /* Fall through to the NaN code */ } - else if ( b->tag == TW_Infinity ) + else if ( tagb == TW_Infinity ) { - if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) ) - { - return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) -#ifdef DENORM_OPERAND - | (((st0_tag == TW_Valid) - && (st0_ptr->exp <= EXP_UNDER)) ? - COMP_Denormal : 0) -#endif DENORM_OPERAND - ; - } + if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) ) + return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); + if ( st0_tag == TW_Denormal ) + return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) + | COMP_Denormal; /* Fall through to the NaN code */ } /* The only possibility now should be that one of the arguments is a NaN */ - if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) ) + if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) ) { - if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000)) - || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) ) - /* At least one arg is a signaling NaN */ + int signalling = 0, unsupported = 0; + if ( st0_tag == TW_NaN ) + { + signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000; + unsupported = !((exponent(st0_ptr) == EXP_OVER) + && (st0_ptr->sigh & 0x80000000)); + } + if ( tagb == TW_NaN ) + { + signalling |= (b->sigh & 0xc0000000) == 0x80000000; + unsupported |= !((exponent(b) == EXP_OVER) + && (b->sigh & 0x80000000)); + } + if ( signalling || unsupported ) return COMP_No_Comp | COMP_SNaN | COMP_NaN; else /* Neither is a signaling NaN */ @@ -110,24 +118,34 @@ EXCEPTION(EX_Invalid); } -#ifdef PARANOID - if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); - if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); -#endif PARANOID + if (st0_sign != signb) + { + return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) + | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? + COMP_Denormal : 0); + } - - if (st0_ptr->sign != b->sign) + if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) ) + { + FPU_to_exp16(st0_ptr, &x); + FPU_to_exp16(b, &y); + st0_ptr = &x; + b = &y; + exp0 = exponent16(st0_ptr); + expb = exponent16(b); + } + else { - return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) -#ifdef DENORM_OPERAND - | - ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? - COMP_Denormal : 0) -#endif DENORM_OPERAND - ; + exp0 = exponent(st0_ptr); + expb = exponent(b); } - diff = st0_ptr->exp - b->exp; +#ifdef PARANOID + if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); + if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); +#endif /* PARANOID */ + + diff = exp0 - expb; if ( diff == 0 ) { diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are @@ -142,42 +160,30 @@ if ( diff > 0 ) { - return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) -#ifdef DENORM_OPERAND - | - ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? - COMP_Denormal : 0) -#endif DENORM_OPERAND - ; + return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) + | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? + COMP_Denormal : 0); } if ( diff < 0 ) { - return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) -#ifdef DENORM_OPERAND - | - ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? - COMP_Denormal : 0) -#endif DENORM_OPERAND - ; + return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) + | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? + COMP_Denormal : 0); } return COMP_A_eq_B -#ifdef DENORM_OPERAND - | - ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? - COMP_Denormal : 0) -#endif DENORM_OPERAND - ; + | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? + COMP_Denormal : 0); } /* This function requires that st(0) is not empty */ -int compare_st_data(FPU_REG const *loaded_data) +int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) { int f, c; - c = compare(loaded_data); + c = compare(loaded_data, loaded_tag); if (c & COMP_NaN) { @@ -204,33 +210,35 @@ EXCEPTION(EX_INTERNAL|0x121); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) { - return denormal_operand(); + return denormal_operand() < 0; } return 0; } -static int compare_st_st(int nr) +static int compare_st_st(int nr, int ftype) { int f, c; + FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) { - setcc(SW_C3 | SW_C2 | SW_C0); + setccf(ftype, SW_C3 | SW_C2 | SW_C0); /* Stack fault */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } - c = compare(&st(nr)); + st_ptr = &st(nr); + c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { - setcc(SW_C3 | SW_C2 | SW_C0); + setccf(ftype, SW_C3 | SW_C2 | SW_C0); EXCEPTION(EX_Invalid); return !(control_word & CW_Invalid); } @@ -254,33 +262,35 @@ EXCEPTION(EX_INTERNAL|0x122); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } - setcc(f); + setccf(ftype, f); if (c & COMP_Denormal) { - return denormal_operand(); + return denormal_operand() < 0; } return 0; } -static int compare_u_st_st(int nr) +static int compare_u_st_st(int nr, int ftype) { int f, c; + FPU_REG *st_ptr; if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) { - setcc(SW_C3 | SW_C2 | SW_C0); + setccf(ftype, SW_C3 | SW_C2 | SW_C0); /* Stack fault */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } - c = compare(&st(nr)); + st_ptr = &st(nr); + c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { - setcc(SW_C3 | SW_C2 | SW_C0); + setccf(ftype, SW_C3 | SW_C2 | SW_C0); if (c & COMP_SNaN) /* This is the only difference between un-ordered and ordinary comparisons */ { @@ -309,12 +319,12 @@ EXCEPTION(EX_INTERNAL|0x123); f = SW_C3 | SW_C2 | SW_C0; break; -#endif PARANOID +#endif /* PARANOID */ } - setcc(f); + setccf(ftype, f); if (c & COMP_Denormal) { - return denormal_operand(); + return denormal_operand() < 0; } return 0; } @@ -324,15 +334,15 @@ void fcom_st() { /* fcom st(i) */ - compare_st_st(FPU_rm); + compare_st_st(FPU_rm, 0); } void fcompst() { /* fcomp st(i) */ - if ( !compare_st_st(FPU_rm) ) - pop(); + if ( !compare_st_st(FPU_rm, 0) ) + FPU_pop(); } @@ -344,7 +354,7 @@ FPU_illegal(); return; } - if ( !compare_st_st(1) ) + if ( !compare_st_st(1, 0) ) poppop(); } @@ -352,7 +362,7 @@ void fucom_() { /* fucom st(i) */ - compare_u_st_st(FPU_rm); + compare_u_st_st(FPU_rm, 0); } @@ -360,8 +370,8 @@ void fucomp() { /* fucomp st(i) */ - if ( !compare_u_st_st(FPU_rm) ) - pop(); + if ( !compare_u_st_st(FPU_rm, 0) ) + FPU_pop(); } @@ -370,9 +380,27 @@ /* fucompp */ if (FPU_rm == 1) { - if ( !compare_u_st_st(1) ) + if ( !compare_u_st_st(1, 0) ) poppop(); } else FPU_illegal(); } + + +#ifndef ONLY_486_FPU +void fcomi() +{ + /* fcom st(i) */ + compare_st_st(FPU_rm, 1); +} + + +void fucomi() +{ + /* fucom st(i) */ + compare_u_st_st(FPU_rm, 1); + +} +#endif /* ONLY_486_FPU */ + diff -urN linux-2.0.39/arch/i386/math-emu/reg_constant.c linux-2.0.40/arch/i386/math-emu/reg_constant.c --- linux-2.0.39/arch/i386/math-emu/reg_constant.c 1996-03-19 03:45:01.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_constant.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | All of the constant FPU_REGs | | | - | Copyright (C) 1992,1993,1994,1996 | + | Copyright (C) 1992,1993,1994,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -17,59 +17,52 @@ #include "control_w.h" -FPU_REG const CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS, - 0x00000000, 0x80000000 }; -FPU_REG const CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1, - 0x00000000, 0x80000000 }; -FPU_REG const CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1, - 0x00000000, 0x80000000 }; -FPU_REG const CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1, - 0xcd1b8afe, 0xd49a784b }; -FPU_REG const CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS, - 0x5c17f0bc, 0xb8aa3b29 }; -FPU_REG const CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1, - 0x2168c235, 0xc90fdaa2 }; -FPU_REG const CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS, - 0x2168c235, 0xc90fdaa2 }; -FPU_REG const CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1, - 0x2168c235, 0xc90fdaa2 }; -FPU_REG const CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2, - 0xfbcff799, 0x9a209a84 }; -FPU_REG const CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1, - 0xd1cf79ac, 0xb17217f7 }; +#define MAKE_REG(s,e,l,h) { l, h, \ + ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) } + +FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000); +FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000); +FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000); +FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b); +FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29); +FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2); +FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2); +FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2); +FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84); +FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7); /* Extra bits to take pi/2 to more than 128 bits precision. */ -FPU_REG const CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66, - 0xfc8f8cbb, 0xece675d1 }; +FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66, + 0xfc8f8cbb, 0xece675d1); /* Only the sign (and tag) is used in internal zeroes */ -FPU_REG const CONST_Z = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 }; +FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0); /* Only the sign and significand (and tag) are used in internal NaNs */ /* The 80486 never generates one of these -FPU_REG const CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 }; +FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000); */ /* This is the real indefinite QNaN */ -FPU_REG const CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 }; +FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000); /* Only the sign (and tag) is used in internal infinities */ -FPU_REG const CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 }; - +FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000); -static void fld_const(FPU_REG const *c, int adj) +static void fld_const(FPU_REG const *c, int adj, u_char tag) { FPU_REG *st_new_ptr; if ( STACK_OVERFLOW ) { - stack_overflow(); + FPU_stack_overflow(); return; } push(); - reg_move(c, st_new_ptr); + reg_copy(c, st_new_ptr); st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to borrow or carry. */ + FPU_settag0(tag); clear_C1(); } @@ -80,37 +73,37 @@ static void fld1(int rc) { - fld_const(&CONST_1, 0); + fld_const(&CONST_1, 0, TAG_Valid); } static void fldl2t(int rc) { - fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0); + fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid); } static void fldl2e(int rc) { - fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0); + fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); } static void fldpi(int rc) { - fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0); + fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); } static void fldlg2(int rc) { - fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0); + fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); } static void fldln2(int rc) { - fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0); + fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); } static void fldz(int rc) { - fld_const(&CONST_Z, 0); + fld_const(&CONST_Z, 0, TAG_Zero); } typedef void (*FUNC_RC)(int); diff -urN linux-2.0.39/arch/i386/math-emu/reg_constant.h linux-2.0.40/arch/i386/math-emu/reg_constant.h --- linux-2.0.39/arch/i386/math-emu/reg_constant.h 1997-03-28 16:12:25.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_constant.h 2004-02-07 23:13:01.000000000 -0800 @@ -28,4 +28,4 @@ extern FPU_REG const CONST_MINF; extern FPU_REG const CONST_QNaN; -#endif _REG_CONSTANT_H_ +#endif /* _REG_CONSTANT_H_ */ diff -urN linux-2.0.39/arch/i386/math-emu/reg_convert.c linux-2.0.40/arch/i386/math-emu/reg_convert.c --- linux-2.0.39/arch/i386/math-emu/reg_convert.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_convert.c 2004-02-07 23:13:01.000000000 -0800 @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------+ + | reg_convert.c | + | | + | Convert register representation. | + | | + | Copyright (C) 1992,1993,1994,1996,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "fpu_emu.h" + + +int FPU_to_exp16(FPU_REG const *a, FPU_REG *x) +{ + int sign = getsign(a); + + *(long long *)&(x->sigl) = *(const long long *)&(a->sigl); + + /* Set up the exponent as a 16 bit quantity. */ + setexponent16(x, exponent(a)); + + if ( exponent16(x) == EXP_UNDER ) + { + /* The number is a de-normal or pseudodenormal. */ + /* We only deal with the significand and exponent. */ + + if (x->sigh & 0x80000000) + { + /* Is a pseudodenormal. */ + /* This is non-80486 behaviour because the number + loses its 'denormal' identity. */ + addexponent(x, 1); + } + else + { + /* Is a denormal. */ + addexponent(x, 1); + FPU_normalize_nuo(x); + } + } + + if ( !(x->sigh & 0x80000000) ) + { + EXCEPTION(EX_INTERNAL | 0x180); + } + + return sign; +} + diff -urN linux-2.0.39/arch/i386/math-emu/reg_div.S linux-2.0.40/arch/i386/math-emu/reg_div.S --- linux-2.0.39/arch/i386/math-emu/reg_div.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_div.S 1969-12-31 16:00:00.000000000 -0800 @@ -1,248 +0,0 @@ - .file "reg_div.S" -/*---------------------------------------------------------------------------+ - | reg_div.S | - | | - | Divide one FPU_REG by another and put the result in a destination FPU_REG.| - | | - | Copyright (C) 1992,1993,1994,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | - | | - | Call from C as: | - | void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | - | unsigned int control_word) | - | | - +---------------------------------------------------------------------------*/ - -#include "exception.h" -#include "fpu_emu.h" - - -.text -ENTRY(reg_div) - pushl %ebp - movl %esp,%ebp -#ifndef NON_REENTRANT_FPU - subl $28,%esp /* Needed by divide_kernel */ -#endif NON_REENTRANT_FPU - - pushl %esi - pushl %edi - pushl %ebx - - movl PARAM1,%esi - movl PARAM2,%ebx - movl PARAM3,%edi - - movb TAG(%esi),%al - orb TAG(%ebx),%al - - jne L_div_special /* Not (both numbers TW_Valid) */ - -#ifdef DENORM_OPERAND -/* Check for denormals */ - cmpl EXP_UNDER,EXP(%esi) - jg xL_arg1_not_denormal - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xL_arg1_not_denormal: - cmpl EXP_UNDER,EXP(%ebx) - jg xL_arg2_not_denormal - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xL_arg2_not_denormal: -#endif DENORM_OPERAND - -/* Both arguments are TW_Valid */ - movb TW_Valid,TAG(%edi) - - movb SIGN(%esi),%cl - cmpb %cl,SIGN(%ebx) - setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */ - - movl EXP(%esi),%edx - movl EXP(%ebx),%eax - subl %eax,%edx - addl EXP_BIAS,%edx - movl %edx,EXP(%edi) - - jmp SYMBOL_NAME(divide_kernel) - - -/*-----------------------------------------------------------------------*/ -L_div_special: - cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */ - je L_arg1_NaN - - cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */ - jne L_no_NaN_arg - -/* Operations on NaNs */ -L_arg1_NaN: -L_arg2_NaN: - pushl %edi /* Destination */ - pushl %esi - pushl %ebx /* Ordering is important here */ - call SYMBOL_NAME(real_2op_NaN) - jmp LDiv_exit - -/* Invalid operations */ -L_zero_zero: -L_inf_inf: - pushl %edi /* Destination */ - call SYMBOL_NAME(arith_invalid) /* 0/0 or Infinity/Infinity */ - jmp LDiv_exit - -L_no_NaN_arg: - cmpb TW_Infinity,TAG(%esi) - jne L_arg1_not_inf - - cmpb TW_Infinity,TAG(%ebx) - je L_inf_inf /* invalid operation */ - - cmpb TW_Valid,TAG(%ebx) - je L_inf_valid - -#ifdef PARANOID - /* arg2 must be zero or valid */ - cmpb TW_Zero,TAG(%ebx) - ja L_unknown_tags -#endif PARANOID - - /* Note that p16-9 says that infinity/0 returns infinity */ - jmp L_copy_arg1 /* Answer is Inf */ - -L_inf_valid: -#ifdef DENORM_OPERAND - cmpl EXP_UNDER,EXP(%ebx) - jg L_copy_arg1 /* Answer is Inf */ - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit -#endif DENORM_OPERAND - - jmp L_copy_arg1 /* Answer is Inf */ - -L_arg1_not_inf: - cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */ - jne L_arg2_not_zero - - cmpb TW_Zero,TAG(%esi) - je L_zero_zero /* invalid operation */ - -#ifdef PARANOID - /* arg1 must be valid */ - cmpb TW_Valid,TAG(%esi) - ja L_unknown_tags -#endif PARANOID - -/* Division by zero error */ - pushl %edi /* destination */ - movb SIGN(%esi),%al - xorb SIGN(%ebx),%al - pushl %eax /* lower 8 bits have the sign */ - call SYMBOL_NAME(divide_by_zero) - jmp LDiv_exit - -L_arg2_not_zero: - cmpb TW_Infinity,TAG(%ebx) - jne L_arg2_not_inf - -#ifdef DENORM_OPERAND - cmpb TW_Valid,TAG(%esi) - jne L_return_zero - - cmpl EXP_UNDER,EXP(%esi) - jg L_return_zero /* Answer is zero */ - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit -#endif DENORM_OPERAND - - jmp L_return_zero /* Answer is zero */ - -L_arg2_not_inf: - -#ifdef PARANOID - cmpb TW_Zero,TAG(%esi) - jne L_unknown_tags -#endif PARANOID - - /* arg1 is zero, arg2 is not Infinity or a NaN */ - -#ifdef DENORM_OPERAND - cmpl EXP_UNDER,EXP(%ebx) - jg L_copy_arg1 /* Answer is zero */ - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit -#endif DENORM_OPERAND - -L_copy_arg1: - movb TAG(%esi),%ax - movb %ax,TAG(%edi) - movl EXP(%esi),%eax - movl %eax,EXP(%edi) - movl SIGL(%esi),%eax - movl %eax,SIGL(%edi) - movl SIGH(%esi),%eax - movl %eax,SIGH(%edi) - -LDiv_set_result_sign: - movb SIGN(%esi),%cl - cmpb %cl,SIGN(%ebx) - jne LDiv_negative_result - - movb SIGN_POS,SIGN(%edi) - xorl %eax,%eax /* Valid result */ - jmp LDiv_exit - -LDiv_negative_result: - movb SIGN_NEG,SIGN(%edi) - xorl %eax,%eax /* Valid result */ - -LDiv_exit: -#ifndef NON_REENTRANT_FPU - leal -40(%ebp),%esp -#else - leal -12(%ebp),%esp -#endif NON_REENTRANT_FPU - - popl %ebx - popl %edi - popl %esi - leave - ret - - -L_return_zero: - xorl %eax,%eax - movl %eax,SIGH(%edi) - movl %eax,SIGL(%edi) - movl EXP_UNDER,EXP(%edi) - movb TW_Zero,TAG(%edi) - jmp LDiv_set_result_sign - -#ifdef PARANOID -L_unknown_tags: - pushl EX_INTERNAL | 0x208 - call EXCEPTION - - /* Generate a NaN for unknown tags */ - movl SYMBOL_NAME(CONST_QNaN),%eax - movl %eax,(%edi) - movl SYMBOL_NAME(CONST_QNaN)+4,%eax - movl %eax,SIGL(%edi) - movl SYMBOL_NAME(CONST_QNaN)+8,%eax - movl %eax,SIGH(%edi) - jmp LDiv_exit /* %eax is nz */ -#endif PARANOID diff -urN linux-2.0.39/arch/i386/math-emu/reg_divide.c linux-2.0.40/arch/i386/math-emu/reg_divide.c --- linux-2.0.39/arch/i386/math-emu/reg_divide.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_divide.c 2004-02-07 23:13:01.000000000 -0800 @@ -0,0 +1,206 @@ +/*---------------------------------------------------------------------------+ + | reg_divide.c | + | | + | Divide one FPU_REG by another and put the result in a destination FPU_REG.| + | | + | Copyright (C) 1996 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@jacobi.maths.monash.edu.au | + | | + | Return value is the tag of the answer, or-ed with FPU_Exception if | + | one was raised, or -1 on internal error. | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | The destination may be any FPU_REG, including one of the source FPU_REGs. | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "fpu_system.h" + +/* + Divide one register by another and put the result into a third register. + */ +int FPU_div(int flags, int rm, int control_w) +{ + FPU_REG x, y; + FPU_REG const *a, *b, *st0_ptr, *st_ptr; + FPU_REG *dest; + u_char taga, tagb, signa, signb, sign, saved_sign; + int tag, deststnr; + + if ( flags & DEST_RM ) + deststnr = rm; + else + deststnr = 0; + + if ( flags & REV ) + { + b = &st(0); + st0_ptr = b; + tagb = FPU_gettag0(); + if ( flags & LOADED ) + { + a = (FPU_REG *)rm; + taga = flags & 0x0f; + } + else + { + a = &st(rm); + st_ptr = a; + taga = FPU_gettagi(rm); + } + } + else + { + a = &st(0); + st0_ptr = a; + taga = FPU_gettag0(); + if ( flags & LOADED ) + { + b = (FPU_REG *)rm; + tagb = flags & 0x0f; + } + else + { + b = &st(rm); + st_ptr = b; + tagb = FPU_gettagi(rm); + } + } + + signa = getsign(a); + signb = getsign(b); + + sign = signa ^ signb; + + dest = &st(deststnr); + saved_sign = getsign(dest); + + if ( !(taga | tagb) ) + { + /* Both regs Valid, this should be the most common case. */ + reg_copy(a, &x); + reg_copy(b, &y); + setpositive(&x); + setpositive(&y); + tag = FPU_u_div(&x, &y, dest, control_w, sign); + + if ( tag < 0 ) + return tag; + + FPU_settagi(deststnr, tag); + return tag; + } + + if ( taga == TAG_Special ) + taga = FPU_Special(a); + if ( tagb == TAG_Special ) + tagb = FPU_Special(b); + + if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) + || ((taga == TW_Denormal) && (tagb == TAG_Valid)) + || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) + { + if ( denormal_operand() < 0 ) + return FPU_Exception; + + FPU_to_exp16(a, &x); + FPU_to_exp16(b, &y); + tag = FPU_u_div(&x, &y, dest, control_w, sign); + if ( tag < 0 ) + return tag; + + FPU_settagi(deststnr, tag); + return tag; + } + else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) ) + { + if ( tagb != TAG_Zero ) + { + /* Want to find Zero/Valid */ + if ( tagb == TW_Denormal ) + { + if ( denormal_operand() < 0 ) + return FPU_Exception; + } + + /* The result is zero. */ + FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); + setsign(dest, sign); + return TAG_Zero; + } + /* We have an exception condition, either 0/0 or Valid/Zero. */ + if ( taga == TAG_Zero ) + { + /* 0/0 */ + return arith_invalid(deststnr); + } + /* Valid/Zero */ + return FPU_divide_by_zero(deststnr, sign); + } + /* Must have infinities, NaNs, etc */ + else if ( (taga == TW_NaN) || (tagb == TW_NaN) ) + { + if ( flags & LOADED ) + return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr); + + if ( flags & DEST_RM ) + { + int tag; + tag = FPU_gettag0(); + if ( tag == TAG_Special ) + tag = FPU_Special(st0_ptr); + return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm)); + } + else + { + int tag; + tag = FPU_gettagi(rm); + if ( tag == TAG_Special ) + tag = FPU_Special(&st(rm)); + return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm)); + } + } + else if (taga == TW_Infinity) + { + if (tagb == TW_Infinity) + { + /* infinity/infinity */ + return arith_invalid(deststnr); + } + else + { + /* tagb must be Valid or Zero */ + if ( (tagb == TW_Denormal) && (denormal_operand() < 0) ) + return FPU_Exception; + + /* Infinity divided by Zero or Valid does + not raise and exception, but returns Infinity */ + FPU_copy_to_regi(a, TAG_Special, deststnr); + setsign(dest, sign); + return taga; + } + } + else if (tagb == TW_Infinity) + { + if ( (taga == TW_Denormal) && (denormal_operand() < 0) ) + return FPU_Exception; + + /* The result is zero. */ + FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); + setsign(dest, sign); + return TAG_Zero; + } +#ifdef PARANOID + else + { + EXCEPTION(EX_INTERNAL|0x102); + return FPU_Exception; + } +#endif /* PARANOID */ + +} diff -urN linux-2.0.39/arch/i386/math-emu/reg_ld_str.c linux-2.0.40/arch/i386/math-emu/reg_ld_str.c --- linux-2.0.39/arch/i386/math-emu/reg_ld_str.c 1996-05-06 06:31:17.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_ld_str.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,9 +3,9 @@ | | | All of the functions which transfer data between user memory and FPU_REGs.| | | - | Copyright (C) 1992,1993,1994,1996 | + | Copyright (C) 1992,1993,1994,1996,1997,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | + | E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ @@ -17,19 +17,14 @@ | other processes using the emulator while swapping is in progress. | +---------------------------------------------------------------------------*/ -#include - +#include "fpu_emu.h" #include "fpu_system.h" #include "exception.h" #include "reg_constant.h" -#include "fpu_emu.h" #include "control_w.h" #include "status_w.h" -#define EXTENDED_Ebias 0x3fff -#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ - #define DOUBLE_Emax 1023 /* largest valid exponent */ #define DOUBLE_Ebias 1023 #define DOUBLE_Emin (-1022) /* smallest valid exponent */ @@ -38,123 +33,85 @@ #define SINGLE_Ebias 127 #define SINGLE_Emin (-126) /* smallest valid exponent */ -static void write_to_extended(FPU_REG *rp, char *d); - -/* Get a long double from user memory */ -int reg_load_extended(long double *s, FPU_REG *loaded_data) +static u_char normalize_no_excep(FPU_REG *r, int exp, int sign) { - unsigned long sigl, sigh, exp; + u_char tag; - RE_ENTRANT_CHECK_OFF; - FPU_verify_area(VERIFY_READ, s, 10); - sigl = get_fs_long((unsigned long *) s); - sigh = get_fs_long(1 + (unsigned long *) s); - exp = get_fs_word(4 + (unsigned short *) s); - RE_ENTRANT_CHECK_ON; + setexponent16(r, exp); - loaded_data->tag = TW_Valid; /* Default */ - loaded_data->sigl = sigl; - loaded_data->sigh = sigh; - if (exp & 0x8000) - loaded_data->sign = SIGN_NEG; - else - loaded_data->sign = SIGN_POS; - exp &= 0x7fff; - loaded_data->exp = exp - EXTENDED_Ebias + EXP_BIAS; + tag = FPU_normalize_nuo(r); + stdexp(r); + if ( sign ) + setnegative(r); + + return tag; +} + + +int FPU_tagof(FPU_REG *ptr) +{ + int exp; + exp = exponent16(ptr) & 0x7fff; if ( exp == 0 ) { - if ( !(sigh | sigl) ) + if ( !(ptr->sigh | ptr->sigl) ) { - loaded_data->tag = TW_Zero; - return 0; + return TAG_Zero; } /* The number is a de-normal or pseudodenormal. */ - if (sigh & 0x80000000) - { - /* Is a pseudodenormal. */ - /* Convert it for internal use. */ - /* This is non-80486 behaviour because the number - loses its 'denormal' identity. */ - loaded_data->exp++; - return 1; - } - else - { - /* Is a denormal. */ - /* Convert it for internal use. */ - loaded_data->exp++; - normalize_nuo(loaded_data); - return 0; - } + return TAG_Special; } - else if ( exp == 0x7fff ) - { - if ( !((sigh ^ 0x80000000) | sigl) ) - { - /* Matches the bit pattern for Infinity. */ - loaded_data->exp = EXP_Infinity; - loaded_data->tag = TW_Infinity; - return 0; - } - loaded_data->exp = EXP_NaN; - loaded_data->tag = TW_NaN; - if ( !(sigh & 0x80000000) ) - { - /* NaNs have the ms bit set to 1. */ - /* This is therefore an Unsupported NaN data type. */ - /* This is non 80486 behaviour */ - /* This should generate an Invalid Operand exception - later, so we convert it to a SNaN */ - loaded_data->sigh = 0x80000000; - loaded_data->sigl = 0x00000001; - loaded_data->sign = SIGN_NEG; - return 1; - } - return 0; + if ( exp == 0x7fff ) + { + /* Is an Infinity, a NaN, or an unsupported data type. */ + return TAG_Special; } - if ( !(sigh & 0x80000000) ) + if ( !(ptr->sigh & 0x80000000) ) { /* Unsupported data type. */ /* Valid numbers have the ms bit set to 1. */ /* Unnormal. */ - /* Convert it for internal use. */ - /* This is non-80486 behaviour */ - /* This should generate an Invalid Operand exception - later, so we convert it to a SNaN */ - loaded_data->sigh = 0x80000000; - loaded_data->sigl = 0x00000001; - loaded_data->sign = SIGN_NEG; - loaded_data->exp = EXP_NaN; - loaded_data->tag = TW_NaN; - return 1; + return TAG_Special; } - return 0; + + return TAG_Valid; +} + + +/* Get a long double from user memory */ +int FPU_load_extended(long double *s, int stnr) +{ + FPU_REG *sti_ptr = &st(stnr); + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 10); + FPU_copy_from_user(sti_ptr, s, 10); + RE_ENTRANT_CHECK_ON; + + return FPU_tagof(sti_ptr); } /* Get a double from user memory */ -int reg_load_double(double *dfloat, FPU_REG *loaded_data) +int FPU_load_double(double *dfloat, FPU_REG *loaded_data) { - int exp; + int exp, tag, negative; unsigned m64, l64; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, dfloat, 8); - m64 = get_fs_long(1 + (unsigned long *) dfloat); - l64 = get_fs_long((unsigned long *) dfloat); + FPU_get_user(m64, 1 + (unsigned long *) dfloat); + FPU_get_user(l64, (unsigned long *) dfloat); RE_ENTRANT_CHECK_ON; - if (m64 & 0x80000000) - loaded_data->sign = SIGN_NEG; - else - loaded_data->sign = SIGN_POS; - exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias; + negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive; + exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias; m64 &= 0xfffff; - if (exp > DOUBLE_Emax) + if ( exp > DOUBLE_Emax + EXTENDED_Ebias ) { /* Infinity or NaN */ if ((m64 == 0) && (l64 == 0)) @@ -162,93 +119,87 @@ /* +- infinity */ loaded_data->sigh = 0x80000000; loaded_data->sigl = 0x00000000; - loaded_data->exp = EXP_Infinity; - loaded_data->tag = TW_Infinity; - return 0; + exp = EXP_Infinity + EXTENDED_Ebias; + tag = TAG_Special; } else { /* Must be a signaling or quiet NaN */ - loaded_data->exp = EXP_NaN; - loaded_data->tag = TW_NaN; + exp = EXP_NaN + EXTENDED_Ebias; loaded_data->sigh = (m64 << 11) | 0x80000000; loaded_data->sigh |= l64 >> 21; loaded_data->sigl = l64 << 11; - return 0; /* The calling function must look for NaNs */ + tag = TAG_Special; /* The calling function must look for NaNs */ } } - else if ( exp < DOUBLE_Emin ) + else if ( exp < DOUBLE_Emin + EXTENDED_Ebias ) { /* Zero or de-normal */ if ((m64 == 0) && (l64 == 0)) { /* Zero */ - int c = loaded_data->sign; - reg_move(&CONST_Z, loaded_data); - loaded_data->sign = c; - return 0; + reg_copy(&CONST_Z, loaded_data); + exp = 0; + tag = TAG_Zero; } else { /* De-normal */ - loaded_data->exp = DOUBLE_Emin + EXP_BIAS; - loaded_data->tag = TW_Valid; loaded_data->sigh = m64 << 11; loaded_data->sigh |= l64 >> 21; loaded_data->sigl = l64 << 11; - normalize_nuo(loaded_data); - return denormal_operand(); + + return normalize_no_excep(loaded_data, DOUBLE_Emin, negative) + | (denormal_operand() < 0 ? FPU_Exception : 0); } } else { - loaded_data->exp = exp + EXP_BIAS; - loaded_data->tag = TW_Valid; loaded_data->sigh = (m64 << 11) | 0x80000000; loaded_data->sigh |= l64 >> 21; loaded_data->sigl = l64 << 11; - return 0; + tag = TAG_Valid; } + + setexponent16(loaded_data, exp | negative); + + return tag; } /* Get a float from user memory */ -int reg_load_single(float *single, FPU_REG *loaded_data) +int FPU_load_single(float *single, FPU_REG *loaded_data) { unsigned m32; - int exp; + int exp, tag, negative; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, single, 4); - m32 = get_fs_long((unsigned long *) single); + FPU_get_user(m32, (unsigned long *) single); RE_ENTRANT_CHECK_ON; - if (m32 & 0x80000000) - loaded_data->sign = SIGN_NEG; - else - loaded_data->sign = SIGN_POS; + negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive; + if (!(m32 & 0x7fffffff)) { /* Zero */ - int c = loaded_data->sign; - reg_move(&CONST_Z, loaded_data); - loaded_data->sign = c; - return 0; + reg_copy(&CONST_Z, loaded_data); + addexponent(loaded_data, negative); + return TAG_Zero; } - exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; + exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias; m32 = (m32 & 0x7fffff) << 8; - if ( exp < SINGLE_Emin ) + if ( exp < SINGLE_Emin + EXTENDED_Ebias ) { /* De-normals */ - loaded_data->exp = SINGLE_Emin + EXP_BIAS; - loaded_data->tag = TW_Valid; loaded_data->sigh = m32; loaded_data->sigl = 0; - normalize_nuo(loaded_data); - return denormal_operand(); + + return normalize_no_excep(loaded_data, SINGLE_Emin, negative) + | (denormal_operand() < 0 ? FPU_Exception : 0); } - else if ( exp > SINGLE_Emax ) + else if ( exp > SINGLE_Emax + EXTENDED_Ebias ) { /* Infinity or NaN */ if ( m32 == 0 ) @@ -256,131 +207,129 @@ /* +- infinity */ loaded_data->sigh = 0x80000000; loaded_data->sigl = 0x00000000; - loaded_data->exp = EXP_Infinity; - loaded_data->tag = TW_Infinity; - return 0; + exp = EXP_Infinity + EXTENDED_Ebias; + tag = TAG_Special; } else { /* Must be a signaling or quiet NaN */ - loaded_data->exp = EXP_NaN; - loaded_data->tag = TW_NaN; + exp = EXP_NaN + EXTENDED_Ebias; loaded_data->sigh = m32 | 0x80000000; loaded_data->sigl = 0; - return 0; /* The calling function must look for NaNs */ + tag = TAG_Special; /* The calling function must look for NaNs */ } } else { - loaded_data->exp = exp + EXP_BIAS; loaded_data->sigh = m32 | 0x80000000; loaded_data->sigl = 0; - loaded_data->tag = TW_Valid; - return 0; + tag = TAG_Valid; } + + setexponent16(loaded_data, exp | negative); /* Set the sign. */ + + return tag; } /* Get a long long from user memory */ -void reg_load_int64(long long *_s, FPU_REG *loaded_data) +int FPU_load_int64(long long *_s) { - int e; long long s; + int sign; + FPU_REG *st0_ptr = &st(0); RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, _s, 8); - ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s); - ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s); + copy_from_user(&s,_s,8); RE_ENTRANT_CHECK_ON; if (s == 0) - { reg_move(&CONST_Z, loaded_data); return; } + { + reg_copy(&CONST_Z, st0_ptr); + return TAG_Zero; + } if (s > 0) - loaded_data->sign = SIGN_POS; + sign = SIGN_Positive; else { s = -s; - loaded_data->sign = SIGN_NEG; + sign = SIGN_Negative; } - e = EXP_BIAS + 63; - significand(loaded_data) = s; - loaded_data->exp = e; - loaded_data->tag = TW_Valid; - normalize_nuo(loaded_data); + significand(st0_ptr) = s; + + return normalize_no_excep(st0_ptr, 63, sign); } /* Get a long from user memory */ -void reg_load_int32(long *_s, FPU_REG *loaded_data) +int FPU_load_int32(long *_s, FPU_REG *loaded_data) { long s; - int e; + int negative; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, _s, 4); - s = (long)get_fs_long((unsigned long *) _s); + FPU_get_user(s, _s); RE_ENTRANT_CHECK_ON; if (s == 0) - { reg_move(&CONST_Z, loaded_data); return; } + { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; } if (s > 0) - loaded_data->sign = SIGN_POS; + negative = SIGN_Positive; else - { - s = -s; - loaded_data->sign = SIGN_NEG; - } + { + s = -s; + negative = SIGN_Negative; + } - e = EXP_BIAS + 31; loaded_data->sigh = s; loaded_data->sigl = 0; - loaded_data->exp = e; - loaded_data->tag = TW_Valid; - normalize_nuo(loaded_data); + + return normalize_no_excep(loaded_data, 31, negative); } /* Get a short from user memory */ -void reg_load_int16(short *_s, FPU_REG *loaded_data) +int FPU_load_int16(short *_s, FPU_REG *loaded_data) { - int s, e; + int s, negative; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, _s, 2); /* Cast as short to get the sign extended. */ - s = (short)get_fs_word((unsigned short *) _s); + FPU_get_user(s, _s); RE_ENTRANT_CHECK_ON; if (s == 0) - { reg_move(&CONST_Z, loaded_data); return; } + { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; } if (s > 0) - loaded_data->sign = SIGN_POS; + negative = SIGN_Positive; else - { - s = -s; - loaded_data->sign = SIGN_NEG; - } + { + s = -s; + negative = SIGN_Negative; + } - e = EXP_BIAS + 15; loaded_data->sigh = s << 16; - loaded_data->sigl = 0; - loaded_data->exp = e; - loaded_data->tag = TW_Valid; - normalize_nuo(loaded_data); + + return normalize_no_excep(loaded_data, 15, negative); } /* Get a packed bcd array from user memory */ -void reg_load_bcd(char *s, FPU_REG *loaded_data) +int FPU_load_bcd(u_char *s) { + FPU_REG *st0_ptr = &st(0); int pos; - unsigned char bcd; + u_char bcd; long long l=0; + int sign; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, s, 10); @@ -389,7 +338,7 @@ { l *= 10; RE_ENTRANT_CHECK_OFF; - bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos); + FPU_get_user(bcd, (u_char *) s+pos); RE_ENTRANT_CHECK_ON; l += bcd >> 4; l *= 10; @@ -397,30 +346,27 @@ } RE_ENTRANT_CHECK_OFF; - loaded_data->sign = - ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ? - SIGN_NEG : SIGN_POS; + FPU_get_user(sign, (u_char *) s+9); + sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive; RE_ENTRANT_CHECK_ON; - if (l == 0) + if ( l == 0 ) { - char sign = loaded_data->sign; - reg_move(&CONST_Z, loaded_data); - loaded_data->sign = sign; + reg_copy(&CONST_Z, st0_ptr); + addexponent(st0_ptr, sign); /* Set the sign. */ + return TAG_Zero; } else { - significand(loaded_data) = l; - loaded_data->exp = EXP_BIAS + 63; - loaded_data->tag = TW_Valid; - normalize_nuo(loaded_data); + significand(st0_ptr) = l; + return normalize_no_excep(st0_ptr, 63, sign); } } /*===========================================================================*/ /* Put a long double into user memory */ -int reg_store_extended(long double *d, FPU_REG *st0_ptr) +int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double *d) { /* The only exception raised by an attempt to store to an @@ -428,12 +374,16 @@ attempting to store from an empty register. */ - if ( st0_ptr->tag != TW_Empty ) + if ( st0_tag != TAG_Empty ) { RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE, d, 10); + + FPU_put_user(st0_ptr->sigl, (unsigned long *) d); + FPU_put_user(st0_ptr->sigh, (unsigned long *) ((u_char *)d + 4)); + FPU_put_user(exponent16(st0_ptr), (unsigned short *) ((u_char *)d + 8)); RE_ENTRANT_CHECK_ON; - write_to_extended(st0_ptr, (char *) d); + return 1; } @@ -445,9 +395,9 @@ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,10); - put_fs_long(0, (unsigned long *) d); - put_fs_long(0xc0000000, 1 + (unsigned long *) d); - put_fs_word(0xffff, 4 + (short *) d); + FPU_put_user(0, (unsigned long *) d); + FPU_put_user(0xc0000000, 1 + (unsigned long *) d); + FPU_put_user(0xffff, 4 + (short *) d); RE_ENTRANT_CHECK_ON; return 1; } @@ -458,38 +408,26 @@ /* Put a double into user memory */ -int reg_store_double(double *dfloat, FPU_REG *st0_ptr) +int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat) { unsigned long l[2]; unsigned long increment = 0; /* avoid gcc warnings */ - char st0_tag = st0_ptr->tag; + int precision_loss; + int exp; + FPU_REG tmp; - if (st0_tag == TW_Valid) + if ( st0_tag == TAG_Valid ) { - int precision_loss; - int exp; - FPU_REG tmp; - - reg_move(st0_ptr, &tmp); - exp = tmp.exp - EXP_BIAS; + reg_copy(st0_ptr, &tmp); + exp = exponent(&tmp); if ( exp < DOUBLE_Emin ) /* It may be a denormal */ { - /* A denormal will always underflow. */ -#ifndef PECULIAR_486 - /* An 80486 is supposed to be able to generate - a denormal exception here, but... */ - if ( st0_ptr->exp <= EXP_UNDER ) - { - /* Underflow has priority. */ - if ( control_word & CW_Underflow ) - denormal_operand(); - } -#endif PECULIAR_486 + addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */ - tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */ + denormal_arg: - if ( (precision_loss = round_to_int(&tmp)) ) + if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) { #ifdef PECULIAR_486 /* Did it round to a non-denormal ? */ @@ -498,7 +436,7 @@ converts to decide underflow. */ if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && (st0_ptr->sigl & 0x000007ff)) ) -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of @@ -526,10 +464,10 @@ ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */ break; case RC_DOWN: /* towards -infinity */ - increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff; + increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff; break; case RC_UP: /* towards +infinity */ - increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0; + increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0; break; case RC_CHOP: increment = 0; @@ -600,33 +538,64 @@ } } } - else if (st0_tag == TW_Zero) + else if (st0_tag == TAG_Zero) { /* Number is zero */ l[0] = 0; l[1] = 0; } - else if (st0_tag == TW_Infinity) - { - l[0] = 0; - l[1] = 0x7ff00000; - } - else if (st0_tag == TW_NaN) + else if ( st0_tag == TAG_Special ) { - /* See if we can get a valid NaN from the FPU_REG */ - l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21); - l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); - if ( !(st0_ptr->sigh & 0x40000000) ) + st0_tag = FPU_Special(st0_ptr); + if ( st0_tag == TW_Denormal ) { - /* It is a signalling NaN */ - EXCEPTION(EX_Invalid); - if ( !(control_word & CW_Invalid) ) - return 0; - l[1] |= (0x40000000 >> 11); + /* A denormal will always underflow. */ +#ifndef PECULIAR_486 + /* An 80486 is supposed to be able to generate + a denormal exception here, but... */ + /* Underflow has priority. */ + if ( control_word & CW_Underflow ) + denormal_operand(); +#endif /* PECULIAR_486 */ + reg_copy(st0_ptr, &tmp); + goto denormal_arg; + } + else if (st0_tag == TW_Infinity) + { + l[0] = 0; + l[1] = 0x7ff00000; + } + else if (st0_tag == TW_NaN) + { + /* Is it really a NaN ? */ + if ( (exponent(st0_ptr) == EXP_OVER) + && (st0_ptr->sigh & 0x80000000) ) + { + /* See if we can get a valid NaN from the FPU_REG */ + l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21); + l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); + if ( !(st0_ptr->sigh & 0x40000000) ) + { + /* It is a signalling NaN */ + EXCEPTION(EX_Invalid); + if ( !(control_word & CW_Invalid) ) + return 0; + l[1] |= (0x40000000 >> 11); + } + l[1] |= 0x7ff00000; + } + else + { + /* It is an unsupported data type */ + EXCEPTION(EX_Invalid); + if ( !(control_word & CW_Invalid) ) + return 0; + l[0] = 0; + l[1] = 0xfff80000; + } } - l[1] |= 0x7ff00000; } - else if ( st0_tag == TW_Empty ) + else if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); @@ -636,21 +605,21 @@ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); - put_fs_long(0, (unsigned long *) dfloat); - put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat); + FPU_put_user(0, (unsigned long *) dfloat); + FPU_put_user(0xfff80000, 1 + (unsigned long *) dfloat); RE_ENTRANT_CHECK_ON; return 1; } else return 0; } - if ( st0_ptr->sign ) + if ( getsign(st0_ptr) ) l[1] |= 0x80000000; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); - put_fs_long(l[0], (unsigned long *)dfloat); - put_fs_long(l[1], 1 + (unsigned long *)dfloat); + FPU_put_user(l[0], (unsigned long *)dfloat); + FPU_put_user(l[1], 1 + (unsigned long *)dfloat); RE_ENTRANT_CHECK_ON; return 1; @@ -658,38 +627,27 @@ /* Put a float into user memory */ -int reg_store_single(float *single, FPU_REG *st0_ptr) +int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single) { long templ; unsigned long increment = 0; /* avoid gcc warnings */ - char st0_tag = st0_ptr->tag; + int precision_loss; + int exp; + FPU_REG tmp; - if (st0_tag == TW_Valid) + if ( st0_tag == TAG_Valid ) { - int precision_loss; - int exp; - FPU_REG tmp; - reg_move(st0_ptr, &tmp); - exp = tmp.exp - EXP_BIAS; + reg_copy(st0_ptr, &tmp); + exp = exponent(&tmp); if ( exp < SINGLE_Emin ) { - /* A denormal will always underflow. */ -#ifndef PECULIAR_486 - /* An 80486 is supposed to be able to generate - a denormal exception here, but... */ - if ( st0_ptr->exp <= EXP_UNDER ) - { - /* Underflow has priority. */ - if ( control_word & CW_Underflow ) - denormal_operand(); - } -#endif PECULIAR_486 + addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */ - tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */ + denormal_arg: - if ( (precision_loss = round_to_int(&tmp)) ) + if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) { #ifdef PECULIAR_486 /* Did it round to a non-denormal ? */ @@ -698,20 +656,20 @@ converts to decide underflow. */ if ( !((tmp.sigl == 0x00800000) && ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) ) -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of the 80486 book */ - if ( !(control_word & EX_Underflow) ) + if ( !(control_word & CW_Underflow) ) return 0; } EXCEPTION(precision_loss); - if ( !(control_word & EX_Precision) ) + if ( !(control_word & CW_Precision) ) return 0; } templ = tmp.sigl; - } + } else { if ( tmp.sigl | (tmp.sigh & 0x000000ff) ) @@ -725,15 +683,15 @@ case RC_RND: increment = ((sigh & 0xff) > 0x80) /* more than half */ || (((sigh & 0xff) == 0x80) && sigl) /* more than half */ - || ((sigh & 0x180) == 0x180); /* round to even */ + || ((sigh & 0x180) == 0x180); /* round to even */ break; case RC_DOWN: /* towards -infinity */ - increment = (tmp.sign == SIGN_POS) - ? 0 : (sigl | (sigh & 0xff)); + increment = signpositive(&tmp) + ? 0 : (sigl | (sigh & 0xff)); break; case RC_UP: /* towards +infinity */ - increment = (tmp.sign == SIGN_POS) - ? (sigl | (sigh & 0xff)) : 0; + increment = signpositive(&tmp) + ? (sigl | (sigh & 0xff)) : 0; break; case RC_CHOP: increment = 0; @@ -766,7 +724,7 @@ } else precision_loss = 0; - + templ = (tmp.sigh >> 8) & 0x007fffff; if ( exp > SINGLE_Emax ) @@ -797,29 +755,66 @@ } } } - else if (st0_tag == TW_Zero) + else if (st0_tag == TAG_Zero) { templ = 0; } - else if (st0_tag == TW_Infinity) - { - templ = 0x7f800000; - } - else if (st0_tag == TW_NaN) + else if ( st0_tag == TAG_Special ) { - /* See if we can get a valid NaN from the FPU_REG */ - templ = st0_ptr->sigh >> 8; - if ( !(st0_ptr->sigh & 0x40000000) ) + st0_tag = FPU_Special(st0_ptr); + if (st0_tag == TW_Denormal) { - /* It is a signalling NaN */ - EXCEPTION(EX_Invalid); - if ( !(control_word & CW_Invalid) ) - return 0; - templ |= (0x40000000 >> 8); + reg_copy(st0_ptr, &tmp); + + /* A denormal will always underflow. */ +#ifndef PECULIAR_486 + /* An 80486 is supposed to be able to generate + a denormal exception here, but... */ + /* Underflow has priority. */ + if ( control_word & CW_Underflow ) + denormal_operand(); +#endif /* PECULIAR_486 */ + goto denormal_arg; + } + else if (st0_tag == TW_Infinity) + { + templ = 0x7f800000; + } + else if (st0_tag == TW_NaN) + { + /* Is it really a NaN ? */ + if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) ) + { + /* See if we can get a valid NaN from the FPU_REG */ + templ = st0_ptr->sigh >> 8; + if ( !(st0_ptr->sigh & 0x40000000) ) + { + /* It is a signalling NaN */ + EXCEPTION(EX_Invalid); + if ( !(control_word & CW_Invalid) ) + return 0; + templ |= (0x40000000 >> 8); + } + templ |= 0x7f800000; + } + else + { + /* It is an unsupported data type */ + EXCEPTION(EX_Invalid); + if ( !(control_word & CW_Invalid) ) + return 0; + templ = 0xffc00000; + } } - templ |= 0x7f800000; +#ifdef PARANOID + else + { + EXCEPTION(EX_INTERNAL|0x164); + return 0; + } +#endif } - else if ( st0_tag == TW_Empty ) + else if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); @@ -829,7 +824,7 @@ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)single,4); - put_fs_long(0xffc00000, (unsigned long *) single); + FPU_put_user(0xffc00000, (unsigned long *) single); RE_ENTRANT_CHECK_ON; return 1; } @@ -843,12 +838,12 @@ return 0; } #endif - if (st0_ptr->sign) + if ( getsign(st0_ptr) ) templ |= 0x80000000; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)single,4); - put_fs_long(templ,(unsigned long *) single); + FPU_put_user(templ,(unsigned long *) single); RE_ENTRANT_CHECK_ON; return 1; @@ -856,34 +851,37 @@ /* Put a long long into user memory */ -int reg_store_int64(long long *d, FPU_REG *st0_ptr) +int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d) { FPU_REG t; long long tll; int precision_loss; - char st0_tag = st0_ptr->tag; - if ( st0_tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - else if ( (st0_tag == TW_Infinity) || - (st0_tag == TW_NaN) ) + else if ( st0_tag == TAG_Special ) { - EXCEPTION(EX_Invalid); - goto invalid_operand; + st0_tag = FPU_Special(st0_ptr); + if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } } - reg_move(st0_ptr, &t); - precision_loss = round_to_int(&t); + reg_copy(st0_ptr, &t); + precision_loss = FPU_round_to_int(&t, st0_tag); ((long *)&tll)[0] = t.sigl; ((long *)&tll)[1] = t.sigh; if ( (precision_loss == 1) || ((t.sigh & 0x80000000) && !((t.sigh == 0x80000000) && (t.sigl == 0) && - (t.sign == SIGN_NEG))) ) + signnegative(&t))) ) { EXCEPTION(EX_Invalid); /* This is a special case: see sec 16.2.5.1 of the 80486 book */ @@ -900,14 +898,13 @@ { if ( precision_loss ) set_precision_flag(precision_loss); - if ( t.sign ) + if ( signnegative(&t) ) tll = - tll; } RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)d,8); - put_fs_long(((long *)&tll)[0],(unsigned long *) d); - put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d); + copy_to_user(d, &tll, 8); RE_ENTRANT_CHECK_ON; return 1; @@ -915,30 +912,33 @@ /* Put a long into user memory */ -int reg_store_int32(long *d, FPU_REG *st0_ptr) +int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d) { FPU_REG t; int precision_loss; - char st0_tag = st0_ptr->tag; - if ( st0_tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - else if ( (st0_tag == TW_Infinity) || - (st0_tag == TW_NaN) ) + else if ( st0_tag == TAG_Special ) { - EXCEPTION(EX_Invalid); - goto invalid_operand; + st0_tag = FPU_Special(st0_ptr); + if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } } - reg_move(st0_ptr, &t); - precision_loss = round_to_int(&t); + reg_copy(st0_ptr, &t); + precision_loss = FPU_round_to_int(&t, st0_tag); if (t.sigh || ((t.sigl & 0x80000000) && - !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) ) + !((t.sigl == 0x80000000) && signnegative(&t))) ) { EXCEPTION(EX_Invalid); /* This is a special case: see sec 16.2.5.1 of the 80486 book */ @@ -955,13 +955,13 @@ { if ( precision_loss ) set_precision_flag(precision_loss); - if ( t.sign ) + if ( signnegative(&t) ) t.sigl = -(long)t.sigl; } RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,4); - put_fs_long(t.sigl, (unsigned long *) d); + FPU_put_user(t.sigl, (unsigned long *) d); RE_ENTRANT_CHECK_ON; return 1; @@ -969,30 +969,33 @@ /* Put a short into user memory */ -int reg_store_int16(short *d, FPU_REG *st0_ptr) +int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d) { FPU_REG t; int precision_loss; - char st0_tag = st0_ptr->tag; - if ( st0_tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } - else if ( (st0_tag == TW_Infinity) || - (st0_tag == TW_NaN) ) + else if ( st0_tag == TAG_Special ) { - EXCEPTION(EX_Invalid); - goto invalid_operand; + st0_tag = FPU_Special(st0_ptr); + if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } } - reg_move(st0_ptr, &t); - precision_loss = round_to_int(&t); + reg_copy(st0_ptr, &t); + precision_loss = FPU_round_to_int(&t, st0_tag); if (t.sigh || ((t.sigl & 0xffff8000) && - !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) ) + !((t.sigl == 0x8000) && signnegative(&t))) ) { EXCEPTION(EX_Invalid); /* This is a special case: see sec 16.2.5.1 of the 80486 book */ @@ -1009,13 +1012,13 @@ { if ( precision_loss ) set_precision_flag(precision_loss); - if ( t.sign ) + if ( signnegative(&t) ) t.sigl = -t.sigl; } RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,2); - put_fs_word((short)t.sigl,(short *) d); + FPU_put_user((short)t.sigl,(short *) d); RE_ENTRANT_CHECK_ON; return 1; @@ -1023,24 +1026,33 @@ /* Put a packed bcd array into user memory */ -int reg_store_bcd(char *d, FPU_REG *st0_ptr) +int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d) { FPU_REG t; unsigned long long ll; - unsigned char b; + u_char b; int i, precision_loss; - unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0; - char st0_tag = st0_ptr->tag; + u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0; - if ( st0_tag == TW_Empty ) + if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } + else if ( st0_tag == TAG_Special ) + { + st0_tag = FPU_Special(st0_ptr); + if ( (st0_tag == TW_Infinity) || + (st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } + } - reg_move(st0_ptr, &t); - precision_loss = round_to_int(&t); + reg_copy(st0_ptr, &t); + precision_loss = FPU_round_to_int(&t, st0_tag); ll = significand(&t); /* Check for overflow, by comparing with 999999999999999999 decimal. */ @@ -1056,10 +1068,10 @@ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,10); for ( i = 0; i < 7; i++) - put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */ - put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */ - put_fs_byte(0xff, (unsigned char *) d+8); - put_fs_byte(0xff, (unsigned char *) d+9); + FPU_put_user(0, (u_char *) d+i); /* These bytes "undefined" */ + FPU_put_user(0xc0, (u_char *) d+7); /* This byte "undefined" */ + FPU_put_user(0xff, (u_char *) d+8); + FPU_put_user(0xff, (u_char *) d+9); RE_ENTRANT_CHECK_ON; return 1; } @@ -1077,14 +1089,14 @@ RE_ENTRANT_CHECK_ON; for ( i = 0; i < 9; i++) { - b = div_small(&ll, 10); - b |= (div_small(&ll, 10)) << 4; + b = FPU_div_small(&ll, 10); + b |= (FPU_div_small(&ll, 10)) << 4; RE_ENTRANT_CHECK_OFF; - put_fs_byte(b,(unsigned char *) d+i); + FPU_put_user(b,(u_char *) d+i); RE_ENTRANT_CHECK_ON; } RE_ENTRANT_CHECK_OFF; - put_fs_byte(sign,(unsigned char *) d+9); + FPU_put_user(sign,(u_char *) d+9); RE_ENTRANT_CHECK_ON; return 1; @@ -1100,25 +1112,25 @@ /* Overflow is signalled by a non-zero return value (in eax). In the case of overflow, the returned significand always has the largest possible value */ -int round_to_int(FPU_REG *r) +int FPU_round_to_int(FPU_REG *r, u_char tag) { - char very_big; + u_char very_big; unsigned eax; - if (r->tag == TW_Zero) + if (tag == TAG_Zero) { /* Make sure that zero is returned */ significand(r) = 0; return 0; /* o.k. */ } - - if (r->exp > EXP_BIAS + 63) + + if (exponent(r) > 63) { r->sigl = r->sigh = ~0; /* The largest representable number */ return 1; /* overflow */ } - eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp); + eax = FPU_shrxs(&r->sigl, 63 - exponent(r)); very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */ #define half_or_more (eax & 0x80000000) #define frac_part (eax) @@ -1135,7 +1147,7 @@ } break; case RC_DOWN: - if (frac_part && r->sign) + if (frac_part && getsign(r)) { if ( very_big ) return 1; /* overflow */ significand(r) ++; @@ -1143,7 +1155,7 @@ } break; case RC_UP: - if (frac_part && !r->sign) + if (frac_part && !getsign(r)) { if ( very_big ) return 1; /* overflow */ significand(r) ++; @@ -1160,10 +1172,10 @@ /*===========================================================================*/ -char *fldenv(fpu_addr_modes addr_modes, char *s) +u_char *fldenv(fpu_addr_modes addr_modes, u_char *s) { unsigned short tag_word = 0; - unsigned char tag; + u_char tag; int i; if ( (addr_modes.default_mode == VM86) || @@ -1172,13 +1184,13 @@ { 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)); - instruction_address.offset = get_fs_word((unsigned short *) (s+6)); - instruction_address.selector = get_fs_word((unsigned short *) (s+8)); - operand_address.offset = get_fs_word((unsigned short *) (s+0x0a)); - operand_address.selector = get_fs_word((unsigned short *) (s+0x0c)); + FPU_get_user(control_word, (unsigned short *) s); + FPU_get_user(partial_status, (unsigned short *) (s+2)); + FPU_get_user(tag_word, (unsigned short *) (s+4)); + FPU_get_user(instruction_address.offset, (unsigned short *) (s+6)); + FPU_get_user(instruction_address.selector, (unsigned short *) (s+8)); + FPU_get_user(operand_address.offset, (unsigned short *) (s+0x0a)); + FPU_get_user(operand_address.selector, (unsigned short *) (s+0x0c)); RE_ENTRANT_CHECK_ON; s += 0x0e; if ( addr_modes.default_mode == VM86 ) @@ -1192,23 +1204,23 @@ { 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)); - instruction_address.offset = get_fs_long((unsigned long *) (s+0x0c)); - instruction_address.selector = get_fs_word((unsigned short *) (s+0x10)); - instruction_address.opcode = get_fs_word((unsigned short *) (s+0x12)); - operand_address.offset = get_fs_long((unsigned long *) (s+0x14)); - operand_address.selector = get_fs_long((unsigned long *) (s+0x18)); + FPU_get_user(control_word, (unsigned short *) s); + FPU_get_user(partial_status, (unsigned short *) (s+4)); + FPU_get_user(tag_word, (unsigned short *) (s+8)); + FPU_get_user(instruction_address.offset, (unsigned long *) (s+0x0c)); + FPU_get_user(instruction_address.selector, (unsigned short *) (s+0x10)); + FPU_get_user(instruction_address.opcode, (unsigned short *) (s+0x12)); + FPU_get_user(operand_address.offset, (unsigned long *) (s+0x14)); + FPU_get_user(operand_address.selector, (unsigned long *) (s+0x18)); RE_ENTRANT_CHECK_ON; s += 0x1c; } #ifdef PECULIAR_486 control_word &= ~0xe080; -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ - top = (partial_status >> SW_Top_Shift) & 7; + FPU_top = (partial_status >> SW_Top_Shift) & 7; if ( partial_status & ~control_word & CW_Exceptions ) partial_status |= (SW_Summary | SW_Backward); @@ -1220,29 +1232,28 @@ tag = tag_word & 3; tag_word >>= 2; - if ( tag == 3 ) + if ( tag == TAG_Empty ) /* New tag is empty. Accept it */ - regs[i].tag = TW_Empty; - else if ( regs[i].tag == TW_Empty ) + FPU_settag(i, TAG_Empty); + else if ( FPU_gettag(i) == TAG_Empty ) { /* Old tag is empty and new tag is not empty. New tag is determined by old reg contents */ - if ( regs[i].exp == EXP_BIAS - EXTENDED_Ebias ) + if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias ) { - if ( !(regs[i].sigl | regs[i].sigh) ) - regs[i].tag = TW_Zero; + if ( !(fpu_register(i).sigl | fpu_register(i).sigh) ) + FPU_settag(i, TAG_Zero); else - regs[i].tag = TW_Valid; + FPU_settag(i, TAG_Special); } - else if ( regs[i].exp == 0x7fff + EXP_BIAS - EXTENDED_Ebias ) + else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias ) { - if ( !((regs[i].sigh & ~0x80000000) | regs[i].sigl) ) - regs[i].tag = TW_Infinity; - else - regs[i].tag = TW_NaN; + FPU_settag(i, TAG_Special); } + else if ( fpu_register(i).sigh & 0x80000000 ) + FPU_settag(i, TAG_Valid); else - regs[i].tag = TW_Valid; + FPU_settag(i, TAG_Special); /* An Un-normal */ } /* Else old tag is not empty and new tag is not empty. Old tag remains correct */ @@ -1252,56 +1263,32 @@ } -void frstor(fpu_addr_modes addr_modes, char *data_address) +void frstor(fpu_addr_modes addr_modes, u_char *data_address) { - int i, stnr; - unsigned char tag; - char *s = fldenv(addr_modes, data_address); + int i, regnr; + u_char *s = fldenv(addr_modes, data_address); + int offset = (FPU_top & 7) * 10, other = 80 - offset; + + /* Copy all registers in stack order. */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ,s,80); + FPU_copy_from_user(register_base+offset, s, other); + if ( offset ) + FPU_copy_from_user(register_base, s+other, offset); + RE_ENTRANT_CHECK_ON; for ( i = 0; i < 8; i++ ) { - /* Load each register. */ - stnr = (i+top) & 7; - tag = regs[stnr].tag; /* Derived from the fldenv() loaded tag word. */ - reg_load_extended((long double *)(s+i*10), ®s[stnr]); - if ( tag == TW_Empty ) /* The loaded data over-rides all other cases. */ - regs[stnr].tag = tag; + regnr = (i+FPU_top) & 7; + if ( FPU_gettag(regnr) != TAG_Empty ) + /* The loaded data over-rides all other cases. */ + FPU_settag(regnr, FPU_tagof(&st(i))); } } -unsigned short tag_word(void) -{ - unsigned short word = 0; - unsigned char tag; - int i; - - for ( i = 7; i >= 0; i-- ) - { - switch ( tag = regs[i].tag ) - { - case TW_Valid: - if ( regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias) ) - tag = 2; - break; - case TW_Infinity: - case TW_NaN: - tag = 2; - break; - case TW_Empty: - tag = 3; - break; - /* TW_Zero already has the correct value */ - } - word <<= 2; - word |= tag; - } - return word; -} - - -char *fstenv(fpu_addr_modes addr_modes, char *d) +u_char *fstenv(fpu_addr_modes addr_modes, u_char *d) { if ( (addr_modes.default_mode == VM86) || ((addr_modes.default_mode == PM16) @@ -1310,25 +1297,25 @@ RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,14); #ifdef PECULIAR_486 - put_fs_long(control_word & ~0xe080, (unsigned short *) d); + FPU_put_user(control_word & ~0xe080, (unsigned long *) 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(instruction_address.offset, (unsigned short *) (d+6)); - put_fs_word(operand_address.offset, (unsigned short *) (d+0x0a)); + FPU_put_user(control_word, (unsigned short *) d); +#endif /* PECULIAR_486 */ + FPU_put_user(status_word(), (unsigned short *) (d+2)); + FPU_put_user(fpu_tag_word, (unsigned short *) (d+4)); + FPU_put_user(instruction_address.offset, (unsigned short *) (d+6)); + FPU_put_user(operand_address.offset, (unsigned short *) (d+0x0a)); if ( addr_modes.default_mode == VM86 ) { - put_fs_word((instruction_address.offset & 0xf0000) >> 4, + FPU_put_user((instruction_address.offset & 0xf0000) >> 4, (unsigned short *) (d+8)); - put_fs_word((operand_address.offset & 0xf0000) >> 4, + FPU_put_user((operand_address.offset & 0xf0000) >> 4, (unsigned short *) (d+0x0c)); } else { - put_fs_word(instruction_address.selector, (unsigned short *) (d+8)); - put_fs_word(operand_address.selector, (unsigned short *) (d+0x0c)); + FPU_put_user(instruction_address.selector, (unsigned short *) (d+8)); + FPU_put_user(operand_address.selector, (unsigned short *) (d+0x0c)); } RE_ENTRANT_CHECK_ON; d += 0x0e; @@ -1336,28 +1323,17 @@ 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)); -#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)); -#endif PECULIAR_486 - put_fs_long(instruction_address.offset, (unsigned long *) (d+0x0c)); - put_fs_word(instruction_address.selector, (unsigned short *) (d+0x10)); - put_fs_word(instruction_address.opcode, (unsigned short *) (d+0x12)); - put_fs_long(operand_address.offset, (unsigned long *) (d+0x14)); + FPU_verify_area(VERIFY_WRITE, d, 7*4); #ifdef PECULIAR_486 - /* An 80486 sets all the reserved bits to 1. */ - put_fs_word(operand_address.selector, (unsigned short *) (d+0x18)); - put_fs_word(0xffff, (unsigned short *) (d+0x1a)); -#else - put_fs_long(operand_address.selector, (unsigned long *) (d+0x18)); -#endif PECULIAR_486 + control_word &= ~0xe080; + /* An 80486 sets nearly all of the reserved bits to 1. */ + control_word |= 0xffff0040; + partial_status = status_word() | 0xffff0000; + fpu_tag_word |= 0xffff0000; + I387.soft.fcs &= ~0xf8000000; + I387.soft.fos |= 0xffff0000; +#endif /* PECULIAR_486 */ + FPU_copy_to_user(d, &control_word, 7*4); RE_ENTRANT_CHECK_ON; d += 0x1c; } @@ -1369,84 +1345,23 @@ } -void fsave(fpu_addr_modes addr_modes, char *data_address) +void fsave(fpu_addr_modes addr_modes, u_char *data_address) { - char *d; - int i; + u_char *d; + int offset = (FPU_top & 7) * 10, other = 80 - offset; d = fstenv(addr_modes, data_address); + RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,80); + + /* Copy all registers in stack order. */ + FPU_copy_to_user(d, register_base+offset, other); + if ( offset ) + FPU_copy_to_user(d+other, register_base, offset); RE_ENTRANT_CHECK_ON; - for ( i = 0; i < 8; i++ ) - write_to_extended(®s[(top + i) & 7], d + 10 * i); finit(); - } /*===========================================================================*/ - -/* - A call to this function must be preceded by a call to - FPU_verify_area() to verify access to the 10 bytes at d - */ -static void write_to_extended(FPU_REG *rp, char *d) -{ - long e; - FPU_REG tmp; - - e = rp->exp - EXP_BIAS + EXTENDED_Ebias; - -#ifdef PARANOID - switch ( rp->tag ) - { - case TW_Zero: - if ( rp->sigh | rp->sigl | e ) - EXCEPTION(EX_INTERNAL | 0x160); - break; - case TW_Infinity: - case TW_NaN: - if ( (e ^ 0x7fff) | !(rp->sigh & 0x80000000) ) - EXCEPTION(EX_INTERNAL | 0x161); - break; - default: - if (e > 0x7fff || e < -63) - EXCEPTION(EX_INTERNAL | 0x162); - } -#endif PARANOID - - /* - All numbers except denormals are stored internally in a - format which is compatible with the extended real number - format. - */ - if ( e > 0 ) - { - /* just copy the reg */ - RE_ENTRANT_CHECK_OFF; - put_fs_long(rp->sigl, (unsigned long *) d); - put_fs_long(rp->sigh, (unsigned long *) (d + 4)); - RE_ENTRANT_CHECK_ON; - } - else - { - /* - The number is a de-normal stored as a normal using our - extra exponent range, or is Zero. - Convert it back to a de-normal, or leave it as Zero. - */ - reg_move(rp, &tmp); - tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 63 */ - round_to_int(&tmp); - e = 0; - RE_ENTRANT_CHECK_OFF; - put_fs_long(tmp.sigl, (unsigned long *) d); - put_fs_long(tmp.sigh, (unsigned long *) (d + 4)); - RE_ENTRANT_CHECK_ON; - } - e |= rp->sign == SIGN_POS ? 0 : 0x8000; - RE_ENTRANT_CHECK_OFF; - put_fs_word(e, (unsigned short *) (d + 8)); - RE_ENTRANT_CHECK_ON; -} diff -urN linux-2.0.39/arch/i386/math-emu/reg_mul.c linux-2.0.40/arch/i386/math-emu/reg_mul.c --- linux-2.0.39/arch/i386/math-emu/reg_mul.c 1994-02-25 04:42:46.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_mul.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,10 +3,11 @@ | | | Multiply one FPU_REG by another, put the result in a destination FPU_REG. | | | - | Copyright (C) 1992,1993 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Copyright (C) 1992,1993,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | + | Returns the tag of the result if no exceptions or errors occurred. | | | +---------------------------------------------------------------------------*/ @@ -14,92 +15,117 @@ | The destination may be any FPU_REG, including one of the source FPU_REGs. | +---------------------------------------------------------------------------*/ +#include "fpu_emu.h" #include "exception.h" #include "reg_constant.h" -#include "fpu_emu.h" #include "fpu_system.h" +/* + Multiply two registers to give a register result. + The sources are st(deststnr) and (b,tagb,signb). + The destination is st(deststnr). + */ /* This routine must be called with non-empty source registers */ -int reg_mul(FPU_REG const *a, FPU_REG const *b, - FPU_REG *dest, unsigned int control_w) +int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w) { - char saved_sign = dest->sign; - char sign = (a->sign ^ b->sign); + FPU_REG *a = &st(deststnr); + FPU_REG *dest = a; + u_char taga = FPU_gettagi(deststnr); + u_char saved_sign = getsign(dest); + u_char sign = (getsign(a) ^ getsign(b)); + int tag; - if (!(a->tag | b->tag)) + + if ( !(taga | tagb) ) { /* Both regs Valid, this should be the most common case. */ - dest->sign = sign; - if ( reg_u_mul(a, b, dest, control_w) ) + + tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b)); + if ( tag < 0 ) { - dest->sign = saved_sign; - return 1; + setsign(dest, saved_sign); + return tag; } - return 0; + FPU_settagi(deststnr, tag); + return tag; } - else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero)) + + if ( taga == TAG_Special ) + taga = FPU_Special(a); + if ( tagb == TAG_Special ) + tagb = FPU_Special(b); + + if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) + || ((taga == TW_Denormal) && (tagb == TAG_Valid)) + || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) { -#ifdef DENORM_OPERAND - if ( ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) || - ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER)) ) + FPU_REG x, y; + if ( denormal_operand() < 0 ) + return FPU_Exception; + + FPU_to_exp16(a, &x); + FPU_to_exp16(b, &y); + tag = FPU_u_mul(&x, &y, dest, control_w, sign, + exponent16(&x) + exponent16(&y)); + if ( tag < 0 ) { - if ( denormal_operand() ) return 1; + setsign(dest, saved_sign); + return tag; } -#endif DENORM_OPERAND + FPU_settagi(deststnr, tag); + return tag; + } + else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) ) + { + if ( ((tagb == TW_Denormal) || (taga == TW_Denormal)) + && (denormal_operand() < 0) ) + return FPU_Exception; + /* Must have either both arguments == zero, or one valid and the other zero. The result is therefore zero. */ - reg_move(&CONST_Z, dest); + FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); /* The 80486 book says that the answer is +0, but a real 80486 behaves this way. IEEE-754 apparently says it should be this way. */ - dest->sign = sign; - return 0; + setsign(dest, sign); + return TAG_Zero; } - else - { /* Must have infinities, NaNs, etc */ - if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) ) - { return real_2op_NaN(a, b, dest); } - else if (a->tag == TW_Infinity) - { - if (b->tag == TW_Zero) - { return arith_invalid(dest); } /* Zero*Infinity is invalid */ - else - { -#ifdef DENORM_OPERAND - if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(a, dest); - dest->sign = sign; - } - return 0; - } - else if (b->tag == TW_Infinity) - { - if (a->tag == TW_Zero) - { return arith_invalid(dest); } /* Zero*Infinity is invalid */ - else - { -#ifdef DENORM_OPERAND - if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && - denormal_operand() ) - return 1; -#endif DENORM_OPERAND - reg_move(b, dest); - dest->sign = sign; - } - return 0; - } + else if ( (taga == TW_NaN) || (tagb == TW_NaN) ) + { + return real_2op_NaN(b, tagb, deststnr, &st(0)); + } + else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero)) + || ((tagb == TW_Infinity) && (taga == TAG_Zero)) ) + { + return arith_invalid(deststnr); /* Zero*Infinity is invalid */ + } + else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal)) + && (denormal_operand() < 0) ) + { + return FPU_Exception; + } + else if (taga == TW_Infinity) + { + FPU_copy_to_regi(a, TAG_Special, deststnr); + setsign(dest, sign); + return TAG_Special; + } + else if (tagb == TW_Infinity) + { + FPU_copy_to_regi(b, TAG_Special, deststnr); + setsign(dest, sign); + return TAG_Special; + } + #ifdef PARANOID - else - { - EXCEPTION(EX_INTERNAL|0x102); - return 1; - } -#endif PARANOID + else + { + EXCEPTION(EX_INTERNAL|0x102); + return FPU_Exception; } +#endif /* PARANOID */ + } diff -urN linux-2.0.39/arch/i386/math-emu/reg_norm.S linux-2.0.40/arch/i386/math-emu/reg_norm.S --- linux-2.0.39/arch/i386/math-emu/reg_norm.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_norm.S 2004-02-07 23:13:01.000000000 -0800 @@ -1,16 +1,19 @@ /*---------------------------------------------------------------------------+ | reg_norm.S | | | - | Copyright (C) 1992,1993,1994,1995 | + | Copyright (C) 1992,1993,1994,1995,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | | Normalize the value in a FPU_REG. | | | | Call from C as: | - | void normalize(FPU_REG *n) | + | int FPU_normalize(FPU_REG *n) | | | - | void normalize_nuo(FPU_REG *n) | + | int FPU_normalize_nuo(FPU_REG *n) | + | | + | Return value is the tag of the answer, or-ed with FPU_Exception if | + | one was raised, or -1 on internal error. | | | +---------------------------------------------------------------------------*/ @@ -18,24 +21,13 @@ .text -ENTRY(normalize) +ENTRY(FPU_normalize) pushl %ebp movl %esp,%ebp pushl %ebx movl PARAM1,%ebx -#ifdef PARANOID - cmpb TW_Valid,TAG(%ebx) - je L_ok - - pushl $0x220 - call SYMBOL_NAME(exception) - addl $4,%esp - -L_ok: -#endif PARANOID - movl SIGH(%ebx),%edx movl SIGL(%ebx),%eax @@ -48,7 +40,7 @@ movl %eax,%edx xorl %eax,%eax - subl $32,EXP(%ebx) /* This can cause an underflow */ + subw $32,EXP(%ebx) /* This can cause an underflow */ /* We need to shift left by 1 - 31 bits */ L_shift_1: @@ -57,18 +49,25 @@ negl %ecx shld %cl,%eax,%edx shl %cl,%eax - subl %ecx,EXP(%ebx) /* This can cause an underflow */ + subw %cx,EXP(%ebx) /* This can cause an underflow */ movl %edx,SIGH(%ebx) movl %eax,SIGL(%ebx) L_done: - cmpl EXP_OVER,EXP(%ebx) + cmpw EXP_OVER,EXP(%ebx) jge L_overflow - cmpl EXP_UNDER,EXP(%ebx) + cmpw EXP_UNDER,EXP(%ebx) jle L_underflow +L_exit_valid: + movl TAG_Valid,%eax + + /* Convert the exponent to 80x87 form. */ + addw EXTENDED_Ebias,EXP(%ebx) + andw $0x7fff,EXP(%ebx) + L_exit: popl %ebx leave @@ -76,56 +75,57 @@ L_zero: - movl EXP_UNDER,EXP(%ebx) - movb TW_Zero,TAG(%ebx) + movw $0,EXP(%ebx) + movl TAG_Zero,%eax jmp L_exit L_underflow: + /* Convert the exponent to 80x87 form. */ + addw EXTENDED_Ebias,EXP(%ebx) push %ebx call SYMBOL_NAME(arith_underflow) pop %ebx jmp L_exit L_overflow: + /* Convert the exponent to 80x87 form. */ + addw EXTENDED_Ebias,EXP(%ebx) + cmpb SIGN_POS,PARAM2 + jne L_ovfl_neg + push $0 + jmp L_ovfl_signed +L_ovfl_neg: + push $1 +L_ovfl_signed: push %ebx call SYMBOL_NAME(arith_overflow) pop %ebx + addl $4,%esp jmp L_exit /* Normalise without reporting underflow or overflow */ -ENTRY(normalize_nuo) +ENTRY(FPU_normalize_nuo) pushl %ebp movl %esp,%ebp pushl %ebx movl PARAM1,%ebx -#ifdef PARANOID - cmpb TW_Valid,TAG(%ebx) - je L_ok_nuo - - pushl $0x221 - call SYMBOL_NAME(exception) - addl $4,%esp - -L_ok_nuo: -#endif PARANOID - movl SIGH(%ebx),%edx movl SIGL(%ebx),%eax orl %edx,%edx /* ms bits */ - js L_exit /* Already normalized */ + js L_exit_nuo_valid /* Already normalized */ jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */ orl %eax,%eax - jz L_zero /* The contents are zero */ + jz L_exit_nuo_zero /* The contents are zero */ movl %eax,%edx xorl %eax,%eax - subl $32,EXP(%ebx) /* This can cause an underflow */ + subw $32,EXP(%ebx) /* This can cause an underflow */ /* We need to shift left by 1 - 31 bits */ L_nuo_shift_1: @@ -134,10 +134,22 @@ negl %ecx shld %cl,%eax,%edx shl %cl,%eax - subl %ecx,EXP(%ebx) /* This can cause an underflow */ + subw %cx,EXP(%ebx) /* This can cause an underflow */ movl %edx,SIGH(%ebx) movl %eax,SIGL(%ebx) - jmp L_exit +L_exit_nuo_valid: + movl TAG_Valid,%eax + popl %ebx + leave + ret + +L_exit_nuo_zero: + movl TAG_Zero,%eax + movw EXP_UNDER,EXP(%ebx) + + popl %ebx + leave + ret diff -urN linux-2.0.39/arch/i386/math-emu/reg_round.S linux-2.0.40/arch/i386/math-emu/reg_round.S --- linux-2.0.39/arch/i386/math-emu/reg_round.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_round.S 2004-02-07 23:13:01.000000000 -0800 @@ -4,17 +4,20 @@ | | | Rounding/truncation/etc for FPU basic arithmetic functions. | | | - | Copyright (C) 1993,1995 | + | Copyright (C) 1993,1995,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | - | This code has four possible entry points. | + | This code has three possible entry points. | | The following must be entered by a jmp instruction: | - | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. | + | fpu_reg_round, and fpu_Arith_exit. | | | - | The _round_reg entry point is intended to be used by C code. | + | The FPU_round entry point is intended to be used by C code. | | From C, call as: | - | void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) | + | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) | + | | + | Return value is the tag of the answer, or-ed with FPU_Exception if | + | one was raised, or -1 on internal error. | | | | For correct "up" and "down" rounding, the argument must have the correct | | sign. | @@ -22,18 +25,17 @@ +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ - | Four entry points. | + | Three entry points. | | | - | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: | + | Needed by the fpu_reg_round entry point: | | %eax:%ebx 64 bit significand | | %edx 32 bit extension of the significand | | %edi pointer to an FPU_REG for the result to be stored | | stack calling function must have set up a C stack frame and | | pushed %esi, %edi, and %ebx | | | - | Needed just for the fpu_reg_round_sqrt entry point: | - | %cx A control word in the same format as the FPU control word. | - | Otherwise, PARAM4 must give such a value. | + | A control word in the same format as the FPU control word must | + | be in PARAM4. | | | | | | The significand and its extension are assumed to be exact in the | @@ -92,21 +94,20 @@ /* Not re-entrant, so we can gain speed by putting local storage in a static area: */ .data - .align 2,0 + .align 4,0 FPU_bits_lost: .byte 0 FPU_denormal: .byte 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text .globl fpu_reg_round -.globl fpu_reg_round_sqrt .globl fpu_Arith_exit /* Entry point when called from C */ -ENTRY(round_reg) +ENTRY(FPU_round) pushl %ebp movl %esp,%ebp pushl %esi @@ -117,30 +118,26 @@ movl SIGH(%edi),%eax movl SIGL(%edi),%ebx movl PARAM2,%edx - movl PARAM3,%ecx - jmp fpu_reg_round_sqrt fpu_reg_round: /* Normal entry point */ movl PARAM4,%ecx -fpu_reg_round_sqrt: /* Entry point from wm_sqrt.S */ - #ifndef NON_REENTRANT_FPU pushl %ebx /* adjust the stack pointer */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ #ifdef PARANOID /* Cannot use this here yet */ /* orl %eax,%eax */ /* jns L_entry_bugged */ -#endif PARANOID +#endif /* PARANOID */ - cmpl EXP_UNDER,EXP(%edi) - jle xMake_denorm /* The number is a de-normal */ + cmpw EXP_UNDER,EXP(%edi) + jle L_Make_denorm /* The number is a de-normal */ movb $0,FPU_denormal /* 0 -> not a de-normal */ -xDenorm_done: +Denorm_done: movb $0,FPU_bits_lost /* No bits yet lost in rounding */ movl %ecx,%esi @@ -161,12 +158,12 @@ je LRound_To_64 #ifdef PARANOID jmp L_bugged_denorm_486 -#endif PARANOID +#endif /* PARANOID */ #else #ifdef PARANOID jmp L_bugged_denorm /* There is no bug, just a bad control word */ -#endif PARANOID -#endif PECULIAR_486 +#endif /* PARANOID */ +#endif /* PECULIAR_486 */ /* Round etc to 24 bit precision */ @@ -187,16 +184,16 @@ #ifdef PARANOID jmp L_bugged_round24 -#endif PARANOID +#endif /* PARANOID */ LUp_24: - cmpb SIGN_POS,SIGN(%edi) + cmpb SIGN_POS,PARAM5 jne LCheck_truncate_24 /* If negative then up==truncate */ jmp LCheck_24_round_up LDown_24: - cmpb SIGN_POS,SIGN(%edi) + cmpb SIGN_POS,PARAM5 je LCheck_truncate_24 /* If positive then down==truncate */ LCheck_24_round_up: @@ -205,7 +202,7 @@ orl %ebx,%ecx orl %edx,%ecx jnz LDo_24_round_up - jmp LRe_normalise + jmp L_Re_normalise LRound_nearest_24: /* Do rounding of the 24th bit if needed (nearest or even) */ @@ -240,13 +237,13 @@ andl $0x000000ff,%ecx orl %ebx,%ecx orl %edx,%ecx - jz LRe_normalise /* No truncation needed */ + jz L_Re_normalise /* No truncation needed */ LDo_truncate_24: andl $0xffffff00,%eax /* Truncate to 24 bits */ xorl %ebx,%ebx movb LOST_DOWN,FPU_bits_lost - jmp LRe_normalise + jmp L_Re_normalise /* Round etc to 53 bit precision */ @@ -267,16 +264,16 @@ #ifdef PARANOID jmp L_bugged_round53 -#endif PARANOID +#endif /* PARANOID */ LUp_53: - cmpb SIGN_POS,SIGN(%edi) + cmpb SIGN_POS,PARAM5 jne LCheck_truncate_53 /* If negative then up==truncate */ jmp LCheck_53_round_up LDown_53: - cmpb SIGN_POS,SIGN(%edi) + cmpb SIGN_POS,PARAM5 je LCheck_truncate_53 /* If positive then down==truncate */ LCheck_53_round_up: @@ -284,7 +281,7 @@ andl $0x000007ff,%ecx orl %edx,%ecx jnz LDo_53_round_up - jmp LRe_normalise + jmp L_Re_normalise LRound_nearest_53: /* Do rounding of the 53rd bit if needed (nearest or even) */ @@ -315,12 +312,12 @@ movl %ebx,%ecx andl $0x000007ff,%ecx orl %edx,%ecx - jz LRe_normalise + jz L_Re_normalise LTruncate_53: movb LOST_DOWN,FPU_bits_lost andl $0xfffff800,%ebx /* Truncate to 53 bits */ - jmp LRe_normalise + jmp L_Re_normalise /* Round etc to 64 bit precision */ @@ -341,23 +338,23 @@ #ifdef PARANOID jmp L_bugged_round64 -#endif PARANOID +#endif /* PARANOID */ LUp_64: - cmpb SIGN_POS,SIGN(%edi) + cmpb SIGN_POS,PARAM5 jne LCheck_truncate_64 /* If negative then up==truncate */ orl %edx,%edx jnz LDo_64_round_up - jmp LRe_normalise + jmp L_Re_normalise LDown_64: - cmpb SIGN_POS,SIGN(%edi) + cmpb SIGN_POS,PARAM5 je LCheck_truncate_64 /* If positive then down==truncate */ orl %edx,%edx jnz LDo_64_round_up - jmp LRe_normalise + jmp L_Re_normalise LRound_nearest_64: cmpl $0x80000000,%edx @@ -366,7 +363,7 @@ jne LDo_64_round_up /* Now test for round-to-even */ - testb $1,%ebx + testb $1,%bl jz LCheck_truncate_64 LDo_64_round_up: @@ -375,49 +372,63 @@ adcl $0,%eax LCheck_Round_Overflow: - jnc LRe_normalise + jnc L_Re_normalise /* Overflow, adjust the result (significand to 1.0) */ rcrl $1,%eax rcrl $1,%ebx - incl EXP(%edi) - jmp LRe_normalise + incw EXP(%edi) + jmp L_Re_normalise LCheck_truncate_64: orl %edx,%edx - jz LRe_normalise + jz L_Re_normalise LTruncate_64: movb LOST_DOWN,FPU_bits_lost -LRe_normalise: +L_Re_normalise: testb $0xff,FPU_denormal - jnz xNormalise_result + jnz Normalise_result -xL_Normalised: +L_Normalised: + movl TAG_Valid,%edx + +L_deNormalised: cmpb LOST_UP,FPU_bits_lost - je xL_precision_lost_up + je L_precision_lost_up cmpb LOST_DOWN,FPU_bits_lost - je xL_precision_lost_down + je L_precision_lost_down -xL_no_precision_loss: +L_no_precision_loss: /* store the result */ - movb TW_Valid,TAG(%edi) -xL_Store_significand: +L_Store_significand: movl %eax,SIGH(%edi) movl %ebx,SIGL(%edi) - xorl %eax,%eax /* No errors detected. */ - - cmpl EXP_OVER,EXP(%edi) + cmpw EXP_OVER,EXP(%edi) jge L_overflow -fpu_reg_round_exit: + movl %edx,%eax + + /* Convert the exponent to 80x87 form. */ + addw EXTENDED_Ebias,EXP(%edi) + andw $0x7fff,EXP(%edi) + +fpu_reg_round_signed_special_exit: + + cmpb SIGN_POS,PARAM5 + je fpu_reg_round_special_exit + + orw $0x8000,EXP(%edi) /* Negative sign for the result. */ + +fpu_reg_round_special_exit: + #ifndef NON_REENTRANT_FPU popl %ebx /* adjust the stack pointer */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ fpu_Arith_exit: popl %ebx @@ -431,21 +442,25 @@ * Set the FPU status flags to represent precision loss due to * round-up. */ -xL_precision_lost_up: +L_precision_lost_up: + push %edx push %eax call SYMBOL_NAME(set_precision_flag_up) popl %eax - jmp xL_no_precision_loss + popl %edx + jmp L_no_precision_loss /* * Set the FPU status flags to represent precision loss due to * truncation. */ -xL_precision_lost_down: +L_precision_lost_down: + push %edx push %eax call SYMBOL_NAME(set_precision_flag_down) popl %eax - jmp xL_no_precision_loss + popl %edx + jmp L_no_precision_loss /* @@ -453,30 +468,30 @@ * Shift the number right the required number of bits, which will * have to be undone later... */ -xMake_denorm: +L_Make_denorm: /* The action to be taken depends upon whether the underflow exception is masked */ testb CW_Underflow,%cl /* Underflow mask. */ - jz xUnmasked_underflow /* Do not make a denormal. */ + jz Unmasked_underflow /* Do not make a denormal. */ movb DENORMAL,FPU_denormal pushl %ecx /* Save */ - movl EXP_UNDER+1,%ecx - subl EXP(%edi),%ecx + movw EXP_UNDER+1,%cx + subw EXP(%edi),%cx - cmpl $64,%ecx /* shrd only works for 0..31 bits */ - jnc xDenorm_shift_more_than_63 + cmpw $64,%cx /* shrd only works for 0..31 bits */ + jnc Denorm_shift_more_than_63 - cmpl $32,%ecx /* shrd only works for 0..31 bits */ - jnc xDenorm_shift_more_than_32 + cmpw $32,%cx /* shrd only works for 0..31 bits */ + jnc Denorm_shift_more_than_32 /* * We got here without jumps by assuming that the most common requirement * is for a small de-normalising shift. * Shift by [1..31] bits */ - addl %ecx,EXP(%edi) + addw %cx,EXP(%edi) orl %edx,%edx /* extension */ setne %ch /* Save whether %edx is non-zero */ xorl %edx,%edx @@ -485,11 +500,11 @@ shr %cl,%eax orb %ch,%dl popl %ecx - jmp xDenorm_done + jmp Denorm_done /* Shift by [32..63] bits */ -xDenorm_shift_more_than_32: - addl %ecx,EXP(%edi) +Denorm_shift_more_than_32: + addw %cx,EXP(%edi) subb $32,%cl orl %edx,%edx setne %ch @@ -506,15 +521,15 @@ movl %eax,%ebx xorl %eax,%eax popl %ecx - jmp xDenorm_done + jmp Denorm_done /* Shift by [64..) bits */ -xDenorm_shift_more_than_63: - cmpl $64,%ecx - jne xDenorm_shift_more_than_64 +Denorm_shift_more_than_63: + cmpw $64,%cx + jne Denorm_shift_more_than_64 /* Exactly 64 bit shift */ - addl %ecx,EXP(%edi) + addw %cx,EXP(%edi) xorl %ecx,%ecx orl %edx,%edx setne %cl @@ -526,34 +541,34 @@ xorl %eax,%eax xorl %ebx,%ebx popl %ecx - jmp xDenorm_done + jmp Denorm_done -xDenorm_shift_more_than_64: - movl EXP_UNDER+1,EXP(%edi) +Denorm_shift_more_than_64: + movw EXP_UNDER+1,EXP(%edi) /* This is easy, %eax must be non-zero, so.. */ movl $1,%edx xorl %eax,%eax xorl %ebx,%ebx popl %ecx - jmp xDenorm_done + jmp Denorm_done -xUnmasked_underflow: +Unmasked_underflow: movb UNMASKED_UNDERFLOW,FPU_denormal - jmp xDenorm_done + jmp Denorm_done /* Undo the de-normalisation. */ -xNormalise_result: +Normalise_result: cmpb UNMASKED_UNDERFLOW,FPU_denormal - je xSignal_underflow + je Signal_underflow /* The number must be a denormal if we got here. */ #ifdef PARANOID /* But check it... just in case. */ - cmpl EXP_UNDER+1,EXP(%edi) + cmpw EXP_UNDER+1,EXP(%edi) jne L_norm_bugged -#endif PARANOID +#endif /* PARANOID */ #ifdef PECULIAR_486 /* @@ -565,41 +580,33 @@ * Actual 80486 behaviour differs from this in some circumstances. */ orl %eax,%eax /* ms bits */ - js LNormalise_shift_done /* Will be masked underflow */ -#endif PECULIAR_486 - + js LPseudoDenormal /* Will be masked underflow */ +#else orl %eax,%eax /* ms bits */ - js xL_Normalised /* No longer a denormal */ + js L_Normalised /* No longer a denormal */ +#endif /* PECULIAR_486 */ - jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits */ + jnz LDenormal_adj_exponent orl %ebx,%ebx jz L_underflow_to_zero /* The contents are zero */ -/* Shift left 32 - 63 bits */ - movl %ebx,%eax - xorl %ebx,%ebx - subl $32,EXP(%edi) - -LNormalise_shift_up_to_31: - bsrl %eax,%ecx /* get the required shift in %ecx */ - subl $31,%ecx - negl %ecx - shld %cl,%ebx,%eax - shl %cl,%ebx - subl %ecx,EXP(%edi) +LDenormal_adj_exponent: + decw EXP(%edi) -LNormalise_shift_done: +LPseudoDenormal: testb $0xff,FPU_bits_lost /* bits lost == underflow */ - jz xL_Normalised + movl TAG_Special,%edx + jz L_deNormalised /* There must be a masked underflow */ push %eax pushl EX_Underflow - call SYMBOL_NAME(exception) + call EXCEPTION popl %eax popl %eax - jmp xL_Normalised + movl TAG_Special,%edx + jmp L_deNormalised /* @@ -613,41 +620,50 @@ push %eax pushl EX_Underflow - call SYMBOL_NAME(exception) + call EXCEPTION popl %eax popl %eax /* Reduce the exponent to EXP_UNDER */ - movl EXP_UNDER,EXP(%edi) - movb TW_Zero,TAG(%edi) - jmp xL_Store_significand + movw EXP_UNDER,EXP(%edi) + movl TAG_Zero,%edx + jmp L_Store_significand /* The operations resulted in a number too large to represent. */ L_overflow: + addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */ + cmpb SIGN_POS,PARAM5 + jne L_ovfl_neg + push $0 + jmp L_ovfl_signed +L_ovfl_neg: + push $1 +L_ovfl_signed: push %edi call SYMBOL_NAME(arith_overflow) pop %edi - jmp fpu_reg_round_exit + addl $4,%esp + jmp fpu_reg_round_signed_special_exit -xSignal_underflow: +Signal_underflow: /* The number may have been changed to a non-denormal */ /* by the rounding operations. */ - cmpl EXP_UNDER,EXP(%edi) - jle xDo_unmasked_underflow + cmpw EXP_UNDER,EXP(%edi) + jle Do_unmasked_underflow - jmp xL_Normalised + jmp L_Normalised -xDo_unmasked_underflow: +Do_unmasked_underflow: /* Increase the exponent by the magic number */ - addl $(3*(1<<13)),EXP(%edi) + addw $(3*(1<<13)),EXP(%edi) push %eax pushl EX_Underflow call EXCEPTION popl %eax popl %eax - jmp xL_Normalised + jmp L_Normalised #ifdef PARANOID @@ -663,7 +679,7 @@ call EXCEPTION popl %ebx jmp L_exception_exit -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ L_bugged_round24: pushl EX_INTERNAL|0x231 @@ -694,6 +710,6 @@ call EXCEPTION popl %ebx L_exception_exit: - mov $1,%eax - jmp fpu_reg_round_exit -#endif PARANOID + mov $-1,%eax + jmp fpu_reg_round_special_exit +#endif /* PARANOID */ diff -urN linux-2.0.39/arch/i386/math-emu/reg_u_add.S linux-2.0.40/arch/i386/math-emu/reg_u_add.S --- linux-2.0.39/arch/i386/math-emu/reg_u_add.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_u_add.S 2004-02-07 23:13:01.000000000 -0800 @@ -2,24 +2,26 @@ /*---------------------------------------------------------------------------+ | reg_u_add.S | | | - | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the | + | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the | | result in a destination FPU_REG. | | | - | Copyright (C) 1992,1993,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Copyright (C) 1992,1993,1995,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | Call from C as: | - | void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | + | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | | int control_w) | + | Return value is the tag of the answer, or-ed with FPU_Exception if | + | one was raised, or -1 on internal error. | | | +---------------------------------------------------------------------------*/ /* - | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ). - | Takes two valid reg f.p. numbers (TW_Valid), which are + | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ). + | Takes two valid reg f.p. numbers (TAG_Valid), which are | treated as unsigned numbers, - | and returns their sum as a TW_Valid or TW_S f.p. number. + | and returns their sum as a TAG_Valid or TAG_Special f.p. number. | The returned number is normalized. | Basic checks are performed if PARANOID is defined. */ @@ -29,7 +31,7 @@ #include "control_w.h" .text -ENTRY(reg_u_add) +ENTRY(FPU_u_add) pushl %ebp movl %esp,%ebp pushl %esi @@ -39,27 +41,9 @@ movl PARAM1,%esi /* source 1 */ movl PARAM2,%edi /* source 2 */ -#ifdef DENORM_OPERAND - cmpl EXP_UNDER,EXP(%esi) - jg xOp1_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp1_not_denorm: - cmpl EXP_UNDER,EXP(%edi) - jg xOp2_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp2_not_denorm: -#endif DENORM_OPERAND - - movl EXP(%esi),%ecx - subl EXP(%edi),%ecx /* exp1 - exp2 */ + movl PARAM6,%ecx + movl %ecx,%edx + subl PARAM7,%ecx /* exp1 - exp2 */ jge L_arg1_larger /* num1 is smaller */ @@ -67,6 +51,7 @@ movl SIGH(%esi),%eax movl %edi,%esi + movl PARAM7,%edx negw %cx jmp L_accum_loaded @@ -77,12 +62,7 @@ L_accum_loaded: movl PARAM3,%edi /* destination */ -/* movb SIGN(%esi),%dl - movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */ - - - movl EXP(%esi),%edx - movl %edx,EXP(%edi) /* Copy exponent to destination */ + movw %dx,EXP(%edi) /* Copy exponent to destination */ xorl %edx,%edx /* clear the extension */ @@ -92,7 +72,7 @@ testl $0x80000000,SIGH(%esi) je L_bugged -#endif PARANOID +#endif /* PARANOID */ /* The number to be shifted is in %eax:%ebx:%edx */ cmpw $32,%cx /* shrd only works for 0..31 bits */ @@ -162,7 +142,7 @@ orl $1,%edx L_no_bit_lost: - incl EXP(%edi) + incw EXP(%edi) L_round_the_result: jmp fpu_reg_round /* Round the result */ @@ -175,9 +155,8 @@ pushl EX_INTERNAL|0x201 call EXCEPTION pop %ebx + movl $-1,%eax jmp L_exit -#endif PARANOID - L_exit: popl %ebx @@ -185,3 +164,4 @@ popl %esi leave ret +#endif /* PARANOID */ diff -urN linux-2.0.39/arch/i386/math-emu/reg_u_div.S linux-2.0.40/arch/i386/math-emu/reg_u_div.S --- linux-2.0.39/arch/i386/math-emu/reg_u_div.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_u_div.S 2004-02-07 23:13:01.000000000 -0800 @@ -2,22 +2,24 @@ /*---------------------------------------------------------------------------+ | reg_u_div.S | | | - | Core division routines | + | Divide one FPU_REG by another and put the result in a destination FPU_REG.| | | - | Copyright (C) 1992,1993,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Copyright (C) 1992,1993,1995,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ - | Kernel for the division routines. | - | | - | void reg_u_div(FPU_REG *a, FPU_REG *a, | - | FPU_REG *dest, unsigned int control_word) | + | Call from C as: | + | int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | + | unsigned int control_word, char *sign) | | | | Does not compute the destination exponent, but does adjust it. | + | | + | Return value is the tag of the answer, or-ed with FPU_Exception if | + | one was raised, or -1 on internal error. | +---------------------------------------------------------------------------*/ #include "exception.h" @@ -50,7 +52,7 @@ Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 Overflow flag: ovfl_flag */ - .align 2,0 + .align 4,0 FPU_accum_3: .long 0 FPU_accum_2: @@ -65,53 +67,50 @@ .long 0 FPU_ovfl_flag: .byte 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ +#define REGA PARAM1 +#define REGB PARAM2 +#define DEST PARAM3 .text -ENTRY(reg_u_div) +ENTRY(FPU_u_div) pushl %ebp movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi pushl %ebx - movl PARAM1,%esi /* pointer to num */ - movl PARAM2,%ebx /* pointer to denom */ - movl PARAM3,%edi /* pointer to answer */ - -#ifdef DENORM_OPERAND - movl EXP(%esi),%eax - cmpl EXP_UNDER,%eax - jg xOp1_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp1_not_denorm: - movl EXP(%ebx),%eax - cmpl EXP_UNDER,%eax - jg xOp2_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit + movl REGA,%esi + movl REGB,%ebx + movl DEST,%edi + + movswl EXP(%esi),%edx + movswl EXP(%ebx),%eax + subl %eax,%edx + addl EXP_BIAS,%edx + + /* A denormal and a large number can cause an exponent underflow */ + cmpl EXP_WAY_UNDER,%edx + jg xExp_not_underflow + + /* Set to a really low value allow correct handling */ + movl EXP_WAY_UNDER,%edx + +xExp_not_underflow: -xOp2_not_denorm: -#endif DENORM_OPERAND + movw %dx,EXP(%edi) -ENTRY(divide_kernel) #ifdef PARANOID /* testl $0x80000000, SIGH(%esi) // Dividend */ /* je L_bugged */ testl $0x80000000, SIGH(%ebx) /* Divisor */ je L_bugged -#endif PARANOID +#endif /* PARANOID */ /* Check if the divisor can be treated as having just 32 bits */ cmpl $0,SIGL(%ebx) @@ -147,7 +146,7 @@ /* Do the shifting here */ /* increase the exponent */ - incl EXP(%edi) + incw EXP(%edi) /* shift the mantissa right one bit */ stc /* To set the ms bit */ @@ -247,7 +246,7 @@ #ifdef PARANOID jb L_bugged_1 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ incl FPU_result_2 /* Correct the answer */ @@ -260,7 +259,7 @@ #ifdef PARANOID sbbl $0,FPU_accum_3 jne L_bugged_1 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* Half of the main problem is done, there is just a reduced numerator @@ -290,7 +289,7 @@ #ifdef PARANOID je L_bugged_2 /* Can't bump the result to 1.0 */ -#endif PARANOID +#endif /* PARANOID */ LDo_2nd_div: cmpl $0,%ecx /* augmented denom msw */ @@ -313,7 +312,7 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ movl FPU_result_1,%eax /* Get the result back */ mull SIGL(%ebx) /* now mul the ls dw of the denom */ @@ -324,14 +323,14 @@ #ifdef PARANOID jc L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ jz LDo_3rd_32_bits #ifdef PARANOID cmpl $1,FPU_accum_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /* need to subtract another once of the denom */ movl SIGL(%ebx),%eax @@ -343,14 +342,14 @@ #ifdef PARANOID jc L_bugged_2 jne L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ addl $1,FPU_result_1 /* Correct the answer */ adcl $0,FPU_result_2 #ifdef PARANOID jc L_bugged_2 /* Must check for non-zero result here */ -#endif PARANOID +#endif /* PARANOID */ /*----------------------------------------------------------------------*/ /* The division is essentially finished here, we just need to perform @@ -423,7 +422,7 @@ testb $255,FPU_ovfl_flag /* was the num > denom ? */ je LRound_precision - incl EXP(%edi) + incw EXP(%edi) /* shift the mantissa right one bit */ stc /* Will set the ms bit */ @@ -433,7 +432,7 @@ /* Round the result as required */ LRound_precision: - decl EXP(%edi) /* binary point between 1st & 2nd bits */ + decw EXP(%edi) /* binary point between 1st & 2nd bits */ movl %eax,%edx movl FPU_result_1,%ebx @@ -462,10 +461,11 @@ jmp L_exit L_exit: + movl $-1,%eax popl %ebx popl %edi popl %esi leave ret -#endif PARANOID +#endif /* PARANOID */ diff -urN linux-2.0.39/arch/i386/math-emu/reg_u_mul.S linux-2.0.40/arch/i386/math-emu/reg_u_mul.S --- linux-2.0.39/arch/i386/math-emu/reg_u_mul.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/reg_u_mul.S 2004-02-07 23:13:01.000000000 -0800 @@ -4,9 +4,9 @@ | | | Core multiplication routine | | | - | Copyright (C) 1992,1993,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Copyright (C) 1992,1993,1995,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ @@ -15,7 +15,7 @@ | Basic multiplication routine. | | Does not check the resulting exponent for overflow/underflow | | | - | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); | + | FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); | | | | Internal working is at approx 128 bits. | | Result is rounded to nearest 53 or 64 bits, using "nearest or even". | @@ -40,16 +40,16 @@ .long 0 FPU_accum_1: .long 0 -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text -ENTRY(reg_u_mul) +ENTRY(FPU_u_mul) pushl %ebp movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $8,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi @@ -63,28 +63,7 @@ jz L_bugged testl $0x80000000,SIGH(%edi) jz L_bugged -#endif PARANOID - -#ifdef DENORM_OPERAND - movl EXP(%esi),%eax - cmpl EXP_UNDER,%eax - jg xOp1_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp1_not_denorm: - movl EXP(%edi),%eax - cmpl EXP_UNDER,%eax - jg xOp2_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp2_not_denorm: -#endif DENORM_OPERAND +#endif /* PARANOID */ xorl %ecx,%ecx xorl %ebx,%ebx @@ -111,13 +90,22 @@ addl %eax,%ebx adcl %edx,%ecx - movl EXP(%esi),%eax /* Compute the exponent */ - addl EXP(%edi),%eax + /* Get the sum of the exponents. */ + movl PARAM6,%eax subl EXP_BIAS-1,%eax + /* Two denormals can cause an exponent underflow */ + cmpl EXP_WAY_UNDER,%eax + jg Exp_not_underflow + + /* Set to a really low value allow correct handling */ + movl EXP_WAY_UNDER,%eax + +Exp_not_underflow: + /* Have now finished with the sources */ movl PARAM3,%edi /* Point to the destination */ - movl %eax,EXP(%edi) + movw %ax,EXP(%edi) /* Now make sure that the result is normalized */ testl $0x80000000,%ecx @@ -128,7 +116,7 @@ rcll $1,FPU_accum_1 rcll $1,%ebx rcll $1,%ecx - decl EXP(%edi) + decw EXP(%edi) LResult_Normalised: movl FPU_accum_0,%eax @@ -156,5 +144,5 @@ popl %esi leave ret -#endif PARANOID +#endif /* PARANOID */ diff -urN linux-2.0.39/arch/i386/math-emu/reg_u_sub.S linux-2.0.40/arch/i386/math-emu/reg_u_sub.S --- linux-2.0.39/arch/i386/math-emu/reg_u_sub.S 1998-11-15 10:32:47.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/reg_u_sub.S 2004-02-07 23:13:01.000000000 -0800 @@ -4,21 +4,23 @@ | | | Core floating point subtraction routine. | | | - | Copyright (C) 1992,1993,1995 | - | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Copyright (C) 1992,1993,1995,1997 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | + | E-mail billm@suburbia.net | | | | Call from C as: | - | void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | + | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | | int control_w) | + | Return value is the tag of the answer, or-ed with FPU_Exception if | + | one was raised, or -1 on internal error. | | | +---------------------------------------------------------------------------*/ /* - | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ). - | Takes two valid reg f.p. numbers (TW_Valid), which are + | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ). + | Takes two valid reg f.p. numbers (TAG_Valid), which are | treated as unsigned numbers, - | and returns their difference as a TW_Valid or TW_Zero f.p. + | and returns their difference as a TAG_Valid or TAG_Zero f.p. | number. | The first number (arg1) must be the larger. | The returned number is normalized. @@ -30,7 +32,7 @@ #include "control_w.h" .text -ENTRY(reg_u_sub) +ENTRY(FPU_u_sub) pushl %ebp movl %esp,%ebp pushl %esi @@ -39,39 +41,20 @@ movl PARAM1,%esi /* source 1 */ movl PARAM2,%edi /* source 2 */ - -#ifdef DENORM_OPERAND - cmpl EXP_UNDER,EXP(%esi) - jg xOp1_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp1_not_denorm: - cmpl EXP_UNDER,EXP(%edi) - jg xOp2_not_denorm - - call SYMBOL_NAME(denormal_operand) - orl %eax,%eax - jnz fpu_Arith_exit - -xOp2_not_denorm: -#endif DENORM_OPERAND - - movl EXP(%esi),%ecx - subl EXP(%edi),%ecx /* exp1 - exp2 */ + + movl PARAM6,%ecx + subl PARAM7,%ecx /* exp1 - exp2 */ #ifdef PARANOID /* source 2 is always smaller than source 1 */ js L_bugged_1 - testl $0x80000000,SIGH(%edi) /* The args are assumed to be normalized */ + testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ je L_bugged_2 testl $0x80000000,SIGH(%esi) je L_bugged_2 -#endif PARANOID +#endif /* PARANOID */ /*--------------------------------------+ | Form a register holding the | @@ -81,10 +64,8 @@ movl SIGL(%edi),%ebx /* register ls word */ movl PARAM3,%edi /* destination */ - movl EXP(%esi),%edx - movl %edx,EXP(%edi) /* Copy exponent to destination */ -/* movb SIGN(%esi),%dl - movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */ + movl PARAM6,%edx + movw %dx,EXP(%edi) /* Copy exponent to destination */ xorl %edx,%edx /* register extension */ @@ -93,8 +74,8 @@ | right the required number of | | places. | +--------------------------------------*/ -L_shift_r: - cmpl $32,%ecx /* shrd only works for 0..31 bits */ + + cmpw $32,%cx /* shrd only works for 0..31 bits */ jnc L_more_than_31 /* less than 32 bits */ @@ -104,7 +85,7 @@ jmp L_shift_done L_more_than_31: - cmpl $64,%ecx + cmpw $64,%cx jnc L_more_than_63 subb $32,%cl @@ -184,7 +165,7 @@ #ifdef PARANOID /* We can never get a borrow */ jc L_bugged -#endif PARANOID +#endif /* PARANOID */ /*--------------------------------------+ | Normalize the result | @@ -210,7 +191,7 @@ jnz L_must_be_zero /* Shift left 64 bits */ - subl $64,EXP(%edi) + subw $64,EXP(%edi) xchg %edx,%eax jmp fpu_reg_round @@ -218,20 +199,20 @@ #ifdef PARANOID orl %edx,%edx jnz L_bugged_3 -#endif PARANOID +#endif /* PARANOID */ /* The result is zero */ - movb TW_Zero,TAG(%edi) - movl $0,EXP(%edi) /* exponent */ + movw $0,EXP(%edi) /* exponent */ movl $0,SIGL(%edi) movl $0,SIGH(%edi) - jmp L_exit /* %eax contains zero */ + movl TAG_Zero,%eax + jmp L_exit L_shift_32: movl %ebx,%eax movl %edx,%ebx movl $0,%edx - subl $32,EXP(%edi) /* Can get underflow here */ + subw $32,EXP(%edi) /* Can get underflow here */ /* We need to shift left by 1 - 31 bits */ L_shift_1: @@ -241,7 +222,7 @@ shld %cl,%ebx,%eax shld %cl,%edx,%ebx shl %cl,%edx - subl %ecx,EXP(%edi) /* Can get underflow here */ + subw %cx,EXP(%edi) /* Can get underflow here */ L_round: jmp fpu_reg_round /* Round the result */ @@ -277,11 +258,12 @@ call EXCEPTION pop %ebx jmp L_error_exit -#endif PARANOID - L_error_exit: - movl $1,%eax + movl $-1,%eax + +#endif /* PARANOID */ + L_exit: popl %ebx popl %edi diff -urN linux-2.0.39/arch/i386/math-emu/status_w.h linux-2.0.40/arch/i386/math-emu/status_w.h --- linux-2.0.39/arch/i386/math-emu/status_w.h 1997-03-28 16:12:25.000000000 -0800 +++ linux-2.0.40/arch/i386/math-emu/status_w.h 2004-02-07 23:13:01.000000000 -0800 @@ -1,9 +1,9 @@ /*---------------------------------------------------------------------------+ | status_w.h | | | - | Copyright (C) 1992,1993 | + | Copyright (C) 1992,1993,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | Australia. E-mail billm@melbpc.org.au | | | +---------------------------------------------------------------------------*/ @@ -18,6 +18,11 @@ #define Const__(x) x #endif +#define CFLAG 1 +#define PFLAG 4 +#define ZFLAG 0x40 +#define SFLAGS (CFLAG | PFLAG | ZFLAG) + #define SW_Backward Const__(0x8000) /* backward compatibility */ #define SW_C3 Const__(0x4000) /* condition bit 3 */ #define SW_Top Const__(0x3800) /* top of stack */ @@ -47,19 +52,21 @@ #define COMP_SNaN 0x80 #define status_word() \ - ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top)) + ((partial_status & ~SW_Top & 0xffff) | ((FPU_top << SW_Top_Shift) & SW_Top)) #define setcc(cc) ({ \ partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \ partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); }) +#define setccf(ftype,cc) { if ( ftype ) setflags((cc) >> 8); else setcc(cc); } + #ifdef PECULIAR_486 /* Default, this conveys no information, but an 80486 does it. */ /* Clear the SW_C1 bit, "other bits undefined". */ # define clear_C1() { partial_status &= ~SW_C1; } # else # define clear_C1() -#endif PECULIAR_486 +#endif /* PECULIAR_486 */ -#endif __ASSEMBLY__ +#endif /* __ASSEMBLY__ */ -#endif _STATUS_H_ +#endif /* _STATUS_H_ */ diff -urN linux-2.0.39/arch/i386/math-emu/version.h linux-2.0.40/arch/i386/math-emu/version.h --- linux-2.0.39/arch/i386/math-emu/version.h 1996-05-06 06:31:17.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/version.h 2004-02-07 23:13:01.000000000 -0800 @@ -2,11 +2,11 @@ | version.h | | | | | - | Copyright (C) 1992,1993,1994,1996 | + | Copyright (C) 1992,1993,1994,1996,1997,1999,2001 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | - | E-mail billm@jacobi.maths.monash.edu.au | + | E-mail billm@melbpc.org.au | | | | | +---------------------------------------------------------------------------*/ -#define FPU_VERSION "wm-FPU-emu version 1.22" +#define FPU_VERSION "wm-FPU-emu version 2.11" diff -urN linux-2.0.39/arch/i386/math-emu/wm_shrx.S linux-2.0.40/arch/i386/math-emu/wm_shrx.S --- linux-2.0.39/arch/i386/math-emu/wm_shrx.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/wm_shrx.S 2004-02-07 23:13:01.000000000 -0800 @@ -9,9 +9,9 @@ | Australia. E-mail billm@jacobi.maths.monash.edu.au | | | | Call from C as: | - | unsigned shrx(void *arg1, unsigned arg2) | + | unsigned FPU_shrx(void *arg1, unsigned arg2) | | and | - | unsigned shrxs(void *arg1, unsigned arg2) | + | unsigned FPU_shrxs(void *arg1, unsigned arg2) | | | +---------------------------------------------------------------------------*/ @@ -19,7 +19,7 @@ .text /*---------------------------------------------------------------------------+ - | unsigned shrx(void *arg1, unsigned arg2) | + | unsigned FPU_shrx(void *arg1, unsigned arg2) | | | | Extended shift right function. | | Fastest for small shifts. | @@ -32,7 +32,7 @@ | Results returned in the 64 bit arg and eax. | +---------------------------------------------------------------------------*/ -ENTRY(shrx) +ENTRY(FPU_shrx) push %ebp movl %esp,%ebp pushl %esi @@ -95,7 +95,7 @@ /*---------------------------------------------------------------------------+ - | unsigned shrxs(void *arg1, unsigned arg2) | + | unsigned FPU_shrxs(void *arg1, unsigned arg2) | | | | Extended shift right function (optimized for small floating point | | integers). | @@ -110,7 +110,7 @@ | part which has been shifted out of the arg. | | Results returned in the 64 bit arg and eax. | +---------------------------------------------------------------------------*/ -ENTRY(shrxs) +ENTRY(FPU_shrxs) push %ebp movl %esp,%ebp pushl %esi diff -urN linux-2.0.39/arch/i386/math-emu/wm_sqrt.S linux-2.0.40/arch/i386/math-emu/wm_sqrt.S --- linux-2.0.39/arch/i386/math-emu/wm_sqrt.S 1995-10-05 06:30:43.000000000 -0700 +++ linux-2.0.40/arch/i386/math-emu/wm_sqrt.S 2004-02-07 23:13:01.000000000 -0800 @@ -4,12 +4,12 @@ | | | Fixed point arithmetic square root evaluation. | | | - | Copyright (C) 1992,1993,1995 | + | Copyright (C) 1992,1993,1995,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | - | Australia. E-mail billm@jacobi.maths.monash.edu.au | + | Australia. E-mail billm@suburbia.net | | | | Call from C as: | - | void wm_sqrt(FPU_REG *n, unsigned int control_word) | + | int wm_sqrt(FPU_REG *n, unsigned int control_word) | | | +---------------------------------------------------------------------------*/ @@ -70,7 +70,7 @@ .long 0 FPU_fsqrt_arg_0: .long 0 /* ls word, at most the ms bit is set */ -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ .text @@ -79,7 +79,7 @@ movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $28,%esp -#endif NON_REENTRANT_FPU +#endif /* NON_REENTRANT_FPU */ pushl %esi pushl %edi pushl %ebx @@ -92,7 +92,7 @@ /* We use a rough linear estimate for the first guess.. */ - cmpl EXP_BIAS,EXP(%esi) + cmpw EXP_BIAS,EXP(%esi) jnz sqrt_arg_ge_2 shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */ @@ -210,7 +210,7 @@ /* It should be possible to get here only if the arg is ffff....ffff */ cmp $0xffffffff,FPU_fsqrt_arg_1 jnz sqrt_stage_2_error -#endif PARANOID +#endif /* PARANOID */ /* The best rounded result. */ xorl %eax,%eax @@ -224,7 +224,7 @@ sqrt_stage_2_error: pushl EX_INTERNAL|0x213 call EXCEPTION -#endif PARANOID +#endif /* PARANOID */ sqrt_stage_2_done: @@ -279,7 +279,7 @@ call EXCEPTION sqrt_stage_3_no_error: -#endif PARANOID +#endif /* PARANOID */ movl FPU_accum_2,%edx movl FPU_accum_1,%eax @@ -347,9 +347,8 @@ movl %esi,%eax movl %edi,%ebx movl PARAM1,%edi - movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */ - movl PARAM2,%ecx - jmp fpu_reg_round_sqrt + movw EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */ + jmp fpu_reg_round sqrt_near_exact_x: @@ -386,7 +385,7 @@ call EXCEPTION sqrt_near_exact_ok: -#endif PARANOID +#endif /* PARANOID */ or %ebx,%ebx js sqrt_near_exact_small @@ -446,7 +445,7 @@ call EXCEPTION sqrt_more_prec_ok: -#endif PARANOID +#endif /* PARANOID */ or %ebx,%ebx js sqrt_more_prec_small diff -urN linux-2.0.39/arch/i386/mm/fault.c linux-2.0.40/arch/i386/mm/fault.c --- linux-2.0.39/arch/i386/mm/fault.c 1997-12-02 13:58:53.000000000 -0800 +++ linux-2.0.40/arch/i386/mm/fault.c 2004-02-07 23:13:01.000000000 -0800 @@ -49,7 +49,7 @@ int write; /* get the address */ - __asm__("movl %%cr2,%0":"=r" (address)); + __asm__("movl %%cr2,%0" : "=r" (address)); down(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) diff -urN linux-2.0.39/arch/i386/mm/init.c linux-2.0.40/arch/i386/mm/init.c --- linux-2.0.39/arch/i386/mm/init.c 1999-06-13 10:21:00.000000000 -0700 +++ linux-2.0.40/arch/i386/mm/init.c 2004-02-07 23:13:01.000000000 -0800 @@ -57,11 +57,13 @@ { extern char empty_bad_page_table[PAGE_SIZE]; - __asm__ __volatile__("cld ; rep ; stosl": - :"a" (pte_val(BAD_PAGE)), - "D" ((long) empty_bad_page_table), - "c" (PAGE_SIZE/4) - :"di","cx"); + __asm__ __volatile__( + "cld ; rep ; stosl" + : + : "a" (pte_val(BAD_PAGE)), + "D" ((long) empty_bad_page_table), + "c" (PAGE_SIZE/4) + : "di","cx"); return (pte_t *) empty_bad_page_table; } @@ -69,11 +71,13 @@ { extern char empty_bad_page[PAGE_SIZE]; - __asm__ __volatile__("cld ; rep ; stosl": - :"a" (0), - "D" ((long) empty_bad_page), - "c" (PAGE_SIZE/4) - :"di","cx"); + __asm__ __volatile__( + "cld ; rep ; stosl" + : + : "a" (0), + "D" ((long) empty_bad_page), + "c" (PAGE_SIZE/4) + : "di","cx"); return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)); } @@ -183,12 +187,16 @@ __asm__("movl %%cr4,%%eax\n\t" "orl $16,%%eax\n\t" "movl %%eax,%%cr4" - : : :"ax"); + : + : + : "ax"); #else __asm__(".byte 0x0f,0x20,0xe0\n\t" "orl $16,%%eax\n\t" ".byte 0x0f,0x22,0xe0" - : : :"ax"); + : + : + : "ax"); #endif wp_works_ok = 1; pgd_val(pg_dir[0]) = _PAGE_TABLE | _PAGE_4M | address; @@ -292,7 +300,7 @@ if (wp_works_ok < 0) { pg0[0] = pte_val(mk_pte(0, PAGE_READONLY)); local_flush_tlb(); - __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory"); + __asm__ __volatile__("movb 0,%%al ; movb %%al,0" : : : "ax", "memory"); pg0[0] = 0; local_flush_tlb(); if (wp_works_ok < 0) diff -urN linux-2.0.39/arch/m68k/config.in linux-2.0.40/arch/m68k/config.in --- linux-2.0.39/arch/m68k/config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/arch/m68k/config.in 2004-02-07 23:13:01.000000000 -0800 @@ -178,4 +178,9 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Memory flooding' CONFIG_SADISTIC_KMALLOC +bool 'Socket-buffer consistency checking' CONFIG_SKB_CHECK +if [ "$CONFIG_SKB_CHECK" = "y" ]; then + bool ' Whole-queue checking' CONFIG_SKB_CHECK_WHOLE_QUEUE +fi endmenu diff -urN linux-2.0.39/arch/m68k/defconfig linux-2.0.40/arch/m68k/defconfig --- linux-2.0.39/arch/m68k/defconfig 1997-09-05 20:43:58.000000000 -0700 +++ linux-2.0.40/arch/m68k/defconfig 2004-02-07 23:13:01.000000000 -0800 @@ -116,6 +116,7 @@ # CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y +# CONFIG_UNSAFE_MMAP is not set CONFIG_NFS_FS=y # CONFIG_ROOT_NFS is not set # CONFIG_SMB_FS is not set diff -urN linux-2.0.39/arch/m68k/kernel/signal.c linux-2.0.40/arch/m68k/kernel/signal.c --- linux-2.0.39/arch/m68k/kernel/signal.c 1996-05-19 21:54:26.000000000 -0700 +++ linux-2.0.40/arch/m68k/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -447,7 +447,7 @@ if (current->pid == 1) continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN linux-2.0.39/arch/mips/config.in linux-2.0.40/arch/mips/config.in --- linux-2.0.39/arch/mips/config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/arch/mips/config.in 2004-02-07 23:13:01.000000000 -0800 @@ -115,4 +115,9 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Memory flooding' CONFIG_SADISTIC_KMALLOC +bool 'Socket-buffer consistency checking' CONFIG_SKB_CHECK +if [ "$CONFIG_SKB_CHECK" = "y" ]; then + bool ' Whole-queue checking' CONFIG_SKB_CHECK_WHOLE_QUEUE +fi endmenu diff -urN linux-2.0.39/arch/mips/defconfig linux-2.0.40/arch/mips/defconfig --- linux-2.0.39/arch/mips/defconfig 1999-06-13 10:21:00.000000000 -0700 +++ linux-2.0.40/arch/mips/defconfig 2004-02-07 23:13:01.000000000 -0800 @@ -58,6 +58,7 @@ # CONFIG_XIA_FS is not set # CONFIG_MSDOS_FS is not set CONFIG_PROC_FS=y +# CONFIG_UNSAFE_MMAP is not set # CONFIG_ISO9660_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set diff -urN linux-2.0.39/arch/mips/kernel/signal.c linux-2.0.40/arch/mips/kernel/signal.c --- linux-2.0.39/arch/mips/kernel/signal.c 1996-03-10 23:39:33.000000000 -0800 +++ linux-2.0.40/arch/mips/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -279,7 +279,7 @@ if (current->pid == 1) continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN linux-2.0.39/arch/mips/kernel/sysmips.c linux-2.0.40/arch/mips/kernel/sysmips.c --- linux-2.0.39/arch/mips/kernel/sysmips.c 1995-12-13 02:39:44.000000000 -0800 +++ linux-2.0.40/arch/mips/kernel/sysmips.c 2004-02-07 23:13:01.000000000 -0800 @@ -52,7 +52,8 @@ { int *p; char *name; - int flags, len, retval = -EINVAL; + int len, retval = -EINVAL; + unsigned long flags; switch(cmd) { diff -urN linux-2.0.39/arch/ppc/config.in linux-2.0.40/arch/ppc/config.in --- linux-2.0.39/arch/ppc/config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/arch/ppc/config.in 2004-02-07 23:13:01.000000000 -0800 @@ -104,4 +104,9 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Memory flooding' CONFIG_SADISTIC_KMALLOC +bool 'Socket-buffer consistency checking' CONFIG_SKB_CHECK +if [ "$CONFIG_SKB_CHECK" = "y" ]; then + bool ' Whole-queue checking' CONFIG_SKB_CHECK_WHOLE_QUEUE +fi endmenu diff -urN linux-2.0.39/arch/ppc/kernel/signal.c linux-2.0.40/arch/ppc/kernel/signal.c --- linux-2.0.39/arch/ppc/kernel/signal.c 1996-07-08 01:27:43.000000000 -0700 +++ linux-2.0.40/arch/ppc/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -148,7 +148,7 @@ if (current->pid == 1) continue; switch (signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN linux-2.0.39/arch/sparc/config.in linux-2.0.40/arch/sparc/config.in --- linux-2.0.39/arch/sparc/config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/arch/sparc/config.in 2004-02-07 23:13:01.000000000 -0800 @@ -111,3 +111,8 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +bool 'Memory flooding' CONFIG_SADISTIC_KMALLOC +bool 'Socket-buffer consistency checking' CONFIG_SKB_CHECK +if [ "$CONFIG_SKB_CHECK" = "y" ]; then + bool ' Whole-queue checking' CONFIG_SKB_CHECK_WHOLE_QUEUE +fi diff -urN linux-2.0.39/arch/sparc/defconfig linux-2.0.40/arch/sparc/defconfig --- linux-2.0.39/arch/sparc/defconfig 1997-09-05 20:43:58.000000000 -0700 +++ linux-2.0.40/arch/sparc/defconfig 2004-02-07 23:13:01.000000000 -0800 @@ -105,6 +105,7 @@ # CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y +# CONFIG_UNSAFE_MMAP is not set CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y CONFIG_RNFS_BOOTP=y diff -urN linux-2.0.39/arch/sparc/kernel/signal.c linux-2.0.40/arch/sparc/kernel/signal.c --- linux-2.0.39/arch/sparc/kernel/signal.c 1996-04-25 03:22:05.000000000 -0700 +++ linux-2.0.40/arch/sparc/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -258,7 +258,7 @@ if(current->pid == 1) continue; switch(signr) { - case SIGCONT: case SIGCHLD: case SIGWINCH: + case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: continue; case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: diff -urN linux-2.0.39/arch/sparc/kernel/sparc-stub.c linux-2.0.40/arch/sparc/kernel/sparc-stub.c --- linux-2.0.39/arch/sparc/kernel/sparc-stub.c 1996-05-06 02:26:03.000000000 -0700 +++ linux-2.0.40/arch/sparc/kernel/sparc-stub.c 2004-02-07 23:13:01.000000000 -0800 @@ -183,7 +183,8 @@ /* Initialize the kgdb_savettable so that debugging can commence */ static void eh_init(void) { - int i, flags; + int i; + unsigned long flags; save_flags(flags); cli(); for(i=0; i < 256; i++) @@ -195,7 +196,7 @@ static void exceptionHandler(int tnum, trapfunc_t trap_entry) { unsigned long te_addr = (unsigned long) trap_entry; - int flags; + unsigned long flags; /* We are dorking with a live trap table, all irqs off */ save_flags(flags); cli(); diff -urN linux-2.0.39/drivers/block/cpqarray.h linux-2.0.40/drivers/block/cpqarray.h --- linux-2.0.39/drivers/block/cpqarray.h 1999-06-13 10:21:00.000000000 -0700 +++ linux-2.0.40/drivers/block/cpqarray.h 2004-02-07 23:13:01.000000000 -0800 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #endif diff -urN linux-2.0.39/drivers/block/ide.c linux-2.0.40/drivers/block/ide.c --- linux-2.0.39/drivers/block/ide.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/drivers/block/ide.c 2004-02-07 23:13:01.000000000 -0800 @@ -2738,6 +2738,10 @@ } else hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ + /* set features register for atapi identify command */ + if ((cmd == WIN_PIDENTIFY)) + OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap mode */ + #if CONFIG_BLK_DEV_PROMISE if (IS_PROMISE_DRIVE) { if (promise_cmd(drive,PROMISE_IDENTIFY)) { diff -urN linux-2.0.39/drivers/block/ll_rw_blk.c linux-2.0.40/drivers/block/ll_rw_blk.c --- linux-2.0.39/drivers/block/ll_rw_blk.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/drivers/block/ll_rw_blk.c 2004-02-07 23:13:01.000000000 -0800 @@ -356,7 +356,7 @@ if (buffer_locked(bh)) { #if 0 printk("make_request(): buffer already locked\n"); -#endif +#endif /* 0 */ return; } /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */ @@ -388,7 +388,7 @@ if (buffer_uptodate(bh)) { #if 0 printk ("make_request(): buffer uptodate for READ\n"); -#endif +#endif /* 0 */ unlock_buffer(bh); /* Hmmph! Already have it */ return; } @@ -402,7 +402,7 @@ if (!buffer_dirty(bh)) { #if 0 printk ("make_request(): buffer clean for WRITE\n"); -#endif +#endif /* 0 */ unlock_buffer(bh); /* Hmmph! Nothing to write */ return; } @@ -609,7 +609,7 @@ "Bad md_map in ll_rw_block\n"); goto sorry; } -#endif +#endif /* CONFIG_BLK_DEV_MD */ } if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) { @@ -626,7 +626,7 @@ md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]); continue; } -#endif +#endif /* CONFIG_BLK_DEV_MD */ make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]); } } @@ -692,8 +692,8 @@ "Bad md_map in ll_rw_swap_file\n"); return; } -#endif - +#endif /* CONFIG_BLK_DEV_MD */ + if (j == 0) { req[j] = get_request_wait(max_req, rdev); } else { @@ -746,62 +746,64 @@ memset(ro_bits,0,sizeof(ro_bits)); #ifdef CONFIG_BLK_DEV_RAM rd_init(); -#endif +#endif /* CONFIG_BLK_DEV_RAM */ #ifdef CONFIG_BLK_DEV_LOOP loop_init(); -#endif +#endif /* CONFIG_BLK_DEV_LOOP */ #ifdef CONFIG_CDI_INIT cdi_init(); /* this MUST precede ide_init */ -#endif CONFIG_CDI_INIT +#endif /* CONFIG_CDI_INIT */ #ifdef CONFIG_BLK_DEV_IDE ide_init(); /* this MUST precede hd_init */ -#endif +#endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_BLK_DEV_HD hd_init(); -#endif +#endif /* CONFIG_BLK_DEV_HD */ #ifdef CONFIG_BLK_DEV_XD xd_init(); -#endif +#endif /* CONFIG_BLK_DEV_XD */ #ifdef CONFIG_PARIDE { extern void paride_init(void); paride_init(); }; -#endif +#endif /* CONFIG_PARIDE */ #ifdef CONFIG_BLK_DEV_FD floppy_init(); -#else +#else /* CONFIG_BLK_DEV_FD */ +#if defined(__i386__) /* Do we even need this? */ outb_p(0xc, 0x3f2); -#endif +#endif /* defined(__i386__) */ +#endif /* !CONFIG_BLK_DEV_FD */ #ifdef CONFIG_CDU31A cdu31a_init(); -#endif CONFIG_CDU31A +#endif /* CONFIG_CDU31A */ #ifdef CONFIG_MCD mcd_init(); -#endif CONFIG_MCD +#endif /* CONFIG_MCD */ #ifdef CONFIG_MCDX mcdx_init(); -#endif CONFIG_MCDX +#endif /* CONFIG_MCDX */ #ifdef CONFIG_SBPCD sbpcd_init(); -#endif CONFIG_SBPCD +#endif /* CONFIG_SBPCD */ #ifdef CONFIG_AZTCD aztcd_init(); -#endif CONFIG_AZTCD +#endif /* CONFIG_AZTCD */ #ifdef CONFIG_CDU535 sony535_init(); -#endif CONFIG_CDU535 +#endif /* CONFIG_CDU535 */ #ifdef CONFIG_GSCD gscd_init(); -#endif CONFIG_GSCD +#endif /* CONFIG_GSCD */ #ifdef CONFIG_CM206 cm206_init(); -#endif +#endif /* CONFIG_CM206 */ #ifdef CONFIG_OPTCD optcd_init(); -#endif CONFIG_OPTCD +#endif /* CONFIG_OPTCD */ #ifdef CONFIG_SJCD sjcd_init(); -#endif CONFIG_SJCD +#endif /* CONFIG_SJCD */ #ifdef CONFIG_BLK_DEV_MD md_init(); -#endif CONFIG_BLK_DEV_MD +#endif /* CONFIG_BLK_DEV_MD */ return 0; } diff -urN linux-2.0.39/drivers/block/promise.h linux-2.0.40/drivers/block/promise.h --- linux-2.0.39/drivers/block/promise.h 1996-03-16 03:52:15.000000000 -0800 +++ linux-2.0.40/drivers/block/promise.h 2004-02-07 23:13:01.000000000 -0800 @@ -49,4 +49,4 @@ void setup_dc4030 (ide_hwif_t *); int init_dc4030 (void); -#endif IDE_PROMISE_H +#endif /* !IDE_PROMISE_H */ diff -urN linux-2.0.39/drivers/block/xd.c linux-2.0.40/drivers/block/xd.c --- linux-2.0.39/drivers/block/xd.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/drivers/block/xd.c 2004-02-07 23:13:01.000000000 -0800 @@ -114,6 +114,7 @@ { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */ { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */ { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */ + { 0x0008,"(C) Copyright 1984 Western Digital Corp", xd_wd_init_controller, xd_wd_init_drive," Western Dig. 1002s-wx2" }, }; static u_char *xd_bases[] = { diff -urN linux-2.0.39/drivers/cdrom/aztcd.c linux-2.0.40/drivers/cdrom/aztcd.c --- linux-2.0.39/drivers/cdrom/aztcd.c 1996-05-19 22:38:42.000000000 -0700 +++ linux-2.0.40/drivers/cdrom/aztcd.c 2004-02-07 23:13:01.000000000 -0800 @@ -334,7 +334,7 @@ #ifdef MODULE int init_module(void); void cleanup_module(void); -#endif MODULE +#endif /* MODULE */ static struct file_operations azt_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ @@ -1748,7 +1748,7 @@ release_region(azt_port,4); /*proprietary interface*/ printk(KERN_INFO "aztcd module released.\n"); } -#endif MODULE +#endif /* MODULE */ /*########################################################################## diff -urN linux-2.0.39/drivers/cdrom/cdi.c linux-2.0.40/drivers/cdrom/cdi.c --- linux-2.0.39/drivers/cdrom/cdi.c 1996-02-13 00:30:25.000000000 -0800 +++ linux-2.0.40/drivers/cdrom/cdi.c 2004-02-07 23:13:01.000000000 -0800 @@ -30,7 +30,7 @@ #include /* where the proto type of cdi_init() is */ #ifdef CONFIG_ISP16_CDI #include -#endif CONFIG_ISP16_CDI +#endif /* CONFIG_ISP16_CDI */ /* * Cdrom interface configuration. @@ -42,7 +42,7 @@ #ifdef CONFIG_ISP16_CDI ret_val &= isp16_init(); -#endif CONFIG_ISP16_CDI +#endif /* CONFIG_ISP16_CDI */ return(ret_val); } diff -urN linux-2.0.39/drivers/cdrom/cdu31a.c linux-2.0.40/drivers/cdrom/cdu31a.c --- linux-2.0.39/drivers/cdrom/cdu31a.c 1997-04-08 08:47:45.000000000 -0700 +++ linux-2.0.40/drivers/cdrom/cdu31a.c 2004-02-07 23:13:01.000000000 -0800 @@ -3243,4 +3243,4 @@ release_region(cdu31a_port,4); printk(KERN_INFO "cdu31a module released.\n"); } -#endif MODULE +#endif /* MODULE */ diff -urN linux-2.0.39/drivers/cdrom/mcd.c linux-2.0.40/drivers/cdrom/mcd.c --- linux-2.0.39/drivers/cdrom/mcd.c 1998-07-13 13:47:28.000000000 -0700 +++ linux-2.0.40/drivers/cdrom/mcd.c 2004-02-07 23:13:01.000000000 -0800 @@ -1644,4 +1644,4 @@ free_irq(mcd_irq, NULL); printk(KERN_INFO "mcd module released.\n"); } -#endif MODULE +#endif /* MODULE */ diff -urN linux-2.0.39/drivers/cdrom/mcdx.c linux-2.0.40/drivers/cdrom/mcdx.c --- linux-2.0.39/drivers/cdrom/mcdx.c 1996-07-23 00:26:54.000000000 -0700 +++ linux-2.0.40/drivers/cdrom/mcdx.c 2004-02-07 23:13:01.000000000 -0800 @@ -1154,7 +1154,7 @@ #endif } -#endif MODULE +#endif /* MODULE */ /* Support functions ************************************************/ diff -urN linux-2.0.39/drivers/cdrom/optcd.c linux-2.0.40/drivers/cdrom/optcd.c --- linux-2.0.39/drivers/cdrom/optcd.c 1996-06-04 00:53:46.000000000 -0700 +++ linux-2.0.40/drivers/cdrom/optcd.c 2004-02-07 23:13:01.000000000 -0800 @@ -915,7 +915,7 @@ return -EIO; return 0; } -#endif MULTISESSION +#endif /* MULTISESSION */ static int update_toc(void) @@ -953,7 +953,7 @@ #ifdef MULTISESSION if (disk_info.xa) get_multi_disk_info(); /* Here disk_info.multi is set */ -#endif MULTISESSION +#endif /* MULTISESSION */ if (disk_info.multi) printk(KERN_WARNING "optcd: Multisession support experimental, " "see linux/Documentation/cdrom/optcd\n"); @@ -1704,11 +1704,11 @@ disk_info.last_session.minute, disk_info.last_session.second, disk_info.last_session.frame); -#endif DEBUG_MULTIS +#endif /* DEBUG_MULTIS */ return 0; } -#endif MULTISESSION +#endif /* MULTISESSION */ static int cdromreset(void) @@ -2081,4 +2081,4 @@ release_region(optcd_port, 4); printk(KERN_INFO "optcd: module released.\n"); } -#endif MODULE +#endif /* MODULE */ diff -urN linux-2.0.39/drivers/cdrom/sbpcd.c linux-2.0.40/drivers/cdrom/sbpcd.c --- linux-2.0.39/drivers/cdrom/sbpcd.c 1999-06-13 10:21:00.000000000 -0700 +++ linux-2.0.40/drivers/cdrom/sbpcd.c 2004-02-07 23:13:01.000000000 -0800 @@ -313,7 +313,7 @@ #ifndef SBPCD_ISSUE #define SBPCD_ISSUE 1 -#endif SBPCD_ISSUE +#endif /* SBPCD_ISSUE */ #include @@ -377,7 +377,7 @@ #else #define SBPCD_CLI #define SBPCD_STI -#endif SBPCD_DIS_IRQ +#endif /* SBPCD_DIS_IRQ */ /*==========================================================================*/ /* * auto-probing address list @@ -434,8 +434,8 @@ 0x370, 0, /* Lasermate, CI-101P */ 0x290, 1, /* Soundblaster 16 */ 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ -#endif MODULE -#endif DISTRIBUTION +#endif /* MODULE */ +#endif /* DISTRIBUTION */ }; #else static int sbpcd[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */ @@ -523,7 +523,7 @@ (1<0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); -#endif 000 +#endif /* 000 */ for (j=0;j>16)&0xFF; drvcmd[2]=(block>>8)&0xFF; drvcmd[3]=block&0xFF; -#endif TEST_UPC +#endif /* TEST_UPC */ response_count=8; flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; } @@ -2891,7 +2891,7 @@ drvcmd[2]=(block>>16)&0xFF; drvcmd[3]=(block>>8)&0xFF; drvcmd[4]=block&0xFF; -#endif TEST_UPC +#endif /* TEST_UPC */ response_count=0; flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; } @@ -2922,12 +2922,12 @@ } #if TEST_UPC checksum=0; -#endif TEST_UPC +#endif /* TEST_UPC */ for (i=0;i<(fam1_drive?8:16);i++) { #if TEST_UPC checksum |= infobuf[i]; -#endif TEST_UPC +#endif /* TEST_UPC */ sprintf(&msgbuf[i*3], " %02X", infobuf[i]); } msgbuf[i*3]=0; @@ -2935,7 +2935,7 @@ #if TEST_UPC if ((checksum&0x7F)!=0) break; } -#endif TEST_UPC +#endif /* TEST_UPC */ D_S[d].UPC_ctl_adr=0; if (fam1_drive) i=0; else i=2; @@ -3047,12 +3047,12 @@ i=cmd_out(); /* which buffer to use? */ return (i); } -#endif FUTURE +#endif /* FUTURE */ /*==========================================================================*/ static void check_datarate(void) { int i=0; - + msg(DBG_IOX,"check_datarate entered.\n"); datarate=0; #if TEST_STI @@ -3074,7 +3074,7 @@ datarate++; #if 1 if (datarate>0x6FFFFFFF) break; -#endif 00000 +#endif /* 00000 */ } while (!timed_out_delay); del_timer(&delay_timer); @@ -3090,7 +3090,7 @@ maxtim_data=datarate/100; #else maxtim_data=datarate/300; -#endif LONG_TIMING +#endif /* LONG_TIMING */ #if 0 msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data); #endif @@ -3244,7 +3244,7 @@ OUT(CDo_reset,0); sbp_sleep(6*HZ); OUT(CDo_enable,D_S[d].drv_sel); -#endif 0 +#endif /* 0 */ drvcmd[0]=CMD2_READ_VER; response_count=12; flags_cmd_out=f_putcmd; @@ -3534,7 +3534,7 @@ OUT(port+3,save_port3); return (0); /* in any case - no real "function" at time */ } -#endif PATH_CHECK +#endif /* PATH_CHECK */ /*==========================================================================*/ /*==========================================================================*/ /* @@ -3543,7 +3543,7 @@ static int check_drives(void) { int i, j; - + msg(DBG_INI,"check_drives entered.\n"); ndrives=0; for (j=0;j1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].audio_state==audio_playing) { i=cc_Pause_Resume(1); @@ -4048,12 +4048,12 @@ } D_S[d].audio_state=audio_playing; RETURN_UP(0); - + case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].audio_state==audio_playing) { msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); @@ -4121,28 +4121,28 @@ else RETURN_UP(-EINVAL); memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry)); RETURN_UP(0); - + case CDROMRESET: /* hard reset the drive */ msg(DBG_IOC,"ioctl: CDROMRESET entered.\n"); i=DriveReset(); D_S[d].audio_state=0; RETURN_UP(i); - + case CDROMSTOP: /* Spin down the drive */ msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ i=cc_Pause_Resume(1); D_S[d].audio_state=0; RETURN_UP(i); - + case CDROMSTART: /* Spin up the drive */ msg(DBG_IOC,"ioctl: CDROMSTART entered.\n"); cc_SpinUp(); D_S[d].audio_state=0; RETURN_UP(0); - + case CDROMEJECT: msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n"); if (fam0_drive) return (0); @@ -4157,7 +4157,7 @@ D_S[d].diskstate_flags=0; D_S[d].audio_state=0; RETURN_UP(0); - + case CDROMEJECT_SW: msg(DBG_IOC,"ioctl: CDROMEJECT_SW entered.\n"); if (fam0_drive) RETURN_UP(0); @@ -4235,27 +4235,27 @@ SC.cdsc_trk,SC.cdsc_ind, SC.cdsc_absaddr,SC.cdsc_reladdr); RETURN_UP(0); - + case CDROMREADMODE1: msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ cc_ModeSelect(CD_FRAMESIZE); cc_ModeSense(); D_S[d].mode=READ_M1; RETURN_UP(0); - + case CDROMREADMODE2: /* not usable at the moment */ msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ cc_ModeSelect(CD_FRAMESIZE_RAW1); cc_ModeSense(); D_S[d].mode=READ_M2; RETURN_UP(0); - + case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */ msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n"); if (D_S[d].sbp_audsiz>0) vfree(D_S[d].aud_buf); @@ -4284,7 +4284,7 @@ u_int data_retrying = 0; int status_tries; int error_flag; - + msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n"); if (fam0_drive) RETURN_UP(-EINVAL); if (famL_drive) RETURN_UP(-EINVAL); @@ -4292,7 +4292,7 @@ if (famT_drive) RETURN_UP(-EINVAL); #if SAFE_MIXED if (D_S[d].has_data>1) RETURN_UP(-EBUSY); -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL); i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio)); if (i) RETURN_UP(i); @@ -4301,7 +4301,7 @@ i=verify_area(VERIFY_WRITE, read_audio.buf, read_audio.nframes*CD_FRAMESIZE_RAW); if (i) RETURN_UP(i); - + if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */ block=msf2lba(&read_audio.addr.msf.minute); else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */ @@ -4317,7 +4317,7 @@ #if OLD_BUSY while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ busy_audio=1; -#endif OLD_BUSY +#endif /* OLD_BUSY */ error_flag=0; for (data_tries=5; data_tries>0; data_tries--) { @@ -4427,7 +4427,7 @@ i=cc_DriveReset(); /* ugly fix to prevent a hang */ #else i=cc_ReadError(); -#endif 0000 +#endif /* 0000 */ continue; } if (fam0L_drive) @@ -4482,7 +4482,7 @@ D_S[d].mode=READ_M1; #if OLD_BUSY busy_audio=0; -#endif OLD_BUSY +#endif /* OLD_BUSY */ if (data_tries == 0) { msg(DBG_AUD,"read_audio: failed after 5 tries.\n"); @@ -4491,7 +4491,7 @@ msg(DBG_AUD,"read_audio: successful return.\n"); RETURN_UP(0); } /* end of CDROMREADAUDIO */ - + case CDROMMULTISESSION: /* tell start-of-last-session */ msg(DBG_IOC,"ioctl: CDROMMULTISESSION entered.\n"); st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession)); @@ -4632,19 +4632,19 @@ #if OLD_BUSY while (busy_audio) sbp_sleep(HZ); /* wait a bit */ busy_data=1; -#endif OLD_BUSY - +#endif /* OLD_BUSY */ + if (D_S[i].audio_state==audio_playing) goto err_done; if (d!=i) switch_drive(i); - + block = req->sector; /* always numbered as 512-byte-pieces */ nsect = req->nr_sectors; /* always counted as 512-byte-pieces */ - + msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect); #if 0 msg(DBG_MUL,"read LBA %d\n", block/4); #endif - + sbp_transfer(req); /* if we satisfied the request from the buffer, we're done. */ if (req->nr_sectors == 0) @@ -4661,10 +4661,10 @@ i=prepare(0,0); /* at moment not really a hassle check, but ... */ if (i!=0) msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i); -#endif FUTURE - +#endif /* FUTURE */ + if (!st_spinning) cc_SpinUp(); - + for (data_tries=n_retries; data_tries > 0; data_tries--) { for (status_tries=3; status_tries > 0; status_tries--) @@ -4680,14 +4680,14 @@ msg(DBG_INF,"sbp_status: failed after 3 tries\n"); break; } - + sbp_read_cmd(req); sbp_sleep(0); if (sbp_data(req) != 0) { #if SAFE_MIXED D_S[d].has_data=2; /* is really a data disk */ -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -4700,7 +4700,7 @@ err_done: #if OLD_BUSY busy_data=0; -#endif OLD_BUSY +#endif /* OLD_BUSY */ #ifdef DEBUG_GTL printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", xnr, req, req->sector, req->nr_sectors, jiffies); @@ -5056,20 +5056,20 @@ } SBPCD_STI; } - + #if 0 if (!success) -#endif 0 +#endif /* 0 */ do { if (fam0LV_drive) cc_ReadStatus(); #if 1 if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i); -#endif 1 +#endif /* 1 */ i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ #if 1 if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i); -#endif 1 +#endif /* 1 */ if (i<0) { msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", D_S[d].status_bits); @@ -5105,7 +5105,7 @@ static int sbpcd_open(struct inode *ip, struct file *fp) { int i; - + i = MINOR(ip->i_rdev); if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { @@ -5114,10 +5114,10 @@ } if (fp->f_mode & 2) return -EROFS; - + down(&ioctl_read_sem); switch_drive(i); - + i=cc_ReadError(); flags_cmd_out |= f_respo2; cc_ReadStatus(); /* command: give 1-byte status */ @@ -5128,7 +5128,7 @@ i=ResponseStatus(); #if 0 sbp_sleep(HZ); -#endif 0 +#endif /* 0 */ i=ResponseStatus(); } if (i<0) @@ -5182,15 +5182,15 @@ i=DiskInfo(); if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n"); if ((D_S[d].ored_ctl_adr&0x40)==0) - { + { msg(DBG_INF,"CD contains no data tracks.\n"); #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } #if SAFE_MIXED else if (D_S[d].has_data<1) D_S[d].has_data=1; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } if (!st_spinning) cc_SpinUp(); RETURN_UP(0); @@ -5202,7 +5202,7 @@ static void sbpcd_release(struct inode * ip, struct file * file) { int i; - + i = MINOR(ip->i_rdev); if ((i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { @@ -5231,7 +5231,7 @@ D_S[d].open_count=0; #if SAFE_MIXED D_S[d].has_data=0; -#endif SAFE_MIXED +#endif /* SAFE_MIXED */ } } up(&ioctl_read_sem); @@ -5396,14 +5396,14 @@ int init_module(void) #else int SBPCD_INIT(void) -#endif MODULE +#endif /* MODULE */ { int i=0, j=0; int addr[2]={1, CDROM_PORT}; int port_index; - + sti(); - + msg(DBG_INF,"sbpcd.c %s\n", VERSION); #ifndef MODULE #if DISTRIBUTION @@ -5422,11 +5422,11 @@ msg(DBG_INF,"with your REAL address.\n"); msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n"); } -#endif DISTRIBUTION +#endif /* DISTRIBUTION */ sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */ -#endif MODULE - +#endif /* MODULE */ + for (port_index=0;port_index=0) break; /* drive found */ } /* end of cycling through the set of possible I/O port addresses */ - + if (ndrives==0) { msg(DBG_INF, "No drive found.\n"); @@ -5464,9 +5464,9 @@ return -EIO; #else goto init_done; -#endif MODULE +#endif /* MODULE */ } - + if (port_index>0) { msg(DBG_INF, "You should read linux/Documentation/cdrom/sbpcd\n"); @@ -5474,14 +5474,14 @@ } check_datarate(); msg(DBG_INI,"check_datarate done.\n"); - + #if 0 if (!famL_drive) { OUT(CDo_reset,0); sbp_sleep(HZ); } -#endif 0 +#endif /* 0 */ for (j=0;j=0) D_S[d].CD_changed=1; } - + /* * Turn on the CD audio channels. * The addresses are obtained from SOUND_BASE (see sbpcd.h). @@ -5545,8 +5545,8 @@ #if SOUND_BASE OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */ OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */ -#endif SOUND_BASE - +#endif /* SOUND_BASE */ + if (register_blkdev(MAJOR_NR, major_name, &sbpcd_fops) != 0) { msg(DBG_INF, "Can't get MAJOR %d for Matsushita CDROM\n", MAJOR_NR); @@ -5554,20 +5554,20 @@ return -EIO; #else goto init_done; -#endif MODULE +#endif /* MODULE */ } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = buffers * (CD_FRAMESIZE / 512); - + request_region(CDo_command,4,major_name); - + for (j=0;j0) { D_S[j].aud_buf=(u_char *) vmalloc(D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW); @@ -5603,15 +5603,15 @@ #if !(SBPCD_ISSUE-1) #ifdef CONFIG_SBPCD2 sbpcd2_init(); -#endif CONFIG_SBPCD2 +#endif /* CONFIG_SBPCD2 */ #ifdef CONFIG_SBPCD3 sbpcd3_init(); -#endif CONFIG_SBPCD3 +#endif /* CONFIG_SBPCD3 */ #ifdef CONFIG_SBPCD4 sbpcd4_init(); -#endif CONFIG_SBPCD4 +#endif /* CONFIG_SBPCD4 */ #endif !(SBPCD_ISSUE-1) -#endif MODULE +#endif /* MODULE */ return 0; } /*==========================================================================*/ @@ -5619,14 +5619,14 @@ void cleanup_module(void) { int j; - + if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) { msg(DBG_INF, "What's that: can't unregister %s.\n", major_name); return; } release_region(CDo_command,4); - + for (j=0;jptr); set_dma_count(fdc.dma, SECTOR_SIZE * buff->sector_count); -#ifdef GCC_2_4_5_BUG - /* This seemingly stupid construction confuses the gcc-2.4.5 - * code generator enough to create correct code. - */ - if (1) { - int i; - - for (i = 0; i < 1; ++i) { - udelay(1); - } - } -#endif enable_dma(fdc.dma); /* Issue FDC command to start reading/writing. */ diff -urN linux-2.0.39/drivers/char/lp_m68k.c linux-2.0.40/drivers/char/lp_m68k.c --- linux-2.0.39/drivers/char/lp_m68k.c 1996-05-06 02:49:43.000000000 -0700 +++ linux-2.0.40/drivers/char/lp_m68k.c 2004-02-07 23:13:01.000000000 -0800 @@ -182,7 +182,7 @@ #endif { unsigned long total_bytes_written = 0; - unsigned int flags; + unsigned long flags; int rc; int dev = MINOR(inode->i_rdev); diff -urN linux-2.0.39/drivers/char/misc.c linux-2.0.40/drivers/char/misc.c --- linux-2.0.39/drivers/char/misc.c 1998-06-03 15:17:47.000000000 -0700 +++ linux-2.0.40/drivers/char/misc.c 2004-02-07 23:13:01.000000000 -0800 @@ -197,7 +197,7 @@ S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL /* ops -- default to array */, &proc_misc_read /* get_info */, - }); + }); #endif /* PROC_FS */ #ifdef CONFIG_BUSMOUSE bus_mouse_init(); @@ -220,15 +220,19 @@ #ifdef CONFIG_SUN_MOUSE sun_mouse_init(); #endif -#ifdef CONFIG_SOFT_WATCHDOG - watchdog_init(); -#endif + /* In 2.0.xx, only the first misc_register() is significant for + * each minor. So we load the hardware watchdogs first, then + * the softdog driver. + */ #ifdef CONFIG_WDT wdt_init(); #endif #ifdef CONFIG_PCWATCHDOG pcwatchdog_init(); #endif +#ifdef CONFIG_SOFT_WATCHDOG + watchdog_init(); +#endif #ifdef CONFIG_APM apm_bios_init(); #endif diff -urN linux-2.0.39/drivers/char/rtc.c linux-2.0.40/drivers/char/rtc.c --- linux-2.0.39/drivers/char/rtc.c 1998-06-03 15:17:47.000000000 -0700 +++ linux-2.0.40/drivers/char/rtc.c 2004-02-07 23:13:01.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Real Time Clock interface for Linux + * Real Time Clock interface for Linux * * Copyright (C) 1996 Paul Gortmaker * @@ -17,7 +17,7 @@ * has been received. If a RTC interrupt has already happened, * it will output an unsigned long and then block. The output value * contains the interrupt status in the low byte and the number of - * interrupts since the last read in the remaining high bytes. The + * interrupts since the last read in the remaining high bytes. The * /dev/rtc interface can also be used with the select(2) call. * * This program is free software; you can redistribute it and/or @@ -37,7 +37,7 @@ #define RTC_VERSION "1.09" -#define RTC_IRQ 8 /* Can't see this changing soon. */ +#define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ /* @@ -110,7 +110,7 @@ static unsigned long epoch = 1900; /* year corresponding to 0x00 */ -unsigned char days_in_mo[] = +unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* @@ -136,7 +136,7 @@ rtc_irq_data += 0x100; rtc_irq_data &= ~0xff; rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); - wake_up_interruptible(&rtc_wait); + wake_up_interruptible(&rtc_wait); if (rtc_status & RTC_TIMER_ON) { del_timer(&rtc_irq_timer); @@ -164,7 +164,7 @@ #else struct wait_queue wait = { current, NULL }; int retval; - + if (count < sizeof(unsigned long)) return -EINVAL; @@ -175,7 +175,7 @@ add_wait_queue(&rtc_wait, &wait); current->state = TASK_INTERRUPTIBLE; - + while (rtc_irq_data == 0) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; @@ -279,7 +279,7 @@ get_rtc_alm_time(&alm_tm); memcpy_tofs((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time)); - + return 0; } case RTC_ALM_SET: /* Store a time into the alarm */ @@ -303,23 +303,25 @@ min = alm_tm.tm_min; sec = alm_tm.tm_sec; - if (hrs >= 24) - hrs = 0xff; - - if (min >= 60) - min = 0xff; - - if (sec >= 60) - sec = 0xff; - save_flags(flags); cli(); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); + if (sec < 60) + BIN_TO_BCD(sec); + else + sec = 0xff; + + if (min < 60) + BIN_TO_BCD(min); + else + min = 0xff; + + if (hrs < 24) + BIN_TO_BCD(hrs); + else + hrs = 0xff; } CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); @@ -332,7 +334,7 @@ { int retval; struct rtc_time rtc_tm; - + retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time)); if (retval !=0 ) return retval; @@ -349,12 +351,12 @@ unsigned char save_control, save_freq_select; unsigned int yrs; unsigned long flags; - + if (!suser()) return -EACCES; retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time)); - if (retval !=0 ) + if (retval != 0) return retval; memcpy_fromfs(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)); @@ -376,7 +378,7 @@ if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) return -EINVAL; - + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; @@ -436,7 +438,7 @@ int tmp = 0; unsigned char val; - /* + /* * The max we can do is 8192Hz. */ if ((arg < 2) || (arg > 8192)) @@ -482,7 +484,7 @@ } case RTC_EPOCH_SET: /* Set the epoch. */ { - /* + /* * There were no RTC clocks before 1900. */ if (arg < 1900) @@ -656,14 +658,14 @@ } /* - * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. + * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. * (usually during an IDE disk interrupt, with IRQ unmasking off) * Since the interrupt handler doesn't get called, the IRQ status * byte doesn't get read, and the RTC stops generating interrupts. * A timer is set, and will call this function if/when that happens. * To get it out of this stalled state, we just read the status. * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. - * (You *really* shouldn't be trying to use a non-realtime system + * (You *really* shouldn't be trying to use a non-realtime system * for something that requires a steady > 1KHz signal anyways.) */ @@ -789,7 +791,7 @@ * can take just over 2ms. We wait 10 to 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable - * periodic update complete interrupts, (via ioctl) and then + * periodic update complete interrupts, (via ioctl) and then * immediately read /dev/rtc which will block until you get the IRQ. * Once the read clears, read the RTC time (again via ioctl). Easy. */ diff -urN linux-2.0.39/drivers/char/vga.c linux-2.0.40/drivers/char/vga.c --- linux-2.0.39/drivers/char/vga.c 1996-05-06 21:50:53.000000000 -0700 +++ linux-2.0.40/drivers/char/vga.c 2004-02-07 23:13:01.000000000 -0800 @@ -271,7 +271,7 @@ /* Make sure that the hardware is not blanked */ outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8); } -#endif CONFIG_HGA +#endif /* CONFIG_HGA */ if (video_mem_term - video_mem_base < offset + video_screen_size) offset = 0; /* strange ... */ diff -urN linux-2.0.39/drivers/isdn/hisax/elsa_ser.c linux-2.0.40/drivers/isdn/hisax/elsa_ser.c --- linux-2.0.39/drivers/isdn/hisax/elsa_ser.c 1998-11-15 10:32:58.000000000 -0800 +++ linux-2.0.40/drivers/isdn/hisax/elsa_ser.c 2004-02-07 23:13:01.000000000 -0800 @@ -1,3 +1,4 @@ +#include #include #include @@ -453,7 +454,7 @@ } } } -#endif 0 +#endif /* 0 */ } #endif diff -urN linux-2.0.39/drivers/isdn/icn/icn.c linux-2.0.40/drivers/isdn/icn/icn.c --- linux-2.0.39/drivers/isdn/icn/icn.c 1998-11-15 10:32:59.000000000 -0800 +++ linux-2.0.40/drivers/isdn/icn/icn.c 2004-02-07 23:13:01.000000000 -0800 @@ -202,6 +202,7 @@ * */ +#include #include "icn.h" /* @@ -772,7 +773,7 @@ int left; u_char c; int ch; - int flags; + unsigned long flags; int i; u_char *p; isdn_ctrl cmd; diff -urN linux-2.0.39/drivers/isdn/isdn_common.c linux-2.0.40/drivers/isdn/isdn_common.c --- linux-2.0.39/drivers/isdn/isdn_common.c 1998-11-15 10:32:59.000000000 -0800 +++ linux-2.0.40/drivers/isdn/isdn_common.c 2004-02-07 23:13:01.000000000 -0800 @@ -391,7 +391,7 @@ } if (tf) { - int flags; + unsigned long flags; save_flags(flags); cli(); @@ -405,7 +405,7 @@ void isdn_timer_ctrl(int tf, int onoff) { - int flags; + unsigned long flags; save_flags(flags); cli(); @@ -2055,7 +2055,7 @@ void cleanup_module(void) { - int flags; + unsigned long flags; int i; #ifdef CONFIG_ISDN_PPP diff -urN linux-2.0.39/drivers/isdn/isdn_common.h linux-2.0.40/drivers/isdn/isdn_common.h --- linux-2.0.39/drivers/isdn/isdn_common.h 1998-11-15 10:32:59.000000000 -0800 +++ linux-2.0.40/drivers/isdn/isdn_common.h 2004-02-07 23:13:01.000000000 -0800 @@ -53,6 +53,8 @@ * */ +#include + #undef ISDN_DEBUG_MODEM_OPEN #undef ISDN_DEBUG_MODEM_IOCTL #undef ISDN_DEBUG_MODEM_WAITSENT diff -urN linux-2.0.39/drivers/isdn/isdn_net.c linux-2.0.40/drivers/isdn/isdn_net.c --- linux-2.0.39/drivers/isdn/isdn_net.c 1999-06-13 10:21:01.000000000 -0700 +++ linux-2.0.40/drivers/isdn/isdn_net.c 2004-02-07 23:13:01.000000000 -0800 @@ -376,8 +376,9 @@ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN, 0 #if (LINUX_VERSION_CODE < 0x02010f) /* 2.1.15 */ - ,dev + , dev #endif + , 1 ); } } @@ -396,6 +397,7 @@ #if (LINUX_VERSION_CODE < 0x02010f) /* 2.1.15 */ , dev #endif + , 1 ); } dev_kfree_skb(skb, FREE_WRITE); @@ -777,7 +779,7 @@ isdn_net_dev *p = dev->netdev; int anymore = 0; int i; - int flags; + unsigned long flags; isdn_ctrl cmd; while (p) { @@ -2521,7 +2523,7 @@ chidx = p->local.pre_channel; } if (cfg->exclusive > 0) { - int flags; + unsigned long flags; /* If binding is exclusive, try to grab the channel */ save_flags(flags); @@ -2733,7 +2735,7 @@ int more = 0; int count = 0; isdn_net_phone *n; - int flags; + unsigned long flags; int ret; if (!p) @@ -2771,7 +2773,7 @@ int inout = phone->outgoing & 1; isdn_net_phone *n; isdn_net_phone *m; - int flags; + unsigned long flags; if (p) { save_flags(flags); @@ -2807,7 +2809,7 @@ { isdn_net_phone *n; isdn_net_phone *m; - int flags; + unsigned long flags; int i; save_flags(flags); @@ -2856,7 +2858,7 @@ static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) { - int flags; + unsigned long flags; save_flags(flags); cli(); @@ -2942,7 +2944,7 @@ int isdn_net_rmall(void) { - int flags; + unsigned long flags; int ret; /* Walk through netdev-chain */ diff -urN linux-2.0.39/drivers/isdn/isdnloop/isdnloop.c linux-2.0.40/drivers/isdn/isdnloop/isdnloop.c --- linux-2.0.39/drivers/isdn/isdnloop/isdnloop.c 1998-11-15 10:33:01.000000000 -0800 +++ linux-2.0.40/drivers/isdn/isdnloop/isdnloop.c 2004-02-07 23:13:01.000000000 -0800 @@ -318,7 +318,7 @@ int left; u_char c; int ch; - int flags; + unsigned long flags; u_char *p; isdn_ctrl cmd; diff -urN linux-2.0.39/drivers/net/3c501.c linux-2.0.40/drivers/net/3c501.c --- linux-2.0.39/drivers/net/3c501.c 1996-11-06 04:39:42.000000000 -0800 +++ linux-2.0.40/drivers/net/3c501.c 2004-02-07 23:13:01.000000000 -0800 @@ -9,15 +9,15 @@ This is a device driver for the 3Com Etherlink 3c501. Do not purchase this card, even as a joke. It's performance is horrible, - and it breaks in many ways. + and it breaks in many ways. The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - + Fixed (again!) the missing interrupt locking on TX/RX shifting. - Alan Cox - + Alan Cox + Removed calls to init_etherdev since they are no longer needed, and cleaned up modularization just a bit. The driver still allows only the default address for cards when loaded as a module, but that's @@ -28,51 +28,50 @@ the board. Now getting 150K/second FTP with a 3c501 card. Still playing with a TX-TX optimisation to see if we can touch 180-200K/second as seems theoretically maximum. - 19950402 Alan Cox - + 19950402 Alan Cox + Some notes on this thing if you have to hack it. [Alan] - + 1] Some documentation is available from 3Com. Due to the boards age - standard responses when you ask for this will range from 'be serious' - to 'give it to a museum'. The documentation is incomplete and mostly - of historical interest anyway. - + standard responses when you ask for this will range from 'be serious' + to 'give it to a museum'. The documentation is incomplete and mostly + of historical interest anyway. + 2] The basic system is a single buffer which can be used to receive or - transmit a packet. A third command mode exists when you are setting - things up. - - 3] If it's transmitting it's not receiving and vice versa. In fact the - time to get the board back into useful state after an operation is - quite large. - + transmit a packet. A third command mode exists when you are setting + things up. + + 3] If it's transmitting it's not receiving and vice versa. In fact the + time to get the board back into useful state after an operation is + quite large. + 4] The driver works by keeping the board in receive mode waiting for a - packet to arrive. When one arrives it is copied out of the buffer - and delivered to the kernel. The card is reloaded and off we go. - + packet to arrive. When one arrives it is copied out of the buffer + and delivered to the kernel. The card is reloaded and off we go. + 5] When transmitting dev->tbusy is set and the card is reset (from - receive mode) [possibly losing a packet just received] to command - mode. A packet is loaded and transmit mode triggered. The interrupt - handler runs different code for transmit interrupts and can handle - returning to receive mode or retransmissions (yes you have to help - out with those too). - + receive mode) [possibly losing a packet just received] to command + mode. A packet is loaded and transmit mode triggered. The interrupt + handler runs different code for transmit interrupts and can handle + returning to receive mode or retransmissions (yes you have to help + out with those too). + Problems: - There are a wide variety of undocumented error returns from the card - and you basically have to kick the board and pray if they turn up. Most + There are a wide variety of undocumented error returns from the card + and you basically have to kick the board and pray if they turn up. Most only occur under extreme load or if you do something the board doesn't like (eg touching a register at the wrong time). - - The driver is less efficient than it could be. It switches through + + The driver is less efficient than it could be. It switches through receive mode even if more transmits are queued. If this worries you buy a real ethernet card. - - The combination of slow receive restart and no real multicast + + The combination of slow receive restart and no real multicast filter makes the board unusable with a kernel compiled for IP - multicasting in a real multicast environment. That's down to the board, + multicasting in a real multicast environment. That's down to the board, but even with no multicast programs running a multicast IP kernel is in group 224.0.0.1 and you will therefore be listening to all multicasts. One nv conference running over that ethernet and you can give up. - */ static const char *version = @@ -107,22 +106,20 @@ /* A zero-terminated list of I/O addresses to be probed. The 3c501 can be at many locations, but here are the popular ones. */ -static unsigned int netcard_portlist[] = - { 0x280, 0x300, 0}; +static unsigned int netcard_portlist[] = { 0x280, 0x300, 0 }; - /* - * Index to functions. + * Index to functions. */ - + int el1_probe(struct device *dev); -static int el1_probe1(struct device *dev, int ioaddr); -static int el_open(struct device *dev); -static int el_start_xmit(struct sk_buff *skb, struct device *dev); +static int el1_probe1(struct device *dev, int ioaddr); +static int el_open(struct device *dev); +static int el_start_xmit(struct sk_buff *skb, struct device *dev); static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void el_receive(struct device *dev); static void el_reset(struct device *dev); -static int el1_close(struct device *dev); +static int el1_close(struct device *dev); static struct enet_statistics *el1_get_stats(struct device *dev); static void set_multicast_list(struct device *dev); @@ -132,12 +129,12 @@ #define EL_DEBUG 0 /* use 0 for production, 1 for devel., >2 for debug */ #endif /* Anything above 5 is wordy death! */ static int el_debug = EL_DEBUG; - -/* - * Board-specific info in dev->priv. + +/* + * Board-specific info in dev->priv. */ - -struct net_local + +struct net_local { struct enet_statistics stats; int tx_pkt_start; /* The length of the current Tx packet. */ @@ -145,12 +142,11 @@ int loading; /* Spot buffer load collisions */ }; - #define RX_STATUS (ioaddr + 0x06) #define RX_CMD RX_STATUS #define TX_STATUS (ioaddr + 0x07) #define TX_CMD TX_STATUS -#define GP_LOW (ioaddr + 0x08) +#define GP_LOW (ioaddr + 0x08) #define GP_HIGH (ioaddr + 0x09) #define RX_BUF_CLR (ioaddr + 0x0A) #define RX_LOW (ioaddr + 0x0A) @@ -164,12 +160,12 @@ #define EL1_DATAPTR 0x08 #define EL1_RXPTR 0x0A #define EL1_SAPROM 0x0C -#define EL1_DATAPORT 0x0f +#define EL1_DATAPORT 0x0f /* * Writes to the ax command register. */ - + #define AX_OFF 0x00 /* Irq off, buffer access on */ #define AX_SYS 0x40 /* Load the buffer */ #define AX_XMIT 0x44 /* Transmit a packet */ @@ -181,16 +177,16 @@ * Normal receive mode written to RX_STATUS. We must intr on short packets * to avoid bogus rx lockups. */ - + #define RX_NORM 0xA8 /* 0x68 == all addrs, 0xA8 only to me. */ #define RX_PROM 0x68 /* Senior Prom, uhmm promiscuous mode. */ #define RX_MULT 0xE8 /* Accept multicast packets. */ #define TX_NORM 0x0A /* Interrupt on everything that might hang the chip */ /* - * TX_STATUS register. + * TX_STATUS register. */ - + #define TX_COLLISION 0x02 #define TX_16COLLISIONS 0x04 #define TX_READY 0x08 @@ -198,14 +194,18 @@ #define RX_RUNT 0x08 #define RX_MISSED 0x01 /* Missed a packet due to 3c501 braindamage. */ #define RX_GOOD 0x30 /* Good packet 0x20, or simple overflow 0x10. */ - /* * The boilerplate probe code. */ - + #ifdef HAVE_DEVLIST -struct netdev_entry el1_drv = {"3c501", el1_probe1, EL1_IO_EXTENT, netcard_portlist}; +struct netdev_entry el1_drv = { + "3c501", + el1_probe1, + EL1_IO_EXTENT, + netcard_portlist +}; #else int el1_probe(struct device *dev) @@ -218,8 +218,7 @@ else if (base_addr != 0) /* Don't probe at all. */ return ENXIO; - for (i = 0; netcard_portlist[i]; i++) - { + for (i = 0; netcard_portlist[i]; i++) { int ioaddr = netcard_portlist[i]; if (check_region(ioaddr, EL1_IO_EXTENT)) continue; @@ -232,8 +231,8 @@ #endif /* - * The actual probe. - */ + * The actual probe. + */ static int el1_probe1(struct device *dev, int ioaddr) { @@ -243,55 +242,50 @@ int i; /* - * Read the station address PROM data from the special port. + * Read the station address PROM data from the special port. */ - - for (i = 0; i < 6; i++) - { + + for (i = 0; i < 6; i++) { outw(i, ioaddr + EL1_DATAPTR); station_addr[i] = inb(ioaddr + EL1_SAPROM); } /* * Check the first three octets of the S.A. for 3Com's prefix, or - * for the Sager NP943 prefix. - */ - - if (station_addr[0] == 0x02 && station_addr[1] == 0x60 - && station_addr[2] == 0x8c) - { + * for the Sager NP943 prefix. + */ + + if (station_addr[0] == 0x02 && station_addr[1] == 0x60 && + station_addr[2] == 0x8c) { mname = "3c501"; - } else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 - && station_addr[2] == 0xC8) - { + } else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 && + station_addr[2] == 0xC8) { mname = "NP943"; - } - else + } else return ENODEV; /* - * Grab the region so we can find the another board if autoIRQ fails. + * Grab the region so we can find the another board if autoIRQ + * fails. */ - request_region(ioaddr, EL1_IO_EXTENT,"3c501"); + request_region(ioaddr, EL1_IO_EXTENT, "3c501"); - /* - * We auto-IRQ by shutting off the interrupt line and letting it float - * high. + /* + * We auto-IRQ by shutting off the interrupt line and letting it + * float high. */ - if (dev->irq < 2) - { + if (dev->irq < 2) { autoirq_setup(2); inb(RX_STATUS); /* Clear pending interrupts. */ inb(TX_STATUS); outb(AX_LOOP + 1, AX_CMD); outb(0x00, AX_CMD); - + autoirq = autoirq_report(1); - if (autoirq == 0) - { + if (autoirq == 0) { printk("%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); return EAGAIN; @@ -307,29 +301,30 @@ if (autoirq) dev->irq = autoirq; - printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, - autoirq ? "auto":"assigned ", dev->irq); - + printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", + dev->name, mname, dev->base_addr, + autoirq ? "auto" : "assigned ", dev->irq); + #ifdef CONFIG_IP_MULTICAST printk("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); -#endif +#endif if (el_debug) printk("%s", version); /* - * Initialize the device structure. + * Initialize the device structure. */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + + dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + memset(dev->priv, 0, sizeof (struct net_local)); /* - * The EL1-specific entries in the device structure. + * The EL1-specific entries in the device structure. */ - + dev->open = &el_open; dev->hard_start_xmit = &el_start_xmit; dev->stop = &el1_close; @@ -337,7 +332,7 @@ dev->set_multicast_list = &set_multicast_list; /* - * Setup the generic properties + * Setup the generic properties */ ether_setup(dev); @@ -346,9 +341,9 @@ } /* - * Open/initialize the board. + * Open/initialize the board. */ - + static int el_open(struct device *dev) { int ioaddr = dev->base_addr; @@ -356,7 +351,7 @@ if (el_debug > 2) printk("%s: Doing el_open()...", dev->name); - if (request_irq(dev->irq, &el_interrupt, 0, "3c501", NULL)) + if (request_irq(dev->irq, &el_interrupt, 0, "3c501", NULL)) return -EAGAIN; irq2dev_map[dev->irq] = dev; @@ -374,21 +369,20 @@ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; - - if(dev->interrupt) /* May be unloading, don't stamp on */ + + if (dev->interrupt) /* May be unloading, don't stamp on */ return 1; /* the packet buffer this time */ - if (dev->tbusy) - { - if (jiffies - dev->trans_start < 20) - { + if (dev->tbusy) { + if (jiffies - dev->trans_start < 20) { if (el_debug > 2) printk(" transmitter busy, deferred.\n"); return 1; } if (el_debug) printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", - dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); + dev->name, inb(TX_STATUS), inb(AX_STATUS), + inb(RX_STATUS)); lp->stats.tx_errors++; outb(TX_NORM, TX_CMD); outb(RX_NORM, RX_CMD); @@ -398,8 +392,7 @@ dev->trans_start = jiffies; } - if (skb == NULL) - { + if (skb == NULL) { dev_tint(dev); return 0; } @@ -411,77 +404,84 @@ * mode as the driver assumes tbusy is a faithful indicator of card * state */ - + cli(); - + /* - * Avoid timer-based retransmission conflicts. + * Avoid timer-based retransmission conflicts. */ - - if (set_bit(0, (void*)&dev->tbusy) != 0) - { + + if (set_bit(0, (void *)&dev->tbusy) != 0) { restore_flags(flags); printk("%s: Transmitter access conflict.\n", dev->name); - } - else - { - int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); + } else { + int len = skb->len; + int pad = 0; + int gp_start; unsigned char *buf = skb->data; + if (len < ETH_ZLEN) + pad = ETH_ZLEN - len; + + gp_start = 0x800 - (len + pad); + load_it_again_sam: lp->tx_pkt_start = gp_start; - lp->collisions = 0; + lp->collisions = 0; /* * Command mode with status cleared should [in theory] * mean no more interrupts can be pending on the card. */ - + #ifdef BLOCKOUT_1 - disable_irq(dev->irq); -#endif + disable_irq(dev->irq); +#endif outb_p(AX_SYS, AX_CMD); inb_p(RX_STATUS); inb_p(TX_STATUS); - - lp->loading=1; - - /* - * Turn interrupts back on while we spend a pleasant afternoon - * loading bytes into the board + + lp->loading = 1; + + /* + * Turn interrupts back on while we spend a pleasant + * afternoon loading bytes into the board */ restore_flags(flags); outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ - outsb(DATAPORT,buf,skb->len); /* load buffer (usual thing each byte increments the pointer) */ + outsb(DATAPORT, buf, len); /* load buffer (usual thing each byte increments the pointer) */ + if (pad) { + while (pad--) + outb(0, DATAPORT); + } outw(gp_start, GP_LOW); /* the board reuses the same register */ -#ifndef BLOCKOUT_1 - if(lp->loading==2) /* A receive upset our load, despite our best efforts */ - { - if(el_debug>2) +#ifndef BLOCKOUT_1 + if (lp->loading == 2) { + /* A receive upset our load, despite our best efforts */ + if (el_debug > 2) printk("%s: burped during tx load.\n", dev->name); goto load_it_again_sam; /* Sigh... */ } #endif outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ - lp->loading=0; -#ifdef BLOCKOUT_1 + lp->loading = 0; +#ifdef BLOCKOUT_1 enable_irq(dev->irq); -#endif +#endif dev->trans_start = jiffies; } if (el_debug > 2) printk(" queued xmit.\n"); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb(skb, FREE_WRITE); return 0; } - /* * The typical workload of the driver: - * Handle the ether interface interrupts. + * Handle the ether interface interrupts. */ static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -491,9 +491,8 @@ int ioaddr; int axsr; /* Aux. status reg. */ - if (dev == NULL || dev->irq != irq) - { - printk ("3c501 driver: irq %d for unknown device.\n", irq); + if (dev == NULL || dev->irq != irq) { + printk("3c501 driver: irq %d for unknown device.\n", irq); return; } @@ -501,9 +500,9 @@ lp = (struct net_local *)dev->priv; /* - * What happened ? + * What happened? */ - + axsr = inb(AX_STATUS); /* @@ -515,55 +514,53 @@ if (dev->interrupt) printk("%s: Reentering the interrupt driver!\n", dev->name); dev->interrupt = 1; -#ifndef BLOCKOUT_1 - if(lp->loading==1 && !dev->tbusy) - printk("%s: Inconsistent state loading while not in tx\n", - dev->name); -#endif +#ifndef BLOCKOUT_1 + if (lp->loading == 1 && !dev->tbusy) + printk("%s: Inconsistent state loading while not in tx\n", + dev->name); +#endif #ifdef BLOCKOUT_3 - lp->loading=2; /* So we can spot loading interruptions */ + lp->loading = 2; /* So we can spot loading interruptions */ #endif - if (dev->tbusy) - { - - /* - * Board in transmit mode. May be loading. If we are - * loading we shouldn't have got this. - */ - + if (dev->tbusy) { + /* + * Board in transmit mode. May be loading. If we are + * loading we shouldn't have got this. + */ + int txsr = inb(TX_STATUS); -#ifdef BLOCKOUT_2 - if(lp->loading==1) - { - if(el_debug > 2) - { - printk("%s: Interrupt while loading [", dev->name); - printk(" txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW)); +#ifdef BLOCKOUT_2 + if (lp->loading == 1) { + if(el_debug > 2) { + printk("%s: Interrupt while loading [", + dev->name); + printk(" txsr=%02x gp=%04x rp=%04x]\n", + txsr, inw(GP_LOW), inw(RX_LOW)); } - lp->loading=2; /* Force a reload */ + lp->loading = 2; /* Force a reload */ dev->interrupt = 0; return; } #endif if (el_debug > 6) - printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW)); + printk(" txsr=%02x gp=%04x rp=%04x", + txsr, inw(GP_LOW), inw(RX_LOW)); - if ((axsr & 0x80) && (txsr & TX_READY) == 0) - { + if ((axsr & 0x80) && (txsr & TX_READY) == 0) { /* - * FIXME: is there a logic to whether to keep on trying or - * reset immediately ? + * FIXME: is there a logic to whether to keep on + * trying or reset immediately ? */ - if(el_debug>1) - printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x" - " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, + if (el_debug > 1) + printk("%s: Unusual interrupt during Tx, " + "txsr=%02x axsr=%02x" + " gp=%03x rp=%03x.\n", dev->name, + txsr, axsr, inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); dev->tbusy = 0; mark_bh(NET_BH); - } - else if (txsr & TX_16COLLISIONS) - { + } else if (txsr & TX_16COLLISIONS) { /* * Timed out */ @@ -571,35 +568,32 @@ printk("%s: Transmit failed 16 times, ethernet jammed?\n",dev->name); outb(AX_SYS, AX_CMD); lp->stats.tx_aborted_errors++; - } - else if (txsr & TX_COLLISION) - { + } else if (txsr & TX_COLLISION) { /* - * Retrigger xmit. + * Retrigger xmit. */ - + if (el_debug > 6) printk(" retransmitting after a collision.\n"); /* - * Poor little chip can't reset its own start pointer + * Poor little chip can't reset its own start + * pointer */ - + outb(AX_SYS, AX_CMD); outw(lp->tx_pkt_start, GP_LOW); outb(AX_XMIT, AX_CMD); lp->stats.collisions++; dev->interrupt = 0; return; - } - else - { + } else { /* * It worked.. we will now fall through and receive */ lp->stats.tx_packets++; if (el_debug > 6) printk(" Tx succeeded %s\n", - (txsr & TX_RDY) ? "." : "but tx is busy!"); + (txsr & TX_RDY) ? "." : "but tx is busy!"); /* * This is safe the interrupt is atomic WRT itself. */ @@ -607,36 +601,31 @@ dev->tbusy = 0; mark_bh(NET_BH); /* In case more to transmit */ } - } - else - { - /* - * In receive mode. - */ - + } else { + /* + * In receive mode. + */ + int rxsr = inb(RX_STATUS); if (el_debug > 5) - printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW)); + printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, + inb(TX_STATUS),inw(RX_LOW)); /* - * Just reading rx_status fixes most errors. + * Just reading rx_status fixes most errors. */ if (rxsr & RX_MISSED) lp->stats.rx_missed_errors++; - else if (rxsr & RX_RUNT) - { /* Handled to avoid board lock-up. */ + else if (rxsr & RX_RUNT) { + /* Handled to avoid board lock-up. */ lp->stats.rx_length_errors++; - if (el_debug > 5) + if (el_debug > 5) printk(" runt.\n"); - } - else if (rxsr & RX_GOOD) - { + } else if (rxsr & RX_GOOD) { /* * Receive worked. */ el_receive(dev); - } - else - { + } else { /* * Nothing? Something is broken! */ @@ -650,7 +639,7 @@ } /* - * Move into receive mode + * Move into receive mode */ outb(AX_RX, AX_CMD); @@ -661,10 +650,9 @@ return; } - /* * We have a good packet. Well, not really "good", just mostly not broken. - * We must check everything to see if it is good. + * We must check everything to see if it is good. */ static void el_receive(struct device *dev) @@ -679,43 +667,39 @@ if (el_debug > 4) printk(" el_receive %d.\n", pkt_len); - if ((pkt_len < 60) || (pkt_len > 1536)) - { + if ((pkt_len < 60) || (pkt_len > 1536)) { if (el_debug) printk("%s: bogus packet, length=%d\n", dev->name, pkt_len); lp->stats.rx_over_errors++; return; } - + /* * Command mode so we can empty the buffer */ - + outb(AX_SYS, AX_CMD); - skb = dev_alloc_skb(pkt_len+2); + skb = dev_alloc_skb(pkt_len + 2); /* * Start of frame */ outw(0x00, GP_LOW); - if (skb == NULL) - { + if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; return; - } - else - { - skb_reserve(skb,2); /* Force 16 byte alignment */ + } else { + skb_reserve(skb,2); /* Force 16 byte alignment */ skb->dev = dev; /* * The read increments through the bytes. The interrupt - * handler will fix the pointer when it returns to + * handler will fix the pointer when it returns to * receive mode. */ - insb(DATAPORT, skb_put(skb,pkt_len), pkt_len); - skb->protocol=eth_type_trans(skb,dev); + insb(DATAPORT, skb_put(skb, pkt_len), pkt_len); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; } @@ -735,7 +719,7 @@ for (i = 0; i < 6; i++) /* Set the station address. */ outb(dev->dev_addr[i], ioaddr + i); } - + outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */ cli(); /* Avoid glitch on writes to CMD regs */ outb(TX_NORM, TX_CMD); /* tx irq on done, collision */ @@ -752,13 +736,14 @@ int ioaddr = dev->base_addr; if (el_debug > 2) - printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr); + printk("%s: Shutting down ethercard at %#x.\n", dev->name, + ioaddr); dev->tbusy = 1; dev->start = 0; /* - * Free and disable the IRQ. + * Free and disable the IRQ. */ free_irq(dev->irq, NULL); @@ -784,18 +769,13 @@ { int ioaddr = dev->base_addr; - if(dev->flags&IFF_PROMISC) - { + if(dev->flags&IFF_PROMISC) { outb(RX_PROM, RX_CMD); inb(RX_STATUS); - } - else if (dev->mc_list || dev->flags&IFF_ALLMULTI) - { + } else if (dev->mc_list || dev->flags&IFF_ALLMULTI) { outb(RX_MULT, RX_CMD); /* Multicast or all multicast is the same */ inb(RX_STATUS); /* Clear status. */ - } - else - { + } else { outb(RX_NORM, RX_CMD); inb(RX_STATUS); } @@ -805,17 +785,17 @@ static char devicename[9] = { 0, }; -static struct device dev_3c501 = +static struct device dev_3c501 = { devicename, /* device name is inserted by linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0x280, 5, - 0, 0, 0, NULL, el1_probe + 0, 0, 0, NULL, el1_probe }; -static int io=0x280; -static int irq=5; - +static int io = 0x280; +static int irq = 5; + int init_module(void) { dev_3c501.irq=irq; @@ -830,24 +810,23 @@ /* * No need to check MOD_IN_USE, as sys_delete_module() checks. */ - + unregister_netdev(&dev_3c501); /* - * Free up the private structure, or leak memory :-) + * Free up the private structure, or leak memory :-) */ - + kfree(dev_3c501.priv); dev_3c501.priv = NULL; /* gets re-allocated by el1_probe1 */ /* - * If we don't do this, we can't re-insmod it later. + * If we don't do this, we can't re-insmod it later. */ release_region(dev_3c501.base_addr, EL1_IO_EXTENT); } #endif /* MODULE */ - /* * Local variables: * compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -m486 -c -o 3c501.o 3c501.c" diff -urN linux-2.0.39/drivers/net/3c505.c linux-2.0.40/drivers/net/3c505.c --- linux-2.0.39/drivers/net/3c505.c 1996-08-05 00:13:52.000000000 -0700 +++ linux-2.0.40/drivers/net/3c505.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,7 +3,7 @@ * By Craig Southeren, Juha Laiho and Philip Blundell * * 3c505.c This module implements an interface to the 3Com - * Etherlink Plus (3c505) ethernet card. Linux device + * Etherlink Plus (3c505) ethernet card. Linux device * driver interface reverse engineered from the Linux 3C509 * device drivers. Some 3C505 information gleaned from * the Crynwr packet driver. Still this driver would not @@ -1092,8 +1092,9 @@ adapter->current_dma.start_time = jiffies; target = virt_to_bus(skb->data); - if ((target + nlen) >= MAX_DMA_ADDRESS) { - memcpy(adapter->dma_buffer, skb->data, nlen); + if ((target + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) { + memcpy(adapter->dma_buffer, skb->data, skb->len); + memset(adapter->dma_buffer + skb->len, 0, nlen - skb->len); target = virt_to_bus(adapter->dma_buffer); } adapter->current_dma.skb = skb; @@ -1132,7 +1133,7 @@ */ if (dev->tbusy) { elp_device *adapter = dev->priv; - int tickssofar = jiffies - dev->trans_start; + int tickssofar = jiffies - dev->trans_start; int stat; if (tickssofar < 1000) diff -urN linux-2.0.39/drivers/net/3c507.c linux-2.0.40/drivers/net/3c507.c --- linux-2.0.39/drivers/net/3c507.c 1996-02-29 21:50:42.000000000 -0800 +++ linux-2.0.40/drivers/net/3c507.c 2004-02-07 23:13:01.000000000 -0800 @@ -66,6 +66,7 @@ #define NET_DEBUG 1 #endif static unsigned int net_debug = NET_DEBUG; +static char padding[ETH_ZLEN]; /* A zero-terminated list of common I/O addresses to be probed. */ static unsigned int netcard_portlist[] = @@ -285,10 +286,10 @@ static int el16_close(struct device *dev); static struct enet_statistics *el16_get_stats(struct device *dev); -static void hardware_send_packet(struct device *dev, void *buf, short length); +static void hardware_send_packet(struct device *dev, void *buf, short length, + short pad); void init_82586_mem(struct device *dev); - #ifdef HAVE_DEVLIST struct netdev_entry netcard_drv = {"3c507", el16_probe1, EL16_IO_EXTENT, netcard_portlist}; @@ -428,8 +429,6 @@ return 0; } - - static int el16_open(struct device *dev) { @@ -438,6 +437,7 @@ /* Initialize the 82586 memory and start it. */ init_82586_mem(dev); + memset(padding, 0, ETH_ZLEN); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; @@ -497,7 +497,7 @@ /* Disable the 82586's input to the interrupt line. */ outb(0x80, ioaddr + MISC_CTRL); - hardware_send_packet(dev, buf, length); + hardware_send_packet(dev, buf, length, length - skb->len); dev->trans_start = jiffies; /* Enable the 82586 interrupt input. */ outb(0x84, ioaddr + MISC_CTRL); @@ -509,7 +509,7 @@ return 0; } - + /* The typical workload of the driver: Handle the network interface interrupts. */ static void @@ -759,7 +759,7 @@ } static void -hardware_send_packet(struct device *dev, void *buf, short length) +hardware_send_packet(struct device *dev, void *buf, short length, short pad) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; @@ -767,14 +767,14 @@ ushort *write_ptr = (ushort *)(dev->mem_start + tx_block); /* Set the write pointer to the Tx block, and put out the header. */ - *write_ptr++ = 0x0000; /* Tx status */ + *write_ptr++ = 0x0000; /* Tx status */ *write_ptr++ = CMD_INTR|CmdTx; /* Tx command */ - *write_ptr++ = tx_block+16; /* Next command is a NoOp. */ - *write_ptr++ = tx_block+8; /* Data Buffer offset. */ + *write_ptr++ = tx_block+16; /* Next command is a NoOp. */ + *write_ptr++ = tx_block+8; /* Data Buffer offset. */ /* Output the data buffer descriptor. */ - *write_ptr++ = length | 0x8000; /* Byte count parameter. */ - *write_ptr++ = -1; /* No next data buffer. */ + *write_ptr++ = (pad + length) | 0x8000; /* Byte count parameter. */ + *write_ptr++ = -1; /* No next data buffer. */ *write_ptr++ = tx_block+22+SCB_BASE;/* Buffer follows the NoOp command. */ *write_ptr++ = 0x0000; /* Buffer address high bits (always zero). */ @@ -785,6 +785,8 @@ /* Output the packet at the write pointer. */ memcpy(write_ptr, buf, length); + if (pad) + memcpy(write_ptr + length, padding, pad); /* Set the old command link pointing to this send packet. */ *(ushort*)(dev->mem_start + lp->tx_cmd_link) = tx_block; @@ -911,7 +913,6 @@ release_region(dev_3c507.base_addr, EL16_IO_EXTENT); } #endif /* MODULE */ - /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c" diff -urN linux-2.0.39/drivers/net/8390.c linux-2.0.40/drivers/net/8390.c --- linux-2.0.39/drivers/net/8390.c 1996-05-18 01:15:09.000000000 -0700 +++ linux-2.0.40/drivers/net/8390.c 2004-02-07 23:13:01.000000000 -0800 @@ -97,12 +97,13 @@ static void ei_receive(struct device *dev); static void ei_rx_overrun(struct device *dev); +static char scratch[ETH_ZLEN]; + /* Routines generic to NS8390-based boards. */ static void NS8390_trigger_send(struct device *dev, unsigned int length, int start_page); static void set_multicast_list(struct device *dev); - /* Open/initialize the board. This routine goes all-out, setting everything up anew at each open, even though many of these registers should only need to be set once at boot. @@ -238,8 +239,13 @@ * trigger the send later, upon receiving a Tx done interrupt. */ - ei_block_output(dev, length, skb->data, output_page); - if (! ei_local->txing) { + if (length == send_length) + ei_block_output(dev, length, skb->data, output_page); + else { + memcpy(scratch, skb->data, skb->len); + ei_block_output(dev, ETH_ZLEN, scratch, output_page); + } + if (!ei_local->txing) { ei_local->txing = 1; NS8390_trigger_send(dev, send_length, output_page); dev->trans_start = jiffies; @@ -263,7 +269,12 @@ * reasonable hardware if you only use one Tx buffer. */ - ei_block_output(dev, length, skb->data, ei_local->tx_start_page); + if (length == send_length) + ei_block_output(dev, length, skb->data, ei_local->tx_start_page); + else { + memcpy(scratch, skb->data, skb->len); + ei_block_output(dev, ETH_ZLEN, scratch, ei_local->tx_start_page); + } ei_local->txing = 1; NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); dev->trans_start = jiffies; @@ -754,7 +765,10 @@ /* Clear the pending interrupts and mask. */ outb_p(0xFF, e8390_base + EN0_ISR); outb_p(0x00, e8390_base + EN0_IMR); - + + /* Zerofill the padding buffer */ + memset(scratch, 0, ETH_ZLEN); + /* Copy the station address into the DS8390 registers, and set the multicast hash bitmap to receive all multicasts. */ save_flags(flags); diff -urN linux-2.0.39/drivers/net/atarilance.c linux-2.0.40/drivers/net/atarilance.c --- linux-2.0.39/drivers/net/atarilance.c 1997-04-08 08:47:45.000000000 -0700 +++ linux-2.0.40/drivers/net/atarilance.c 2004-02-07 23:13:01.000000000 -0800 @@ -771,6 +771,17 @@ DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); + /* The old LANCE chips doesn't automatically pad buffers to min size */ + if ((len = skb->len) < ETH_ZLEN) + len = ETH_ZLEN; + else if (lp->cardtype == PAM_CARD && (len & 1)) + ++len; + + if (len > skb->len) { + if (!(skb = skb_padto(skb, len))) + return 0; + } + /* 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) { @@ -807,17 +818,11 @@ /* Mask to ring buffer boundary. */ entry = lp->cur_tx & TX_RING_MOD_MASK; head = &(MEM->tx_head[entry]); - + /* Caution: the write order is important here, set the "ownership" bits * last. */ - /* The old LANCE chips doesn't automatically pad buffers to min. size. */ - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - /* PAM-Card has a bug: Can only send packets with even number of bytes! */ - if (lp->cardtype == PAM_CARD && (len & 1)) - ++len; - head->length = -len; head->misc = 0; lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); diff -urN linux-2.0.39/drivers/net/atp.c linux-2.0.40/drivers/net/atp.c --- linux-2.0.39/drivers/net/atp.c 1997-08-12 13:21:12.000000000 -0700 +++ linux-2.0.40/drivers/net/atp.c 2004-02-07 23:13:01.000000000 -0800 @@ -537,7 +537,7 @@ } else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; - int flags; + unsigned long flags; /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. This sequence must not be interrupted by an incoming packet. */ diff -urN linux-2.0.39/drivers/net/auto_irq.c linux-2.0.40/drivers/net/auto_irq.c --- linux-2.0.39/drivers/net/auto_irq.c 1998-06-03 15:17:47.000000000 -0700 +++ linux-2.0.40/drivers/net/auto_irq.c 2004-02-07 23:13:01.000000000 -0800 @@ -24,6 +24,20 @@ The idea of using the setup timeout to filter out bogus IRQs came from the serial driver. + +Update 2000-09-04, by Michael Deutschmann : + + The code used to rely upon freeing an IRQ handler, within the same + handler. This is not correct -- it causes the kernel to free a + structure that is still in use. + + Because the read-after-free takes place with interrupts off, it's + probably impossible for anything else to reallocate the memory and + trash the structure -- but in SADISTIC_KMALLOC mode it will crash + every time. + + I've fixed the code so it doesn't do that. + */ @@ -52,13 +66,14 @@ static void autoirq_probe(int irq, void *dev_id, struct pt_regs * regs) { + /* Only act on first instance of this IRQ. We can't free the + * handler from here, so we just make sure second trips do nothing. + */ + if (test_bit(irq, (void *)&irq_bitmap)) + return; + irq_number = irq; set_bit(irq, (void *)&irq_bitmap); /* irq_bitmap |= 1 << irq; */ - /* This code used to disable the irq. However, the interrupt stub - * would then re-enable the interrupt with (potentially) disastrous - * consequences - */ - free_irq(irq, dev_id); return; } @@ -102,8 +117,6 @@ if (irq_number) break; - irq_handled &= ~irq_bitmap; /* This eliminates the already reset handlers */ - /* Retract the irq handlers that we installed. */ for (i = 0; i < 16; i++) { if (test_bit(i, (void *)&irq_handled)) diff -urN linux-2.0.39/drivers/net/de4x5.c linux-2.0.40/drivers/net/de4x5.c --- linux-2.0.39/drivers/net/de4x5.c 1999-06-13 10:21:01.000000000 -0700 +++ linux-2.0.40/drivers/net/de4x5.c 2004-02-07 23:13:01.000000000 -0800 @@ -414,6 +414,7 @@ #include #include +#include #include #include #include diff -urN linux-2.0.39/drivers/net/de600.c linux-2.0.40/drivers/net/de600.c --- linux-2.0.39/drivers/net/de600.c 1996-02-29 21:50:43.000000000 -0800 +++ linux-2.0.40/drivers/net/de600.c 2004-02-07 23:13:01.000000000 -0800 @@ -36,7 +36,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **************************************************************/ /* Add another "; SLOW_DOWN_IO" here if your adapter won't work OK: */ @@ -400,6 +400,7 @@ int len; int tickssofar; byte *buffer = skb->data; + int i; /* * If some higher layer thinks we've missed a @@ -454,8 +455,10 @@ #endif de600_setup_address(transmit_from, RW_ADDR); - for ( ; len > 0; --len, ++buffer) + for (i = 0 ; i < skb->len; ++i, ++buffer) de600_put_byte(*buffer); + for (; i < len; ++i) + de600_put_byte(0); if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */ dev->trans_start = jiffies; @@ -468,9 +471,9 @@ dev->tbusy = !free_tx_pages; select_prn(); } - + sti(); /* interrupts back on */ - + #ifdef FAKE_SMALL_MAX /* This will "patch" the socket TCP proto at an early moment */ if (skb->sk && (skb->sk->protocol == IPPROTO_TCP) && @@ -812,7 +815,7 @@ /* * Hack! You might want to play with commenting away the following line, * if you know what you do! - sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF; + sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF; */ if (sk->rmem_alloc >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0); @@ -823,7 +826,7 @@ return(0); } #endif - + #ifdef MODULE static char nullname[8]; static struct device de600_dev = { diff -urN linux-2.0.39/drivers/net/de620.c linux-2.0.40/drivers/net/de620.c --- linux-2.0.39/drivers/net/de620.c 1996-02-29 21:50:43.000000000 -0800 +++ linux-2.0.40/drivers/net/de620.c 2004-02-07 23:13:01.000000000 -0800 @@ -304,7 +304,7 @@ } static inline void -de620_write_block(struct device *dev, byte *buffer, int count) +de620_write_block(struct device *dev, byte *buffer, int count, int pad) { #ifndef LOWSPEED byte uflip = NIC_Cmd ^ (DS0 | DS1); @@ -320,9 +320,10 @@ tot_cnt = 0; #endif /* COUNT_LOOPS */ /* No further optimization useful, the limit is in the adapter. */ - for ( ; count > 0; --count, ++buffer) { + for (; count > 0; --count, ++buffer) de620_put_byte(dev,*buffer); - } + for (count = pad; count > 0; --count, ++buffer) + de620_put_byte(dev, 0); de620_send_command(dev,W_DUMMY); #ifdef COUNT_LOOPS /* trial debug output: loops per byte in de620_ready() */ @@ -578,20 +579,20 @@ return 1; break; } - de620_write_block(dev, buffer, len); + de620_write_block(dev, buffer, skb->len, len - skb->len); dev->trans_start = jiffies; dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */ ((struct netstats *)(dev->priv))->tx_packets++; - + restore_flags(flags); /* interrupts maybe back on */ - + dev_kfree_skb (skb, FREE_WRITE); return 0; } - + /***************************************************** * * Handle the network interface interrupts. diff -urN linux-2.0.39/drivers/net/depca.c linux-2.0.40/drivers/net/depca.c --- linux-2.0.39/drivers/net/depca.c 1999-06-13 10:21:01.000000000 -0700 +++ linux-2.0.40/drivers/net/depca.c 2004-02-07 23:13:01.000000000 -0800 @@ -229,6 +229,7 @@ #include #include +#include #include #include #include @@ -842,6 +843,10 @@ } else if (skb == NULL) { dev_tint(dev); } else if (skb->len > 0) { + if (skb->len < ETH_ZLEN) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) + return 0; + } /* Enforce 1 process per h/w access */ if (set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); diff -urN linux-2.0.39/drivers/net/epic100.c linux-2.0.40/drivers/net/epic100.c --- linux-2.0.39/drivers/net/epic100.c 1999-06-13 10:21:01.000000000 -0700 +++ linux-2.0.40/drivers/net/epic100.c 2004-02-07 23:13:01.000000000 -0800 @@ -865,6 +865,11 @@ int entry; u32 flag; + if (skb->len < ETH_ZLEN) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) + return 0; + } + /* 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 (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { diff -urN linux-2.0.39/drivers/net/hp100.c linux-2.0.40/drivers/net/hp100.c --- linux-2.0.39/drivers/net/hp100.c 1998-11-15 10:33:03.000000000 -0800 +++ linux-2.0.40/drivers/net/hp100.c 2004-02-07 23:13:01.000000000 -0800 @@ -1555,9 +1555,14 @@ #endif return 0; } - - if ( skb->len <= 0 ) return 0; - + + if (skb->len <= 0) + return 0; + + if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) + return 0; + } /* Get Tx ring tail pointer */ if( lp->txrtail->next==lp->txrhead ) { diff -urN linux-2.0.39/drivers/net/ni52.c linux-2.0.40/drivers/net/ni52.c --- linux-2.0.39/drivers/net/ni52.c 1999-06-13 10:21:01.000000000 -0700 +++ linux-2.0.40/drivers/net/ni52.c 2004-02-07 23:13:01.000000000 -0800 @@ -1176,10 +1176,13 @@ return 1; } #endif - else - { + else { + if ((len = skb->len) < ETH_ZLEN) { + len = ETH_ZLEN; + memset((char *)p->xmit_cbuffs[p->xmit_count] + skb->len, 0, + len - skb->len); + } memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len); - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; #if (NUM_XMIT_BUFFS == 1) # ifdef NO_NOPCOMMANDS diff -urN linux-2.0.39/drivers/net/ni65.c linux-2.0.40/drivers/net/ni65.c --- linux-2.0.39/drivers/net/ni65.c 1996-11-01 13:07:23.000000000 -0800 +++ linux-2.0.40/drivers/net/ni65.c 2004-02-07 23:13:01.000000000 -0800 @@ -1112,8 +1112,11 @@ if( (unsigned long) (skb->data + skb->len) > 0x1000000) { #endif - memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, + memcpy((char *) p->tmdbounce[p->tmdbouncenum], (char *)skb->data, (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); + if (len > skb->len) + memset((char *)p->tmdbounce[p->tmdbouncenum] + skb->len, 0, + len - skb->len); dev_kfree_skb (skb, FREE_WRITE); save_flags(flags); diff -urN linux-2.0.39/drivers/net/rtl8139.c linux-2.0.40/drivers/net/rtl8139.c --- linux-2.0.39/drivers/net/rtl8139.c 1999-06-13 10:21:01.000000000 -0700 +++ linux-2.0.40/drivers/net/rtl8139.c 2004-02-07 23:13:01.000000000 -0800 @@ -922,6 +922,13 @@ return 1; } + if (skb->len < ETH_ZLEN) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) { + clear_bit(0, (void *)&dev->tbusy); + return 0; + } + } + /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; diff -urN linux-2.0.39/drivers/net/seeq8005.c linux-2.0.40/drivers/net/seeq8005.c --- linux-2.0.39/drivers/net/seeq8005.c 1996-05-06 02:26:08.000000000 -0700 +++ linux-2.0.40/drivers/net/seeq8005.c 2004-02-07 23:13:01.000000000 -0800 @@ -402,10 +402,18 @@ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + short length = skb->len; unsigned char *buf = skb->data; - hardware_send_packet(dev, buf, length); + if (length < ETH_ZLEN) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) { + dev->tbusy = 0; + return 0; + } + length = ETH_ZLEN; + } + + hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; } dev_kfree_skb (skb, FREE_WRITE); diff -urN linux-2.0.39/drivers/net/sk_g16.c linux-2.0.40/drivers/net/sk_g16.c --- linux-2.0.39/drivers/net/sk_g16.c 1998-06-03 15:17:47.000000000 -0700 +++ linux-2.0.40/drivers/net/sk_g16.c 2004-02-07 23:13:01.000000000 -0800 @@ -1192,6 +1192,7 @@ { struct priv *p = (struct priv *) dev->priv; struct tmd *tmdp; + static char pad[64]; if (dev->tbusy) { @@ -1253,8 +1254,11 @@ /* Copy data into dual ported ram */ - memcpy((char *) (tmdp->u.buffer & 0x00ffffff), (char *)skb->data, + memcpy((char *)(tmdp->u.buffer & 0x00ffffff), (char *)skb->data, skb->len); + if (len != skb->len) + memcpy((char *)(tmdp->u.buffer & 0x00ffffff) + skb->len, pad, + len - skb->len); tmdp->blen = -len; /* set length to transmit */ diff -urN linux-2.0.39/drivers/net/smc9194.c linux-2.0.40/drivers/net/smc9194.c --- linux-2.0.39/drivers/net/smc9194.c 1996-04-11 23:49:39.000000000 -0700 +++ linux-2.0.40/drivers/net/smc9194.c 2004-02-07 23:13:01.000000000 -0800 @@ -558,10 +558,15 @@ printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); return 1; } + + if ((length = skb->len) < ETH_ZLEN) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) { + return 0; + } + length = ETH_ZLEN; + } lp->saved_skb = skb; - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - /* . the MMU wants the number of pages to be the number of 256 bytes . 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) diff -urN linux-2.0.39/drivers/net/tulip.c linux-2.0.40/drivers/net/tulip.c --- linux-2.0.39/drivers/net/tulip.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/net/tulip.c 2004-02-07 23:13:01.000000000 -0800 @@ -296,7 +296,7 @@ 0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 }, {0}, }; -#endif CARD_BUS +#endif /* CARD_BUS */ /* This table use during operation for capabilities and media timer. */ @@ -585,7 +585,11 @@ if (tulip_debug > 0 && did_version++ == 0) printk(KERN_INFO "%s", version); - dev = init_etherdev(dev, 0); + if (!(dev = init_etherdev(dev, 0))) { + printk(KERN_ERR "tulip: Unable to allocate net_device " + "structure!\n"); + return NULL; + } /* Bring the 21143 out of sleep mode. Caution: Snooze mode does not work with some boards! */ diff -urN linux-2.0.39/drivers/net/via-rhine.c linux-2.0.40/drivers/net/via-rhine.c --- linux-2.0.39/drivers/net/via-rhine.c 1998-11-15 10:33:04.000000000 -0800 +++ linux-2.0.40/drivers/net/via-rhine.c 2004-02-07 23:13:01.000000000 -0800 @@ -848,6 +848,13 @@ /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; + if (skb->len < ETH_ZLEN) { + if (!(skb = skb_padto(skb,ETH_ZLEN))) { + dev->tbusy = 0; + return 0; + } + } + np->tx_skbuff[entry] = skb; if ((long)skb->data & 3) { /* Must use alignment buffer. */ diff -urN linux-2.0.39/drivers/net/znet.c linux-2.0.40/drivers/net/znet.c --- linux-2.0.39/drivers/net/znet.c 1996-02-29 21:50:49.000000000 -0800 +++ linux-2.0.40/drivers/net/znet.c 2004-02-07 23:13:01.000000000 -0800 @@ -317,10 +317,17 @@ static int znet_send_packet(struct sk_buff *skb, struct device *dev) { int ioaddr = dev->base_addr; + short length = skb->len; if (znet_debug > 4) printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy); + if (length < ETH_ZLEN) { + if (!(skb = skb_padto(skb, ETH_ZLEN))) + return 0; + length = ETH_ZLEN; + } + /* Transmitter timeout, likely just recovery after suspending the machine. */ if (dev->tbusy) { ushort event, tx_status, rx_offset, state; @@ -357,7 +364,6 @@ if (set_bit(0, (void*)&dev->tbusy) != 0) printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = (void *)skb->data; ushort *tx_link = zn.tx_cur - 1; ushort rnd_len = (length + 1)>>1; diff -urN linux-2.0.39/drivers/sbus/char/sunserial.c linux-2.0.40/drivers/sbus/char/sunserial.c --- linux-2.0.39/drivers/sbus/char/sunserial.c 1996-05-06 02:26:09.000000000 -0700 +++ linux-2.0.40/drivers/sbus/char/sunserial.c 2004-02-07 23:13:01.000000000 -0800 @@ -904,7 +904,8 @@ void kbd_put_char(unsigned char ch) { struct sun_zschannel *chan = zs_kbdchan; - int flags, loops = 0; + int loops = 0; + unsigned long flags; if(!chan) return; @@ -923,7 +924,8 @@ void mouse_put_char(char ch) { struct sun_zschannel *chan = zs_mousechan; - int flags, loops = 0; + int loops = 0; + unsigned long flags; if(!chan) return; @@ -944,7 +946,8 @@ static void rs_put_char(char ch) { struct sun_zschannel *chan = zs_conschan; - int flags, loops = 0; + int loops = 0; + unsigned long flags; if(!chan) return; @@ -1900,8 +1903,9 @@ /* rs_init inits the driver */ int rs_init(void) { - int chip, channel, i, flags; + int chip, channel, i; struct sun_serial *info; + unsigned long flags; #if CONFIG_AP1000 printk("not doing rs_init()\n"); @@ -1917,7 +1921,7 @@ /* Initialize the tty_driver structure */ /* SPARC: Not all of this is exactly right for us. */ - + memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.name = "ttyS"; diff -urN linux-2.0.39/drivers/scsi/NCR5380.h linux-2.0.40/drivers/scsi/NCR5380.h --- linux-2.0.39/drivers/scsi/NCR5380.h 1998-06-03 15:17:48.000000000 -0700 +++ linux-2.0.40/drivers/scsi/NCR5380.h 2004-02-07 23:13:01.000000000 -0800 @@ -368,6 +368,6 @@ } #endif /* defined(i386) || defined(__alpha__) */ #endif /* defined(REAL_DMA) */ -#endif __KERNEL_ +#endif /* __KERNEL_ */ #endif /* ndef ASM */ #endif /* NCR5380_H */ diff -urN linux-2.0.39/drivers/scsi/NCR53c406a.c linux-2.0.40/drivers/scsi/NCR53c406a.c --- linux-2.0.39/drivers/scsi/NCR53c406a.c 1998-07-13 13:47:32.000000000 -0700 +++ linux-2.0.40/drivers/scsi/NCR53c406a.c 2004-02-07 23:13:01.000000000 -0800 @@ -222,8 +222,8 @@ (void *)0xc8000 }; #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned )) -#endif USE_BIOS - +#endif /* USE_BIOS */ + /* possible i/o port addresses */ static unsigned short ports[] = { 0x230, 0x330 }; #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short )) @@ -244,7 +244,7 @@ { "Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82 }, }; #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) -#endif USE_BIOS +#endif /* USE_BIOS */ /* ============================================================ */ @@ -345,10 +345,10 @@ clear_dma_ff(dma_chan); tmp = get_dma_residue(dma_chan); restore_flags(flags); - + return tmp; } -#endif USE_DMA +#endif /* USE_DMA */ #if USE_PIO static __inline__ int NCR53c406a_pio_read(unsigned char *request, @@ -357,14 +357,14 @@ int i; int len; /* current scsi fifo size */ unsigned long flags = 0; - + REG1; while (reqlen) { i = inb(PIO_STATUS); /* VDEB(printk("pio_status=%x\n", i)); */ if (i & 0x80) return 0; - + switch( i & 0x1e ) { default: case 0x10: @@ -456,15 +456,15 @@ } return 0; } -#endif USE_PIO +#endif /* USE_PIO */ -int +int NCR53c406a_detect(Scsi_Host_Template * tpnt){ struct Scsi_Host *shpnt; #ifndef PORT_BASE int i; #endif - + #if USE_BIOS int ii, jj; bios_base = 0; @@ -475,15 +475,15 @@ (void *) signatures[jj].signature, (int) signatures[jj].sig_length)) bios_base=addresses[ii]; - + if(!bios_base){ printk("NCR53c406a: BIOS signature not found\n"); return 0; } - + DEB(printk("NCR53c406a BIOS found at %X\n", (unsigned int) bios_base);); -#endif USE_BIOS - +#endif /* USE_BIOS */ + #ifdef PORT_BASE if (check_region(port_base, 0x10)) /* ports already snatched */ port_base = 0; @@ -511,18 +511,18 @@ } } } -#endif PORT_BASE - +#endif /* PORT_BASE */ + if(!port_base){ /* no ports found */ printk("NCR53c406a: no available ports found\n"); return 0; } - + DEB(printk("NCR53c406a detected\n")); - + calc_port_addr(); chip_init(); - + #ifndef IRQ_LEV if (irq_level < 0) { /* LILO override if >= 0*/ irq_level=irq_probe(); @@ -532,10 +532,10 @@ } } #endif - + DEB(printk("NCR53c406a: using port_base %x\n", port_base)); request_region(port_base, 0x10, "NCR53c406a"); - + if(irq_level > 0) { if(request_irq(irq_level, NCR53c406a_intr, 0, "NCR53c406a", NULL)){ printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level); @@ -550,26 +550,26 @@ #if USE_DMA printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n"); return 0; -#endif USE_DMA +#endif /* USE_DMA */ } else { DEB(printk("NCR53c406a: Shouldn't get here!\n")); return 0; } - + #if USE_DMA dma_chan = DMA_CHAN; if(request_dma(dma_chan, "NCR53c406a") != 0){ printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan); return 0; } - + DEB(printk("Allocated DMA channel %d\n", dma_chan)); -#endif USE_DMA - +#endif /* USE_DMA */ + tpnt->present = 1; tpnt->proc_dir = &proc_scsi_NCR53c406a; - + shpnt = scsi_register(tpnt, 0); shpnt->irq = irq_level; shpnt->io_port = port_base; @@ -796,9 +796,9 @@ printk("\n"); #else printk(", pio=%02x\n", pio_status); -#endif USE_DMA -#endif NCR53C406A_DEBUG - +#endif /* USE_DMA */ +#endif /* NCR53C406A_DEBUG */ + if(int_reg & 0x80){ /* SCSI reset intr */ rtrc(3); DEB(printk("NCR53c406a: reset intr received\n")); @@ -807,7 +807,7 @@ current_SC->scsi_done(current_SC); return; } - + #if USE_PIO if(pio_status & 0x80) { printk("NCR53C406A: Warning: PIO error!\n"); @@ -816,8 +816,8 @@ current_SC->scsi_done(current_SC); return; } -#endif USE_PIO - +#endif /* USE_PIO */ + if(status & 0x20) { /* Parity error */ printk("NCR53c406a: Warning: parity error!\n"); current_SC->SCp.phase = idle; @@ -861,7 +861,7 @@ #if USE_DMA /* No s/g support for DMA */ NCR53c406a_dma_write(current_SC->request_buffer, current_SC->request_bufflen); -#endif USE_DMA +#endif /* USE_DMA */ outb(TRANSFER_INFO | DMA_OP, CMD_REG); #if USE_PIO if (!current_SC->use_sg) /* Don't use scatter-gather */ @@ -876,10 +876,10 @@ } } REG0; -#endif USE_PIO +#endif /* USE_PIO */ } break; - + case 0x01: /* DATA-IN */ if(int_reg & 0x10){ /* Target requesting info transfer */ rtrc(6); @@ -890,7 +890,7 @@ #if USE_DMA /* No s/g support for DMA */ NCR53c406a_dma_read(current_SC->request_buffer, current_SC->request_bufflen); -#endif USE_DMA +#endif /* USE_DMA */ outb(TRANSFER_INFO | DMA_OP, CMD_REG); #if USE_PIO if (!current_SC->use_sg) /* Don't use scatter-gather */ @@ -905,10 +905,10 @@ } } REG0; -#endif USE_PIO +#endif /* USE_PIO */ } break; - + case 0x02: /* COMMAND */ current_SC->SCp.phase = command_ph; printk("NCR53c406a: Warning: Unknown interrupt occurred in command phase!\n"); @@ -978,17 +978,17 @@ probe_irq_off(irqs); return -1; } - + irq = probe_irq_off(irqs); - + /* Kick the chip */ outb(CHIP_RESET, CMD_REG); outb(SCSI_NOP, CMD_REG); chip_init(); - + return irq; } -#endif IRQ_LEV +#endif /* IRQ_LEV */ static void chip_init() { @@ -999,12 +999,12 @@ outb(0x01, PIO_STATUS); #endif outb(0x00, PIO_FLAG); - + outb(C4_IMG, CONFIG4); /* REG0; */ outb(C3_IMG, CONFIG3); outb(C2_IMG, CONFIG2); outb(C1_IMG, CONFIG1); - + outb(0x05, CLKCONV); /* clock conversion factor */ outb(0x9C, SRTIMOUT); /* Selection timeout */ outb(0x05, SYNCPRD); /* Synchronous transfer period */ diff -urN linux-2.0.39/drivers/scsi/aha152x.c linux-2.0.40/drivers/scsi/aha152x.c --- linux-2.0.39/drivers/scsi/aha152x.c 1998-11-15 10:33:07.000000000 -0800 +++ linux-2.0.40/drivers/scsi/aha152x.c 2004-02-07 23:13:01.000000000 -0800 @@ -1536,7 +1536,7 @@ void aha152x_intr(int irqno, void *dev_id, struct pt_regs * regs) { struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; - unsigned int flags; + unsigned long flags; int done=0, phase; #if defined(DEBUG_RACE) diff -urN linux-2.0.39/drivers/scsi/aha1542.c linux-2.0.40/drivers/scsi/aha1542.c --- linux-2.0.39/drivers/scsi/aha1542.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/scsi/aha1542.c 2004-02-07 23:13:01.000000000 -0800 @@ -356,7 +356,7 @@ void (*my_done)(Scsi_Cmnd *) = NULL; int errstatus, mbi, mbo, mbistatus; int number_serviced; - unsigned int flags; + unsigned long flags; struct Scsi_Host * shost; Scsi_Cmnd * SCtmp; int flag; diff -urN linux-2.0.39/drivers/scsi/aic7xxx.c linux-2.0.40/drivers/scsi/aic7xxx.c --- linux-2.0.39/drivers/scsi/aic7xxx.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/scsi/aic7xxx.c 2004-02-07 23:13:01.000000000 -0800 @@ -9455,7 +9455,7 @@ } /* while(pdev=....) */ } /* for PCI_DEVICES */ } /* PCI BIOS present */ -#endif CONFIG_PCI +#endif /* CONFIG_PCI */ /* * Now, we re-order the probed devices by BIOS address and BUS class. * In general, we follow this algorithm to make the adapters show up diff -urN linux-2.0.39/drivers/scsi/aic7xxx_proc.c linux-2.0.40/drivers/scsi/aic7xxx_proc.c --- linux-2.0.39/drivers/scsi/aic7xxx_proc.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/scsi/aic7xxx_proc.c 2004-02-07 23:13:01.000000000 -0800 @@ -29,6 +29,8 @@ * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ *-M*************************************************************************/ +#include + #define BLS (&aic7xxx_buffer[size]) #define HDRB \ " < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" diff -urN linux-2.0.39/drivers/scsi/ini9100u.c linux-2.0.40/drivers/scsi/ini9100u.c --- linux-2.0.39/drivers/scsi/ini9100u.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/scsi/ini9100u.c 2004-02-07 23:13:01.000000000 -0800 @@ -116,12 +116,8 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include -#include #include -#include #include -#include -#include #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92) #include #endif @@ -136,33 +132,28 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "ini9100u.h" #include -#include #include #else -#include #include #include -#include -#include - #include #include #include -#include #include "../block/blk.h" -#include "scsi.h" +#endif + #include "sd.h" #include "hosts.h" -#include +#include "scsi.h" #include "ini9100u.h" -#endif +#include +#include +#include +#include +#include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,93) #ifdef CONFIG_PCI diff -urN linux-2.0.39/drivers/scsi/inia100.c linux-2.0.40/drivers/scsi/inia100.c --- linux-2.0.39/drivers/scsi/inia100.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/scsi/inia100.c 2004-02-07 23:13:01.000000000 -0800 @@ -73,11 +73,8 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0) #include -#include #include -#include #include -#include #include #include #include @@ -93,34 +90,29 @@ #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) #include #endif -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "inia100.h" #include -#include #include - #else -#include #include #include -#include #include #include #include #include -#include #include "../block/blk.h" -#include "scsi.h" +#endif + #include "sd.h" +#include "scsi.h" #include "hosts.h" -#include #include "inia100.h" -#endif +#include +#include +#include +#include #ifdef MODULE Scsi_Host_Template driver_template = INIA100; diff -urN linux-2.0.39/drivers/scsi/megaraid.c linux-2.0.40/drivers/scsi/megaraid.c --- linux-2.0.39/drivers/scsi/megaraid.c 1999-06-13 10:21:02.000000000 -0700 +++ linux-2.0.40/drivers/scsi/megaraid.c 2004-02-07 23:13:01.000000000 -0800 @@ -65,7 +65,6 @@ #define CRLFSTR "\n" -#include #include #ifdef MODULE @@ -82,8 +81,6 @@ #include #include #include -#include -#include #include #include #include diff -urN linux-2.0.39/drivers/scsi/pci2000.c linux-2.0.40/drivers/scsi/pci2000.c --- linux-2.0.39/drivers/scsi/pci2000.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/drivers/scsi/pci2000.c 2004-02-07 23:13:01.000000000 -0800 @@ -53,7 +53,9 @@ #include "pci2000.h" #include "psi_roy.h" -#include +#include "pci2220i.h" + +#include struct proc_dir_entry Proc_Scsi_Pci2000 = { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; diff -urN linux-2.0.39/drivers/scsi/ultrastor.c linux-2.0.40/drivers/scsi/ultrastor.c --- linux-2.0.39/drivers/scsi/ultrastor.c 1997-08-12 20:27:06.000000000 -0700 +++ linux-2.0.40/drivers/scsi/ultrastor.c 2004-02-07 23:13:01.000000000 -0800 @@ -333,7 +333,7 @@ { static char fmt[80] = "abort %d (%x); MSCP free pool: %x;"; register int i; - int flags; + unsigned long flags; save_flags(flags); cli(); @@ -681,7 +681,7 @@ int mscp_index; #endif unsigned int status; - int flags; + unsigned long flags; /* Next test is for debugging; "can't happen" */ if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0) @@ -853,7 +853,7 @@ { int port0 = (config.slot << 12) | 0xc80; int i; - int flags; + unsigned long flags; save_flags(flags); cli(); strcpy(out, "OGM %d:%x ICM %d:%x ports: "); @@ -879,7 +879,7 @@ if (config.slot ? inb(config.icm_address - 1) == 2 : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) { - int flags; + unsigned long flags; save_flags(flags); printk("Ux4F: abort while completed command pending\n"); restore_flags(flags); @@ -901,7 +901,7 @@ and the interrupt handler will call done. */ if (config.slot && inb(config.ogm_address - 1) == 0) { - int flags; + unsigned long flags; save_flags(flags); cli(); @@ -953,7 +953,7 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { - int flags; + unsigned long flags; register int i; #if (ULTRASTOR_DEBUG & UD_RESET) printk("US14F: reset: called\n"); diff -urN linux-2.0.39/drivers/sound/gus_wave.c linux-2.0.40/drivers/sound/gus_wave.c --- linux-2.0.39/drivers/sound/gus_wave.c 1996-08-20 23:18:09.000000000 -0700 +++ linux-2.0.40/drivers/sound/gus_wave.c 2004-02-07 23:13:01.000000000 -0800 @@ -545,7 +545,7 @@ { unsigned vol, prev_vol, phase; unsigned char rate; - long int flags; + unsigned long flags; if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) { @@ -618,7 +618,7 @@ } static void -start_release (int voice, long int flags) +start_release (int voice, unsigned long flags) { if (gus_read8 (0x00) & 0x03) return; /* Voice already stopped */ @@ -639,7 +639,7 @@ gus_voice_fade (int voice) { int instr_no = sample_map[voice], is16bits; - long int flags; + unsigned long flags; save_flags (flags); cli (); @@ -1581,7 +1581,7 @@ static int guswave_start_note (int dev, int voice, int note_num, int volume) { - long int flags; + unsigned long flags; int mode; int ret_val = 0; diff -urN linux-2.0.39/fs/Config.in linux-2.0.40/fs/Config.in --- linux-2.0.39/fs/Config.in 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/fs/Config.in 2004-02-07 23:13:01.000000000 -0800 @@ -53,6 +53,9 @@ fi bool '/proc filesystem support' CONFIG_PROC_FS +if [ "$CONFIG_PROC_FS" = "y" ]; then + bool ' Enable mmap on /proc/*/mem (UNSECURE!)' CONFIG_UNSAFE_MMAP +fi if [ "$CONFIG_INET" = "y" ]; then tristate 'NFS filesystem support' CONFIG_NFS_FS if [ "$CONFIG_NFS_FS" = "y" ]; then diff -urN linux-2.0.39/fs/buffer.c linux-2.0.40/fs/buffer.c --- linux-2.0.39/fs/buffer.c 1998-11-15 10:33:11.000000000 -0800 +++ linux-2.0.40/fs/buffer.c 2004-02-07 23:13:01.000000000 -0800 @@ -99,7 +99,7 @@ /* These are the min and max parameter values that we will allow to be assigned */ int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 100, 100, 1, 1}; -int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5}; +int bdflush_max[N_PARAM] = {100, 5000, 2000, 2000, 100, 60000, 60000, 2047, 5}; /* * Rewrote the wait-routines to use the "new" wait-queue functionality, @@ -266,7 +266,7 @@ return -EBADF; if (!file->f_op || !file->f_op->fsync) return -EINVAL; - if (file->f_op->fsync(inode,file)) + if (file->f_op->fsync(inode, file)) return -EIO; return 0; } @@ -281,7 +281,7 @@ if (!file->f_op || !file->f_op->fsync) return -EINVAL; /* this needs further work, at the moment it is identical to fsync() */ - if (file->f_op->fsync(inode,file)) + if (file->f_op->fsync(inode, file)) return -EIO; return 0; } @@ -311,8 +311,8 @@ } } -#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block))&HASH_MASK) -#define hash(dev,block) hash_table[_hashfn(dev,block)] +#define _hashfn(dev, block) (((unsigned)(HASHDEV(dev)^block))&HASH_MASK) +#define hash(dev, block) hash_table[_hashfn(dev, block)] static inline void remove_from_hash_queue(struct buffer_head * bh) { @@ -320,8 +320,8 @@ bh->b_next->b_prev = bh->b_prev; if (bh->b_prev) bh->b_prev->b_next = bh->b_next; - if (hash(bh->b_dev,bh->b_blocknr) == bh) - hash(bh->b_dev,bh->b_blocknr) = bh->b_next; + if (hash(bh->b_dev, bh->b_blocknr) == bh) + hash(bh->b_dev, bh->b_blocknr) = bh->b_next; bh->b_next = bh->b_prev = NULL; } @@ -440,23 +440,25 @@ bh->b_next = NULL; if (!(bh->b_dev)) return; - bh->b_next = hash(bh->b_dev,bh->b_blocknr); - hash(bh->b_dev,bh->b_blocknr) = bh; + bh->b_next = hash(bh->b_dev, bh->b_blocknr); + hash(bh->b_dev, bh->b_blocknr) = bh; if (bh->b_next) bh->b_next->b_prev = bh; } static inline struct buffer_head * find_buffer(kdev_t dev, int block, int size) -{ +{ struct buffer_head * tmp; - for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) + for (tmp = hash(dev, block) ; tmp != NULL ; tmp = tmp->b_next) if (tmp->b_blocknr == block && tmp->b_dev == dev) if (tmp->b_size == size) return tmp; else { +/* printk("VFS: Wrong blocksize on device %s\n", kdevname(dev)); +*/ return NULL; } return NULL; @@ -479,7 +481,7 @@ struct buffer_head * bh; for (;;) { - if (!(bh=find_buffer(dev,block,size))) + if (!(bh=find_buffer(dev, block, size))) return NULL; bh->b_count++; wait_on_buffer(bh); @@ -568,26 +570,26 @@ if (!bh) goto no_candidate; - + for (; (*list_len) > 0; bh = bh->b_next_free, (*list_len)--) { if (size != bh->b_size) { /* this provides a mechanism for freeing blocks of other sizes, this is necessary now that we no longer have the lav code. */ - try_to_free_buffer(bh,&bh,1); + try_to_free_buffer(bh, &bh, 1); if (!bh) break; lookahead = 7; continue; } - else if (buffer_locked(bh) && + else if (buffer_locked(bh) && (bh->b_list == BUF_LOCKED || bh->b_list == BUF_LOCKED1)) { if (!--lookahead) { (*list_len) = 0; goto no_candidate; } } - else if (can_reclaim(bh,size)) + else if (can_reclaim(bh, size)) return bh; } @@ -602,7 +604,7 @@ kfree(bh); return; } - memset(bh,0,sizeof(*bh)); + memset(bh, 0, sizeof(*bh)); nr_unused_buffer_heads++; bh->b_next_free = unused_list; unused_list = bh; @@ -707,15 +709,15 @@ needed -= bh->b_size; buffers[i]--; if(buffers[i] == 0) candidate[i] = NULL; - - if (candidate[i] && !can_reclaim(candidate[i],size)) - candidate[i] = find_candidate(candidate[i],&buffers[i], size); + + if (candidate[i] && !can_reclaim(candidate[i], size)) + candidate[i] = find_candidate(candidate[i], &buffers[i], size); } goto repeat; } /* Too bad, that was not enough. Try a little harder to grow some. */ - + if (nr_free_pages > limit) { if (grow_buffers(GFP_BUFFER, size)) { needed -= PAGE_SIZE; @@ -806,7 +808,7 @@ refill: allow_interrupts(); refill_freelist(size); - if (!find_buffer(dev,block,size)) + if (!find_buffer(dev, block, size)) goto get_free; goto repeat; } @@ -946,29 +948,29 @@ if (pos >= filesize) return NULL; - if (block < 0 || !(bh = getblk(dev,block,bufsize))) + if (block < 0 || !(bh = getblk(dev, block, bufsize))) return NULL; index = BUFSIZE_INDEX(bh->b_size); if (buffer_uptodate(bh)) - return(bh); + return(bh); else ll_rw_block(READ, 1, &bh); blocks = (filesize - pos) >> (9+index); if (blocks < (read_ahead[MAJOR(dev)] >> index)) blocks = read_ahead[MAJOR(dev)] >> index; - if (blocks > NBUF) + if (blocks > NBUF) blocks = NBUF; -/* if (blocks) printk("breada (new) %d blocks\n",blocks); */ +/* if (blocks) printk("breada (new) %d blocks\n", blocks); */ bhlist[0] = bh; j = 1; for(i=1; i PAGE_SIZE)) { - printk("VFS: grow_buffers: size = %d\n",size); + printk("VFS: grow_buffers: size = %d\n", size); return 0; } @@ -1477,9 +1479,9 @@ int nlist; static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","LOCKED1","DIRTY"}; - printk("Buffer memory: %6dkB\n",buffermem>>10); - printk("Buffer heads: %6d\n",nr_buffer_heads); - printk("Buffer blocks: %6d\n",nr_buffers); + printk("Buffer memory: %6dkB\n", buffermem>>10); + printk("Buffer heads: %6d\n", nr_buffer_heads); + printk("Buffer blocks: %6d\n", nr_buffers); for(nlist = 0; nlist < NR_LIST; nlist++) { found = locked = dirty = used = lastused = protected = 0; @@ -1515,7 +1517,7 @@ hash_table = (struct buffer_head **)vmalloc(NR_HASH*sizeof(struct buffer_head *)); if (!hash_table) panic("Failed to allocate buffer hash table\n"); - memset(hash_table,0,NR_HASH*sizeof(struct buffer_head *)); + memset(hash_table, 0, NR_HASH*sizeof(struct buffer_head *)); lru_list[BUF_CLEAN] = 0; grow_buffers(GFP_KERNEL, BLOCK_SIZE); @@ -1577,7 +1579,7 @@ allow_interrupts(); bh = lru_list[nlist]; - if(bh) + if (bh) for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) { /* We may have stalled while waiting for I/O to complete. */ if(bh->b_list != nlist) goto repeat; @@ -1681,7 +1683,7 @@ /* * We have a bare-bones task_struct, and really should fill * in a few more things so "top" and /proc/2/{exe,root,cwd} - * display semi-sane things. Not real crucial though... + * display semi-sane things. Not real crucial though... */ current->session = 1; @@ -1748,15 +1750,14 @@ ndirty++; bh->b_flushtime = 0; if (major == LOOP_MAJOR) { - ll_rw_block(wrta_cmd,1, &bh); + ll_rw_block(wrta_cmd, 1, &bh); wrta_cmd = WRITEA; if (buffer_dirty(bh)) --ndirty; - } - else - ll_rw_block(WRITE, 1, &bh); + } else + ll_rw_block(WRITE, 1, &bh); #ifdef DEBUG - if(nlist != BUF_DIRTY) ncount++; + if (nlist != BUF_DIRTY) ncount++; #endif bh->b_count--; next->b_count--; diff -urN linux-2.0.39/fs/exec.c linux-2.0.40/fs/exec.c --- linux-2.0.39/fs/exec.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/fs/exec.c 2004-02-07 23:13:01.000000000 -0800 @@ -497,8 +497,9 @@ int ch; char * name; + bprm->dumpable = 0; if (current->euid == current->uid && current->egid == current->gid) - current->dumpable = 1; + bprm->dumpable = 1; name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -515,9 +516,9 @@ flush_thread(); - if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - permission(bprm->inode,MAY_READ)) - current->dumpable = 0; + if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || + permission(bprm->inode, MAY_READ)) + bprm->dumpable = 0; flush_old_signals(current->sig); flush_old_files(current->files); @@ -707,6 +708,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs) { struct linux_binprm bprm; + int was_dumpable; int retval; int i; @@ -726,6 +728,9 @@ if ((bprm.envc = count(envp, sizeof(char *), bprm.p)) < 0) return bprm.envc; + was_dumpable = current->dumpable; + current->dumpable = 0; + retval = prepare_binprm(&bprm); if(retval>=0) { @@ -739,14 +744,20 @@ if(retval>=0) retval = search_binary_handler(&bprm,regs); - if(retval>=0) + + if(retval>=0) { /* execve success */ + current->dumpable = bprm.dumpable; return retval; + } /* Something went wrong, return the inode and free the argument pages*/ if(!bprm.dont_iput) iput(bprm.inode); for (i=0 ; idumpable = was_dumpable; + return(retval); } diff -urN linux-2.0.39/fs/ext2/dir.c linux-2.0.40/fs/ext2/dir.c --- linux-2.0.39/fs/ext2/dir.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/fs/ext2/dir.c 2004-02-07 23:13:01.000000000 -0800 @@ -145,7 +145,7 @@ brelse (bha[i]); } } - + revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid @@ -153,7 +153,7 @@ * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ext2_dir_entry *) + de = (struct ext2_dir_entry_2 *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this @@ -170,8 +170,8 @@ | offset; filp->f_version = inode->i_version; } - - while (!error && filp->f_pos < inode->i_size + + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext2_dir_entry_2 *) (bh->b_data + offset); if (!ext2_check_dir_entry ("ext2_readdir", inode, de, diff -urN linux-2.0.39/fs/ext2/ialloc.c linux-2.0.40/fs/ext2/ialloc.c --- linux-2.0.39/fs/ext2/ialloc.c 1998-11-15 10:33:12.000000000 -0800 +++ linux-2.0.40/fs/ext2/ialloc.c 2004-02-07 23:13:01.000000000 -0800 @@ -299,7 +299,7 @@ { struct super_block * sb; struct buffer_head * bh; - struct buffer_head * bh2; + struct buffer_head * bh2, * tmpbh2; int i, j, avefreei; struct inode * inode; int bitmap_nr; @@ -327,9 +327,10 @@ /* I am not yet convinced that this next bit is necessary. i = dir->u.ext2_i.i_block_group; for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { - tmp = get_group_desc (sb, i, &bh2); + tmp = get_group_desc (sb, i, &tmpbh2); if ((tmp->bg_used_dirs_count << 8) < tmp->bg_free_inodes_count) { + bh2 = tmpbh2; gdp = tmp; break; } @@ -339,13 +340,14 @@ */ if (!gdp) { for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { - tmp = get_group_desc (sb, j, &bh2); + tmp = get_group_desc (sb, j, &tmpbh2); if (tmp->bg_free_inodes_count && tmp->bg_free_inodes_count >= avefreei) { if (!gdp || (tmp->bg_free_blocks_count > gdp->bg_free_blocks_count)) { i = j; + bh2 = tmpbh2; gdp = tmp; } } @@ -358,11 +360,11 @@ * Try to place the inode in its parent directory */ i = dir->u.ext2_i.i_block_group; - tmp = get_group_desc (sb, i, &bh2); - if (tmp->bg_free_inodes_count) + tmp = get_group_desc (sb, i, &tmpbh2); + if (tmp->bg_free_inodes_count) { + bh2 = tmpbh2; gdp = tmp; - else - { + } else { /* * Use a quadratic hash to find a group with a * free inode @@ -371,8 +373,9 @@ i += j; if (i >= sb->u.ext2_sb.s_groups_count) i -= sb->u.ext2_sb.s_groups_count; - tmp = get_group_desc (sb, i, &bh2); + tmp = get_group_desc (sb, i, &tmpbh2); if (tmp->bg_free_inodes_count) { + bh2 = tmpbh2; gdp = tmp; break; } @@ -386,8 +389,9 @@ for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) { if (++i >= sb->u.ext2_sb.s_groups_count) i = 0; - tmp = get_group_desc (sb, i, &bh2); + tmp = get_group_desc (sb, i, &tmpbh2); if (tmp->bg_free_inodes_count) { + bh2 = tmpbh2; gdp = tmp; break; } diff -urN linux-2.0.39/fs/ext2/super.c linux-2.0.40/fs/ext2/super.c --- linux-2.0.39/fs/ext2/super.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/fs/ext2/super.c 2004-02-07 23:13:01.000000000 -0800 @@ -711,7 +711,6 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) { unsigned long overhead; - unsigned long overhead_per_group; struct statfs tmp; int ngroups, i; diff -urN linux-2.0.39/fs/ext2/truncate.c linux-2.0.40/fs/ext2/truncate.c --- linux-2.0.39/fs/ext2/truncate.c 1995-12-10 20:56:35.000000000 -0800 +++ linux-2.0.40/fs/ext2/truncate.c 2004-02-07 23:13:01.000000000 -0800 @@ -93,9 +93,9 @@ if (free_count == 0) { block_to_free = tmp; free_count++; - } else if (free_count > 0 && block_to_free == tmp - free_count) + } else if (free_count > 0 && block_to_free == tmp - free_count) { free_count++; - else { + } else { ext2_free_blocks (inode, block_to_free, free_count); block_to_free = tmp; free_count = 1; @@ -160,9 +160,9 @@ if (free_count == 0) { block_to_free = tmp; free_count++; - } else if (free_count > 0 && block_to_free == tmp - free_count) + } else if (free_count > 0 && block_to_free == tmp - free_count) { free_count++; - else { + } else { ext2_free_blocks (inode, block_to_free, free_count); block_to_free = tmp; free_count = 1; @@ -177,16 +177,17 @@ for (i = 0; i < addr_per_block; i++) if (*(ind++)) break; - if (i >= addr_per_block) - if (ind_bh->b_count != 1) + if (i >= addr_per_block) { + if (ind_bh->b_count != 1) { retry = 1; - else { + } else { tmp = *p; *p = 0; inode->i_blocks -= blocks; inode->i_dirt = 1; ext2_free_blocks (inode, tmp, 1); } + } if (IS_SYNC(inode) && buffer_dirty(ind_bh)) { ll_rw_block (WRITE, 1, &ind_bh); wait_on_buffer (ind_bh); @@ -238,9 +239,9 @@ if (*(dind++)) break; if (i >= addr_per_block) - if (dind_bh->b_count != 1) + if (dind_bh->b_count != 1) { retry = 1; - else { + } else { tmp = *p; *p = 0; inode->i_blocks -= blocks; @@ -296,16 +297,17 @@ for (i = 0; i < addr_per_block; i++) if (*(tind++)) break; - if (i >= addr_per_block) - if (tind_bh->b_count != 1) + if (i >= addr_per_block) { + if (tind_bh->b_count != 1) { retry = 1; - else { + } else { tmp = *p; *p = 0; inode->i_blocks -= blocks; inode->i_dirt = 1; ext2_free_blocks (inode, tmp, 1); } + } if (IS_SYNC(inode) && buffer_dirty(tind_bh)) { ll_rw_block (WRITE, 1, &tind_bh); wait_on_buffer (tind_bh); @@ -313,7 +315,7 @@ brelse (tind_bh); return retry; } - + void ext2_truncate (struct inode * inode) { int retry; diff -urN linux-2.0.39/fs/isofs/inode.c linux-2.0.40/fs/isofs/inode.c --- linux-2.0.39/fs/isofs/inode.c 1999-06-13 10:21:03.000000000 -0700 +++ linux-2.0.40/fs/isofs/inode.c 2004-02-07 23:13:01.000000000 -0800 @@ -241,18 +241,18 @@ CDROMMULTISESSION, (unsigned long) &ms_info); set_fs(old_fs); -#if 0 +#if 0 printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); if (i==0) { printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no"); printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba); } -#endif 0 +#endif /* 0 */ if (i==0) #if WE_OBEY_THE_WRITTEN_STANDARDS if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ -#endif WE_OBEY_THE_WRITTEN_STANDARDS +#endif /* WE_OBEY_THE_WRITTEN_STANDARDS */ vol_desc_start=ms_info.addr.lba; } return vol_desc_start; @@ -302,7 +302,7 @@ printk("gid = %d\n", opt.gid); printk("uid = %d\n", opt.uid); #endif - + blocksize_bits = 0; { int i = opt.blocksize; @@ -318,7 +318,7 @@ s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ vol_desc_start = isofs_get_last_session(dev); - + for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) { @@ -405,7 +405,7 @@ printk("Multi-volume disks not supported.\n"); goto out; } -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); @@ -416,14 +416,14 @@ printk("Multi-volume disks not supported.\n"); goto out; } -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); } - + s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */ - + /* RDE: convert log zone size to bit shift */ orig_zonesize = s -> u.isofs_sb.s_log_zone_size; @@ -438,16 +438,16 @@ } s->s_magic = ISOFS_SUPER_MAGIC; - + /* The CDROM is read-only, has no nodes (devices) on it, and since all of the files appear to be owned by root, we really do not want to allow suid. (suid or devices will not show up unless we have Rock Ridge extensions) */ - + s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; - + brelse(bh); - + /* RDE: data zone now byte offset! */ s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) + @@ -564,7 +564,7 @@ #else check_disk_change(s->s_dev); return s; -#endif +#endif out: /* Kick out for various error conditions */ brelse(bh); @@ -657,7 +657,7 @@ #endif nextino = ino->u.isofs_i.i_next_section_ino; iput(ino); - + if(++i > MAX_FILE_SECTIONS) { printk("isofs_bmap: More than %d file sections ?!?, aborting...\n", MAX_FILE_SECTIONS); @@ -880,14 +880,14 @@ printk("Get inode %d: %d %d: %d\n",inode->i_ino, block, ((int)pnt) & 0x3ff, inode->i_size); #endif - + inode->i_mtime = inode->i_atime = inode->i_ctime = iso_date(raw_inode->date, high_sierra); inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) + isonum_711 (raw_inode->ext_attr_length)) << inode -> i_sb -> u.isofs_sb.s_log_zone_size; - + inode->u.isofs_i.i_backlink = 0xffffffff; /* Will be used for previous directory */ switch (inode->i_sb->u.isofs_sb.s_conversion){ case 'a': @@ -912,12 +912,12 @@ /* hmm..if we want uid or gid set, override the rock ridge setting */ test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid); } - + #ifdef DEBUG printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent); #endif brelse(bh); - + inode->i_op = NULL; /* get the volume sequence number */ @@ -940,7 +940,7 @@ (volume_seq_no != 0) && (volume_seq_no != 1)) { printk("Multi volume CD somehow got mounted.\n"); } else -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ { if (S_ISREG(inode->i_mode)) inode->i_op = &isofs_file_inode_operations; diff -urN linux-2.0.39/fs/open.c linux-2.0.40/fs/open.c --- linux-2.0.39/fs/open.c 1999-06-13 10:21:03.000000000 -0700 +++ linux-2.0.40/fs/open.c 2004-02-07 23:13:01.000000000 -0800 @@ -27,17 +27,17 @@ struct inode * inode; int error; - error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); + error = verify_area(VERIFY_WRITE, buf, sizeof (struct statfs)); if (error) return error; - error = namei(path,&inode); + error = namei(path, &inode); if (error) return error; if (!inode->i_sb->s_op->statfs) { iput(inode); return -ENOSYS; } - inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); + inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof (struct statfs)); iput(inode); return 0; } @@ -48,7 +48,7 @@ struct file * file; int error; - error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); + error = verify_area(VERIFY_WRITE, buf, sizeof (struct statfs)); if (error) return error; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) @@ -59,7 +59,7 @@ return -ENODEV; if (!inode->i_sb->s_op->statfs) return -ENOSYS; - inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); + inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof (struct statfs)); return 0; } @@ -70,8 +70,8 @@ /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */ if ((off_t) length < 0) - return -EINVAL; - + return -EINVAL; + down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; @@ -91,7 +91,7 @@ struct inode * inode; int error; - error = namei(path,&inode); + error = namei(path, &inode); if (error) return error; @@ -99,7 +99,7 @@ if (S_ISDIR(inode->i_mode)) goto out; - error = permission(inode,MAY_WRITE); + error = permission(inode, MAY_WRITE); if (error) goto out; @@ -170,7 +170,7 @@ struct inode * inode; struct iattr newattrs; - error = namei(filename,&inode); + error = namei(filename, &inode); if (error) return error; if (IS_RDONLY(inode)) { @@ -180,7 +180,7 @@ /* Don't worry, the checks are done in inode_change_ok() */ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { - error = verify_area(VERIFY_READ, times, sizeof(*times)); + error = verify_area(VERIFY_READ, times, sizeof (*times)); if (error) { iput(inode); return error; @@ -190,7 +190,7 @@ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && - (error = permission(inode,MAY_WRITE)) != 0) { + (error = permission(inode, MAY_WRITE)) != 0) { iput(inode); return error; } @@ -212,7 +212,7 @@ struct inode * inode; struct iattr newattrs; - error = namei(filename,&inode); + error = namei(filename, &inode); if (error) return error; if (IS_RDONLY(inode)) { @@ -223,17 +223,18 @@ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (utimes) { struct timeval times[2]; - error = verify_area(VERIFY_READ, utimes, sizeof(times)); + error = verify_area(VERIFY_READ, utimes, sizeof (times)); if (error) { iput(inode); return error; } - memcpy_fromfs(×, utimes, sizeof(times)); + memcpy_fromfs(×, utimes, sizeof (times)); newattrs.ia_atime = times[0].tv_sec; newattrs.ia_mtime = times[1].tv_sec; newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { - if ((error = permission(inode,MAY_WRITE)) != 0) { + if (current->fsuid != inode->i_uid && + (error = permission(inode, MAY_WRITE)) != 0) { iput(inode); return error; } @@ -259,7 +260,7 @@ old_fsgid = current->fsgid; current->fsuid = current->uid; current->fsgid = current->gid; - res = namei(filename,&inode); + res = namei(filename, &inode); if (!res) { res = permission(inode, mode); iput(inode); @@ -274,14 +275,14 @@ struct inode * inode; int error; - error = namei(filename,&inode); + error = namei(filename, &inode); if (error) return error; if (!S_ISDIR(inode->i_mode)) { iput(inode); return -ENOTDIR; } - if ((error = permission(inode,MAY_EXEC)) != 0) { + if ((error = permission(inode, MAY_EXEC)) != 0) { iput(inode); return error; } @@ -302,7 +303,7 @@ return -ENOENT; if (!S_ISDIR(inode->i_mode)) return -ENOTDIR; - if ((error = permission(inode,MAY_EXEC)) != 0) + if ((error = permission(inode, MAY_EXEC)) != 0) return error; iput(current->fs->pwd); current->fs->pwd = inode; @@ -315,7 +316,7 @@ struct inode * inode; int error; - error = namei(filename,&inode); + error = namei(filename, &inode); if (error) return error; if (!S_ISDIR(inode->i_mode)) { @@ -359,7 +360,7 @@ int error; struct iattr newattrs; - error = namei(filename,&inode); + error = namei(filename, &inode); if (error) return error; if (IS_RDONLY(inode)) { @@ -439,7 +440,7 @@ int error; struct iattr newattrs; - error = lnamei(filename,&inode); + error = lnamei(filename, &inode); if (error) return error; if (IS_RDONLY(inode)) { @@ -503,22 +504,22 @@ * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ -static int do_open(const char * filename,int flags,int mode, int fd) +static int do_open(const char * filename, int flags, int mode, int fd) { struct inode * inode; struct file * f; - int flag,error; + int flag, error; f = get_empty_filp(); if (!f) return -ENFILE; f->f_flags = flag = flags; - f->f_mode = (flag+1) & O_ACCMODE; + f->f_mode = (flag + 1) & O_ACCMODE; if (f->f_mode) flag++; if (flag & O_TRUNC) flag |= 2; - error = open_namei(filename,flag,mode,&inode,NULL); + error = open_namei(filename, flag, mode, &inode, NULL); if (error) goto cleanup_file; if (f->f_mode & FMODE_WRITE) { @@ -534,7 +535,7 @@ if (inode->i_op) f->f_op = inode->i_op->default_file_ops; if (f->f_op && f->f_op->open) { - error = f->f_op->open(inode,f); + error = f->f_op->open(inode, f); if (error) goto cleanup_all; } @@ -575,7 +576,7 @@ FD_CLR(fd, ¤t->files->open_fds); } -asmlinkage int sys_open(const char * filename,int flags,int mode) +asmlinkage int sys_open(const char * filename, int flags, int mode) { char * tmp; int fd, error; @@ -585,7 +586,7 @@ return fd; error = getname(filename, &tmp); if (!error) { - error = do_open(tmp,flags,mode, fd); + error = do_open(tmp, flags, mode, fd); putname(tmp); if (!error) return fd; @@ -610,7 +611,7 @@ void __fput(struct file *filp, struct inode *inode) { if (filp->f_op && filp->f_op->release) - filp->f_op->release(inode,filp); + filp->f_op->release(inode, filp); filp->f_inode = NULL; if (filp->f_mode & FMODE_WRITE) put_write_access(inode); diff -urN linux-2.0.39/fs/pipe.c linux-2.0.40/fs/pipe.c --- linux-2.0.39/fs/pipe.c 1998-11-15 10:33:14.000000000 -0800 +++ linux-2.0.40/fs/pipe.c 2004-02-07 23:13:01.000000000 -0800 @@ -35,11 +35,13 @@ if (filp->f_flags & O_NONBLOCK) { if (PIPE_LOCK(*inode)) return -EAGAIN; - if (PIPE_EMPTY(*inode)) - if (PIPE_WRITERS(*inode)) + if (PIPE_EMPTY(*inode)) { + if (PIPE_WRITERS(*inode)) { return -EAGAIN; - else + } else { return 0; + } + } } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) { if (PIPE_EMPTY(*inode)) { if (!PIPE_WRITERS(*inode)) diff -urN linux-2.0.39/fs/proc/array.c linux-2.0.40/fs/proc/array.c --- linux-2.0.39/fs/proc/array.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/fs/proc/array.c 2004-02-07 23:13:01.000000000 -0800 @@ -14,7 +14,7 @@ * EVERY character on the current page. * * - * Danny ter Haar : added cpuinfo + * Danny ter Haar : added cpuinfo * * * Alessandro Rubini : profile extension. diff -urN linux-2.0.39/fs/proc/mem.c linux-2.0.40/fs/proc/mem.c --- linux-2.0.39/fs/proc/mem.c 1998-11-15 10:33:14.000000000 -0800 +++ linux-2.0.40/fs/proc/mem.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -17,7 +18,7 @@ /* * mem_write isn't really a good idea right now. It needs - * to check a lot more: if the process we try to write to + * to check a lot more: if the process we try to write to * dies in the middle right now, mem_write will overwrite * kernel memory.. This disables it altogether. */ @@ -209,6 +210,7 @@ } } +#ifdef CONFIG_UNSAFE_MMAP /* * This isn't really reliable by any means.. */ @@ -311,6 +313,7 @@ flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end); return 0; } +#endif /* CONFIG_UNSAFE_MMAP */ static struct file_operations proc_mem_operations = { mem_lseek, @@ -319,7 +322,11 @@ NULL, /* mem_readdir */ NULL, /* mem_select */ NULL, /* mem_ioctl */ +#ifdef CONFIG_UNSAFE_MMAP mem_mmap, /* mmap */ +#else + NULL, /* mmap */ +#endif /* CONFIG_UNSAFE_MMAP */ NULL, /* no special open code */ NULL, /* no special release code */ NULL /* can't fsync */ diff -urN linux-2.0.39/include/asm-i386/bugs.h linux-2.0.40/include/asm-i386/bugs.h --- linux-2.0.39/include/asm-i386/bugs.h 1999-06-13 10:21:03.000000000 -0700 +++ linux-2.0.40/include/asm-i386/bugs.h 2004-02-07 23:13:01.000000000 -0800 @@ -228,8 +228,7 @@ if (d > 20*K6_BUG_LOOP) { printk("system stability may be impaired when more than 32 MB are used.\n"); - } - else + } else printk("probably OK (after B9730xxxx).\n"); } } @@ -346,7 +345,7 @@ int eax, dummy; /* get processor info */ - + cpuid(1, &eax, &dummy, &dummy, &x86_capability); diff -urN linux-2.0.39/include/asm-i386/math_emu.h linux-2.0.40/include/asm-i386/math_emu.h --- linux-2.0.39/include/asm-i386/math_emu.h 1997-11-07 09:11:42.000000000 -0800 +++ linux-2.0.40/include/asm-i386/math_emu.h 2004-02-07 23:13:01.000000000 -0800 @@ -3,17 +3,8 @@ #include -void restore_i387_soft(struct _fpstate *buf); -struct _fpstate * save_i387_soft(struct _fpstate * buf); - -struct fpu_reg { - char sign; - char tag; - long exp; - unsigned sigl; - unsigned sigh; -}; - +int restore_i387_soft(void *s387, struct _fpstate *buf); +int save_i387_soft(void *s387, struct _fpstate * buf); /* This structure matches the layout of the data saved to the stack following a device-not-present interrupt, part of it saved @@ -45,13 +36,4 @@ long ___vm86_gs; }; -/* Interface for converting data between the emulator format - * and the hardware format. Used for core dumping and for - * ptrace(2) */ -void hardreg_to_softreg(const char hardreg[10], - struct fpu_reg *soft_reg); - -void softreg_to_hardreg(const struct fpu_reg *rp, char d[10], - long int control_word); - #endif diff -urN linux-2.0.39/include/asm-i386/mtrr.h linux-2.0.40/include/asm-i386/mtrr.h --- linux-2.0.39/include/asm-i386/mtrr.h 1998-11-15 10:33:15.000000000 -0800 +++ linux-2.0.40/include/asm-i386/mtrr.h 2004-02-07 23:13:01.000000000 -0800 @@ -52,6 +52,8 @@ #ifdef __KERNEL__ +#include + #ifdef CONFIG_MTRR extern void check_mtrr_config(void); diff -urN linux-2.0.39/include/asm-i386/page.h linux-2.0.40/include/asm-i386/page.h --- linux-2.0.39/include/asm-i386/page.h 1999-06-13 10:21:03.000000000 -0700 +++ linux-2.0.40/include/asm-i386/page.h 2004-02-07 23:13:01.000000000 -0800 @@ -52,6 +52,8 @@ #endif #endif /* !__ASSEMBLY__ */ +#include + /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) diff -urN linux-2.0.39/include/asm-i386/processor.h linux-2.0.40/include/asm-i386/processor.h --- linux-2.0.39/include/asm-i386/processor.h 1999-06-13 10:21:03.000000000 -0700 +++ linux-2.0.40/include/asm-i386/processor.h 2004-02-07 23:13:01.000000000 -0800 @@ -114,9 +114,8 @@ long fcs; long foo; long fos; - long top; - struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */ - unsigned char lookahead; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ + unsigned char ftop, changed, lookahead, no_update, rm, alimit; struct info *info; unsigned long entry_eip; }; diff -urN linux-2.0.39/include/asm-m68k/zorro.h linux-2.0.40/include/asm-m68k/zorro.h --- linux-2.0.39/include/asm-m68k/zorro.h 1996-05-19 21:54:29.000000000 -0700 +++ linux-2.0.40/include/asm-m68k/zorro.h 2004-02-07 23:13:01.000000000 -0800 @@ -385,7 +385,7 @@ #ifdef CONFIG_ZORRO extern void zorro_identify(void); extern int zorro_get_list(char *buffer); -#endif CONFIG_ZORRO +#endif /* CONFIG_ZORRO */ #endif /* __ASSEMBLY__ */ diff -urN linux-2.0.39/include/asm-sparc/bitops.h linux-2.0.40/include/asm-sparc/bitops.h --- linux-2.0.39/include/asm-sparc/bitops.h 1996-04-21 02:30:33.000000000 -0700 +++ linux-2.0.40/include/asm-sparc/bitops.h 2004-02-07 23:13:01.000000000 -0800 @@ -31,9 +31,10 @@ extern __inline__ unsigned long set_bit(unsigned long nr, SMPVOL void *addr) { - int mask, flags; + int mask; unsigned long *ADDR = (unsigned long *) addr; unsigned long oldbit; + unsigned long flags; ADDR += nr >> 5; mask = 1 << (nr & 31); @@ -46,9 +47,10 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, SMPVOL void *addr) { - int mask, flags; + int mask; unsigned long *ADDR = (unsigned long *) addr; unsigned long oldbit; + unsigned long flags; ADDR += nr >> 5; mask = 1 << (nr & 31); @@ -61,9 +63,10 @@ extern __inline__ unsigned long change_bit(unsigned long nr, SMPVOL void *addr) { - int mask, flags; + int mask; unsigned long *ADDR = (unsigned long *) addr; unsigned long oldbit; + unsigned long flags; ADDR += nr >> 5; mask = 1 << (nr & 31); @@ -144,8 +147,9 @@ extern __inline__ int ext2_set_bit(int nr,void * addr) { - int mask, retval, flags; + int mask, retval; unsigned char *ADDR = (unsigned char *) addr; + unsigned long flags; ADDR += nr >> 3; mask = 1 << (nr & 0x07); @@ -158,8 +162,9 @@ extern __inline__ int ext2_clear_bit(int nr, void * addr) { - int mask, retval, flags; + int mask, retval; unsigned char *ADDR = (unsigned char *) addr; + unsigned long flags; ADDR += nr >> 3; mask = 1 << (nr & 0x07); diff -urN linux-2.0.39/include/asm-sparc/head.h linux-2.0.40/include/asm-sparc/head.h --- linux-2.0.39/include/asm-sparc/head.h 1996-05-06 02:26:16.000000000 -0700 +++ linux-2.0.40/include/asm-sparc/head.h 2004-02-07 23:13:01.000000000 -0800 @@ -99,4 +99,4 @@ #define WINDOW_FILL \ rd %psr, %l0; rd %wim, %l3; b fill_window_entry; andcc %l0, PSR_PS, %g0; -#endif __SPARC_HEAD_H +#endif /* __SPARC_HEAD_H */ diff -urN linux-2.0.39/include/linux/binfmts.h linux-2.0.40/include/linux/binfmts.h --- linux-2.0.39/include/linux/binfmts.h 1997-10-15 14:56:43.000000000 -0700 +++ linux-2.0.40/include/linux/binfmts.h 2004-02-07 23:13:01.000000000 -0800 @@ -24,6 +24,7 @@ char * filename; /* Name of binary */ unsigned long loader, exec; int dont_iput; /* binfmt handler has put inode */ + int dumpable; }; /* diff -urN linux-2.0.39/include/linux/blk.h linux-2.0.40/include/linux/blk.h --- linux-2.0.39/include/linux/blk.h 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/include/linux/blk.h 2004-02-07 23:13:01.000000000 -0800 @@ -30,63 +30,63 @@ */ #if defined(IDE_DRIVER) || defined(MD_DRIVER) #define SECTOR_MASK ((BLOCK_SIZE >> 9) - 1) -#else +#else /* defined(IDE_DRIVER) || defined(MD_DRIVER) */ #define SECTOR_MASK (blksize_size[MAJOR_NR] && \ blksize_size[MAJOR_NR][MINOR(CURRENT->rq_dev)] ? \ ((blksize_size[MAJOR_NR][MINOR(CURRENT->rq_dev)] >> 9) - 1) : \ ((BLOCK_SIZE >> 9) - 1)) -#endif /* IDE_DRIVER */ +#endif /* !(defined(IDE_DRIVER) || defined(MD_DRIVER)) */ #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0) #ifdef CONFIG_CDU31A extern int cdu31a_init(void); -#endif CONFIG_CDU31A +#endif /* CONFIG_CDU31A */ #ifdef CONFIG_MCD extern int mcd_init(void); -#endif CONFIG_MCD +#endif /* CONFIG_MCD */ #ifdef CONFIG_MCDX extern int mcdx_init(void); -#endif CONFIG_MCDX +#endif /* CONFIG_MCDX */ #ifdef CONFIG_SBPCD extern int sbpcd_init(void); -#endif CONFIG_SBPCD +#endif /* CONFIG_SBPCD */ #ifdef CONFIG_AZTCD extern int aztcd_init(void); -#endif CONFIG_AZTCD +#endif /* CONFIG_AZTCD */ #ifdef CONFIG_CDU535 extern int sony535_init(void); -#endif CONFIG_CDU535 +#endif /* CONFIG_CDU535 */ #ifdef CONFIG_GSCD extern int gscd_init(void); -#endif CONFIG_GSCD +#endif /* CONFIG_GSCD */ #ifdef CONFIG_CM206 extern int cm206_init(void); -#endif CONFIG_CM206 +#endif /* CONFIG_CM206 */ #ifdef CONFIG_OPTCD extern int optcd_init(void); -#endif CONFIG_OPTCD +#endif /* CONFIG_OPTCD */ #ifdef CONFIG_SJCD extern int sjcd_init(void); -#endif CONFIG_SJCD +#endif /* CONFIG_SJCD */ #ifdef CONFIG_CDI_INIT extern int cdi_init(void); -#endif CONFIG_CDI_INIT +#endif /* CONFIG_CDI_INIT */ #ifdef CONFIG_BLK_DEV_HD extern int hd_init(void); -#endif +#endif /* CONFIG_BLK_DEV_HD */ #ifdef CONFIG_BLK_DEV_IDE extern int ide_init(void); -#endif +#endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_BLK_DEV_XD extern int xd_init(void); -#endif +#endif /* CONFIG_BLK_DEV_XD */ #ifdef CONFIG_BLK_DEV_LOOP extern int loop_init(void); -#endif +#endif /* CONFIG_BLK_DEV_LOOP */ #ifdef CONFIG_BLK_DEV_MD extern int md_init(void); -#endif CONFIG_BLK_DEV_MD +#endif /* CONFIG_BLK_DEV_MD */ extern void set_device_ro(kdev_t dev,int flag); void add_blkdev_randomness(int major); @@ -106,7 +106,7 @@ extern int mount_initrd; /* zero if initrd should not be mounted */ void initrd_init(void); -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ #define RO_IOCTLS(dev,where) \ case BLKROSET: { int __err; if (!suser()) return -EACCES; \ @@ -114,7 +114,7 @@ if (!__err) set_device_ro((dev),get_fs_long((long *) (where))); return __err; } \ case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \ if (!__err) put_fs_long(0!=is_read_only(dev),(long *) (where)); return __err; } - + #if defined(MAJOR_NR) || defined(IDE_DRIVER) /* @@ -133,7 +133,7 @@ #define DEVICE_NAME "ramdisk" #define DEVICE_REQUEST rd_request #define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) +#define DEVICE_ON(device) #define DEVICE_OFF(device) #define DEVICE_NO_RANDOM @@ -163,7 +163,7 @@ #elif (MAJOR_NR == SCSI_DISK_MAJOR) #define DEVICE_NAME "scsidisk" -#define DEVICE_INTR do_sd +#define DEVICE_INTR do_sd #define TIMEOUT_VALUE (2*HZ) #define DEVICE_REQUEST do_sd_request #define DEVICE_NR(device) (MINOR(device) >> 4) @@ -182,7 +182,7 @@ #elif (MAJOR_NR == SCSI_TAPE_MAJOR) #define DEVICE_NAME "scsitape" -#define DEVICE_INTR do_st +#define DEVICE_INTR do_st #define DEVICE_NR(device) (MINOR(device) & 0x7f) #define DEVICE_ON(device) #define DEVICE_OFF(device) @@ -327,13 +327,13 @@ #ifndef CURRENT #define CURRENT (blk_dev[MAJOR_NR].current_request) -#endif +#endif /* !CURRENT */ #define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev) #ifdef DEVICE_INTR static void (*DEVICE_INTR)(void) = NULL; -#endif +#endif /* DEVICE_INTR */ #ifdef DEVICE_TIMEOUT #define SET_TIMER \ @@ -349,19 +349,19 @@ else \ CLEAR_TIMER; -#else +#else /* DEVICE_TIMEOUT */ #define SET_INTR(x) (DEVICE_INTR = (x)) -#endif /* DEVICE_TIMEOUT */ +#endif /* !DEVICE_TIMEOUT */ static void (DEVICE_REQUEST)(void); - + #ifdef DEVICE_INTR #define CLEAR_INTR SET_INTR(NULL) -#else +#else /* DEVICE_INTR */ #define CLEAR_INTR -#endif +#endif /* !DEVICE_INTR */ #define INIT_REQUEST \ if (!CURRENT) {\ @@ -380,19 +380,19 @@ /* end_request() - SCSI devices have their own version */ /* - IDE drivers have their own copy too */ -#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR) +#if !SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR) #if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); -#else +#else /* defined(IDE_DRIVER) && !defined(_IDE_C) */ #ifdef IDE_DRIVER void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) { struct request *req = hwgroup->rq; -#else +#else /* IDE_DRIVER */ static void end_request(int uptodate) { struct request *req = CURRENT; -#endif /* IDE_DRIVER */ +#endif /* !IDE_DRIVER */ struct buffer_head * bh; int nsect; @@ -412,24 +412,21 @@ if ((bh = req->bh) != NULL) { req->bh = bh->b_reqnext; bh->b_reqnext = NULL; - - /* - * This is our 'MD IO has finished' event handler. - * note that b_state should be cached in a register - * anyways, so the overhead if this checking is almost - * zero. But anyways .. we never get OO for free :) - */ - if (test_bit(BH_MD, &bh->b_state)) { - struct md_personality * pers=(struct md_personality *)bh->personality; - pers->end_request(bh,uptodate); - } - /* - * the normal (nonmirrored and no RAID5) case: - */ - else { - mark_buffer_uptodate(bh, uptodate); - unlock_buffer(bh); - } + + /* This is our 'MD IO has finished' event handler. + * note that b_state should be cached in a register + * anyways, so the overhead if this checking is almost + * zero. But anyways .. we never get OO for free :) + */ + if (test_bit(BH_MD, &bh->b_state)) { + struct md_personality * pers=(struct md_personality *)bh->personality; + pers->end_request(bh,uptodate); + } else { + /* the normal (nonmirrored and no RAID5) case: + */ + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); + } if ((bh = req->bh) != NULL) { req->current_nr_sectors = bh->b_size >> 9; if (req->nr_sectors < req->current_nr_sectors) { @@ -442,21 +439,21 @@ } #ifndef DEVICE_NO_RANDOM add_blkdev_randomness(MAJOR(req->rq_dev)); -#endif +#endif /* !DEVICE_NO_RANDOM */ #ifdef IDE_DRIVER blk_dev[MAJOR(req->rq_dev)].current_request = req->next; hwgroup->rq = NULL; -#else +#else /* IDE_DRIVER */ DEVICE_OFF(req->rq_dev); CURRENT = req->next; -#endif /* IDE_DRIVER */ +#endif /* !IDE_DRIVER */ if (req->sem != NULL) up(req->sem); req->rq_status = RQ_INACTIVE; wake_up(&wait_for_request); } -#endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */ -#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */ +#endif /* !(defined(IDE_DRIVER) && !defined(_IDE_C)) */ +#endif /* !SCSI_BLK_MAJOR(MAJOR_NR) */ #endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */ #endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */ diff -urN linux-2.0.39/include/linux/cdrom.h linux-2.0.40/include/linux/cdrom.h --- linux-2.0.39/include/linux/cdrom.h 1996-09-20 07:00:36.000000000 -0700 +++ linux-2.0.40/include/linux/cdrom.h 2004-02-07 23:13:01.000000000 -0800 @@ -67,14 +67,14 @@ * CDROM IOCTL structures */ -struct cdrom_blk +struct cdrom_blk { unsigned from; unsigned short len; }; -struct cdrom_msf +struct cdrom_msf { u_char cdmsf_min0; /* start minute */ u_char cdmsf_sec0; /* start second */ @@ -84,7 +84,7 @@ u_char cdmsf_frame1; /* end frame */ }; -struct cdrom_ti +struct cdrom_ti { u_char cdti_trk0; /* start track */ u_char cdti_ind0; /* start index */ @@ -92,7 +92,7 @@ u_char cdti_ind1; /* end index */ }; -struct cdrom_tochdr +struct cdrom_tochdr { u_char cdth_trk0; /* start track */ u_char cdth_trk1; /* end track */ @@ -111,7 +111,7 @@ int lba; }; -struct cdrom_tocentry +struct cdrom_tocentry { u_char cdte_track; u_char cdte_adr :4; @@ -137,7 +137,7 @@ */ #define CDROM_LEADOUT 0xAA -struct cdrom_subchnl +struct cdrom_subchnl { u_char cdsc_format; u_char cdsc_audiostatus; @@ -204,9 +204,9 @@ #ifdef FIVETWELVE #define CDROM_MODE1_SIZE 512 -#else +#else /* FIVETWELVE */ #define CDROM_MODE1_SIZE 2048 -#endif FIVETWELVE +#endif /* !FIVETWELVE */ #define CDROM_MODE2_SIZE 2336 /* @@ -419,7 +419,7 @@ /* * cache parameters */ -struct ccs_cache +struct ccs_cache { u_char _r1 : 2; /* reserved */ u_char page_code : 6; /* page code */ @@ -433,13 +433,13 @@ u_char _r2[8]; }; -#endif _LINUX_CDROM_H +#endif /* _LINUX_CDROM_H */ /*==========================================================================*/ /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end - * of the file. + * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 8 diff -urN linux-2.0.39/include/linux/cm206.h linux-2.0.40/include/linux/cm206.h --- linux-2.0.39/include/linux/cm206.h 1996-05-15 00:06:26.000000000 -0700 +++ linux-2.0.40/include/linux/cm206.h 2004-02-07 23:13:01.000000000 -0800 @@ -137,7 +137,7 @@ #if !defined(CDROM_GET_UPC) #define CDROM_GET_UPC _IO( 'S', 0x11 ) #define CDROMRESET _IO( 'S', 0x12 ) -#endif +#endif /* !defined(CDROM_GET_UPC) */ #ifdef STATISTICS @@ -147,10 +147,10 @@ #ifdef __KERNEL__ #define x(a) st_ ## a #define y enum -#else +#else /* __KERNEL__ */ #define x(a) #a -#define y char * stats_name[] = -#endif +#define y char * stats_name[] = +#endif /* !__KERNEL__ */ y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error), x(crc_error), x(sync_error), x(lost_intr), x(echo), @@ -160,18 +160,18 @@ x(bh), x(open), x(ioctl_multisession), x(attention) #ifdef __KERNEL__ , x(last_entry) -#endif +#endif /* __KERNEL__ */ }; #ifdef __KERNEL__ #define NR_STATS st_last_entry -#else +#else /* __KERNEL__ */ #define NR_STATS (sizeof(stats_name)/sizeof(char*)) -#endif +#endif /* __KERNEL__ */ #undef y #undef x -#endif STATISTICS +#endif /* STATISTICS */ -#endif LINUX_CM206_H +#endif /* LINUX_CM206_H */ diff -urN linux-2.0.39/include/linux/hdlcdrv.h linux-2.0.40/include/linux/hdlcdrv.h --- linux-2.0.39/include/linux/hdlcdrv.h 1998-07-13 13:47:39.000000000 -0700 +++ linux-2.0.40/include/linux/hdlcdrv.h 2004-02-07 23:13:01.000000000 -0800 @@ -9,7 +9,6 @@ #include #include -#include #if LINUX_VERSION_CODE < 0x20119 #include #endif diff -urN linux-2.0.39/include/linux/if_frad.h linux-2.0.40/include/linux/if_frad.h --- linux-2.0.39/include/linux/if_frad.h 1998-06-03 15:17:49.000000000 -0700 +++ linux-2.0.40/include/linux/if_frad.h 2004-02-07 23:13:01.000000000 -0800 @@ -132,13 +132,13 @@ unsigned char control __attribute__((packed)); /* for IP packets, this can be the NLPID */ - unsigned char pad __attribute__((packed)); + unsigned char pad __attribute__((packed)); unsigned char NLPID __attribute__((packed)); unsigned char OUI[3] __attribute__((packed)); unsigned short PID __attribute__((packed)); -#define IP_NLPID pad +#define IP_NLPID pad }; /* see RFC 1490 for the definition of the following */ @@ -190,6 +190,6 @@ int register_frad(const char *name); int unregister_frad(const char *name); -#endif __KERNEL__ +#endif /* __KERNEL__ */ -#endif +#endif /* _FRAD_H_ */ diff -urN linux-2.0.39/include/linux/interrupt.h linux-2.0.40/include/linux/interrupt.h --- linux-2.0.39/include/linux/interrupt.h 1998-11-15 10:33:17.000000000 -0800 +++ linux-2.0.40/include/linux/interrupt.h 2004-02-07 23:13:01.000000000 -0800 @@ -3,7 +3,9 @@ #define _LINUX_INTERRUPT_H #include + #include +#include struct irqaction { void (*handler)(int, void *, struct pt_regs *); @@ -25,7 +27,7 @@ /* Who gets which entry in bh_base. Things which will occur most often should come first - in which case NET should be up the top with SERIAL/TQUEUE! */ - + enum { TIMER_BH = 0, CONSOLE_BH, @@ -33,7 +35,7 @@ DIGI_BH, SERIAL_BH, RISCOM8_BH, - SPECIALIX_BH, + SPECIALIX_BH, BAYCOM_BH, NET_BH, IMMEDIATE_BH, @@ -117,4 +119,4 @@ extern unsigned long probe_irq_on(void); /* returns 0 on failure */ extern int probe_irq_off(unsigned long); /* returns 0 or negative on failure */ -#endif +#endif /* _LINUX_INTERRUPT_H */ diff -urN linux-2.0.39/include/linux/kernel.h linux-2.0.40/include/linux/kernel.h --- linux-2.0.39/include/linux/kernel.h 1997-08-14 10:05:47.000000000 -0700 +++ linux-2.0.40/include/linux/kernel.h 2004-02-07 23:13:01.000000000 -0800 @@ -39,8 +39,12 @@ NORET_TYPE void do_exit(long error_code) ATTRIB_NORET; extern unsigned long simple_strtoul(const char *,char **,unsigned int); -extern int sprintf(char * buf, const char * fmt, ...); -extern int vsprintf(char *buf, const char *, va_list); +extern int sprintf(char *buf, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); +extern int vsprintf(char *buf, const char *, va_list) + __attribute__ ((format (printf, 2, 0))); +extern int _vsnprintf(char *buf, int n, const char *, va_list) + __attribute__ ((format (printf, 3, 0))); extern int session_of_pgrp(int pgrp); diff -urN linux-2.0.39/include/linux/md.h linux-2.0.40/include/linux/md.h --- linux-2.0.39/include/linux/md.h 1998-07-13 13:47:39.000000000 -0700 +++ linux-2.0.40/include/linux/md.h 2004-02-07 23:13:01.000000000 -0800 @@ -3,15 +3,15 @@ Copyright (C) 1994-96 Marc ZYNGIER or - + 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, or (at your option) any later version. - + You should have received a copy of the GNU General Public License (for example /usr/src/linux/COPYING); if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _MD_H @@ -271,5 +271,5 @@ extern void md_wakeup_thread(struct md_thread *thread); extern int md_update_sb (int minor); -#endif __KERNEL__ -#endif _MD_H +#endif /* __KERNEL__ */ +#endif /* _MD_H */ diff -urN linux-2.0.39/include/linux/module.h linux-2.0.40/include/linux/module.h --- linux-2.0.39/include/linux/module.h 1998-06-03 15:17:49.000000000 -0700 +++ linux-2.0.40/include/linux/module.h 2004-02-07 23:13:01.000000000 -0800 @@ -46,7 +46,7 @@ struct internal_symbol { void *addr; const char *name; - }; +}; struct symbol_table { /* received from "insmod" */ int size; /* total, including string table!!! */ @@ -65,7 +65,7 @@ struct symbol_table *symtab; const char *name; int size; /* size of module in pages */ - void* addr; /* address of module */ + void *addr; /* address of module */ int state; void (*cleanup)(void); /* cleanup routine */ }; diff -urN linux-2.0.39/include/linux/optcd.h linux-2.0.40/include/linux/optcd.h --- linux-2.0.39/include/linux/optcd.h 1996-06-04 00:53:46.000000000 -0700 +++ linux-2.0.40/include/linux/optcd.h 2004-02-07 23:13:01.000000000 -0800 @@ -49,4 +49,4 @@ #define N_BUFS 6 -#endif _LINUX_OPTCD_H +#endif /* _LINUX_OPTCD_H */ diff -urN linux-2.0.39/include/linux/sbpcd.h linux-2.0.40/include/linux/sbpcd.h --- linux-2.0.39/include/linux/sbpcd.h 1996-09-02 05:18:26.000000000 -0700 +++ linux-2.0.40/include/linux/sbpcd.h 2004-02-07 23:13:01.000000000 -0800 @@ -117,16 +117,16 @@ /* tray control: eject tray if no disk is in */ #if DISTRIBUTION #define JUKEBOX 0 -#else +#else /* DISTRIBUTION */ #define JUKEBOX 1 -#endif DISTRIBUTION +#endif /* !DISTRIBUTION */ /* tray control: eject tray after last use */ #if DISTRIBUTION #define EJECT 0 -#else +#else /* DISTRIBUTION */ #define EJECT 1 -#endif DISTRIBUTION +#endif /* !DISTRIBUTION */ /* max. number of audio frames to read with one */ /* request (allocates n* 2352 bytes kernel memory!) */ @@ -157,14 +157,13 @@ * nothing to change below here if you are not fully aware what you're doing */ #ifndef _LINUX_SBPCD_H - #define _LINUX_SBPCD_H /*==========================================================================*/ /*==========================================================================*/ /* * driver's own read_ahead, data mode */ -#define SBP_BUFFER_FRAMES 8 +#define SBP_BUFFER_FRAMES 8 #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ #undef FUTURE @@ -838,13 +837,13 @@ /*==========================================================================*/ /*==========================================================================*/ -#endif _LINUX_SBPCD_H +#endif /* _LINUX_SBPCD_H */ /*==========================================================================*/ /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end - * of the file. + * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 8 diff -urN linux-2.0.39/include/linux/sched.h linux-2.0.40/include/linux/sched.h --- linux-2.0.39/include/linux/sched.h 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/include/linux/sched.h 2004-02-07 23:13:01.000000000 -0800 @@ -327,7 +327,7 @@ extern unsigned long volatile jiffies; extern unsigned long itimer_ticks; extern unsigned long itimer_next; -extern struct timeval xtime; +extern volatile struct timeval xtime; extern int need_resched; extern void do_timer(struct pt_regs *); @@ -457,7 +457,7 @@ return; if (p->nr >= __MAX_SELECT_TABLE_ENTRIES) return; - entry = p->entry + p->nr; + entry = p->entry + p->nr; entry->wait_address = wait_address; entry->wait.task = current; entry->wait.next = NULL; diff -urN linux-2.0.39/include/linux/skbuff.h linux-2.0.40/include/linux/skbuff.h --- linux-2.0.39/include/linux/skbuff.h 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/include/linux/skbuff.h 2004-02-07 23:13:01.000000000 -0800 @@ -10,7 +10,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - + #ifndef _LINUX_SKBUFF_H #define _LINUX_SKBUFF_H @@ -20,8 +20,6 @@ #include #include -#define CONFIG_SKB_CHECK 0 - #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ @@ -33,10 +31,10 @@ #define CHECKSUM_HW 1 #define CHECKSUM_UNNECESSARY 2 -struct sk_buff_head +struct sk_buff_head { - struct sk_buff * next; - struct sk_buff * prev; + struct sk_buff *next; + struct sk_buff *prev; __u32 qlen; /* Must be same length as a pointer for using debugging */ #if CONFIG_SKB_CHECK @@ -45,20 +43,20 @@ }; -struct sk_buff +struct sk_buff { - struct sk_buff * next; /* Next buffer in list */ - struct sk_buff * prev; /* Previous buffer in list */ - struct sk_buff_head * list; /* List we are on */ + struct sk_buff *next; /* Next buffer in list */ + struct sk_buff *prev; /* Previous buffer in list */ + struct sk_buff_head *list; /* List we are on */ #if CONFIG_SKB_CHECK int magic_debug_cookie; #endif - struct sk_buff *link3; /* Link for IP protocol level buffer chains */ - struct sock *sk; /* Socket we are owned by */ - unsigned long when; /* used to compute rtt's */ - struct timeval stamp; /* Time we arrived */ - struct device *dev; /* Device we arrived on/are leaving by */ - union + struct sk_buff *link3; /* Link for IP protocol level buffer chains */ + struct sock *sk; /* Socket we are owned by */ + unsigned long when; /* used to compute rtt's */ + struct timeval stamp; /* Time we arrived */ + struct device *dev; /* Device we arrived on/are leaving by */ + union { struct tcphdr *th; struct ethhdr *eth; @@ -68,50 +66,50 @@ /* for passing file handles in a unix domain socket */ void *filp; } h; - - union - { + + union + { /* As yet incomplete physical layer views */ - unsigned char *raw; - struct ethhdr *ethernet; + unsigned char *raw; + struct ethhdr *ethernet; } mac; - - struct iphdr *ip_hdr; /* For IPPROTO_RAW */ - unsigned long len; /* Length of actual data */ - unsigned long csum; /* Checksum */ - __u32 saddr; /* IP source address */ - __u32 daddr; /* IP target address */ - __u32 raddr; /* IP next hop address */ - __u32 seq; /* TCP sequence number */ - __u32 end_seq; /* seq [+ fin] [+ syn] + datalen */ - __u32 ack_seq; /* TCP ack sequence number */ - unsigned char proto_priv[16]; /* Protocol private data */ - volatile char acked, /* Are we acked ? */ - used, /* Are we in use ? */ - free, /* How to free this buffer */ - arp; /* Has IP/ARP resolution finished */ - unsigned char tries, /* Times tried */ - lock, /* Are we locked ? */ - localroute, /* Local routing asserted for this frame */ - pkt_type, /* Packet class */ - pkt_bridged, /* Tracker for bridging */ - ip_summed; /* Driver fed us an IP checksum */ -#define PACKET_HOST 0 /* To us */ -#define PACKET_BROADCAST 1 /* To all */ -#define PACKET_MULTICAST 2 /* To group */ -#define PACKET_OTHERHOST 3 /* To someone else */ - unsigned short users; /* User count - see datagram.c,tcp.c */ - unsigned short protocol; /* Packet protocol from driver. */ - unsigned int truesize; /* Buffer size */ - - atomic_t count; /* reference count */ - struct sk_buff *data_skb; /* Link to the actual data skb */ - unsigned char *head; /* Head of buffer */ - unsigned char *data; /* Data head pointer */ - unsigned char *tail; /* Tail pointer */ - unsigned char *end; /* End pointer */ - void (*destructor)(struct sk_buff *); /* Destruct function */ - __u16 redirport; /* Redirect port */ + + struct iphdr *ip_hdr; /* For IPPROTO_RAW */ + unsigned long len; /* Length of actual data */ + unsigned long csum; /* Checksum */ + __u32 saddr; /* IP source address */ + __u32 daddr; /* IP target address */ + __u32 raddr; /* IP next hop address */ + __u32 seq; /* TCP sequence number */ + __u32 end_seq; /* seq [+ fin] [+ syn] + datalen */ + __u32 ack_seq; /* TCP ack sequence number */ + unsigned char proto_priv[16]; /* Protocol private data */ + volatile char acked, /* Are we acke ? */ + used, /* Are we in use ? */ + free, /* How to free this buffer */ + arp; /* Has IP/ARP resolution finished */ + unsigned char tries, /* Times tried */ + lock, /* Are we locked ? */ + localroute, /* Local routing asserted for this frame */ + pkt_type, /* Packet class */ + pkt_bridged, /* Tracker for bridging */ + ip_summed; /* Driver fed us an IP checksum */ +#define PACKET_HOST 0 /* To us */ +#define PACKET_BROADCAST 1 /* To all */ +#define PACKET_MULTICAST 2 /* To group */ +#define PACKET_OTHERHOST 3 /* To someone else */ + unsigned short users; /* User count - see datagram.c,tcp.c */ + unsigned short protocol; /* Packet protocol from driver. */ + unsigned int truesize; /* Buffer size */ + + atomic_t count; /* reference count */ + struct sk_buff *data_skb; /* Link to the actual data skb */ + unsigned char *head; /* Head of buffer */ + unsigned char *data; /* Data head pointer */ + unsigned char *tail; /* Tail pointer */ + unsigned char *end; /* End pointer */ + void (*destructor)(struct sk_buff *); /* Destruct function */ + __u16 redirport; /* Redirect port */ /* * Keep this at the end then we wont break stuff. @@ -152,11 +150,11 @@ #endif extern void kfree_skb(struct sk_buff *skb, int rw); extern void skb_queue_head_init(struct sk_buff_head *list); -extern void skb_queue_head(struct sk_buff_head *list,struct sk_buff *buf); -extern void skb_queue_tail(struct sk_buff_head *list,struct sk_buff *buf); +extern void skb_queue_head(struct sk_buff_head *list, struct sk_buff *buf); +extern void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *buf); extern struct sk_buff * skb_dequeue(struct sk_buff_head *list); -extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk); -extern void skb_append(struct sk_buff *old,struct sk_buff *newsk); +extern void skb_insert(struct sk_buff *old, struct sk_buff *newsk); +extern void skb_append(struct sk_buff *old, struct sk_buff *newsk); extern void skb_unlink(struct sk_buff *buf); extern __u32 skb_queue_len(struct sk_buff_head *list); extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list); @@ -165,6 +163,7 @@ extern void kfree_skbmem(struct sk_buff *skb); extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); extern struct sk_buff * skb_copy(struct sk_buff *skb, int priority); +extern struct sk_buff * skb_pad(struct sk_buff *skb, int pad); extern void skb_device_lock(struct sk_buff *skb); extern void skb_device_unlock(struct sk_buff *skb); extern void dev_kfree_skb(struct sk_buff *skb, int mode); @@ -175,7 +174,7 @@ extern int skb_headroom(struct sk_buff *skb); extern int skb_tailroom(struct sk_buff *skb); extern void skb_reserve(struct sk_buff *skb, int len); -extern void skb_trim(struct sk_buff *skb, int len); +extern void skb_trim(struct sk_buff *skb, int len); extern __inline__ int skb_queue_empty(struct sk_buff_head *list) { @@ -199,19 +198,34 @@ /* * Return the length of an sk_buff queue */ - + extern __inline__ __u32 skb_queue_len(struct sk_buff_head *list_) { return(list_->qlen); } #if CONFIG_SKB_CHECK -extern int skb_check(struct sk_buff *skb,int,int, char *); -#define IS_SKB(skb) skb_check((skb), 0, __LINE__,__FILE__) -#define IS_SKB_HEAD(skb) skb_check((skb), 1, __LINE__,__FILE__) +extern int skb_check(struct sk_buff *skb, int, int, char *); +#define IS_SKB(skb) skb_check((skb), 0, __LINE__, __FILE__) +#define IS_SKB_HEAD(skb) skb_check((skb), 1, __LINE__, __FILE__) +#define IS_SKB_LINKED(skb) skb_check((skb), 2, __LINE__, __FILE__) +#define IS_SKB_UNLINKED(skb) skb_check((skb), 3, __LINE__, __FILE__) +/* Note: IS_SKB_LINKED will accept skb_heads in addition to linked-in + * data skbs */ + +extern void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk); +extern void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk); +extern struct sk_buff *__skb_dequeue(struct sk_buff_head *list); +extern void __skb_insert(struct sk_buff *newsk, + struct sk_buff * prev, struct sk_buff *next, + struct sk_buff_head * list); +extern void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list); + #else -#define IS_SKB(skb) -#define IS_SKB_HEAD(skb) +#define IS_SKB(skb) +#define IS_SKB_HEAD(skb) +#define IS_SKB_LINKED(skb) +#define IS_SKB_UNLINKED(skb) extern __inline__ void skb_queue_head_init(struct sk_buff_head *list) { @@ -397,7 +411,7 @@ /* * Add data to an sk_buff */ - + extern __inline__ unsigned char *skb_put(struct sk_buff *skb, int len) { unsigned char *tmp=skb->tail; @@ -406,8 +420,8 @@ if(skb->tail>skb->end) { __label__ here; - panic("skput:over: %p:%d", &&here,len); -here: + panic("skput:over: %p:%d", &&here, len); +here:; } return tmp; } @@ -419,8 +433,8 @@ if(skb->datahead) { __label__ here; - panic("skpush:under: %p:%d", &&here,len); -here: + panic("skpush:under: %p:%d", &&here, len); +here:; } return skb->data; } @@ -461,6 +475,14 @@ #endif +static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len) +{ + unsigned int size = skb->len; + if (size >= len) + return skb; + return skb_pad(skb, len-size); +} + extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err); extern int datagram_select(struct sock *sk, int sel_type, select_table *wait); extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); diff -urN linux-2.0.39/include/net/icmp.h linux-2.0.40/include/net/icmp.h --- linux-2.0.39/include/net/icmp.h 1997-12-02 14:20:24.000000000 -0800 +++ linux-2.0.40/include/net/icmp.h 2004-02-07 23:13:01.000000000 -0800 @@ -28,7 +28,8 @@ extern struct icmp_mib icmp_statistics; extern void icmp_send(struct sk_buff *skb_in, int type, int code, - unsigned long info, struct device *dev); + unsigned long info, struct device *dev, + int hdrincl); extern int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, __u32 daddr, unsigned short len, __u32 saddr, diff -urN linux-2.0.39/init/main.c linux-2.0.40/init/main.c --- linux-2.0.39/init/main.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/init/main.c 2004-02-07 23:13:01.000000000 -0800 @@ -35,13 +35,13 @@ #include #ifdef CONFIG_ROOT_NFS #include -#endif +#endif /* CONFIG_ROOT_NFS */ #ifdef CONFIG_MTRR #include -#endif +#endif /* CONFIG_MTRR */ #ifdef CONFIG_APM #include -#endif +#endif /* CONFIG_APM */ #include @@ -53,7 +53,7 @@ */ #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) #error sorry, your GCC is too old. It builds incorrect kernels. -#endif +#endif /* __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) */ extern char _stext, _etext; extern const char *linux_banner; @@ -70,7 +70,7 @@ extern void init_IRQ(void); extern void init_modules(void); extern long console_init(long, long); -extern long kmalloc_init(long,long); +extern long kmalloc_init(long, long); extern void sock_init(void); extern unsigned long pci_init(unsigned long, unsigned long); extern void sysctl_init(void); @@ -116,108 +116,108 @@ extern void reboot_setup(char *str, int *ints); #ifdef CONFIG_CDU31A extern void cdu31a_setup(char *str, int *ints); -#endif CONFIG_CDU31A +#endif /* CONFIG_CDU31A */ #ifdef CONFIG_MCD extern void mcd_setup(char *str, int *ints); -#endif CONFIG_MCD +#endif /* CONFIG_MCD */ #ifdef CONFIG_MCDX extern void mcdx_setup(char *str, int *ints); -#endif CONFIG_MCDX +#endif /* CONFIG_MCDX */ #ifdef CONFIG_SBPCD extern void sbpcd_setup(char *str, int *ints); -#endif CONFIG_SBPCD +#endif /* CONFIG_SBPCD */ #ifdef CONFIG_AZTCD extern void aztcd_setup(char *str, int *ints); -#endif CONFIG_AZTCD +#endif /* CONFIG_AZTCD */ #ifdef CONFIG_CDU535 extern void sonycd535_setup(char *str, int *ints); -#endif CONFIG_CDU535 +#endif /* CONFIG_CDU535 */ #ifdef CONFIG_GSCD extern void gscd_setup(char *str, int *ints); -#endif CONFIG_GSCD +#endif /* CONFIG_GSCD */ #ifdef CONFIG_CM206 extern void cm206_setup(char *str, int *ints); -#endif CONFIG_CM206 +#endif /* CONFIG_CM206 */ #ifdef CONFIG_OPTCD extern void optcd_setup(char *str, int *ints); -#endif CONFIG_OPTCD +#endif /* CONFIG_OPTCD */ #ifdef CONFIG_SJCD extern void sjcd_setup(char *str, int *ints); -#endif CONFIG_SJCD +#endif /* CONFIG_SJCD */ #ifdef CONFIG_ISP16_CDI extern void isp16_setup(char *str, int *ints); -#endif CONFIG_ISP16_CDI +#endif /* CONFIG_ISP16_CDI */ #ifdef CONFIG_BLK_DEV_RAM static void ramdisk_start_setup(char *str, int *ints); static void load_ramdisk(char *str, int *ints); static void prompt_ramdisk(char *str, int *ints); static void ramdisk_size(char *str, int *ints); #ifdef CONFIG_BLK_DEV_INITRD -static void no_initrd(char *s,int *ints); -#endif -#endif CONFIG_BLK_DEV_RAM +static void no_initrd(char *s, int *ints); +#endif /* CONFIG_BLK_DEV_INITRD */ +#endif /* CONFIG_BLK_DEV_RAM */ #ifdef CONFIG_ISDN_DRV_ICN extern void icn_setup(char *str, int *ints); -#endif +#endif /* CONFIG_ISDN_DRV_ICN */ #ifdef CONFIG_ISDN_DRV_HISAX extern void HiSax_setup(char *str, int *ints); -#endif +#endif /* CONFIG_ISDN_DRV_HISAX */ #ifdef CONFIG_ISDN_DRV_PCBIT extern void pcbit_setup(char *str, int *ints); -#endif +#endif /* CONFIG_ISDN_DRV_PCBIT */ #ifdef CONFIG_ATARIMOUSE extern void atari_mouse_setup (char *str, int *ints); -#endif +#endif /* CONFIG_ATARIMOUSE */ #ifdef CONFIG_DMASOUND extern void dmasound_setup (char *str, int *ints); -#endif +#endif /* CONFIG_DMASOUND */ #ifdef CONFIG_ATARI_SCSI extern void atari_scsi_setup (char *str, int *ints); -#endif +#endif /* CONFIG_ATARI_SCSI */ extern void wd33c93_setup (char *str, int *ints); extern void gvp11_setup (char *str, int *ints); #ifdef CONFIG_CYCLADES extern void cy_setup(char *str, int *ints); -#endif +#endif /* CONFIG_CYCLADES */ #ifdef CONFIG_DIGI extern void pcxx_setup(char *str, int *ints); -#endif +#endif /* CONFIG_DIGI */ #ifdef CONFIG_RISCOM8 extern void riscom8_setup(char *str, int *ints); -#endif +#endif /* CONFIG_RISCOM8 */ #ifdef CONFIG_SPECIALIX extern void specialix_setup(char *str, int *ints); -#endif +#endif /* CONFIG_SPECIALIX */ #ifdef CONFIG_BAYCOM extern void baycom_setup(char *str, int *ints); -#endif +#endif /* CONFIG_BAYCOM */ #ifdef CONFIG_PARIDE_PD extern void pd_setup(char *str, int *ints); -#endif +#endif /* CONFIG_PARIDE_PD */ #ifdef CONFIG_PARIDE_PF extern void pf_setup(char *str, int *ints); -#endif +#endif /* CONFIG_PARIDE_PF */ #ifdef CONFIG_PARIDE_PT extern void pt_setup(char *str, int *ints); -#endif +#endif /* CONFIG_PARIDE_PT */ #ifdef CONFIG_PARIDE_PG extern void pg_setup(char *str, int *ints); -#endif +#endif /* CONFIG_PARIDE_PG */ #ifdef CONFIG_PARIDE_PCD extern void pcd_setup(char *str, int *ints); -#endif +#endif /* CONFIG_PARIDE_PCD */ #ifdef CONFIG_BLK_CPQ_DA #ifdef CONFIG_BLK_CPQ_DA_EISA extern void cpqarray_setup(char *str, int *ints); -#endif -#endif +#endif /* CONFIG_BLK_CPQ_DA_EISA */ +#endif /* CONFIG_BLK_CPQ_DA */ #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) extern void ipc_init(void); -#endif +#endif /* defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) */ /* * Boot command-line arguments @@ -239,8 +239,8 @@ extern int rd_image_start; /* starting block # of image */ #ifdef CONFIG_BLK_DEV_INITRD kdev_t real_root_dev; -#endif -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ +#endif /* CONFIG_BLK_DEV_RAM */ int root_mountflags = MS_RDONLY; char *execute_command = 0; @@ -248,7 +248,7 @@ #ifdef CONFIG_ROOT_NFS char nfs_root_name[NFS_ROOT_NAME_LEN] = { "default" }; char nfs_root_addrs[NFS_ROOT_ADDRS_LEN] = { "" }; -#endif +#endif /* CONFIG_ROOT_NFS */ extern void dquot_init(void); @@ -258,7 +258,7 @@ static char * argv_rc[] = { "/bin/sh", NULL }; static char * envp_rc[] = { "HOME=/", "TERM=linux", NULL }; -static char * argv[] = { "-/bin/sh",NULL }; +static char * argv[] = { "-/bin/sh", NULL }; static char * envp[] = { "HOME=/usr/root", "TERM=linux", NULL }; char *get_options(char *str, int *ints) @@ -267,8 +267,8 @@ int i=1; while (cur && isdigit(*cur) && i <= 10) { - ints[i++] = simple_strtoul(cur,NULL,0); - if ((cur = strchr(cur,',')) != NULL) + ints[i++] = simple_strtoul(cur, NULL, 0); + if ((cur = strchr(cur, ',')) != NULL) cur++; } ints[0] = i-1; @@ -282,9 +282,9 @@ else #ifdef CONFIG_PROFILE_SHIFT prof_shift = CONFIG_PROFILE_SHIFT; -#else +#else /* CONFIG_PROFILE_SHIFT */ prof_shift = 2; -#endif +#endif /* !CONFIG_PROFILE_SHIFT */ } struct kernel_param { @@ -303,8 +303,8 @@ { "ramdisk_size=", ramdisk_size }, #ifdef CONFIG_BLK_DEV_INITRD { "noinitrd", no_initrd }, -#endif -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ +#endif /* CONFIG_BLK_DEV_RAM */ { "swap=", swap_setup }, { "buff=", buff_setup }, { "panic=", panic_setup }, @@ -313,182 +313,182 @@ { "no-hlt", no_halt }, { "no387", no_387 }, { "reboot=", reboot_setup }, -#endif +#endif /* CONFIG_BUGi386 */ #ifdef CONFIG_INET { "ether=", eth_setup }, -#endif +#endif /* CONFIG_INET */ #ifdef CONFIG_PRINTER { "lp=", lp_setup }, -#endif +#endif /* CONFIG_PRINTER */ #ifdef CONFIG_SCSI { "max_scsi_luns=", scsi_luns_setup }, -#endif +#endif /* CONFIG_SCSI */ #ifdef CONFIG_SCSI_ADVANSYS { "advansys=", advansys_setup }, -#endif +#endif /* CONFIG_SCSI_ADVANSYS */ #if defined(CONFIG_BLK_DEV_HD) { "hd=", hd_setup }, -#endif +#endif /* defined(CONFIG_BLK_DEV_HD) */ #ifdef CONFIG_CHR_DEV_ST { "st=", st_setup }, -#endif +#endif /* CONFIG_CHR_DEV_ST */ #ifdef CONFIG_BUSMOUSE { "bmouse=", bmouse_setup }, -#endif +#endif /* CONFIG_BUSMOUSE */ #ifdef CONFIG_MS_BUSMOUSE { "msmouse=", msmouse_setup }, -#endif +#endif /* CONFIG_MS_BUSMOUSE */ #ifdef CONFIG_SCSI_SEAGATE { "st0x=", st0x_setup }, { "tmc8xx=", tmc8xx_setup }, -#endif +#endif /* CONFIG_SCSI_SEAGATE */ #ifdef CONFIG_SCSI_T128 { "t128=", t128_setup }, -#endif +#endif /* CONFIG_SCSI_T128 */ #ifdef CONFIG_SCSI_PAS16 { "pas16=", pas16_setup }, -#endif +#endif /* CONFIG_SCSI_PAS16 */ #ifdef CONFIG_SCSI_GENERIC_NCR5380 { "ncr5380=", generic_NCR5380_setup }, { "ncr53c400=", generic_NCR53C400_setup }, -#endif +#endif /* CONFIG_SCSI_GENERIC_NCR5380 */ #ifdef CONFIG_SCSI_AHA152X { "aha152x=", aha152x_setup}, -#endif +#endif /* CONFIG_SCSI_AHA152X */ #ifdef CONFIG_SCSI_AHA1542 { "aha1542=", aha1542_setup}, -#endif +#endif /* CONFIG_SCSI_AHA1542 */ #ifdef CONFIG_SCSI_GDTH { "gdth=", gdth_setup}, -#endif +#endif /* CONFIG_SCSI_GDTH */ #ifdef CONFIG_SCSI_AIC7XXX { "aic7xxx=", aic7xxx_setup}, -#endif +#endif /* CONFIG_SCSI_AIC7XXX */ #ifdef CONFIG_SCSI_BUSLOGIC { "BusLogic=", BusLogic_Setup}, -#endif +#endif /* CONFIG_SCSI_BUSLOGIC */ #ifdef CONFIG_SCSI_NCR53C8XX { "ncr53c8xx=", ncr53c8xx_setup}, -#endif +#endif /* CONFIG_SCSI_NCR53C8XX */ #ifdef CONFIG_SCSI_EATA { "eata=", eata2x_setup}, -#endif +#endif /* CONFIG_SCSI_EATA */ #ifdef CONFIG_SCSI_U14_34F { "u14-34f=", u14_34f_setup}, -#endif +#endif /* CONFIG_SCSI_U14_34F */ #ifdef CONFIG_SCSI_AM53C974 { "AM53C974=", AM53C974_setup}, -#endif +#endif /* CONFIG_SCSI_AM53C974 */ #ifdef CONFIG_SCSI_NCR53C406A { "ncr53c406a=", NCR53c406a_setup}, -#endif +#endif /* CONFIG_SCSI_NCR53C406A */ #ifdef CONFIG_SCSI_SYM53C416 - { "sym53c416=", sym53c416_setup}, -#endif + { "sym53c416=", sym53c416_setup}, +#endif /* CONFIG_SCSI_SYM53C416 */ #ifdef CONFIG_SCSI_FUTURE_DOMAIN { "fdomain=", fdomain_setup}, -#endif +#endif /* CONFIG_SCSI_FUTURE_DOMAIN */ #ifdef CONFIG_SCSI_IN2000 { "in2000=", in2000_setup}, -#endif +#endif /* CONFIG_SCSI_IN2000 */ #ifdef CONFIG_SCSI_7000FASST { "wd7000=", wd7000_setup}, -#endif +#endif /* CONFIG_SCSI_7000FASST */ #ifdef CONFIG_SCSI_PPA { "ppa=", ppa_setup }, -#endif -#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP) +#endif /* CONFIG_SCSI_PPA */ +#if defined(CONFIG_SCSI_DC390T) && !defined(CONFIG_SCSI_DC390T_NOGENSUPP) { "tmscsim=", dc390_setup }, -#endif +#endif /* defined(CONFIG_SCSI_DC390T) && !defined(CONFIG_SCSI_DC390T_NOGENSUPP) */ #ifdef CONFIG_BLK_DEV_XD { "xd=", xd_setup }, { "xd_geo=", xd_manual_geo_init }, -#endif +#endif /* CONFIG_BLK_DEV_XD */ #ifdef CONFIG_BLK_DEV_FD { "floppy=", floppy_setup }, -#endif +#endif /* CONFIG_BLK_DEV_FD */ #ifdef CONFIG_CDU31A { "cdu31a=", cdu31a_setup }, -#endif CONFIG_CDU31A +#endif /* CONFIG_CDU31A */ #ifdef CONFIG_MCD { "mcd=", mcd_setup }, -#endif CONFIG_MCD +#endif /* CONFIG_MCD */ #ifdef CONFIG_MCDX { "mcdx=", mcdx_setup }, -#endif CONFIG_MCDX +#endif /* CONFIG_MCDX */ #ifdef CONFIG_SBPCD { "sbpcd=", sbpcd_setup }, -#endif CONFIG_SBPCD +#endif /* CONFIG_SBPCD */ #ifdef CONFIG_AZTCD { "aztcd=", aztcd_setup }, -#endif CONFIG_AZTCD +#endif /* CONFIG_AZTCD */ #ifdef CONFIG_CDU535 { "sonycd535=", sonycd535_setup }, -#endif CONFIG_CDU535 +#endif /* CONFIG_CDU535 */ #ifdef CONFIG_GSCD { "gscd=", gscd_setup }, -#endif CONFIG_GSCD +#endif /* CONFIG_GSCD */ #ifdef CONFIG_CM206 { "cm206=", cm206_setup }, -#endif CONFIG_CM206 +#endif /* CONFIG_CM206 */ #ifdef CONFIG_OPTCD { "optcd=", optcd_setup }, -#endif CONFIG_OPTCD +#endif /* CONFIG_OPTCD */ #ifdef CONFIG_SJCD { "sjcd=", sjcd_setup }, -#endif CONFIG_SJCD +#endif /* CONFIG_SJCD */ #ifdef CONFIG_ISP16_CDI { "isp16=", isp16_setup }, -#endif CONFIG_ISP16_CDI +#endif /* CONFIG_ISP16_CDI */ #ifdef CONFIG_SOUND { "sound=", sound_setup }, -#endif +#endif /* CONFIG_SOUND */ #ifdef CONFIG_ISDN_DRV_ICN { "icn=", icn_setup }, -#endif +#endif /* CONFIG_ISDN_DRV_ICN */ #ifdef CONFIG_ISDN_DRV_HISAX { "hisax=", HiSax_setup }, { "HiSax=", HiSax_setup }, -#endif +#endif /* CONFIG_ISDN_DRV_HISAX */ #ifdef CONFIG_ISDN_DRV_PCBIT { "pcbit=", pcbit_setup }, -#endif +#endif /* CONFIG_ISDN_DRV_PCBIT */ #ifdef CONFIG_ATARIMOUSE { "atamouse=", atari_mouse_setup }, -#endif +#endif /* CONFIG_ATARIMOUSE */ #ifdef CONFIG_DMASOUND { "dmasound=", dmasound_setup }, -#endif +#endif /* CONFIG_DMASOUND */ #ifdef CONFIG_ATARI_SCSI { "atascsi=", atari_scsi_setup }, -#endif +#endif /* CONFIG_ATARI_SCSI */ #if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \ || defined(CONFIG_GVP11_SCSI) { "wd33c93=", wd33c93_setup }, -#endif +#endif /* defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) || defined(CONFIG_GVP11_SCSI */ #if defined(CONFIG_GVP11_SCSI) { "gvp11=", gvp11_setup }, -#endif +#endif /* defined(CONFIG_GVP11_SCSI) */ #ifdef CONFIG_CYCLADES { "cyclades=", cy_setup }, -#endif +#endif /* CONFIG_CYCLADES */ #ifdef CONFIG_DIGI { "digi=", pcxx_setup }, -#endif +#endif /* CONFIG_DIGI */ #ifdef CONFIG_RISCOM8 { "riscom8=", riscom8_setup }, -#endif +#endif /* CONFIG_RISCOM8 */ #ifdef CONFIG_SPECIALIX { "specialix=", specialix_setup }, -#endif +#endif /* CONFIG_SPECIALIX */ #ifdef CONFIG_BAYCOM { "baycom=", baycom_setup }, -#endif +#endif /* CONFIG_BAYCOM */ #ifdef CONFIG_BLK_CPQ_DA #ifdef CONFIG_BLK_CPQ_DA_EISA { "smart2=", cpqarray_setup }, -#endif -#endif +#endif /* CONFIG_BLK_CPQ_DA_EISA */ +#endif /* CONFIG_BLK_CPQ_DA */ { 0, 0 } }; @@ -496,22 +496,22 @@ #ifdef CONFIG_PARIDE_PD { "pd.", pd_setup }, -#endif +#endif /* CONFIG_PARIDE_PD */ #ifdef CONFIG_PARIDE_PCD { "pcd.", pcd_setup }, -#endif +#endif /* CONFIG_PARIDE_PCD */ #ifdef CONFIG_PARIDE_PF { "pf.", pf_setup }, -#endif +#endif /* CONFIG_PARIDE_PF */ #ifdef CONFIG_PARIDE_PT { "pt.", pt_setup }, -#endif +#endif /* CONFIG_PARIDE_PT */ #ifdef CONFIG_PARIDE_PG { "pg.", pg_setup }, -#endif +#endif /* CONFIG_PARIDE_PG */ #ifdef CONFIG_APM { "apm=", apm_setup }, -#endif +#endif /* CONFIG_APM */ { 0, 0 } } ; @@ -541,7 +541,7 @@ rd_size = ints[1]; } -#endif +#endif /* CONFIG_BLK_DEV_RAM */ static int checksetup(char *line) { @@ -550,15 +550,15 @@ #ifdef CONFIG_BLK_DEV_IDE /* ide driver needs the basic string, rather than pre-processed values */ - if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '=')) { + if (!strncmp(line, "ide", 3) || (!strncmp(line, "hd", 2) && line[2] != '=')) { ide_setup(line); return 1; } -#endif +#endif /* CONFIG_BLK_DEV_IDE */ while (bootsetups[i].str) { int n = strlen(bootsetups[i].str); - if (!strncmp(line,bootsetups[i].str,n)) { - bootsetups[i].setup_func(get_options(line+n,ints), ints); + if (!strncmp(line, bootsetups[i].str, n)) { + bootsetups[i].setup_func(get_options(line+n, ints), ints); return 1; } i++; @@ -566,7 +566,7 @@ for (i=0; raw_params[i].str; i++) { int n = strlen(raw_params[i].str); - if (!strncmp(line,raw_params[i].str,n)) { + if (!strncmp(line, raw_params[i].str, n)) { raw_params[i].setup_func(line+n, NULL); return 1; } @@ -581,7 +581,7 @@ #if defined(__SMP__) && defined(__i386__) unsigned long smp_loops_per_tick = 1000000; -#endif +#endif /* defined(__SMP__) && defined(__i386__) */ /* This is the number of bits of precision for the loops_per_second. Each bit takes on average 1.5/HZ seconds. This (like the original) is a little @@ -608,13 +608,13 @@ ticks = jiffies - ticks; if (ticks) break; - } + } /* Do a binary approximation to get loops_per_second set to equal one clock (up to lps_precision bits) */ loops_per_sec >>= 1; loopbit = loops_per_sec; - while ( lps_precision-- && (loopbit >>= 1) ) { + while (lps_precision-- && (loopbit >>= 1) ) { loops_per_sec |= loopbit; ticks = jiffies; while (ticks == jiffies); @@ -624,16 +624,16 @@ loops_per_sec &= ~loopbit; } -/* finally, adjust loops per second in terms of seconds instead of clocks */ +/* finally, adjust loops per second in terms of seconds instead of clocks */ loops_per_sec *= HZ; -/* Round the value and print it */ +/* Round the value and print it */ printk("ok - %lu.%02lu BogoMIPS\n", (loops_per_sec+2500)/500000, ((loops_per_sec+2500)/5000) % 100); #if defined(__SMP__) && defined(__i386__) smp_loops_per_tick = loops_per_sec / 400; -#endif +#endif /* defined(__SMP__) && defined(__i386__) */ } static void parse_root_dev(char * line) @@ -674,23 +674,23 @@ { "sdo", 0x08e0 }, { "sdp", 0x08f0 }, #ifdef CONFIG_BLK_DEV_DAC960 - { "rd/c0d0p",0x3000 }, - { "rd/c0d1p",0x3008 }, - { "rd/c0d2p",0x3010 }, - { "rd/c0d3p",0x3018 }, - { "rd/c0d4p",0x3020 }, - { "rd/c0d5p",0x3028 }, - { "rd/c0d6p",0x3030 }, - { "rd/c0d7p",0x3038 }, - { "rd/c0d8p",0x3040 }, - { "rd/c0d9p",0x3048 }, - { "rd/c0d10p",0x3050 }, - { "rd/c0d11p",0x3058 }, - { "rd/c0d12p",0x3060 }, - { "rd/c0d13p",0x3068 }, - { "rd/c0d14p",0x3070 }, - { "rd/c0d15p",0x3078 }, -#endif + { "rd/c0d0p", 0x3000 }, + { "rd/c0d1p", 0x3008 }, + { "rd/c0d2p", 0x3010 }, + { "rd/c0d3p", 0x3018 }, + { "rd/c0d4p", 0x3020 }, + { "rd/c0d5p", 0x3028 }, + { "rd/c0d6p", 0x3030 }, + { "rd/c0d7p", 0x3038 }, + { "rd/c0d8p", 0x3040 }, + { "rd/c0d9p", 0x3048 }, + { "rd/c0d10p", 0x3050 }, + { "rd/c0d11p", 0x3058 }, + { "rd/c0d12p", 0x3060 }, + { "rd/c0d13p", 0x3068 }, + { "rd/c0d14p", 0x3070 }, + { "rd/c0d15p", 0x3078 }, +#endif /* CONFIG_BLK_DEV_DAC960 */ { "fd", 0x0200 }, { "xda", 0x0d00 }, { "xdb", 0x0d40 }, @@ -704,26 +704,26 @@ { "sbpcd", 0x1900 }, { "sonycd", 0x1800 }, #ifdef CONFIG_PARIDE_PD - { "pda", 0x2d00 }, - { "pdb", 0x2d10 }, - { "pdc", 0x2d20 }, - { "pdd", 0x2d30 }, -#endif + { "pda", 0x2d00 }, + { "pdb", 0x2d10 }, + { "pdc", 0x2d20 }, + { "pdd", 0x2d30 }, +#endif /* CONFIG_PARIDE_PD */ #ifdef CONFIG_PARIDE_PCD - { "pcd", 0x2e00 }, -#endif + { "pcd", 0x2e00 }, +#endif /* CONFIG_PARIDE_PCD */ #ifdef CONFIG_PARIDE_PF - { "pf", 0x2f00 }, -#endif + { "pf", 0x2f00 }, +#endif /* CONFIG_PARIDE_PF */ { NULL, 0 } }; - if (strncmp(line,"/dev/",5) == 0) { + if (strncmp(line, "/dev/", 5) == 0) { struct dev_name_struct *dev = devices; line += 5; do { int len = strlen(dev->name); - if (strncmp(line,dev->name,len) == 0) { + if (strncmp(line, dev->name, len) == 0) { line += len; base = dev->num; break; @@ -731,7 +731,7 @@ dev++; } while (dev->name); } - ROOT_DEV = to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); + ROOT_DEV = to_kdev_t(base + simple_strtoul(line, NULL, base ? 10 : 16)); } /* @@ -755,12 +755,12 @@ envs = 1; /* TERM is set to 'linux' by default */ next = line; while ((line = next) != NULL) { - if ((next = strchr(line,' ')) != NULL) + if ((next = strchr(line, ' ')) != NULL) *next++ = 0; /* * check for kernel options first.. */ - if (!strncmp(line,"root=",5)) { + if (!strncmp(line, "root=", 5)) { parse_root_dev(line+5); continue; } @@ -786,20 +786,20 @@ nfs_root_addrs[sizeof(nfs_root_addrs)-1] = '\0'; continue; } -#endif - if (!strcmp(line,"ro")) { +#endif /* CONFIG_ROOT_NFS */ + if (!strcmp(line, "ro")) { root_mountflags |= MS_RDONLY; continue; } - if (!strcmp(line,"rw")) { + if (!strcmp(line, "rw")) { root_mountflags &= ~MS_RDONLY; continue; } - if (!strcmp(line,"debug")) { + if (!strcmp(line, "debug")) { console_loglevel = 10; continue; } - if (!strncmp(line,"init=",5)) { + if (!strncmp(line, "init=", 5)) { line += 5; execute_command = line; continue; @@ -810,7 +810,7 @@ * Then check if it's an environment variable or * an option. */ - if (strchr(line,'=')) { + if (strchr(line, '=')) { if (envs >= MAX_INIT_ENVS) break; envp_init[++envs] = line; @@ -833,25 +833,25 @@ /* * Uniprocessor idle thread */ - + int cpu_idle(void *unused) { for(;;) idle(); } -#else +#else /* !__SMP__ */ /* * Multiprocessor idle thread is in arch/... */ - + extern int cpu_idle(void * unused); /* * Activate a secondary processor. */ - + asmlinkage void start_secondary(void) { trap_init(); @@ -902,26 +902,26 @@ task[i]->next_run = task[i]->prev_run = task[i]; sti(); } -} +} /* * The autoprobe routines assume CPU#0 on the i386 * so we don't actually set the game in motion until * they are finished. */ - + static void smp_begin(void) { smp_threads_ready=1; smp_commence(); } - -#endif + +#endif /* __SMP__ */ /* * Activate the first processor. */ - + asmlinkage void start_kernel(void) { char * command_line; @@ -932,18 +932,18 @@ #ifdef __SMP__ static int first_cpu=1; - + if(!first_cpu) start_secondary(); first_cpu=0; - -#endif + +#endif /* __SMP__ */ /* * Interrupts are still disabled. Do necessary setups, then * enable them */ setup_arch(&command_line, &memory_start, &memory_end); - memory_start = paging_init(memory_start,memory_end); + memory_start = paging_init(memory_start, memory_end); trap_init(); init_IRQ(); sched_init(); @@ -951,15 +951,15 @@ parse_options(command_line); #ifdef CONFIG_MODULES init_modules(); -#endif +#endif /* CONFIG_MODULES */ #ifdef CONFIG_PROFILE if (!prof_shift) #ifdef CONFIG_PROFILE_SHIFT prof_shift = CONFIG_PROFILE_SHIFT; -#else +#else /* CONFIG_PROFILE_SHIFT */ prof_shift = 2; -#endif -#endif +#endif /* !CONFIG_PROFILE_SHIFT */ +#endif /* CONFIG_PROFILE */ if (prof_shift) { prof_buffer = (unsigned int *) memory_start; /* only text is profiled */ @@ -968,29 +968,29 @@ memory_start += prof_len * sizeof(unsigned int); memset(prof_buffer, 0, prof_len * sizeof(unsigned int)); } - memory_start = console_init(memory_start,memory_end); + memory_start = console_init(memory_start, memory_end); #ifdef CONFIG_PCI - memory_start = pci_init(memory_start,memory_end); -#endif - memory_start = kmalloc_init(memory_start,memory_end); + memory_start = pci_init(memory_start, memory_end); +#endif /* CONFIG_PCI */ + memory_start = kmalloc_init(memory_start, memory_end); sti(); calibrate_delay(); - memory_start = inode_init(memory_start,memory_end); - memory_start = file_table_init(memory_start,memory_end); - memory_start = name_cache_init(memory_start,memory_end); + memory_start = inode_init(memory_start, memory_end); + memory_start = file_table_init(memory_start, memory_end); + memory_start = name_cache_init(memory_start, memory_end); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && initrd_start < memory_start) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " - "disabling it.\n",initrd_start,memory_start); + "disabling it.\n", initrd_start, memory_start); initrd_start = 0; } -#endif - mem_init(memory_start,memory_end); +#endif /* CONFIG_BLK_DEV_INITRD */ + mem_init(memory_start, memory_end); buffer_init(); sock_init(); #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) ipc_init(); -#endif +#endif /* defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) */ dquot_init(); arch_syms_export(); sti(); @@ -998,16 +998,16 @@ #if defined(CONFIG_MTRR) && defined(__SMP__) init_mtrr_config(); -#endif +#endif /* defined(CONFIG_MTRR) && defined(__SMP__) */ printk(linux_banner); #ifdef __SMP__ smp_init(); -#endif +#endif /* __SMP__ */ sysctl_init(); - /* - * We count on the initial thread going ok + /* + * We count on the initial thread going ok * Like idlers init is an unlocked kernel thread, which will * make syscalls (and thus be locked). */ @@ -1021,7 +1021,7 @@ * * Right now task[0] just does a infinite idle loop. */ - cpu_idle(NULL); + cpu_idle(NULL); } static int printf(const char *fmt, ...) @@ -1030,7 +1030,7 @@ int i; va_start(args, fmt); - write(1,printbuf,i=vsprintf(printbuf, fmt, args)); + write(1, printbuf, i=vsprintf(printbuf, fmt, args)); va_end(args); return i; } @@ -1038,16 +1038,16 @@ static int do_rc(void * rc) { close(0); - if (open(rc,O_RDONLY,0)) + if (open(rc, O_RDONLY, 0)) return -1; return execve("/bin/sh", argv_rc, envp_rc); } static int do_shell(void * shell) { - close(0);close(1);close(2); + close(0); close(1); close(2); setsid(); - (void) open("/dev/tty1",O_RDWR,0); + (void) open("/dev/tty1", O_RDWR, 0); (void) dup(0); (void) dup(0); return execve(shell, argv, envp); @@ -1060,24 +1060,24 @@ close(0);close(1);close(2); setsid(); - (void) open("/dev/tty1",O_RDWR,0); + (void) open("/dev/tty1", O_RDWR, 0); (void) dup(0); (void) dup(0); return execve(shell, argv, envp_init); } -static void no_initrd(char *s,int *ints) +static void no_initrd(char *s, int *ints) { mount_initrd = 0; } -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ static int init(void * unused) { - int pid,i; + int pid, i; #ifdef CONFIG_BLK_DEV_INITRD int real_root_mountflags; -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ /* Launch bdflush from here, instead of the old syscall way. */ kernel_thread(bdflush, NULL, 0); @@ -1090,7 +1090,7 @@ real_root_mountflags = root_mountflags; if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; else mount_initrd =0; -#endif +#endif /* CONFIG_BLK_DEV_INITRD */ setup(); #ifdef __SMP__ @@ -1098,11 +1098,11 @@ * With the devices probed and setup we can * now enter SMP mode. */ - + smp_begin(); -#endif +#endif /* __SMP__ */ - #ifdef CONFIG_UMSDOS_FS +#ifdef CONFIG_UMSDOS_FS { /* When mounting a umsdos fs as root, we detect @@ -1110,47 +1110,47 @@ pseudo_root is defined in fs/umsdos/inode.c */ extern struct inode *pseudo_root; - if (pseudo_root != NULL){ + if (pseudo_root != NULL) { current->fs->root = pseudo_root; current->fs->pwd = pseudo_root; } } - #endif +#endif /* CONFIG_UMSDOS_FS */ #ifdef CONFIG_BLK_DEV_INITRD root_mountflags = real_root_mountflags; - if (mount_initrd && ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) { + if (mount_initrd && ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR, 0)) { int error; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid>0) while (pid != wait(&i)); if (real_root_dev != MKDEV(RAMDISK_MAJOR, 0)) { - error = change_root(real_root_dev,"/initrd"); + error = change_root(real_root_dev, "/initrd"); if (error) printk(KERN_ERR "Change root to /initrd: " - "error %d\n",error); + "error %d\n", error); } } -#endif - +#endif /* CONFIG_BLK_DEV_INITRD */ + /* * This keeps serial console MUCH cleaner, but does assume * the console driver checks there really is a video device * attached (Sparc effectively does). */ - if ((open("/dev/tty1",O_RDWR,0) < 0) && - (open("/dev/ttyS0",O_RDWR,0) < 0)) + if ((open("/dev/tty1", O_RDWR, 0) < 0) && + (open("/dev/ttyS0", O_RDWR, 0) < 0)) printk("Unable to open an initial console.\n"); - + (void) dup(0); (void) dup(0); if (!execute_command) { - execve("/etc/init",argv_init,envp_init); - execve("/bin/init",argv_init,envp_init); - execve("/sbin/init",argv_init,envp_init); + execve("/etc/init", argv_init, envp_init); + execve("/bin/init", argv_init, envp_init); + execve("/sbin/init", argv_init, envp_init); /* if this fails, fall through to original stuff */ pid = kernel_thread(do_rc, "/etc/rc", SIGCHLD); @@ -1170,7 +1170,7 @@ while (1) if (pid == wait(&i)) break; - printf("\n\rchild %d died with code %04x\n\r",pid,i); + printf("\n\rchild %d died with code %04x\n\r", pid, i); sync(); } return -1; diff -urN linux-2.0.39/ipc/msg.c linux-2.0.40/ipc/msg.c --- linux-2.0.39/ipc/msg.c 1996-08-31 23:15:33.000000000 -0700 +++ linux-2.0.40/ipc/msg.c 2004-02-07 23:13:01.000000000 -0800 @@ -609,6 +609,8 @@ if (err) return err; break; + default: + break; } id = (unsigned int) msqid % MSGMNI; diff -urN linux-2.0.39/ipc/sem.c linux-2.0.40/ipc/sem.c --- linux-2.0.39/ipc/sem.c 1996-08-31 23:15:34.000000000 -0700 +++ linux-2.0.40/ipc/sem.c 2004-02-07 23:13:01.000000000 -0800 @@ -40,10 +40,10 @@ #include #include -extern int ipcperms (struct ipc_perm *ipcp, short semflg); -static int newary (key_t, int, int); -static int findkey (key_t key); -static void freeary (int id); +extern int ipcperms(struct ipc_perm *ipcp, short semflg); +static int newary(key_t, int, int); +static int findkey(key_t key); +static void freeary(int id); static struct semid_ds *semary[SEMMNI]; static int used_sems = 0, used_semids = 0; @@ -52,7 +52,7 @@ static unsigned short sem_seq = 0; -void sem_init (void) +void sem_init(void) { int i; @@ -63,14 +63,14 @@ return; } -static int findkey (key_t key) +static int findkey(key_t key) { int id; struct semid_ds *sma; for (id = 0; id <= max_semid; id++) { while ((sma = semary[id]) == IPC_NOID) - interruptible_sleep_on (&sem_lock); + interruptible_sleep_on(&sem_lock); if (sma == IPC_UNUSED) continue; if (key == sma->sem_perm.key) @@ -79,7 +79,7 @@ return -1; } -static int newary (key_t key, int nsems, int semflg) +static int newary(key_t key, int nsems, int semflg) { int id; struct semid_ds *sma; @@ -99,14 +99,14 @@ found: size = sizeof (*sma) + nsems * sizeof (struct sem); used_sems += nsems; - sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL); + sma = (struct semid_ds *) kmalloc(size, GFP_KERNEL); if (!sma) { semary[id] = (struct semid_ds *) IPC_UNUSED; used_sems -= nsems; - wake_up (&sem_lock); + wake_up(&sem_lock); return -ENOMEM; } - memset (sma, 0, size); + memset(sma, 0, size); sma->sem_base = (struct sem *) &sma[1]; ipcp = &sma->sem_perm; ipcp->mode = (semflg & S_IRWXUGO); @@ -123,11 +123,11 @@ max_semid = id; used_semids++; semary[id] = sma; - wake_up (&sem_lock); + wake_up(&sem_lock); return (unsigned int) sma->sem_perm.seq * SEMMNI + id; } -asmlinkage int sys_semget (key_t key, int nsems, int semflg) +asmlinkage int sys_semget(key_t key, int nsems, int semflg) { int id; struct semid_ds *sma; @@ -136,7 +136,7 @@ return -EINVAL; if (key == IPC_PRIVATE) return newary(key, nsems, semflg); - if ((id = findkey (key)) == -1) { /* key not used */ + if ((id = findkey(key)) == -1) { /* key not used */ if (!(semflg & IPC_CREAT)) return -ENOENT; return newary(key, nsems, semflg); @@ -154,12 +154,12 @@ /* Manage the doubly linked list sma->sem_pending as a FIFO: * insert new queue elements at the tail sma->sem_pending_last. */ -static inline void insert_into_queue (struct semid_ds * sma, struct sem_queue * q) +static inline void insert_into_queue(struct semid_ds * sma, struct sem_queue * q) { *(q->prev = sma->sem_pending_last) = q; *(sma->sem_pending_last = &q->next) = NULL; } -static inline void remove_from_queue (struct semid_ds * sma, struct sem_queue * q) +static inline void remove_from_queue(struct semid_ds * sma, struct sem_queue * q) { *(q->prev) = q->next; if (q->next) @@ -172,7 +172,7 @@ /* Determine whether a sequence of semaphore operations would succeed * all at once. Return 0 if yes, 1 if need to sleep, else return error code. */ -static int try_semop (struct semid_ds * sma, struct sembuf * sops, int nsops) +static int try_semop(struct semid_ds * sma, struct sembuf * sops, int nsops) { int result = 0; int i = 0; @@ -211,8 +211,8 @@ /* Actually perform a sequence of semaphore operations. Atomically. */ /* This assumes that try_semop() already returned 0. */ -static int do_semop (struct semid_ds * sma, struct sembuf * sops, int nsops, - struct sem_undo * un, int pid) +static int do_semop(struct semid_ds * sma, struct sembuf * sops, int nsops, + struct sem_undo * un, int pid) { int i; @@ -252,7 +252,7 @@ * looking for tasks that can be completed. Keep cycling through * the queue until a pass is made in which no process is woken up. */ -static void update_queue (struct semid_ds * sma) +static void update_queue(struct semid_ds * sma) { int wokeup, error; struct sem_queue * q; @@ -269,7 +269,7 @@ error = do_semop(sma, q->sops, q->nsops, q->undo, q->pid); q->status = error; /* Remove it from the queue */ - remove_from_queue(sma,q); + remove_from_queue(sma, q); /* Wake it up */ wake_up_interruptible(&q->sleeper); /* doesn't sleep! */ wokeup++; @@ -286,7 +286,7 @@ * The counts we return here are a rough approximation, but still * warrant that semncnt+semzcnt>0 if the task is on the pending queue. */ -static int count_semncnt (struct semid_ds * sma, ushort semnum) +static int count_semncnt(struct semid_ds * sma, ushort semnum) { int semncnt; struct sem_queue * q; @@ -304,7 +304,7 @@ } return semncnt; } -static int count_semzcnt (struct semid_ds * sma, ushort semnum) +static int count_semzcnt(struct semid_ds * sma, ushort semnum) { int semzcnt; struct sem_queue * q; @@ -324,7 +324,7 @@ } /* Free a semaphore set. */ -static void freeary (int id) +static void freeary(int id) { struct semid_ds *sma = semary[id]; struct sem_undo *un; @@ -355,7 +355,7 @@ kfree(sma); } -asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) +asmlinkage int sys_semctl(int semid, int semnum, int cmd, union semun arg) { struct semid_ds *buf = NULL; struct semid_ds tbuf; @@ -390,16 +390,16 @@ seminfo.semusz = used_semids; seminfo.semaem = used_sems; } - i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); + i = verify_area(VERIFY_WRITE, tmp, sizeof (struct seminfo)); if (i) return i; - memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo)); + memcpy_tofs(tmp, &seminfo, sizeof (struct seminfo)); return max_semid; } case SEM_STAT: buf = arg.buf; - i = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); + i = verify_area(VERIFY_WRITE, buf, sizeof (*buf)); if (i) return i; if (semid > max_semid) @@ -407,15 +407,17 @@ sma = semary[semid]; if (sma == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; - if (ipcperms (&sma->sem_perm, S_IRUGO)) + if (ipcperms(&sma->sem_perm, S_IRUGO)) return -EACCES; id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid; tbuf.sem_perm = sma->sem_perm; tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; - memcpy_tofs (buf, &tbuf, sizeof(*buf)); + memcpy_tofs(buf, &tbuf, sizeof (*buf)); return id; + default: + break; } id = (unsigned int) semid % SEMMNI; @@ -437,6 +439,8 @@ return -EINVAL; curr = &sma->sem_base[semnum]; break; + default: + break; } switch (cmd) { @@ -445,16 +449,16 @@ case GETNCNT: case GETZCNT: case GETALL: - if (ipcperms (ipcp, S_IRUGO)) + if (ipcperms(ipcp, S_IRUGO)) return -EACCES; switch (cmd) { case GETVAL : return curr->semval; case GETPID : return curr->sempid; - case GETNCNT: return count_semncnt(sma,semnum); - case GETZCNT: return count_semzcnt(sma,semnum); + case GETNCNT: return count_semncnt(sma, semnum); + case GETZCNT: return count_semzcnt(sma, semnum); case GETALL: array = arg.array; - i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort)); + i = verify_area(VERIFY_WRITE, array, nsems * sizeof (ushort)); if (i) return i; } @@ -466,29 +470,31 @@ break; case IPC_RMID: if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) { - freeary (id); + freeary(id); return 0; } return -EPERM; case SETALL: /* arg is a pointer to an array of ushort */ array = arg.array; - if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort)))) + if ((i = verify_area(VERIFY_READ, array, nsems * sizeof (ushort)))) return i; - memcpy_fromfs (sem_io, array, nsems*sizeof(ushort)); + memcpy_fromfs(sem_io, array, nsems * sizeof (ushort)); for (i = 0; i < nsems; i++) if (sem_io[i] > SEMVMX) return -ERANGE; break; case IPC_STAT: buf = arg.buf; - if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf)))) + if ((i = verify_area(VERIFY_WRITE, buf, sizeof (*buf)))) return i; break; case IPC_SET: buf = arg.buf; - if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf)))) + if ((i = verify_area(VERIFY_READ, buf, sizeof (*buf)))) return i; - memcpy_fromfs (&tbuf, buf, sizeof (*buf)); + memcpy_fromfs(&tbuf, buf, sizeof (*buf)); + break; + default: break; } @@ -499,18 +505,19 @@ switch (cmd) { case GETALL: - if (ipcperms (ipcp, S_IRUGO)) + if (ipcperms(ipcp, S_IRUGO)) return -EACCES; for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; - memcpy_tofs (array, sem_io, nsems*sizeof(ushort)); + memcpy_tofs(array, sem_io, nsems * sizeof (ushort)); break; case SETVAL: - if (ipcperms (ipcp, S_IWUGO)) + if (ipcperms(ipcp, S_IWUGO)) return -EACCES; for (un = sma->undo; un; un = un->id_next) un->semadj[semnum] = 0; curr->semval = val; + curr->sempid = current->pid; sma->sem_ctime = CURRENT_TIME; /* maybe some queued-up processes were waiting for this */ update_queue(sma); @@ -526,16 +533,16 @@ } return -EPERM; case IPC_STAT: - if (ipcperms (ipcp, S_IRUGO)) + if (ipcperms(ipcp, S_IRUGO)) return -EACCES; tbuf.sem_perm = sma->sem_perm; tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; - memcpy_tofs (buf, &tbuf, sizeof(*buf)); + memcpy_tofs(buf, &tbuf, sizeof (*buf)); break; case SETALL: - if (ipcperms (ipcp, S_IWUGO)) + if (ipcperms(ipcp, S_IWUGO)) return -EACCES; for (i = 0; i < nsems; i++) sma->sem_base[i].semval = sem_io[i]; @@ -552,7 +559,7 @@ return 0; } -asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) +asmlinkage int sys_semop(int semid, struct sembuf *tsops, unsigned nsops) { int i, id, size, error; struct semid_ds *sma; @@ -566,9 +573,9 @@ return -E2BIG; if (!tsops) return -EFAULT; - if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops)))) + if ((i = verify_area(VERIFY_READ, tsops, nsops * sizeof (*tsops)))) return i; - memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops)); + memcpy_fromfs(sops, tsops, nsops * sizeof (*tsops)); id = (unsigned int) semid % SEMMNI; if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; @@ -596,7 +603,7 @@ if (un->semid == semid) break; if (!un) { - size = sizeof(struct sem_undo) + sizeof(short)*sma->sem_nsems; + size = sizeof (struct sem_undo) + sizeof (short) * sma->sem_nsems; un = (struct sem_undo *) kmalloc(size, GFP_ATOMIC); if (!un) return -ENOMEM; @@ -658,7 +665,7 @@ * The current implementation does not do so. The POSIX standard * and SVID should be consulted to determine what behavior is mandated. */ -void sem_exit (void) +void sem_exit(void) { struct sem_queue *q; struct sem_undo *u, *un = NULL, **up, **unp; @@ -670,7 +677,7 @@ */ if ((q = current->semsleeping)) { if (q->prev) - remove_from_queue(q->sma,q); + remove_from_queue(q->sma, q); current->semsleeping = NULL; } @@ -687,7 +694,7 @@ if (u == un) goto found; } - printk ("sem_exit undo list error id=%d\n", u->semid); + printk("sem_exit undo list error id=%d\n", u->semid); break; found: *unp = un->id_next; diff -urN linux-2.0.39/ipc/shm.c linux-2.0.40/ipc/shm.c --- linux-2.0.39/ipc/shm.c 1998-11-15 10:33:19.000000000 -0800 +++ linux-2.0.40/ipc/shm.c 2004-02-07 23:13:01.000000000 -0800 @@ -275,6 +275,8 @@ tbuf.shm_nattch = shp->shm_nattch; memcpy_tofs (buf, &tbuf, sizeof(*buf)); return id; + default: + break; } shp = shm_segs[id = (unsigned int) shmid % SHMMNI]; diff -urN linux-2.0.39/kernel/dma.c linux-2.0.40/kernel/dma.c --- linux-2.0.39/kernel/dma.c 1995-08-01 00:02:47.000000000 -0700 +++ linux-2.0.40/kernel/dma.c 2004-02-07 23:13:01.000000000 -0800 @@ -94,6 +94,6 @@ if (xchg(&dma_chan_busy[dmanr].lock, 0) == 0) { printk("Trying to free free DMA%d\n", dmanr); return; - } + } } /* free_dma */ diff -urN linux-2.0.39/kernel/ksyms.c linux-2.0.40/kernel/ksyms.c --- linux-2.0.39/kernel/ksyms.c 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/kernel/ksyms.c 2004-02-07 23:13:01.000000000 -0800 @@ -61,9 +61,6 @@ #include #endif #include -#ifdef __SMP__ -#include -#endif extern char *get_options(char *str, int *ints); extern void set_device_ro(kdev_t dev,int flag); diff -urN linux-2.0.39/kernel/printk.c linux-2.0.40/kernel/printk.c --- linux-2.0.39/kernel/printk.c 1996-06-07 01:54:06.000000000 -0700 +++ linux-2.0.40/kernel/printk.c 2004-02-07 23:13:01.000000000 -0800 @@ -158,7 +158,7 @@ save_flags(flags); cli(); va_start(args, fmt); - i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */ + i = _vsnprintf(buf + 3, sizeof(buf) - sizeof(buf) / 8 - 3, fmt, args); buf_end = buf + 3 + i; va_end(args); for (p = buf + 3; p < buf_end; p++) { diff -urN linux-2.0.39/kernel/sched.c linux-2.0.40/kernel/sched.c --- linux-2.0.39/kernel/sched.c 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/kernel/sched.c 2004-02-07 23:13:01.000000000 -0800 @@ -49,7 +49,7 @@ int securelevel = 0; /* system security level */ long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ -volatile struct timeval xtime; /* The current time */ +volatile struct timeval xtime __attribute__ ((aligned (16))); /* The current time */ int tickadj = 500/HZ ? 500/HZ : 1; /* microsecs */ DECLARE_TASK_QUEUE(tq_timer); @@ -98,7 +98,7 @@ struct mm_struct init_mm = INIT_MM; struct task_struct init_task = INIT_TASK; -unsigned long volatile jiffies=0; +unsigned long volatile jiffies = 0; struct task_struct *current_set[NR_CPUS]; struct task_struct *last_task_used_math = NULL; @@ -111,7 +111,7 @@ { #ifdef __SMP__ int cpu=smp_processor_id(); -#endif +#endif #if 1 /* sanity tests */ if (p->next_run || p->prev_run) { printk("task already on run-queue\n"); @@ -144,7 +144,7 @@ int i; for (i=0;ipid) + if (0==current_set[cpu_logical_map[i]]->pid) { smp_message_pass(cpu_logical_map[i], MSG_RESCHEDULE, 0L, 0); break; @@ -241,15 +241,15 @@ { int weight; -#ifdef __SMP__ +#ifdef __SMP__ /* We are not permitted to run a task someone else is running */ if (p->processor != NO_PROC_ID) return -1000; -#ifdef PAST_2_0 +#ifdef PAST_2_0 /* This process is locked to a processor group */ - if (p->processor_mask && !(p->processor_mask & (1<processor_mask && !(p->processor_mask & (1<counter; if (weight) { - + #ifdef __SMP__ /* Give a largish advantage to the same processor... */ /* (this is equivalent to penalizing other processors) */ @@ -425,11 +425,11 @@ } default: del_from_runqueue(prev); - case TASK_RUNNING: + case TASK_RUNNING:; } p = init_task.next_run; sti(); - + #ifdef __SMP__ /* * This is safe as we do not permit re-entry of schedule() @@ -438,7 +438,7 @@ #define idle_task (task[cpu_number_map[this_cpu]]) #else #define idle_task (&init_task) -#endif +#endif /* * Note! there may appear new tasks on the run-queue during this, as @@ -464,11 +464,11 @@ /* * Allocate process to CPU */ - + next->processor = this_cpu; next->last_processor = this_cpu; -#endif -#ifdef __SMP_PROF__ +#endif +#ifdef __SMP_PROF__ /* mark processor running an idle thread */ if (0==next->pid) set_bit(this_cpu,&smp_idle_map); @@ -591,8 +591,8 @@ */ static inline int waking_non_zero(struct semaphore *sem) { - int ret ; - long flags ; + int ret; + unsigned long flags; get_buzz_lock(&sem->lock) ; save_flags(flags) ; @@ -695,12 +695,12 @@ void __down(struct semaphore * sem) { - __do_down(sem,TASK_UNINTERRUPTIBLE) ; + __do_down(sem, TASK_UNINTERRUPTIBLE); } int __down_interruptible(struct semaphore * sem) { - return(__do_down(sem,TASK_INTERRUPTIBLE)) ; + return (__do_down(sem, TASK_INTERRUPTIBLE)); } @@ -1114,7 +1114,7 @@ time_adjust_step = tickadj; else if (time_adjust < -tickadj) time_adjust_step = -tickadj; - + /* Reduce by this step the amount of time left */ time_adjust -= time_adjust_step; } @@ -1208,7 +1208,7 @@ do_process_times(p, user, system); do_it_virt(p, user); do_it_prof(p, ticks); -} +} static void update_process_times(unsigned long ticks, unsigned long system) { @@ -1235,9 +1235,9 @@ { int i = cpu_logical_map[j]; struct task_struct *p; - + #ifdef __SMP_PROF__ - if (test_bit(i,&smp_idle_map)) + if (test_bit(i,&smp_idle_map)) smp_idle_count[i]++; #endif p = current_set[i]; @@ -1428,7 +1428,8 @@ #endif -static struct task_struct *find_process_by_pid(pid_t pid) { +static struct task_struct *find_process_by_pid(pid_t pid) +{ struct task_struct *p, *q; if (pid == 0) @@ -1445,8 +1446,7 @@ return p; } -static int setscheduler(pid_t pid, int policy, - struct sched_param *param) +static int setscheduler(pid_t pid, int policy, struct sched_param *param) { int error; struct sched_param lp; @@ -1463,13 +1463,13 @@ p = find_process_by_pid(pid); if (!p) return -ESRCH; - + if (policy < 0) policy = p->policy; else if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) return -EINVAL; - + /* * Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid * priority for SCHED_OTHER is 0. @@ -1495,7 +1495,7 @@ return 0; } -asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, +asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param) { return setscheduler(pid, policy, param); @@ -1516,7 +1516,7 @@ p = find_process_by_pid(pid); if (!p) return -ESRCH; - + return p->policy; } @@ -1588,7 +1588,7 @@ if (error) return error; - /* Values taken from 2.1.38 */ + /* Values taken from 2.1.38 */ t.tv_sec = 0; t.tv_nsec = 150000; /* is this right for non-intel architecture too?*/ memcpy_tofs(interval, &t, sizeof(struct timespec)); @@ -1597,7 +1597,7 @@ } /* - * change timeval to jiffies, trying to avoid the + * change timeval to jiffies, trying to avoid the * most obvious overflows.. */ static unsigned long timespectojiffies(struct timespec *value) @@ -1783,7 +1783,7 @@ * process right in SMP mode. */ int cpu=smp_processor_id(); -#ifndef __SMP__ +#ifndef __SMP__ current_set[cpu]=&init_task; #else init_task.processor=cpu; diff -urN linux-2.0.39/kernel/signal.c linux-2.0.40/kernel/signal.c --- linux-2.0.39/kernel/signal.c 1996-07-02 09:08:43.000000000 -0700 +++ linux-2.0.40/kernel/signal.c 2004-02-07 23:13:01.000000000 -0800 @@ -32,7 +32,7 @@ int error; if (set) { - error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); + error = verify_area(VERIFY_READ, set, sizeof (sigset_t)); if (error) return error; new_set = get_user(set) & _BLOCKABLE; @@ -51,7 +51,7 @@ } } if (oset) { - error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t)); + error = verify_area(VERIFY_WRITE, oset, sizeof (sigset_t)); if (error) return error; put_user(old_set, oset); @@ -81,7 +81,7 @@ { int error; /* fill in "set" with signals pending but blocked. */ - error = verify_area(VERIFY_WRITE, set, sizeof(sigset_t)); + error = verify_area(VERIFY_WRITE, set, sizeof (sigset_t)); if (!error) put_user(current->blocked & current->signal, set); return error; @@ -112,11 +112,12 @@ return; } if (p->sa_handler == SIG_DFL) { - if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH) + if (signum != SIGCONT && signum != SIGCHLD && + signum != SIGURG && signum != SIGWINCH) return; current->signal &= ~_S(signum); return; - } + } } #ifndef __alpha__ @@ -128,16 +129,16 @@ int err; struct sigaction tmp; - if (signum<1 || signum>32) + if (signum < 1 || signum > 32) return -EINVAL; - if (signum==SIGKILL || signum==SIGSTOP) + if (signum == SIGKILL || signum == SIGSTOP) return -EINVAL; if (handler != SIG_DFL && handler != SIG_IGN) { err = verify_area(VERIFY_READ, handler, 1); if (err) return err; } - memset(&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof (tmp)); tmp.sa_handler = handler; tmp.sa_flags = SA_ONESHOT | SA_NOMASK; handler = current->sig->action[signum-1].sa_handler; @@ -152,16 +153,16 @@ { struct sigaction new_sa, *p; - if (signum<1 || signum>32) + if (signum < 1 || signum > 32) return -EINVAL; p = signum - 1 + current->sig->action; if (action) { - int err = verify_area(VERIFY_READ, action, sizeof(*action)); + int err = verify_area(VERIFY_READ, action, sizeof (*action)); if (err) return err; - if (signum==SIGKILL || signum==SIGSTOP) + if (signum == SIGKILL || signum == SIGSTOP) return -EINVAL; - memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); + memcpy_fromfs(&new_sa, action, sizeof (struct sigaction)); if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) @@ -169,10 +170,10 @@ } } if (oldaction) { - int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction)); + int err = verify_area(VERIFY_WRITE, oldaction, sizeof (*oldaction)); if (err) return err; - memcpy_tofs(oldaction, p, sizeof(struct sigaction)); + memcpy_tofs(oldaction, p, sizeof (struct sigaction)); } if (action) { *p = new_sa; diff -urN linux-2.0.39/kernel/sysctl.c linux-2.0.40/kernel/sysctl.c --- linux-2.0.39/kernel/sysctl.c 1998-07-13 13:47:40.000000000 -0700 +++ linux-2.0.40/kernel/sysctl.c 2004-02-07 23:13:01.000000000 -0800 @@ -21,7 +21,6 @@ #include #include -#include /* External variables not in a header file. */ extern int panic_timeout; diff -urN linux-2.0.39/lib/string.c linux-2.0.40/lib/string.c --- linux-2.0.39/lib/string.c 1996-04-23 03:24:52.000000000 -0700 +++ linux-2.0.40/lib/string.c 2004-02-07 23:13:01.000000000 -0800 @@ -10,25 +10,41 @@ * * These are buggy as well.. */ - + #include #include -char * ___strtok = NULL; +char *___strtok = NULL; #ifndef __HAVE_ARCH_STRCPY -char * strcpy(char * dest,const char *src) +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char *strcpy(char *dest, const char *src) { char *tmp = dest; while ((*dest++ = *src++) != '\0') /* nothing */; + return tmp; } -#endif +#endif /* __HAVE_ARCH_STRCPY */ #ifndef __HAVE_ARCH_STRNCPY -char * strncpy(char * dest,const char *src,size_t count) +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char *strncpy(char *dest, const char *src, size_t count) { char *tmp = dest; @@ -37,21 +53,26 @@ return tmp; } -#endif +#endif /* __HAVE_ARCH_STRNCPY */ #ifndef __HAVE_ARCH_STRCAT -char * strcat(char * dest, const char * src) +/** + * strcat - Append one %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + */ +char *strcat(char *dest, const char *src) { char *tmp = dest; while (*dest) dest++; while ((*dest++ = *src++) != '\0') - ; + /* nothing */; return tmp; } -#endif +#endif /* __HAVE_ARCH_STRCAT */ #ifndef __HAVE_ARCH_STRNCAT char * strncat(char *dest, const char *src, size_t count) @@ -71,10 +92,19 @@ return tmp; } -#endif +#endif /* __HAVE_ARCH_STRNCAT */ #ifndef __HAVE_ARCH_STRCMP -int strcmp(const char * cs,const char * ct) +/** + * strncat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @count: The maximum numbers of bytes to copy + * + * Note that in contrast to strncpy, strncat ensures the result is + * terminated. + */ +int strcmp(const char *cs, const char *ct) { register signed char __res; @@ -85,10 +115,15 @@ return __res; } -#endif +#endif /* __HAVE_ARCH_STRCMP */ #ifndef __HAVE_ARCH_STRNCMP -int strncmp(const char * cs,const char * ct,size_t count) +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + */ +int strncmp(const char *cs, const char *ct, size_t count) { register signed char __res = 0; @@ -100,32 +135,47 @@ return __res; } -#endif +#endif /* __HAVE_ARCH_STRNCMP */ #ifndef __HAVE_ARCH_STRCHR -char * strchr(const char * s, int c) +/** + * strncmp - Compare two length-limited strings + * @cs: One string + * @ct: Another string + * @count: The maximum number of bytes to compare + */ +char *strchr(const char *s, int c) { - for(; *s != (char) c; ++s) + for (; *s != (char)c; ++s) if (*s == '\0') return NULL; - return (char *) s; + return (char *)s; } -#endif +#endif /* __HAVE_ARCH_STRCHR */ #ifndef __HAVE_ARCH_STRRCHR -char * strrchr(const char * s, int c) +/** + * strchr - Find the first occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char *strrchr(const char *s, int c) { - const char *p = s + strlen(s); - do { - if (*p == (char)c) - return (char *)p; - } while (--p >= s); - return NULL; + const char *p = s + strlen(s); + do { + if (*p == (char)c) + return (char *)p; + } while (--p >= s); + return NULL; } -#endif +#endif /* __HAVE_ARCH_STRRCHR */ #ifndef __HAVE_ARCH_STRLEN -size_t strlen(const char * s) +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char *s) { const char *sc; @@ -133,10 +183,15 @@ /* nothing */; return sc - s; } -#endif +#endif /* __HAVE_ARCH_STRLEN */ #ifndef __HAVE_ARCH_STRNLEN -size_t strnlen(const char * s, size_t count) +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char *s, size_t count) { const char *sc; @@ -144,9 +199,15 @@ /* nothing */; return sc - s; } -#endif +#endif /* __HAVE_ARCH_STRNLEN */ #ifndef __HAVE_ARCH_STRSPN +/** + * strspn - Calculate the length of the initial substring of @s which only + * contain letters in @accept + * @s: The string to be searched + * @accept: The string to search for + */ size_t strspn(const char *s, const char *accept) { const char *p; @@ -165,25 +226,35 @@ return count; } -#endif +#endif /* __HAVE_ARCH_STRSPN */ #ifndef __HAVE_ARCH_STRPBRK -char * strpbrk(const char * cs,const char * ct) +/** + * strpbrk - Find the first occurrence of a set of characters + * @cs: The string to be searched + * @ct: The characters to search for + */ +char *strpbrk(const char *cs, const char *ct) { - const char *sc1,*sc2; + const char *sc1, *sc2; - for( sc1 = cs; *sc1 != '\0'; ++sc1) { - for( sc2 = ct; *sc2 != '\0'; ++sc2) { + for (sc1 = cs; *sc1 != '\0'; ++sc1) { + for (sc2 = ct; *sc2 != '\0'; ++sc2) { if (*sc1 == *sc2) - return (char *) sc1; + return (char *)sc1; } } return NULL; } -#endif +#endif /* __HAVE_ARCH_STRPBRK */ #ifndef __HAVE_ARCH_STRTOK -char * strtok(char * s,const char * ct) +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + */ +char *strtok(char *s, const char *ct) { char *sbegin, *send; @@ -191,33 +262,53 @@ if (!sbegin) { return NULL; } - sbegin += strspn(sbegin,ct); + sbegin += strspn(sbegin, ct); if (*sbegin == '\0') { ___strtok = NULL; - return( NULL ); + return NULL; } - send = strpbrk( sbegin, ct); + send = strpbrk(sbegin, ct); if (send && *send != '\0') *send++ = '\0'; ___strtok = send; - return (sbegin); + return sbegin; } -#endif +#endif /* __HAVE_ARCH_STRTOK */ #ifndef __HAVE_ARCH_MEMSET -void * memset(void * s,char c,size_t count) +/** + * memset - Fill a region of memory with the given value + * @s: Pointer to the start of the area. + * @c: The byte to fill the area with + * @count: The size of the area. + * + * Do not use memset() to access IO space, use memset_io() instead. + */ +void *memset(void *s, char c, size_t count) { - char *xs = (char *) s; + char *xs = (char *)s; while (count--) *xs++ = c; return s; } -#endif +#endif /* __HAVE_ARCH_MEMSET */ #ifndef __HAVE_ARCH_BCOPY -char * bcopy(const char * src, char * dest, int count) +/** + * bcopy - Copy one area of memory to another + * @src: Where to copy from + * @dest: Where to copy to + * @count: The size of the area. + * + * Note that this is the same as memcpy(), with the arguments reversed. + * memcpy() is the standard, bcopy() is a legacy BSD function. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +char *bcopy(const char *src, char *dest, int count) { char *tmp = dest; @@ -226,88 +317,121 @@ return dest; } -#endif +#endif /* __HAVE_ARCH_BCOPY */ #ifndef __HAVE_ARCH_MEMCPY -void * memcpy(void * dest,const void *src,size_t count) +/** + * memcpy - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +void *memcpy(void *dest, const void *src, size_t count) { - char *tmp = (char *) dest, *s = (char *) src; + char *tmp = (char *)dest, *s = (char *)src; while (count--) *tmp++ = *s++; return dest; } -#endif +#endif /* __HAVE_ARCH_MEMCPY */ #ifndef __HAVE_ARCH_MEMMOVE -void * memmove(void * dest,const void *src,size_t count) +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void *memmove(void *dest, const void *src, size_t count) { char *tmp, *s; if (dest <= src) { - tmp = (char *) dest; - s = (char *) src; + tmp = (char *)dest; + s = (char *)src; while (count--) *tmp++ = *s++; - } - else { + } else { tmp = (char *) dest + count; s = (char *) src + count; while (count--) *--tmp = *--s; - } + } return dest; } -#endif +#endif /* __HAVE_ARCH_MEMMOVE */ #ifndef __HAVE_ARCH_MEMCMP -int memcmp(const void * cs,const void * ct,size_t count) +/** + * memcmp - Compare two areas of memory + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + */ +int memcmp(const void *cs, const void *ct, size_t count) { const unsigned char *su1, *su2; signed char res = 0; - for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) if ((res = *su1 - *su2) != 0) break; return res; } -#endif +#endif /* __HAVE_ARCH_MEMCMP */ -/* - * find the first occurrence of byte 'c', or 1 past the area if none - */ #ifndef __HAVE_ARCH_MEMSCAN -void * memscan(void * addr, int c, size_t size) +/** + * memscan - Find a character in an area of memory. + * @addr: The memory area + * @c: The byte to search for + * @size: The size of the area. + * + * returns the address of the first occurrence of @c, or 1 byte past + * the area if @c is not found + */ +void *memscan(void *addr, int c, size_t size) { - unsigned char * p = (unsigned char *) addr; + unsigned char *p = (unsigned char *)addr; while (size) { if (*p == c) - return (void *) p; + return (void *)p; p++; size--; } - return (void *) p; + return (void *)p; } -#endif +#endif /* __HAVE_ARCH_MEMSCAN */ #ifndef __HAVE_ARCH_STRSTR -char * strstr(const char * s1,const char * s2) +/** + * strstr - Find the first substring in a %NUL terminated string + * @s1: The string to be searched + * @s2: The string to search for + */ +char *strstr(const char *s1, const char *s2) { int l1, l2; l2 = strlen(s2); if (!l2) - return (char *) s1; + return (char *)s1; l1 = strlen(s1); while (l1 >= l2) { l1--; - if (!memcmp(s1,s2,l2)) - return (char *) s1; + if (!memcmp(s1, s2, l2)) + return (char *)s1; s1++; } return NULL; } -#endif +#endif /* __HAVE_ARCH_STRSTR */ diff -urN linux-2.0.39/lib/vsprintf.c linux-2.0.40/lib/vsprintf.c --- linux-2.0.39/lib/vsprintf.c 1995-08-01 00:02:48.000000000 -0700 +++ linux-2.0.40/lib/vsprintf.c 2004-02-07 23:13:01.000000000 -0800 @@ -112,13 +112,14 @@ *str++ = ' '; if (sign) *str++ = sign; - if (type & SPECIAL) - if (base==8) + if (type & SPECIAL) { + if (base==8) { *str++ = '0'; - else if (base==16) { + } else if (base==16) { *str++ = '0'; *str++ = digits[33]; } + } if (!(type & LEFT)) while (size-- > 0) *str++ = c; @@ -131,7 +132,7 @@ return str; } -int vsprintf(char *buf, const char *fmt, va_list args) +int _vsnprintf(char *buf, int n, const char *fmt, va_list args) { int len; unsigned long num; @@ -146,24 +147,36 @@ number of chars for from string */ int qualifier; /* 'h', 'l', or 'L' for integer fields */ - for (str=buf ; *fmt ; ++fmt) { + for (str = buf; *fmt && (n == -1 || str - buf < n); ++fmt) { if (*fmt != '%') { *str++ = *fmt; continue; } - + /* process flags */ flags = 0; - repeat: - ++fmt; /* this also skips first '%' */ - switch (*fmt) { - case '-': flags |= LEFT; goto repeat; - case '+': flags |= PLUS; goto repeat; - case ' ': flags |= SPACE; goto repeat; - case '#': flags |= SPECIAL; goto repeat; - case '0': flags |= ZEROPAD; goto repeat; - } - + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + default: + break; + } + /* get field width */ field_width = -1; if (is_digit(*fmt)) @@ -220,6 +233,12 @@ len = strnlen(s, precision); + if (n != -1 && len >= n - (str - buf)) { + len = n - 1 - (str - buf); + if (len <= 0) break; + if (len < field_width) field_width = len; + } + if (!(flags & LEFT)) while (len < field_width--) *str++ = ' '; @@ -293,6 +312,11 @@ return str-buf; } +int vsprintf(char *buf, const char *fmt, va_list args) +{ + return _vsnprintf(buf, -1, fmt, args); +} + int sprintf(char * buf, const char *fmt, ...) { va_list args; diff -urN linux-2.0.39/mm/kmalloc.c linux-2.0.40/mm/kmalloc.c --- linux-2.0.39/mm/kmalloc.c 1997-11-07 09:57:31.000000000 -0800 +++ linux-2.0.40/mm/kmalloc.c 2004-02-07 23:13:01.000000000 -0800 @@ -16,14 +16,12 @@ #include #include +#include #include #include #include -/* Define this if you want slow routines that try to trip errors */ -#undef SADISTIC_KMALLOC - /* Private flags. */ #define MF_USED 0xffaa0055 @@ -295,7 +293,7 @@ bucket->nbytesmalloced += size; p->bh_flags = type; /* As of now this block is officially in use */ p->bh_length = size; -#ifdef SADISTIC_KMALLOC +#if CONFIG_SADISTIC_KMALLOC memset(p+1, 0xf0, size); #endif return p + 1; /* Pointer arithmetic: increments past header */ @@ -405,7 +403,7 @@ if (ptr->bh_flags != MF_USED) goto bad_order; ptr->bh_flags = MF_FREE; /* As of now this block is officially free */ -#ifdef SADISTIC_KMALLOC +#if CONFIG_SADISTIC_KMALLOC memset(ptr+1, 0xe0, ptr->bh_length); #endif save_flags(flags); diff -urN linux-2.0.39/mm/vmalloc.c linux-2.0.40/mm/vmalloc.c --- linux-2.0.39/mm/vmalloc.c 1998-06-03 15:17:50.000000000 -0700 +++ linux-2.0.40/mm/vmalloc.c 2004-02-07 23:13:01.000000000 -0800 @@ -157,7 +157,6 @@ unsigned long end = address + size; dir = pgd_offset(&init_mm, address); - flush_cache_all(); while (address < end) { pmd_t *pmd = pmd_alloc_kernel(dir, address); if (!pmd) @@ -168,7 +167,7 @@ address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } - flush_tlb_all(); + flush_cache_all(); return 0; } diff -urN linux-2.0.39/net/802/tr.c linux-2.0.40/net/802/tr.c --- linux-2.0.39/net/802/tr.c 1995-07-30 23:46:27.000000000 -0700 +++ linux-2.0.40/net/802/tr.c 2004-02-07 23:13:01.000000000 -0800 @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff -urN linux-2.0.39/net/bridge/br.c linux-2.0.40/net/bridge/br.c --- linux-2.0.39/net/bridge/br.c 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/net/bridge/br.c 2004-02-07 23:13:01.000000000 -0800 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff -urN linux-2.0.39/net/core/firewall.c linux-2.0.40/net/core/firewall.c --- linux-2.0.39/net/core/firewall.c 1998-11-15 10:33:21.000000000 -0800 +++ linux-2.0.40/net/core/firewall.c 2004-02-07 23:13:01.000000000 -0800 @@ -6,8 +6,7 @@ * much hacked by: Alan Cox */ -#include -#include +#include #include #include @@ -18,24 +17,24 @@ /* * Register a firewall */ - + int register_firewall(int pf, struct firewall_ops *fw) { struct firewall_ops **p; - + if(pf<0||pf>=NPROTO) return -EINVAL; - + /* * Don't allow two people to adjust at once. */ - + while(firewall_lock) schedule(); firewall_lock=1; - + p=&firewall_chain[pf]; - + while(*p) { if(fw->fw_priority > (*p)->fw_priority) @@ -43,7 +42,7 @@ p=&((*p)->next); } - + /* * We need to use a memory barrier to make sure that this * works correctly even in SMP with weakly ordered writes. @@ -71,20 +70,20 @@ int unregister_firewall(int pf, struct firewall_ops *fw) { struct firewall_ops **nl; - + if(pf<0||pf>=NPROTO) return -EINVAL; - + /* * Don't allow two people to adjust at once. */ - + while(firewall_lock) schedule(); firewall_lock=1; nl=&firewall_chain[pf]; - + while(*nl!=NULL) { if(*nl==fw) @@ -93,7 +92,7 @@ *nl = f; firewall_lock=0; return 0; - } + } nl=&((*nl)->next); } firewall_lock=0; @@ -103,7 +102,7 @@ int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg) { struct firewall_ops *fw=firewall_chain[pf]; - + while(fw!=NULL) { int rc=fw->fw_forward(fw,pf,dev,phdr,arg); @@ -117,11 +116,11 @@ /* * Actual invocation of the chains */ - + int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg) { struct firewall_ops *fw=firewall_chain[pf]; - + while(fw!=NULL) { int rc=fw->fw_input(fw,pf,dev,phdr,arg); @@ -135,7 +134,7 @@ int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg) { struct firewall_ops *fw=firewall_chain[pf]; - + while(fw!=NULL) { int rc=fw->fw_output(fw,pf,dev,phdr,arg); diff -urN linux-2.0.39/net/core/skbuff.c linux-2.0.40/net/core/skbuff.c --- linux-2.0.39/net/core/skbuff.c 1998-11-15 10:33:21.000000000 -0800 +++ linux-2.0.40/net/core/skbuff.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,22 +4,27 @@ * Authors: Alan Cox * Florian La Roche * - * Fixes: - * Alan Cox : Fixed the worst of the load balancer bugs. - * Dave Platt : Interrupt stacking fix. - * Richard Kooijman : Timestamp fixes. - * Alan Cox : Changed buffer format. - * Alan Cox : destructor hook for AF_UNIX etc. - * Linus Torvalds : Better skb_clone. - * Alan Cox : Added skb_copy. + * Fixes: + * Alan Cox : Fixed the worst of the load + * balancer bugs + * Dave Platt : Interrupt stacking fix + * Richard Kooijman : Timestamp fixes + * Alan Cox : Changed buffer format + * Alan Cox : destructor hook for AF_UNIX etc + * Linus Torvalds : Better skb_clone + * Alan Cox : Added skb_copy * Alan Cox : Added all the changed routines Linus * only put in the headers * Ray VanTassle : Fixed --skb->lock in free + * Michael Deutschmann : Corrected and expanded + * CONFIG_SKB_CHECK system + * David Weinehall : Attempt to pad skb's properly + * (partial backport form 2.2.25) * * TO FIX: * The __skb_ routines ought to check interrupts are disabled * when called, and bitch like crazy if not. Unfortunately I don't think - * we currently have a portable way to check if interrupts are off - + * we currently have a portable way to check if interrupts are off - * Linus ??? * * This program is free software; you can redistribute it and/or @@ -81,79 +86,166 @@ #if CONFIG_SKB_CHECK -/* - * Debugging paranoia. Can go later when this crud stack works +/* Verify that an SKB has an appropriate magic number, and note the list + * to which it belongs. + * + * If (*list) is NULL, it will be overwritten with the list membership of + * this SKB (which might also be null). Otherwise, an error will be + * reported if the SKB does not belong to the same list. */ +static __inline__ int skb_magiccheck(struct sk_buff *skb, + struct sk_buff_head **list, + int line, + char *file, + char *direct) +{ + struct sk_buff_head *list2; + + if (!skb) { + printk("File: %s Line %d, found a null skb pointer (%s)\n", + file,line,direct); + return -1; + } + + if (skb->magic_debug_cookie == SK_HEAD_SKB) { + list2 = (struct sk_buff_head *) skb; + goto match_list; + } + + if (skb->magic_debug_cookie == SK_GOOD_SKB) { + list2 = skb->list; + match_list: + if (!*list) *list = list2; + + if (*list == list2) + return 0; + + printk("File %s: Line %d, list mismatch on linked skb (%s)\n", + file,line,direct); + return -1; + } + + if (skb->magic_debug_cookie == SK_FREED_SKB) { + printk("File: %s Line %d, found a freed skb (%s)\n", + file,line,direct); + printk("skb=%p, real size=%d, free=%d\n", + skb,skb->truesize,skb->free); + return -1; + } + + printk("File: %s Line %d, found an invalid skb (%s)\n", + file,line,direct); + + return -1; +} -int skb_check(struct sk_buff *skb, int head, int line, char *file) +/* Check that the links on an SKB both point to valid SKBs in the same + * list, and are reciprocal (s->p->n == s == s->n->p) + */ +static __inline__ int skb_linkscheck(struct sk_buff *skb, + struct sk_buff_head *list, + int line, + char *file) +{ + if (list->magic_debug_cookie != SK_HEAD_SKB) { + printk("File %s: Line %d, skb list is not skb-head\n", + file,line); + return -1; + } + + if (skb_magiccheck(skb->next,&list,line,file,"next")) + return -1; + + if (skb_magiccheck(skb->prev,&list,line,file,"prev")) + return -1; + + if (skb->next->prev != skb || + skb->prev->next != skb) { + printk("File %s: Line %d, skb links not reciprocal\n", + file,line); + return -1; + } + return 0; +} + +/* Checks specific to sk_buff_head objects. This actually devolves to + * linkscheck unless whole-queue paranoia is enabled. + */ +static __inline__ int skb_headcheck(struct sk_buff_head *list, + int line, char *file) { - if (head) { - if (skb->magic_debug_cookie != SK_HEAD_SKB) { - printk("File: %s Line %d, found a bad skb-head\n", - file,line); - return -1; - } - if (!skb->next || !skb->prev) { - printk("skb_check: head without next or prev\n"); - return -1; - } - if (skb->next->magic_debug_cookie != SK_HEAD_SKB - && skb->next->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad next head-skb member\n", - file,line); +#if CONFIG_SKB_CHECK_WHOLE_QUEUE + struct sk_buff *skb = (struct sk_buff *) list; + + int qlen = 0; + + while (skb->next != (struct sk_buff *) list) { + if (skb_magiccheck(skb->next,&list,line,file,"scan")); return -1; - } - if (skb->prev->magic_debug_cookie != SK_HEAD_SKB - && skb->prev->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad prev head-skb member\n", - file,line); + + if (skb->next->prev != skb) { + printk("File %s: Line %d, nonreciprocal links" + " in skb queue\n",file,line); return -1; } -#if 0 - { - struct sk_buff *skb2 = skb->next; - int i = 0; - while (skb2 != skb && i < 5) { - if (skb_check(skb2, 0, line, file) < 0) { - printk("bad queue element in whole queue\n"); - return -1; - } - i++; - skb2 = skb2->next; - } - } -#endif - return 0; - } - if (skb->next != NULL && skb->next->magic_debug_cookie != SK_HEAD_SKB - && skb->next->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad next skb member\n", - file,line); + + qlen++; + skb = skb->next; + } + + if (list->prev != skb) + { + printk("File %s: Line %d, skb-head prev link not" + " consistent\n",file,line); return -1; } - if (skb->prev != NULL && skb->prev->magic_debug_cookie != SK_HEAD_SKB - && skb->prev->magic_debug_cookie != SK_GOOD_SKB) { - printk("File: %s Line %d, bad prev skb member\n", - file,line); + + if (qlen != list->qlen) { + printk("File %s: Line %d, skb-head queue length wrong\n", + file,line); return -1; } + return 0; +#else /* ! CONFIG_SKB_CHECK_WHOLE_QUEUE */ + return skb_linkscheck( (struct sk_buff *) list, list, line, file); +#endif /* ! CONFIG_SKB_CHECK_WHOLE_QUEUE */ +} - if(skb->magic_debug_cookie==SK_FREED_SKB) - { - printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n", - file,line); - printk("skb=%p, real size=%d, free=%d\n", - skb,skb->truesize,skb->free); +/* + * Debugging paranoia. + */ +int skb_check(struct sk_buff *skb, int type, int line, char *file) +{ + struct sk_buff_head *list = NULL; + + if (skb_magiccheck(skb,&list,line,file,"self")) + return -1; + + if (skb->magic_debug_cookie == SK_HEAD_SKB) { + if (type != 0) + return skb_headcheck(list,line,file); + + printk("File %s: Line %d, found skb-head instead of skb\n", + file,line); return -1; } - if(skb->magic_debug_cookie!=SK_GOOD_SKB) - { - printk("File: %s Line %d, passed a non skb!\n", file,line); - printk("skb=%p, real size=%d, free=%d\n", - skb,skb->truesize,skb->free); + + if (list) { + if (type == 3) { + printk("File %s: Line %d, skb is already linked\n", + file,line); + return -1; + } + if (skb_linkscheck(skb,list,line,file)) + return -1; + } + else if (skb->prev || skb->next) { + printk("File %s: Line %d, skb has prev/next field," + " but no list\n",file,line); return -1; } + if(skb->head>skb->data) { printk("File: %s Line %d, head > data !\n", file,line); @@ -182,7 +274,8 @@ skb,skb->data,skb->end,skb->len); return -1; } - if((unsigned long) skb->end > (unsigned long) skb) + if((unsigned long) skb->end > + (unsigned long) (skb->data_skb ? skb->data_skb : skb)) { printk("File: %s Line %d, control overrun\n", file,line); printk("skb=%p, end=%p\n", @@ -217,7 +310,7 @@ save_flags(flags); cli(); - IS_SKB(newsk); + IS_SKB_UNLINKED(newsk); IS_SKB_HEAD(list); if (newsk->next || newsk->prev) printk("Suspicious queue head: sk_buff on list!\n"); @@ -238,7 +331,7 @@ struct sk_buff *list = (struct sk_buff *)list_; - IS_SKB(newsk); + IS_SKB_UNLINKED(newsk); IS_SKB_HEAD(list); if (newsk->next || newsk->prev) printk("Suspicious queue head: sk_buff on list!\n"); @@ -266,7 +359,7 @@ if (newsk->next || newsk->prev) printk("Suspicious queue tail: sk_buff on list!\n"); - IS_SKB(newsk); + IS_SKB_UNLINKED(newsk); IS_SKB_HEAD(list); newsk->next = list; @@ -287,7 +380,7 @@ if (newsk->next || newsk->prev) printk("Suspicious queue tail: sk_buff on list!\n"); - IS_SKB(newsk); + IS_SKB_UNLINKED(newsk); IS_SKB_HEAD(list); newsk->next = list; @@ -332,7 +425,7 @@ restore_flags(flags); - IS_SKB(result); + IS_SKB_UNLINKED(result); return result; } @@ -356,7 +449,7 @@ list_->qlen--; result->list = NULL; - IS_SKB(result); + IS_SKB_UNLINKED(result); return result; } @@ -367,8 +460,8 @@ { unsigned long flags; - IS_SKB(old); - IS_SKB(newsk); + IS_SKB_LINKED(old); + IS_SKB_UNLINKED(newsk); if(!old->next || !old->prev) printk("insert before unlisted item!\n"); @@ -395,9 +488,9 @@ struct sk_buff * prev, struct sk_buff *next, struct sk_buff_head * list) { - IS_SKB(prev); - IS_SKB(newsk); - IS_SKB(next); + IS_SKB_LINKED(prev); + IS_SKB_UNLINKED(newsk); + IS_SKB_LINKED(next); if(!prev->next || !prev->prev) printk("insert after unlisted item!\n"); @@ -422,8 +515,8 @@ { unsigned long flags; - IS_SKB(old); - IS_SKB(newsk); + IS_SKB_LINKED(old); + IS_SKB_UNLINKED(newsk); if(!old->next || !old->prev) printk("append before unlisted item!\n"); @@ -474,10 +567,13 @@ restore_flags(flags); } -void __skb_unlink(struct sk_buff *skb) +void __skb_unlink(struct sk_buff *skb,struct sk_buff_head *list) { IS_SKB(skb); + if(skb->list != list) + printk("__skb_unlink called with wrong list argument\n"); + if(skb->list) { skb->list->qlen--; @@ -581,9 +677,9 @@ __builtin_return_address(0)); return; } -#if CONFIG_SKB_CHECK - IS_SKB(skb); -#endif + + IS_SKB_UNLINKED(skb); + /* Check it twice, this is such a rare event and only occurs under * extremely high load, normal code path should not suffer from the * overhead of the cli. @@ -755,13 +851,16 @@ struct sk_buff *n; IS_SKB(skb); - n = kmalloc(sizeof(*n), priority); - if (!n) + + if (!(n = kmalloc(sizeof (*n), priority))) return NULL; - memcpy(n, skb, sizeof(*n)); + + memcpy(n, skb, sizeof (*n)); n->count = 1; + if (skb->data_skb) skb = skb->data_skb; + atomic_inc(&skb->count); atomic_inc(&net_allocs); atomic_inc(&net_skbcount); @@ -773,13 +872,14 @@ n->tries = 0; n->lock = 0; n->users = 0; + return n; } /* - * This is slower, and copies the whole data area + * This is slower, and copies the whole data area */ - + struct sk_buff *skb_copy(struct sk_buff *skb, int priority) { struct sk_buff *n; @@ -788,54 +888,129 @@ /* * Allocate the copy buffer */ - + IS_SKB(skb); - - n=alloc_skb(skb->truesize-sizeof(struct sk_buff),priority); - if(n==NULL) + + if (!(n = alloc_skb(skb->truesize - sizeof (struct sk_buff), priority))) return NULL; /* * Shift between the two data areas in bytes */ - - offset=n->head-skb->head; + + offset = n->head - skb->head; /* Set the data pointer */ - skb_reserve(n,skb->data-skb->head); + skb_reserve(n, skb->data - skb->head); /* Set the tail pointer and length */ - skb_put(n,skb->len); + skb_put(n, skb->len); /* Copy the bytes */ - memcpy(n->head,skb->head,skb->end-skb->head); - n->link3=NULL; - n->list=NULL; - n->sk=NULL; - n->when=skb->when; - n->dev=skb->dev; - n->h.raw=skb->h.raw+offset; - n->mac.raw=skb->mac.raw+offset; - n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset); - n->saddr=skb->saddr; - n->daddr=skb->daddr; - n->raddr=skb->raddr; - n->seq=skb->seq; - n->end_seq=skb->end_seq; - n->ack_seq=skb->ack_seq; - n->acked=skb->acked; - memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv)); - n->used=skb->used; - n->free=1; - n->arp=skb->arp; - n->tries=0; - n->lock=0; - n->users=0; - n->pkt_type=skb->pkt_type; - n->stamp=skb->stamp; - + memcpy(n->head, skb->head, skb->end - skb->head); + n->link3 = NULL; + n->list = NULL; + n->sk = NULL; + n->when = skb->when; + n->dev = skb->dev; + n->h.raw = skb->h.raw+offset; + n->mac.raw = skb->mac.raw+offset; + n->ip_hdr = (struct iphdr *)(((char *)skb->ip_hdr) + offset); + n->saddr = skb->saddr; + n->daddr = skb->daddr; + n->raddr = skb->raddr; + n->seq = skb->seq; + n->end_seq = skb->end_seq; + n->ack_seq = skb->ack_seq; + n->acked = skb->acked; + memcpy(n->proto_priv, skb->proto_priv, sizeof (skb->proto_priv)); + n->used = skb->used; + n->free = 1; + n->arp = skb->arp; + n->tries = 0; + n->lock = 0; + n->users = 0; + n->pkt_type = skb->pkt_type; + n->stamp = skb->stamp; + + IS_SKB(n); + + return n; +} + +static struct sk_buff *skb_copy_grow(struct sk_buff *skb, int pad, int priority) +{ + struct sk_buff *n; + unsigned long offset; + + /* + * Allocate the copy buffer + */ + + IS_SKB(skb); + + if (!(n = alloc_skb(skb->truesize - sizeof (struct sk_buff) + pad, priority))) + return NULL; + + /* + * Shift between the two data areas in bytes + */ + + offset = n->head - skb->head; + + /* Set the data pointer */ + skb_reserve(n, skb->data - skb->head); + /* Set the tail pointer and length */ + skb_put(n, skb->len); + /* Copy the bytes */ + memcpy(n->head, skb->head, skb->end - skb->head); + n->link3 = NULL; + n->list = NULL; + n->sk = NULL; + n->when = skb->when; + n->dev = skb->dev; + n->h.raw = skb->h.raw+offset; + n->mac.raw = skb->mac.raw+offset; + n->ip_hdr = (struct iphdr *)(((char *)skb->ip_hdr) + offset); + n->saddr = skb->saddr; + n->daddr = skb->daddr; + n->raddr = skb->raddr; + n->seq = skb->seq; + n->end_seq = skb->end_seq; + n->ack_seq = skb->ack_seq; + n->acked = skb->acked; + memcpy(n->proto_priv, skb->proto_priv, sizeof (skb->proto_priv)); + n->used = skb->used; + n->free = 1; + n->arp = skb->arp; + n->tries = 0; + n->lock = 0; + n->users = 0; + n->pkt_type = skb->pkt_type; + n->stamp = skb->stamp; + IS_SKB(n); + return n; } +struct sk_buff *skb_pad(struct sk_buff *skb, int pad) +{ + struct sk_buff *nskb; + + /* If the skbuff is non linear tailroom is always zero.. */ + if (skb_tailroom(skb) >= pad) { + memset(skb->data + skb->len, 0, pad); + return skb; + } + + nskb = skb_copy_grow(skb, pad, GFP_ATOMIC); + kfree_skb(skb, FREE_WRITE); + + if (nskb) + memset(nskb->data + nskb->len, 0, pad); + + return nskb; +} + /* * Skbuff device locking */ diff -urN linux-2.0.39/net/ipv4/arp.c linux-2.0.40/net/ipv4/arp.c --- linux-2.0.39/net/ipv4/arp.c 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/net/ipv4/arp.c 2004-02-07 23:13:01.000000000 -0800 @@ -1430,7 +1430,7 @@ */ else { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev, 1); skb_device_unlock(skb); /* else it is lost forever */ dev_kfree_skb(skb, FREE_WRITE); } diff -urN linux-2.0.39/net/ipv4/icmp.c linux-2.0.40/net/ipv4/icmp.c --- linux-2.0.39/net/ipv4/icmp.c 1998-06-03 15:17:50.000000000 -0700 +++ linux-2.0.40/net/ipv4/icmp.c 2004-02-07 23:13:01.000000000 -0800 @@ -1,6 +1,6 @@ /* - * NET3: Implementation of the ICMP protocol layer. - * + * NET3: Implementation of the ICMP protocol layer. + * * Alan Cox, * * This program is free software; you can redistribute it and/or @@ -16,25 +16,25 @@ * Fixes: * Mike Shaver : RFC1122 checks. * Alan Cox : Multicast ping reply as self. - * Alan Cox : Fix atomicity lockup in ip_build_xmit + * Alan Cox : Fix atomicity lockup in ip_build_xmit * call. - * Alan Cox : Added 216,128 byte paths to the MTU + * Alan Cox : Added 216,128 byte paths to the MTU * code. * Martin Mares : RFC1812 checks. - * Martin Mares : Can be configured to follow redirects + * Martin Mares : Can be configured to follow redirects * if acting as a router _without_ a * routing protocol (RFC 1812). - * Martin Mares : Echo requests may be configured to + * Martin Mares : Echo requests may be configured to * be ignored (RFC 1812). - * Martin Mares : Limitation of ICMP error message + * Martin Mares : Limitation of ICMP error message * transmit rate (RFC 1812). - * Martin Mares : TOS and Precedence set correctly + * Martin Mares : TOS and Precedence set correctly * (RFC 1812). - * Martin Mares : Now copying as much data from the + * Martin Mares : Now copying as much data from the * original packet as we can without * exceeding 576 bytes (RFC 1812). * Willy Konynenberg : Transparent proxying support. - * Keith Owens : RFC1191 correction for 4.2BSD based + * Keith Owens : RFC1191 correction for 4.2BSD based * path MTU bug. * Thomas Quinot : ICMP Dest Unreach codes up to 15 are * valid (RFC 1812). @@ -76,7 +76,7 @@ * 3.2.2.5 (Parameter Problem) * SHOULD generate these (OK) * MUST pass received PARAMPROBLEM to transport layer (NOT YET) - * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC + * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC * 3.2.2.6 (Echo Request/Reply) * MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK) * MAY discard broadcast ECHO_REQUESTs. (We don't, but that's OK.) @@ -95,7 +95,7 @@ * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency) * MUST reply using same source address as the request was sent to. (OK) * MUST reverse source route, as per ECHO (NOT YET) - * MUST pass REPLYs to transport/user layer (requires RAW, just like + * MUST pass REPLYs to transport/user layer (requires RAW, just like * ECHO) (OK) * MUST update clock for timestamp at least 15 times/sec (OK) * MUST be "correct within a few minutes" (OK) @@ -123,10 +123,10 @@ * MUST use one of addresses for the interface the orig. packet arrived as * source address (OK) * 4.3.2.5 (TOS and Precedence) - * SHOULD leave TOS set to the same value unless the packet would be + * SHOULD leave TOS set to the same value unless the packet would be * discarded for that reason (OK) * MUST use TOS=0 if not possible to leave original value (OK) - * MUST leave IP Precedence for Source Quench messages (OK -- not sent + * MUST leave IP Precedence for Source Quench messages (OK -- not sent * at all) * SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control) * for all other error messages (OK, we use 6) @@ -153,7 +153,7 @@ * is enabled on the interface (OK -- ignores) * 4.3.3.3 (Source Quench) * SHOULD NOT originate SQ messages (OK) - * MUST be able to limit SQ rate if originates them (OK as we don't + * MUST be able to limit SQ rate if originates them (OK as we don't * send them) * MAY ignore SQ messages it receives (OK -- we don't) * 4.3.3.4 (Time Exceeded) @@ -183,18 +183,18 @@ * MUST reply using same source address as the request was sent to. (OK) * MUST use reversed Source Route if possible (NOT YET) * SHOULD update Record Route / Timestamp options (??) - * MUST pass REPLYs to transport/user layer (requires RAW, just like + * MUST pass REPLYs to transport/user layer (requires RAW, just like * ECHO) (OK) * MUST update clock for timestamp at least 16 times/sec (OK) * MUST be "correct within a few minutes" (OK) * 4.3.3.9 (Address Mask Request/Reply) - * MUST have support for receiving AMRq and responding with AMRe (OK, + * MUST have support for receiving AMRq and responding with AMRe (OK, * but only as a compile-time option) - * SHOULD have option for each interface for AMRe's, MUST default to + * SHOULD have option for each interface for AMRe's, MUST default to * NO (NOT YET) * MUST NOT reply to AMRq before knows the correct AM (OK) * MUST NOT respond to AMRq with source address 0.0.0.0 on physical - * interfaces having multiple logical i-faces with different masks + * interfaces having multiple logical i-faces with different masks * (NOT YET) * SHOULD examine all AMRe's it receives and check them (NOT YET) * SHOULD log invalid AMRe's (AM+sender) (NOT YET) @@ -247,7 +247,6 @@ #include #include #include -#include #include #include #include @@ -268,7 +267,7 @@ /* * Statistics */ - + struct icmp_mib icmp_statistics; /* An array of errno for error messages from dest unreach. */ @@ -281,7 +280,7 @@ { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */ { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */ { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */ - { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */ + { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */ { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */ { ENONET, 1 }, /* ICMP_HOST_ISOLATED */ { ENETUNREACH, 1 }, /* ICMP_NET_ANO */ @@ -296,7 +295,7 @@ /* * A spare long used to speed up statistics updating */ - + unsigned long dummy; /* @@ -330,7 +329,7 @@ /* * ICMP control array. This specifies what to do with each ICMP. */ - + struct icmp_control { unsigned long *output; /* Address to increment on output */ @@ -353,7 +352,7 @@ struct icmphdr icmph; unsigned long csum; struct options replyopts; - unsigned char optbuf[40]; + unsigned char optbuf[40]; }; /* @@ -361,7 +360,7 @@ * our ICMP output as well as maintain a clean interface throughout * all layers. All Socketless IP sends will soon be gone. */ - + struct socket icmp_socket; /* @@ -380,10 +379,10 @@ int type, entry; struct icmp_xrlim *xr; - for (type=0; type<=18; type++) { + for (type = 0; type <= 18; type++) { xr = icmp_pointers[type].xrlim; if (xr) { - for (entry=0; entrycache[entry].daddr = INADDR_NONE; } } @@ -393,7 +392,7 @@ * Check transmit rate limitation for given message. * * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate - * SHOULD allow setting of rate limits (we allow + * SHOULD allow setting of rate limits (we allow * in the source) */ @@ -409,7 +408,7 @@ if (!r) return 1; - for (c = r->cache; c < &r->cache[XRLIM_CACHE_SIZE]; c++) + for (c = r->cache; c < &r->cache[XRLIM_CACHE_SIZE]; c++) /* Cache lookup */ if (c->daddr == addr) break; @@ -465,19 +464,19 @@ /* * Maintain the counters used in the SNMP statistics for outgoing ICMP */ - + static void icmp_out_count(int type) { - if(type>18) + if (type > 18) return; (*icmp_pointers[type].output)++; icmp_statistics.IcmpOutMsgs++; } - + /* * Checksum each fragment, and on the first include the headers and final checksum. */ - + static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen) { struct icmp_bxm *icmp_param = (struct icmp_bxm *)p; @@ -485,8 +484,11 @@ unsigned long csum; if (offset) { - icmp_param->csum=csum_partial_copy(icmp_param->data_ptr+offset-sizeof(struct icmphdr), - to, fraglen,icmp_param->csum); + icmp_param->csum = csum_partial_copy(icmp_param->data_ptr + + offset - + sizeof (struct icmphdr), + to, fraglen, + icmp_param->csum); return; } @@ -496,32 +498,31 @@ * for the whole packet here. */ csum = csum_partial_copy((void *)&icmp_param->icmph, - to, sizeof(struct icmphdr), - icmp_param->csum); + to, sizeof (struct icmphdr), + icmp_param->csum); csum = csum_partial_copy(icmp_param->data_ptr, - to+sizeof(struct icmphdr), - fraglen-sizeof(struct icmphdr), csum); - icmph=(struct icmphdr *)to; + to + sizeof (struct icmphdr), + fraglen - sizeof (struct icmphdr), csum); + icmph = (struct icmphdr *)to; icmph->checksum = csum_fold(csum); } - + /* * Driving logic for building and sending ICMP messages. */ static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr, __u8 tos) { - struct sock *sk=icmp_socket.data; - icmp_param->icmph.checksum=0; - icmp_param->csum=0; + struct sock *sk = icmp_socket.data; + icmp_param->icmph.checksum = 0; + icmp_param->csum = 0; icmp_out_count(icmp_param->icmph.type); sk->ip_tos = tos; - ip_build_xmit(sk, icmp_glue_bits, icmp_param, - icmp_param->data_len+sizeof(struct icmphdr), + ip_build_xmit(sk, icmp_glue_bits, icmp_param, + icmp_param->data_len + sizeof (struct icmphdr), daddr, saddr, &icmp_param->replyopts, 0, IPPROTO_ICMP, 1); } - /* * Send an ICMP message in response to a situation * @@ -532,61 +533,62 @@ * MUST reply to only the first fragment. */ -void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev) +void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev, int hdrincl) { struct iphdr *iph; struct icmphdr *icmph; int atype, room; struct icmp_bxm icmp_param; __u32 saddr; - + /* * Find the original header */ - + iph = skb_in->ip_hdr; - + /* * No replies to physical multicast/broadcast */ - - if(skb_in->pkt_type!=PACKET_HOST) + + if (skb_in->pkt_type!=PACKET_HOST) return; - + /* * Now check at the protocol level */ - - atype=ip_chk_addr(iph->daddr); - if(atype==IS_BROADCAST||atype==IS_MULTICAST) + + atype = ip_chk_addr(iph->daddr); + if (atype == IS_BROADCAST || atype == IS_MULTICAST) return; - + /* * Only reply to fragment 0. We byte re-order the constant * mask for efficiency. */ - - if(iph->frag_off&htons(IP_OFFSET)) + + if (iph->frag_off&htons(IP_OFFSET)) return; - - /* + + /* * If we send an ICMP error to an ICMP error a mess would result.. */ - - if(icmp_pointers[type].error) - { + + if (icmp_pointers[type].error) { /* - * We are an error, check if we are replying to an ICMP error + * We are an error, + * check if we are replying to an ICMP error */ - - if(iph->protocol==IPPROTO_ICMP) - { + + if (iph->protocol == IPPROTO_ICMP) { icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); /* - * Assume any unknown ICMP type is an error. This isn't - * specified by the RFC, but think about it.. + * Assume any unknown ICMP type is an error. + * This isn't specified by the RFC, + * but think about it.. */ - if(icmph->type>18 || icmp_pointers[icmph->type].error) + if (icmph->type > 18 || + icmp_pointers[icmph->type].error) return; } } @@ -598,203 +600,214 @@ #ifndef CONFIG_NO_ICMP_LIMIT if (!xrlim_allow(type, iph->saddr)) return; -#endif +#endif /* * Construct source address and options. */ - - saddr=iph->daddr; - if(saddr!=dev->pa_addr && ip_chk_addr(saddr)!=IS_MYADDR) - saddr=dev->pa_addr; - if(ip_options_echo(&icmp_param.replyopts, NULL, saddr, iph->saddr, skb_in)) + + saddr = iph->daddr; + if (saddr != dev->pa_addr && ip_chk_addr(saddr) != IS_MYADDR) + saddr = dev->pa_addr; + if (ip_options_echo(&icmp_param.replyopts, NULL, saddr, + iph->saddr, skb_in)) return; /* * Prepare data for ICMP header. */ - icmp_param.icmph.type=type; - icmp_param.icmph.code=code; + icmp_param.icmph.type = type; + icmp_param.icmph.code = code; icmp_param.icmph.un.gateway = info; - icmp_param.data_ptr=iph; - room = 576 - sizeof(struct iphdr) - icmp_param.replyopts.optlen; - icmp_param.data_len=(iph->ihl<<2)+skb_in->len; /* RFC says return as much as we can without exceeding 576 bytes */ + icmp_param.data_ptr = iph; + /* + * RFC says return as much as we can without exceeding 576 bytes + */ + room = 576 - sizeof (struct iphdr) - icmp_param.replyopts.optlen; + icmp_param.data_len = skb_in->len; + if (!hdrincl) + icmp_param.data_len += (iph->ihl << 2); if (icmp_param.data_len > room) icmp_param.data_len = room; - + /* * Build and send the packet. */ - icmp_build_xmit(&icmp_param, saddr, iph->saddr, - icmp_pointers[type].error ? + icmp_build_xmit(&icmp_param, saddr, iph->saddr, + icmp_pointers[type].error ? (iph->tos & 0x1E) | 0xC0 : iph->tos); } -/* - * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. +/* + * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. */ - + static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { struct iphdr *iph; int hash; struct inet_protocol *ipprot; - unsigned char *dp; - int match_addr=0; - - if(lenihl<<2; - if(len<0) + + iph = (struct iphdr *)(icmph + 1); + + len -= iph->ihl<<2; + if (len < 0) goto flush_it; - - dp= ((unsigned char *)iph)+(iph->ihl<<2); - - if(icmph->type==ICMP_DEST_UNREACH) - { - switch(icmph->code & 15) - { - case ICMP_NET_UNREACH: - break; - case ICMP_HOST_UNREACH: - break; - case ICMP_PROT_UNREACH: - NETDEBUG(printk(KERN_INFO "ICMP: %s:%d: protocol unreachable.\n", - in_ntoa(iph->daddr), (int)iph->protocol)); + + dp = ((unsigned char *)iph) + (iph->ihl << 2); + + if (icmph->type == ICMP_DEST_UNREACH) { + switch (icmph->code & 15) { + case ICMP_NET_UNREACH: + break; + case ICMP_HOST_UNREACH: + break; + case ICMP_PROT_UNREACH: + NETDEBUG(printk(KERN_INFO + "ICMP: %s:%d: protocol unreachable.\n", + in_ntoa(iph->daddr), + (int)iph->protocol)); /* Drop through */ - case ICMP_PORT_UNREACH: - match_addr=1; - break; - case ICMP_FRAG_NEEDED: + case ICMP_PORT_UNREACH: + match_addr = 1; + break; + case ICMP_FRAG_NEEDED: #ifdef CONFIG_NO_PATH_MTU_DISCOVERY - NETDEBUG(printk(KERN_INFO "ICMP: %s: fragmentation needed and DF set.\n", - in_ntoa(iph->daddr))); - break; + NETDEBUG(printk(KERN_INFO + "ICMP: %s: fragmentation needed and DF set.\n", + in_ntoa(iph->daddr))); + break; #else - { - unsigned short old_mtu = ntohs(iph->tot_len); - unsigned short new_mtu = ntohs(icmph->un.echo.sequence); + { + unsigned short old_mtu = ntohs(iph->tot_len); + unsigned short new_mtu = ntohs(icmph->un.echo.sequence); + /* + * RFC1191 5. 4.2BSD based router can return incorrect + * Total Length. If current mtu is unknown or old_mtu + * is not less than current mtu, reduce old_mtu by + * 4 times the header length. + */ + + if (skb->sk == NULL || /* can this happen? */ + skb->sk->ip_route_cache == NULL || + skb->sk->ip_route_cache->rt_mtu <= old_mtu) { + NETDEBUG(printk(KERN_INFO + "4.2BSD based fragmenting router between here and %s, mtu corrected from %d", + in_ntoa(iph->daddr), old_mtu)); + old_mtu -= 4 * iph->ihl; + NETDEBUG(printk(" to %d\n", old_mtu)); + } + + if (new_mtu < 68 || new_mtu >= old_mtu) { /* - * RFC1191 5. 4.2BSD based router can return incorrect - * Total Length. If current mtu is unknown or old_mtu - * is not less than current mtu, reduce old_mtu by 4 times - * the header length. + * It is either dumb router, which does not + * understand Path MTU Disc. protocol + * or broken (f.e. Linux<=1.3.37 8) router. + * Try to guess... + * The table is taken from RFC-1191. */ - - if (skb->sk == NULL /* can this happen? */ - || skb->sk->ip_route_cache == NULL - || skb->sk->ip_route_cache->rt_mtu <= old_mtu) - { - NETDEBUG(printk(KERN_INFO "4.2BSD based fragmenting router between here and %s, mtu corrected from %d", in_ntoa(iph->daddr), old_mtu)); - old_mtu -= 4 * iph->ihl; - NETDEBUG(printk(" to %d\n", old_mtu)); - } - - if (new_mtu < 68 || new_mtu >= old_mtu) - { - /* - * It is either dumb router, which does not - * understand Path MTU Disc. protocol - * or broken (f.e. Linux<=1.3.37 8) router. - * Try to guess... - * The table is taken from RFC-1191. - */ - if (old_mtu > 32000) - new_mtu = 32000; - else if (old_mtu > 17914) - new_mtu = 17914; - else if (old_mtu > 8166) - new_mtu = 8166; - else if (old_mtu > 4352) - new_mtu = 4352; - else if (old_mtu > 2002) - new_mtu = 2002; - else if (old_mtu > 1492) - new_mtu = 1492; - else if (old_mtu > 576) - new_mtu = 576; - else if (old_mtu > 296) - new_mtu = 296; - /* - * These two are not from the RFC but - * are needed for AMPRnet AX.25 paths. - */ - else if (old_mtu > 216) - new_mtu = 216; - else if (old_mtu > 128) - new_mtu = 128; - else - /* - * Despair.. - */ - new_mtu = 68; - } + if (old_mtu > 32000) + new_mtu = 32000; + else if (old_mtu > 17914) + new_mtu = 17914; + else if (old_mtu > 8166) + new_mtu = 8166; + else if (old_mtu > 4352) + new_mtu = 4352; + else if (old_mtu > 2002) + new_mtu = 2002; + else if (old_mtu > 1492) + new_mtu = 1492; + else if (old_mtu > 576) + new_mtu = 576; + else if (old_mtu > 296) + new_mtu = 296; /* - * Ugly trick to pass MTU to protocol layer. - * Really we should add argument "info" to error handler. + * These two are not from the RFC but + * are needed for AMPRnet AX.25 paths. */ - iph->id = htons(new_mtu); - break; + else if (old_mtu > 216) + new_mtu = 216; + else if (old_mtu > 128) + new_mtu = 128; + else + /* + * Despair.. + */ + new_mtu = 68; } + /* + * Ugly trick to pass MTU to protocol layer. + * Really we should add argument "info" to error handler. + */ + iph->id = htons(new_mtu); + break; + } #endif - case ICMP_SR_FAILED: - NETDEBUG(printk(KERN_INFO "ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr))); - break; - default: - break; + case ICMP_SR_FAILED: + NETDEBUG(printk(KERN_INFO + "ICMP: %s: Source Route Failed.\n", + in_ntoa(iph->daddr))); + break; + default: + break; } - if(icmph->code>NR_ICMP_UNREACH) /* Invalid type */ + if (icmph->code > NR_ICMP_UNREACH) /* Invalid type */ goto flush_it; } - + /* * Throw it at our lower layers * - * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header. - * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer. - * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer. + * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed + * header. + * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the + * transport layer. + * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to + * transport layer. * * Rule: Require port unreachable and protocol unreachable come * from the host in question. Stop junk spoofs. */ - - if(!match_addr || saddr == iph->daddr) - { + + if (!match_addr || saddr == iph->daddr) { /* - * Get the protocol(s). + * Get the protocol(s). */ - + hash = iph->protocol & (MAX_INET_PROTOS -1); /* - * This can't change while we are doing it. + * This can't change while we are doing it. */ - - ipprot = (struct inet_protocol *) inet_protos[hash]; - while(ipprot != NULL) - { + + ipprot = (struct inet_protocol *)inet_protos[hash]; + while (ipprot != NULL) { struct inet_protocol *nextip; - + nextip = (struct inet_protocol *) ipprot->next; - - /* - * Pass it off to everyone who wants it. + + /* + * Pass it off to everyone who wants it. */ - + /* RFC1122: OK. Passes appropriate ICMP errors to the */ /* appropriate protocol layer (MUST), as per 3.2.2. */ - - if (iph->protocol == ipprot->protocol && ipprot->err_handler) - { - ipprot->err_handler(icmph->type, icmph->code, dp, - iph->daddr, iph->saddr, ipprot, len); + + if (iph->protocol == ipprot->protocol && + ipprot->err_handler) { + ipprot->err_handler(icmph->type, icmph->code, + dp, iph->daddr, iph->saddr, + ipprot, len); } ipprot = nextip; @@ -804,9 +817,8 @@ kfree_skb(skb, FREE_READ); } - /* - * Handle ICMP_REDIRECT. + * Handle ICMP_REDIRECT. */ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 source, __u32 daddr, int len) @@ -817,122 +829,128 @@ /* * Get the copied header of the packet that caused the redirect */ - - if(len<=sizeof(struct iphdr)) + + if (len <= sizeof (struct iphdr)) goto flush_it; - - iph = (struct iphdr *) (icmph + 1); + + iph = (struct iphdr *)(icmph + 1); ip = iph->daddr; /* - * If we are a router and we run a routing protocol, we MUST NOT follow redirects. - * When using no routing protocol, we MAY follow redirects. (RFC 1812, 5.2.7.2) + * If we are a router and we run a routing protocol, we MUST NOT + * follow redirects. + * When using no routing protocol, we MAY follow redirects. (RFC + * 1812, 5.2.7.2) */ #if !defined(CONFIG_IP_DUMB_ROUTER) if (sysctl_ip_forward) { - NETDEBUG(printk(KERN_INFO "icmp: ICMP redirect ignored. dest = %lX, " - "orig gw = %lX, \"new\" gw = %lX, device = %s.\n", ntohl(ip), - ntohl(source), ntohl(icmph->un.gateway), dev->name)); + NETDEBUG(printk(KERN_INFO + "icmp: ICMP redirect ignored. dest = %lX, " + "orig gw = %lX, \"new\" gw = %lX, device = %s.\n", + ntohl(ip), ntohl(source), + ntohl(icmph->un.gateway), dev->name)); goto flush_it; } #endif - switch(icmph->code & 7) - { - case ICMP_REDIR_NET: - /* - * This causes a problem with subnetted networks. What we should do - * is use ICMP_ADDRESS to get the subnet mask of the problem route - * and set both. But we don't.. [RFC1812 says routers MUST NOT - * generate Network Redirects] - */ + switch (icmph->code & 7) { + case ICMP_REDIR_NET: + /* + * This causes a problem with subnetted networks. What we + * should do is use ICMP_ADDRESS to get the subnet mask of + * the problem route and set both. But we don't.. [RFC1812 + * says routers MUST NOT generate Network Redirects] + */ #ifdef not_a_good_idea - ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), - ip, 0, icmph->un.gateway, dev,0, 0, 0); + ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), + ip, 0, icmph->un.gateway, dev, 0, 0, 0); #endif - /* - * As per RFC recommendations now handle it as - * a host redirect. - */ - - case ICMP_REDIR_HOST: - /* - * Add better route to host. - * But first check that the redirect - * comes from the old gateway.. - * And make sure it's an ok host address - * (not some confused thing sending our - * address) - */ - NETDEBUG(printk(KERN_INFO "ICMP redirect from %s\n", in_ntoa(source))); - ip_rt_redirect(source, ip, icmph->un.gateway, dev); - break; - case ICMP_REDIR_NETTOS: - case ICMP_REDIR_HOSTTOS: - NETDEBUG(printk(KERN_INFO "ICMP: cannot handle TOS redirects yet!\n")); - break; - default: - break; - } + /* + * As per RFC recommendations now handle it as + * a host redirect. + */ + + case ICMP_REDIR_HOST: + /* + * Add better route to host. But first check that the + * redirect comes from the old gateway.. And make sure + * it's an ok host address (not some confused thing + * sending our address) + */ + NETDEBUG(printk(KERN_INFO + "ICMP redirect from %s\n", in_ntoa(source))); + ip_rt_redirect(source, ip, icmph->un.gateway, dev); + break; + case ICMP_REDIR_NETTOS: + case ICMP_REDIR_HOSTTOS: + NETDEBUG(printk(KERN_INFO + "ICMP: cannot handle TOS redirects yet!\n")); + break; + default: + break; + } - /* - * Discard the original packet - */ + /* + * Discard the original packet + */ flush_it: - kfree_skb(skb, FREE_READ); + kfree_skb(skb, FREE_READ); } /* - * Handle ICMP_ECHO ("ping") requests. + * Handle ICMP_ECHO ("ping") requests. * - * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests. - * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply. - * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring echo requests, MUST have default=NOT. + * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo + * requests. + * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be + * included in the reply. + * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring + * echo requests, MUST have default=NOT. * See also WRT handling of options once they are done and working. */ - + static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { #ifndef CONFIG_IP_IGNORE_ECHO_REQUESTS struct icmp_bxm icmp_param; - icmp_param.icmph=*icmph; - icmp_param.icmph.type=ICMP_ECHOREPLY; - icmp_param.data_ptr=(icmph+1); - icmp_param.data_len=len; - if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0) + icmp_param.icmph = *icmph; + icmp_param.icmph.type = ICMP_ECHOREPLY; + icmp_param.data_ptr = (icmph + 1); + icmp_param.data_len = len; + if (ip_options_echo(&icmp_param.replyopts, + NULL, daddr, saddr, skb) == 0) icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos); #endif kfree_skb(skb, FREE_READ); } /* - * Handle ICMP Timestamp requests. + * Handle ICMP Timestamp requests. * RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests. * SHOULD be in the kernel for minimum random latency. * MUST be accurate to a few minutes. * MUST be updated at least at 15Hz. */ - + static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { __u32 times[3]; /* So the new timestamp works on ALPHA's.. */ struct icmp_bxm icmp_param; - + /* * Too short. */ - - if(len<12) - { + + if (len < 12) { icmp_statistics.IcmpInErrors++; kfree_skb(skb, FREE_READ); return; } - + /* - * Fill in the current time as ms since midnight UT: + * Fill in the current time as ms since midnight UT: */ - + { struct timeval tv; do_gettimeofday(&tv); @@ -940,43 +958,44 @@ } times[2] = times[1]; memcpy((void *)×[0], icmph+1, 4); /* Incoming stamp */ - icmp_param.icmph=*icmph; - icmp_param.icmph.type=ICMP_TIMESTAMPREPLY; - icmp_param.icmph.code=0; - icmp_param.data_ptr=× - icmp_param.data_len=12; - if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0) + icmp_param.icmph = *icmph; + icmp_param.icmph.type = ICMP_TIMESTAMPREPLY; + icmp_param.icmph.code = 0; + icmp_param.data_ptr = × + icmp_param.data_len = 12; + if (ip_options_echo(&icmp_param.replyopts, + NULL, daddr, saddr, skb) == 0) icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos); kfree_skb(skb,FREE_READ); } - -/* +/* * Handle ICMP_ADDRESS_MASK requests. (RFC950) * - * RFC1122 (3.2.2.9). A host MUST only send replies to - * ADDRESS_MASK requests if it's been configured as an address mask - * agent. Receiving a request doesn't constitute implicit permission to - * act as one. Of course, implementing this correctly requires (SHOULD) - * a way to turn the functionality on and off. Another one for sysctl(), - * I guess. -- MS - * Botched with a CONFIG option for now - Linus add scts sysctl please.. + * RFC1122 (3.2.2.9). A host MUST only send replies to + * ADDRESS_MASK requests if it's been configured as an address mask + * agent. Receiving a request doesn't constitute implicit permission to + * act as one. Of course, implementing this correctly requires (SHOULD) + * a way to turn the functionality on and off. Another one for sysctl(), + * I guess. -- MS + * Botched with a CONFIG option for now - Linus add scts sysctl please.. */ - + static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { #ifdef CONFIG_IP_ADDR_AGENT /* Don't use, broken */ struct icmp_bxm icmp_param; - icmp_param.icmph.type=ICMP_ADDRESSREPLY; - icmp_param.icmph.code=0; + icmp_param.icmph.type = ICMP_ADDRESSREPLY; + icmp_param.icmph.code = 0; icmp_param.icmph.un.echo.id = icmph->un.echo.id; icmp_param.icmph.un.echo.sequence = icmph->un.echo.sequence; - icmp_param.data_ptr=&dev->pa_mask; - icmp_param.data_len=4; - if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0) + icmp_param.data_ptr = &dev->pa_mask; + icmp_param.data_len = 4; + if (ip_options_echo(&icmp_param.replyopts, + NULL, daddr, saddr, skb) == 0) icmp_build_xmit(&icmp_param, daddr, saddr, skb->iph->tos); -#endif - kfree_skb(skb, FREE_READ); +#endif + kfree_skb(skb, FREE_READ); } static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) @@ -1000,52 +1019,63 @@ int icmp_chkaddr(struct sk_buff *skb) { - struct icmphdr *icmph=(struct icmphdr *)(skb->h.raw + skb->h.iph->ihl*4); - struct iphdr *iph = (struct iphdr *) (icmph + 1); - void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) = icmp_pointers[icmph->type].handler; + struct icmphdr *icmph = (struct icmphdr *)(skb->h.raw + + skb->h.iph->ihl * 4); + struct iphdr *iph = (struct iphdr *)(icmph + 1); + void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, + struct device *dev, __u32 saddr, __u32 daddr, + int len) = icmp_pointers[icmph->type].handler; if (handler == icmp_unreach || handler == icmp_redirect) { struct sock *sk; switch (iph->protocol) { case IPPROTO_TCP: - { - struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); + { + struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph) + (iph->ihl << 2)); - sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, skb->dev); - if (!sk) return 0; - if (sk->saddr != iph->saddr) return 0; - if (sk->daddr != iph->daddr) return 0; - if (sk->dummy_th.dest != th->dest) return 0; + sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, + th->source, skb->dev); + if (!sk) + return 0; + if (sk->saddr != iph->saddr) + return 0; + if (sk->daddr != iph->daddr) + return 0; + if (sk->dummy_th.dest != th->dest) + return 0; /* * This packet came from us. */ return 1; - } + } case IPPROTO_UDP: - { - struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2)); + { + struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph) + (iph->ihl << 2)); - sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev); - if (!sk) return 0; - if (sk->saddr != iph->saddr && ip_chk_addr(iph->saddr) != IS_MYADDR) + sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, + uh->source, skb->dev); + if (!sk) + return 0; + if (sk->saddr != iph->saddr && + ip_chk_addr(iph->saddr) != IS_MYADDR) return 0; /* * This packet may have come from us. * Assume it did. */ return 1; - } + } } } return 0; } #endif -/* - * Deal with incoming ICMP packets. +/* + * Deal with incoming ICMP packets. */ - + int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, __u32 daddr, unsigned short len, __u32 saddr, int redo, struct inet_protocol *protocol) @@ -1055,43 +1085,43 @@ int r; #endif icmp_statistics.IcmpInMsgs++; - - if(len < sizeof(struct icmphdr)) - { + + if (len < sizeof (struct icmphdr)) { icmp_statistics.IcmpInErrors++; NETDEBUG(printk(KERN_INFO "ICMP: runt packet\n")); kfree_skb(skb, FREE_READ); return 0; } - - /* + + /* * Validate the packet - */ - - if (ip_compute_csum((unsigned char *) icmph, len)) - { + */ + + if (ip_compute_csum((unsigned char *)icmph, len)) { /* Failed checksum! */ icmp_statistics.IcmpInErrors++; - NETDEBUG(printk(KERN_INFO "ICMP: failed checksum from %s!\n", in_ntoa(saddr))); + NETDEBUG(printk(KERN_INFO + "ICMP: failed checksum from %s!\n", + in_ntoa(saddr))); kfree_skb(skb, FREE_READ); - return(0); + return 0; } - + /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * - * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. + * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently + * discarded. */ - - if(icmph->type > 18) - { + + if (icmph->type > 18) { icmp_statistics.IcmpInErrors++; /* Is this right - or do we ignore ? */ kfree_skb(skb,FREE_READ); - return(0); + return 0; } - + /* - * Parse the ICMP message + * Parse the ICMP message */ #ifdef CONFIG_IP_TRANSPARENT_PROXY @@ -1100,38 +1130,41 @@ * locally, due to transparent proxying. * Thus, narrow down the test to what is really meant. */ - if (daddr!=dev->pa_addr && ((r = ip_chk_addr(daddr)) == IS_BROADCAST || r == IS_MULTICAST)) + if (daddr != dev->pa_addr && + ((r = ip_chk_addr(daddr)) == IS_BROADCAST || r == IS_MULTICAST)) { #else - if (daddr!=dev->pa_addr && ip_chk_addr(daddr) != IS_MYADDR) + if (daddr != dev->pa_addr && ip_chk_addr(daddr) != IS_MYADDR) { #endif - { /* - * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be silently ignored (we don't as it is used - * by some network mapping tools). - * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently discarded if to broadcast/multicast. + * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be + * silently ignored (we don't as it is used by some + * network mapping tools). + * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently + * discarded if to broadcast/multicast. */ - if (icmph->type != ICMP_ECHO) - { + if (icmph->type != ICMP_ECHO) { icmp_statistics.IcmpInErrors++; kfree_skb(skb, FREE_READ); - return(0); - } - /* - * Reply the multicast/broadcast using a legal - * interface - in this case the device we got - * it from. - */ - daddr=dev->pa_addr; + return 0; + } + /* + * Reply the multicast/broadcast using a legal + * interface - in this case the device we got + * it from. + */ + daddr = dev->pa_addr; } - - len-=sizeof(struct icmphdr); + + len -= sizeof (struct icmphdr); (*icmp_pointers[icmph->type].input)++; - (icmp_pointers[icmph->type].handler)(icmph,skb,skb->dev,saddr,daddr,len); + (icmp_pointers[icmph->type].handler)(icmph, skb, skb->dev, saddr, + daddr, len); return 0; } /* - * This table defined limits of ICMP sending rate for various ICMP messages. + * This table defined limits of ICMP sending rate for various ICMP + * messages. */ static struct icmp_xrlim @@ -1142,7 +1175,7 @@ /* * This table is the definition of how we handle ICMP. */ - + static struct icmp_control icmp_pointers[19] = { /* ECHO REPLY (0) */ { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, NULL }, @@ -1183,15 +1216,14 @@ { struct sock *sk; int err; - icmp_socket.type=SOCK_RAW; - icmp_socket.ops=ops; - if((err=ops->create(&icmp_socket, IPPROTO_ICMP))<0) + icmp_socket.type = SOCK_RAW; + icmp_socket.ops = ops; + if ((err = ops->create(&icmp_socket, IPPROTO_ICMP)) < 0) panic("Failed to create the ICMP control socket.\n"); - sk=icmp_socket.data; - sk->allocation=GFP_ATOMIC; + sk = icmp_socket.data; + sk->allocation = GFP_ATOMIC; sk->num = 256; /* Don't receive any data */ #ifndef CONFIG_NO_ICMP_LIMIT xrlim_init(); #endif } - diff -urN linux-2.0.39/net/ipv4/ip_forward.c linux-2.0.40/net/ipv4/ip_forward.c --- linux-2.0.39/net/ipv4/ip_forward.c 1998-06-03 15:17:50.000000000 -0700 +++ linux-2.0.40/net/ipv4/ip_forward.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,13 +4,13 @@ * interface as the means of communication with the user level. * * The IP forwarding functionality. - * + * * Authors: see ip.c * * Fixes: - * Many : Split from ip.c , see ip_input.c for + * Many : Split from ip.c , see ip_input.c for * history. - * Dave Gregorich : NULL ip_rt_put fix for multicast + * Dave Gregorich : NULL ip_rt_put fix for multicast * routing. * Jos Vos : Add call_out_firewall before sending, * use output device for accounting. @@ -42,19 +42,18 @@ #include #ifdef CONFIG_IP_FORWARD /* set the default */ -int sysctl_ip_forward = 1; +int sysctl_ip_forward = 1; #else -int sysctl_ip_forward = 0; +int sysctl_ip_forward = 0; #endif #ifdef CONFIG_IP_MROUTE - /* - * Encapsulate a packet by attaching a valid IPIP header to it. + * Encapsulate a packet by attaching a valid IPIP header to it. * This avoids tunnel drivers and other mess and gives us the speed so * important for multicast video. */ - + static void ip_encap(struct sk_buff *skb, int len, struct device *out, __u32 daddr) { /* @@ -62,46 +61,46 @@ * * Firstly push down and install the IPIP header. */ - struct iphdr *iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr)); - - if(len>65515) - len=65515; + struct iphdr *iph = (struct iphdr *)skb_push(skb, + sizeof (struct iphdr)); + if (len > 65515) + len = 65515; - iph->version = 4; - iph->tos = skb->ip_hdr->tos; - iph->ttl = skb->ip_hdr->ttl; - iph->frag_off = 0; - iph->daddr = daddr; - iph->saddr = out->pa_addr; - iph->protocol = IPPROTO_IPIP; - iph->ihl = 5; - iph->tot_len = htons(skb->len + len); /* Anand, ernet */ - iph->id = htons(ip_id_count++); + iph->version = 4; + iph->tos = skb->ip_hdr->tos; + iph->ttl = skb->ip_hdr->ttl; + iph->frag_off = 0; + iph->daddr = daddr; + iph->saddr = out->pa_addr; + iph->protocol = IPPROTO_IPIP; + iph->ihl = 5; + iph->tot_len = htons(skb->len + len); /* Anand, ernet */ + iph->id = htons(ip_id_count++); ip_send_check(iph); skb->dev = out; skb->arp = 1; - skb->raddr=daddr; /* Router address is not destination address. The - * correct value is given eventually. I have not - * removed this statement. But could have. - * Anand, ernet. - */ + skb->raddr = daddr; /* Router address is not destination address. + * The correct value is given eventually. I + * have not removed this statement. But could + * have. Anand, ernet. + */ /* * Now add the physical header (driver will push it down). */ /* The last parameter of out->hard_header() needed skb->len + len. - * Anand, ernet. + * Anand, ernet. */ - if (out->hard_header && out->hard_header(skb, out, ETH_P_IP, NULL, NULL, - skb->len + len)<0) - skb->arp=0; + if (out->hard_header && + out->hard_header(skb, out, ETH_P_IP, NULL, NULL, + skb->len + len) < 0) + skb->arp = 0; /* * Read to queue for transmission. */ } - #endif /* @@ -121,16 +120,16 @@ struct hh_cache *hh = NULL; int encap = 0; /* Encap length */ #ifdef CONFIG_FIREWALL - int fw_res = 0; /* Forwarding result */ -#ifdef CONFIG_IP_MASQUERADE + int fw_res = 0; /* Forwarding result */ +#ifdef CONFIG_IP_MASQUERADE struct sk_buff *skb_in = skb; /* So we can remember if the masquerader did some swaps */ #endif /* CONFIG_IP_MASQUERADE */ #endif /* CONFIG_FIREWALL */ - + /* * According to the RFC, we must first decrease the TTL field. If - * that reaches zero, we must reply an ICMP control message telling - * that the packet's lifetime expired. + * that reaches zero, we must reply an ICMP control message + * telling that the packet's lifetime expired. * * Exception: * We may not generate an ICMP for an ICMP. icmp_send does the @@ -139,8 +138,7 @@ */ iph = skb->h.iph; - if (!(is_frag&IPFWD_NOTTLDEC)) - { + if (!(is_frag&IPFWD_NOTTLDEC)) { unsigned long checksum = iph->check; iph->ttl--; @@ -156,41 +154,39 @@ iph->check = checksum; } - if (iph->ttl <= 0) - { + if (iph->ttl <= 0) { /* Tell the sender its packet died... */ - icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev); + icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev, 1); return -1; } /* If IPFWD_MULTITUNNEL flag is set, then we have to perform routing * decision so as to reach the other end of the tunnel. This condition - * also means that we are dealing with a unicast IP packet "in a way". + * also means that we are dealing with a unicast IP packet "in a way". * Anand, ernet. */ #ifdef CONFIG_IP_MROUTE - if(!(is_frag&IPFWD_MULTICASTING) || (is_frag&IPFWD_MULTITUNNEL)) - { -#endif + if (!(is_frag & IPFWD_MULTICASTING) || (is_frag & IPFWD_MULTITUNNEL)) { +#endif /* - * OK, the packet is still valid. Fetch its destination address, - * and give it to the IP sender for further processing. + * OK, the packet is still valid. Fetch its destination + * address, and give it to the IP sender for further + * processing. */ rt = ip_rt_route(target_addr, 0, NULL); - if (rt == NULL) - { + if (rt == NULL) { /* * Tell the sender its packet cannot be delivered. Again * ICMP is screened later. */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, + 0, dev, 1); return -1; } - - + /* * Gosh. Not only is the packet valid; we even know how to * forward it onto its final destination. Can we say this @@ -200,14 +196,15 @@ */ raddr = rt->rt_gateway; - + if (opt->is_strictroute && (rt->rt_flags & RTF_GATEWAY)) { /* * Strict routing permits no gatewaying */ - + ip_rt_put(rt); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0, dev); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, + 0, dev, 1); return -1; } @@ -219,66 +216,61 @@ dev2 = rt->rt_dev; hh = rt->rt_hh; /* - * In IP you never have to forward a frame on the interface that it - * arrived upon. We now generate an ICMP HOST REDIRECT giving the route - * we calculated. + * In IP you never have to forward a frame on the + * interface that it arrived upon. We now generate an ICMP + * HOST REDIRECT giving the route we calculated. */ #ifndef CONFIG_IP_NO_ICMP_REDIRECT - if (dev == dev2 && - !((iph->saddr^dev->pa_addr)&dev->pa_mask) && - /* The daddr!=raddr test isn't obvious - what it's doing - is avoiding sending a frame the receiver will not - believe anyway.. */ - iph->daddr != raddr/*ANK*/ && !opt->srr) - icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev); + /* The daddr != raddr test isn't obvious - what it's doing is + * avoiding sending a frame the receiver will not believe + * anyway.. + */ + if (dev == dev2 && + !((iph->saddr ^ dev->pa_addr) & dev->pa_mask) && + iph->daddr != raddr && !opt->srr) + icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, + raddr, dev, 1); #endif #ifdef CONFIG_IP_MROUTE - /* This is for ip encap. Anand, ernet.*/ + /* This is for ip encap. Anand, ernet. */ - if (is_frag&IPFWD_MULTITUNNEL) - { - encap=20; + if (is_frag & IPFWD_MULTITUNNEL) { + encap = 20; } - } - else - { + } else { /* * Multicast route forward. Routing is already done */ - dev2=skb->dev; - raddr=skb->raddr; - if(is_frag&IPFWD_MULTITUNNEL) /* VIFF_TUNNEL mode */ - encap=20; - rt=NULL; + dev2 = skb->dev; + raddr = skb->raddr; + if (is_frag & IPFWD_MULTITUNNEL) /* VIFF_TUNNEL mode */ + encap = 20; + rt = NULL; } -#endif - - /* +#endif + + /* * See if we are allowed to forward this. - * Note: demasqueraded fragments are always 'back'warded. + * Note: demasqueraded fragments are always 'back'warded. */ - + #ifdef CONFIG_FIREWALL - if(!(is_frag&IPFWD_MASQUERADED)) - { + if (!(is_frag & IPFWD_MASQUERADED)) { #ifdef CONFIG_IP_MASQUERADE - /* - * Check that any ICMP packets are not for a + /* + * Check that any ICMP packets are not for a * masqueraded connection. If so rewrite them * and skip the firewall checks */ - if (iph->protocol == IPPROTO_ICMP) - { + if (iph->protocol == IPPROTO_ICMP) { #ifdef CONFIG_IP_MASQUERADE_ICMP -#define icmph ((struct icmphdr *)((char *)iph + (iph->ihl<<2))) - if ((icmph->type==ICMP_DEST_UNREACH)|| - (icmph->type==ICMP_SOURCE_QUENCH)|| - (icmph->type==ICMP_TIME_EXCEEDED)) - { +#define icmph ((struct icmphdr *)((char *)iph + (iph->ihl << 2))) + if ((icmph->type == ICMP_DEST_UNREACH) || + (icmph->type == ICMP_SOURCE_QUENCH) || + (icmph->type == ICMP_TIME_EXCEEDED)) { #endif - if ((fw_res = ip_fw_masq_icmp(&skb, dev2)) < 0) - { + if ((fw_res = ip_fw_masq_icmp(&skb, dev2)) < 0) { if (rt) ip_rt_put(rt); /* Problem - ie bad checksum */ @@ -290,16 +282,17 @@ goto skip_call_fw_firewall; #ifdef CONFIG_IP_MASQUERADE_ICMP } -#endif +#endif } #endif - fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL); + fw_res = call_fw_firewall(PF_INET, dev2, iph, NULL); switch (fw_res) { case FW_ACCEPT: case FW_MASQUERADE: break; case FW_REJECT: - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, + 0, dev, 1); /* fall thru */ default: if (rt) @@ -308,8 +301,8 @@ } #ifdef CONFIG_IP_MASQUERADE - skip_call_fw_firewall: -#endif +skip_call_fw_firewall: +#endif } #endif @@ -318,17 +311,15 @@ * If the indicated interface is up and running, kick it. */ - if (dev2->flags & IFF_UP) - { + if (dev2->flags & IFF_UP) { #ifdef CONFIG_IP_MASQUERADE - __u32 premasq_saddr = iph->saddr; - __u16 premasq_sport = 0; - __u16 *portptr=NULL; - long premasq_len_diff = skb->len; - - if (iph->protocol==IPPROTO_UDP || - iph->protocol==IPPROTO_TCP) { - portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]); + __u32 premasq_saddr = iph->saddr; + __u16 premasq_sport = 0; + __u16 *portptr = NULL; + long premasq_len_diff = skb->len; + + if (iph->protocol==IPPROTO_UDP || iph->protocol==IPPROTO_TCP) { + portptr = (__u16 *)&(((char *)iph)[iph->ihl * 4]); premasq_sport = portptr[0]; } @@ -336,9 +327,8 @@ * If this fragment needs masquerading, make it so... * (Don't masquerade de-masqueraded fragments) */ - if (!(is_frag&IPFWD_MASQUERADED) && fw_res==FW_MASQUERADE) - if (ip_fw_masquerade(&skb, dev2) < 0) - { + if (!(is_frag & IPFWD_MASQUERADED) && fw_res == FW_MASQUERADE) + if (ip_fw_masquerade(&skb, dev2) < 0) { /* * Masquerading failed; silently discard this packet. */ @@ -349,75 +339,80 @@ #endif IS_SKB(skb); - if (skb->len+encap > dev2->mtu && (iph->frag_off & htons(IP_DF))) - { + if (skb->len + encap > dev2->mtu && + (iph->frag_off & htons(IP_DF))) { ip_statistics.IpFragFails++; #ifdef CONFIG_IP_MASQUERADE - /* If we're demasquerading, put the correct daddr back */ + /* If we're demasquerading, put the correct daddr back + */ if (is_frag&IPFWD_MASQUERADED) iph->daddr = dev->pa_addr; - /* If we're masquerading, put the correct source back */ else if (fw_res==FW_MASQUERADE) { iph->saddr = premasq_saddr; if (premasq_sport) portptr[0] = premasq_sport; } - - /* If the packet has got larger and this has caused it to - exceed the MTU, then we'll claim that our MTU just got - smaller and hope it works */ + + /* If the packet has got larger and this has caused it + * to exceed the MTU, then we'll claim that our MTU + * just got smaller and hope it works + */ premasq_len_diff -= skb->len; if (premasq_len_diff < 0) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(dev2->mtu+premasq_len_diff), dev); + icmp_send(skb, ICMP_DEST_UNREACH, + ICMP_FRAG_NEEDED, + htonl(dev2->mtu + premasq_len_diff), + dev, 1); else #endif - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(dev2->mtu), dev); - if(rt) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(dev2->mtu), dev, 1); + if (rt) ip_rt_put(rt); return -1; } #ifdef CONFIG_IP_MROUTE - if(skb_headroom(skb)-encaphard_header_len) - { - skb2 = alloc_skb(dev2->hard_header_len + skb->len + encap + 15, GFP_ATOMIC); + if (skb_headroom(skb) - encap < dev2->hard_header_len) { + skb2 = alloc_skb(dev2->hard_header_len + skb->len + + encap + 15, GFP_ATOMIC); #else - if(skb_headroom(skb)hard_header_len) - { - skb2 = alloc_skb(dev2->hard_header_len + skb->len + 15, GFP_ATOMIC); -#endif + if (skb_headroom(skb) < dev2->hard_header_len) { + skb2 = alloc_skb(dev2->hard_header_len + skb->len + 15, + GFP_ATOMIC); +#endif /* * This is rare and since IP is tolerant of network failures * quite harmless. */ - - if (skb2 == NULL) - { + + if (skb2 == NULL) { NETDEBUG(printk("\nIP: No memory available for IP forward\n")); - if(rt) + if (rt) ip_rt_put(rt); return -1; } - + IS_SKB(skb2); /* * Add the physical headers. */ - skb2->protocol=htons(ETH_P_IP); + skb2->protocol = htons(ETH_P_IP); #ifdef CONFIG_IP_MROUTE - if(is_frag&IPFWD_MULTITUNNEL) - { - skb_reserve(skb2,(encap+dev2->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ - -/* We need to pass on IP information of the incoming packet to ip_encap() - * to fillin ttl, and tos fields.The destination should be target_addr. - * Anand, ernet. + if (is_frag & IPFWD_MULTITUNNEL) { + /* 16 byte aligned IP headers are good */ + skb_reserve(skb2, + (encap + + dev2->hard_header_len + 15) & ~15); + +/* We need to pass on IP information of the incoming packet to ip_encap() + * to fillin ttl, and tos fields.The destination should be target_addr. + * Anand, ernet. */ - skb2->ip_hdr = skb->ip_hdr; + skb2->ip_hdr = skb->ip_hdr; ip_encap(skb2,skb->len, dev2, target_addr); @@ -425,69 +420,71 @@ * Anand, ernet. */ skb2->raddr = rt->rt_gateway; - } - else -#endif - ip_send(rt,skb2,raddr,skb->len,dev2,dev2->pa_addr); + } else +#endif + ip_send(rt, skb2, raddr, skb->len, dev2, dev2->pa_addr); /* * We have to copy the bytes over as the new header wouldn't fit * the old buffer. This should be very rare. - */ - - ptr = skb_put(skb2,skb->len); + */ + + ptr = skb_put(skb2, skb->len); skb2->free = 1; skb2->h.raw = ptr; /* * Copy the packet data into the new buffer. */ memcpy(ptr, skb->h.raw, skb->len); - memcpy(skb2->proto_priv, skb->proto_priv, sizeof(skb->proto_priv)); + memcpy(skb2->proto_priv, skb->proto_priv, + sizeof (skb->proto_priv)); iph = skb2->ip_hdr = skb2->h.iph; - } - else - { - /* - * Build a new MAC header. + } else { + /* + * Build a new MAC header. */ - skb2 = skb; + skb2 = skb; skb2->dev=dev2; #ifdef CONFIG_IP_MROUTE - if(is_frag&IPFWD_MULTITUNNEL) + if (is_frag&IPFWD_MULTITUNNEL) ip_encap(skb, 0, dev2, target_addr); - else - { + else { #endif - skb->arp=1; - skb->raddr=raddr; - if (hh) - { - memcpy(skb_push(skb, dev2->hard_header_len), hh->hh_data, dev2->hard_header_len); - if (!hh->hh_uptodate) - { + skb->arp = 1; + skb->raddr = raddr; + if (hh) { + memcpy(skb_push(skb, + dev2->hard_header_len), + hh->hh_data, + dev2->hard_header_len); + if (!hh->hh_uptodate) { #if RT_CACHE_DEBUG >= 2 - printk("ip_forward: hh miss %08x via %08x\n", target_addr, rt->rt_gateway); -#endif + printk("ip_forward: hh miss %08x via %08x\n", + target_addr, + rt->rt_gateway); +#endif skb->arp = 0; } - } - else if (dev2->hard_header) - { - if(dev2->hard_header(skb, dev2, ETH_P_IP, NULL, NULL, skb->len)<0) - skb->arp=0; + } else if (dev2->hard_header) { + if (dev2->hard_header(skb, dev2, + ETH_P_IP, NULL, + NULL, + skb->len) < 0) + skb->arp = 0; } #ifdef CONFIG_IP_MROUTE - } -#endif + } +#endif } #ifdef CONFIG_FIREWALL - if((fw_res = call_out_firewall(PF_INET, skb2->dev, iph, NULL)) < FW_ACCEPT) - { + if ((fw_res = call_out_firewall(PF_INET, skb2->dev, + iph, NULL)) < FW_ACCEPT) { /* FW_ACCEPT and FW_MASQUERADE are treated equal: masquerading is only supported via forward rules */ if (fw_res == FW_REJECT) - icmp_send(skb2, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); + icmp_send(skb2, ICMP_DEST_UNREACH, + ICMP_HOST_UNREACH, 0, dev, 1); if (skb != skb2) kfree_skb(skb2,FREE_WRITE); if (rt) @@ -497,49 +494,41 @@ #endif ip_statistics.IpForwDatagrams++; - if (opt->optlen) - { + if (opt->optlen) { unsigned char * optptr; - if (opt->rr_needaddr) - { + if (opt->rr_needaddr) { optptr = (unsigned char *)iph + opt->rr; memcpy(&optptr[optptr[2]-5], &dev2->pa_addr, 4); opt->is_changed = 1; } - if (opt->srr_is_hit) - { + if (opt->srr_is_hit) { int srrptr, srrspace; optptr = (unsigned char *)iph + opt->srr; - for ( srrptr=optptr[2], srrspace = optptr[1]; - srrptr <= srrspace; - srrptr += 4 - ) - { + for (srrptr = optptr[2], srrspace = optptr[1]; + srrptr <= srrspace; srrptr += 4) { if (srrptr + 3 > srrspace) break; - if (memcmp(&target_addr, &optptr[srrptr-1], 4) == 0) + if (memcmp(&target_addr, + &optptr[srrptr-1], 4) == 0) break; } - if (srrptr + 3 <= srrspace) - { + if (srrptr + 3 <= srrspace) { opt->is_changed = 1; memcpy(&optptr[srrptr-1], &dev2->pa_addr, 4); iph->daddr = target_addr; - optptr[2] = srrptr+4; - } - else - printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); + optptr[2] = srrptr + 4; + } else + printk(KERN_CRIT + "ip_forward(): Argh! Destination lost!\n"); } - if (opt->ts_needaddr) - { + if (opt->ts_needaddr) { optptr = (unsigned char *)iph + opt->ts; memcpy(&optptr[optptr[2]-9], &dev2->pa_addr, 4); opt->is_changed = 1; } - if (opt->is_changed) - { + if (opt->is_changed) { opt->is_changed = 0; ip_send_check(iph); } @@ -555,65 +544,55 @@ * the fragmenter does the right thing. */ - if(skb2->len > dev2->mtu + dev2->hard_header_len) - { - ip_fragment(NULL,skb2,dev2, is_frag); - kfree_skb(skb2,FREE_WRITE); - } - else - { -#ifdef CONFIG_IP_ACCT + if (skb2->len > dev2->mtu + dev2->hard_header_len) { + ip_fragment(NULL, skb2, dev2, is_frag); + kfree_skb(skb2, FREE_WRITE); + } else { +#ifdef CONFIG_IP_ACCT /* * Count mapping we shortcut */ - - ip_fw_chk(iph,dev2,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT); -#endif - + + ip_fw_chk(iph, dev2, NULL, ip_acct_chain, + 0, IP_FW_MODE_ACCT_OUT); +#endif + /* * Map service types to priority. We lie about * throughput being low priority, but it's a good * choice to help improve general usage. */ - if(iph->tos & IPTOS_LOWDELAY) + if (iph->tos & IPTOS_LOWDELAY) dev_queue_xmit(skb2, dev2, SOPRI_INTERACTIVE); - else if(iph->tos & IPTOS_THROUGHPUT) + else if (iph->tos & IPTOS_THROUGHPUT) dev_queue_xmit(skb2, dev2, SOPRI_BACKGROUND); else dev_queue_xmit(skb2, dev2, SOPRI_NORMAL); } - } - else - { - if(rt) - ip_rt_put(rt); + } else { + if (rt) + ip_rt_put(rt); return -1; } - if(rt) + if (rt) ip_rt_put(rt); - + /* * Tell the caller if their buffer is free. - */ - - if(skb==skb2) - return 0; + */ + + if (skb == skb2) + return 0; -#ifdef CONFIG_IP_MASQUERADE +#ifdef CONFIG_IP_MASQUERADE /* * The original is free. Free our copy and * tell the caller not to free. */ - if(skb!=skb_in) - { + if (skb != skb_in) { kfree_skb(skb_in, FREE_WRITE); return 0; } -#endif +#endif return 1; } - - - - - diff -urN linux-2.0.39/net/ipv4/ip_fragment.c linux-2.0.40/net/ipv4/ip_fragment.c --- linux-2.0.39/net/ipv4/ip_fragment.c 1998-06-03 15:17:50.000000000 -0700 +++ linux-2.0.40/net/ipv4/ip_fragment.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,12 +4,13 @@ * interface as the means of communication with the user level. * * The IP fragmentation functionality. - * + * * Authors: Fred N. van Kempen * Alan Cox * * Fixes: - * Alan Cox : Split from ip.c , see ip_input.c for history. + * Alan Cox : Split from ip.c, see ip_input.c for + * history. * Alan Cox : Handling oversized frames * Uriel Maimon : Accounting errors in two fringe cases. */ @@ -37,16 +38,16 @@ * even the most extreme cases without allowing an attacker to measurably * harm machine performance. */ - -#define IPFRAG_HIGH_THRESH (256*1024) -#define IPFRAG_LOW_THRESH (192*1024) + +#define IPFRAG_HIGH_THRESH (256 * 1024) +#define IPFRAG_LOW_THRESH (192 * 1024) /* - * This fragment handler is a bit of a heap. On the other hand it works quite - * happily and handles things quite well. + * This fragment handler is a bit of a heap. On the other hand it works + * quite happily and handles things quite well. */ -static struct ipq *ipqueue = NULL; /* IP fragment queue */ +static struct ipq *ipqueue = NULL; /* IP fragment queue */ atomic_t ip_frag_mem = 0; /* Memory used for fragments */ @@ -55,28 +56,28 @@ /* * Memory Tracking Functions */ - + extern __inline__ void frag_kfree_skb(struct sk_buff *skb, int type) { atomic_sub(skb->truesize, &ip_frag_mem); - kfree_skb(skb,type); + kfree_skb(skb, type); } extern __inline__ void frag_kfree_s(void *ptr, int len) { atomic_sub(len, &ip_frag_mem); - kfree_s(ptr,len); + kfree_s(ptr, len); } - + extern __inline__ void *frag_kmalloc(int size, int pri) { - void *vp=kmalloc(size,pri); - if(!vp) + void *vp = kmalloc(size,pri); + if (!vp) return NULL; atomic_add(size, &ip_frag_mem); return vp; } - + /* * Create a new fragment entry. */ @@ -86,13 +87,12 @@ struct ipfrag *fp; unsigned long flags; - fp = (struct ipfrag *) frag_kmalloc(sizeof(struct ipfrag), GFP_ATOMIC); - if (fp == NULL) - { + fp = (struct ipfrag *)frag_kmalloc(sizeof (struct ipfrag), GFP_ATOMIC); + if (fp == NULL) { NETDEBUG(printk("IP: frag_create: no memory left !\n")); - return(NULL); + return NULL; } - memset(fp, 0, sizeof(struct ipfrag)); + memset(fp, 0, sizeof (struct ipfrag)); /* Fill in the structure. */ fp->offset = offset; @@ -100,20 +100,19 @@ fp->len = end - offset; fp->skb = skb; fp->ptr = ptr; - + /* * Charge for the SKB as well. */ - + save_flags(flags); cli(); - ip_frag_mem+=skb->truesize; + ip_frag_mem += skb->truesize; restore_flags(flags); - return(fp); + return fp; } - /* * Find the correct entry in the "incomplete datagrams" queue for * this IP datagram, and return the queue entry address if found. @@ -126,21 +125,22 @@ cli(); qplast = NULL; - for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next) - { - if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr && - iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol) - { - del_timer(&qp->timer); /* So it doesn't vanish on us. The timer will be reset anyway */ + for (qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next) { + if (iph->id == qp->iph->id && iph->saddr == qp->iph->saddr && + iph->daddr == qp->iph->daddr && + iph->protocol == qp->iph->protocol) { + /* So it doesn't vanish on us. The timer will be reset + * anyway + */ + del_timer(&qp->timer); sti(); - return(qp); + return qp; } } sti(); - return(NULL); + return NULL; } - /* * Remove an entry from the "incomplete datagrams" queue, either * because we completed, reassembled and processed it, or because @@ -160,14 +160,11 @@ /* Remove this entry from the "incomplete datagrams" queue. */ cli(); - if (qp->prev == NULL) - { + if (qp->prev == NULL) { ipqueue = qp->next; if (ipqueue != NULL) ipqueue->prev = NULL; - } - else - { + } else { qp->prev->next = qp->next; if (qp->next != NULL) qp->next->prev = qp->prev; @@ -176,12 +173,11 @@ /* Release all fragment data. */ fp = qp->fragments; - while (fp != NULL) - { + while (fp != NULL) { xp = fp->next; IS_SKB(fp->skb); - frag_kfree_skb(fp->skb,FREE_READ); - frag_kfree_s(fp, sizeof(struct ipfrag)); + frag_kfree_skb(fp->skb, FREE_READ); + frag_kfree_s(fp, sizeof (struct ipfrag)); fp = xp; } @@ -189,11 +185,10 @@ frag_kfree_s(qp->iph, 64 + 8); /* Finally, release the queue descriptor itself. */ - frag_kfree_s(qp, sizeof(struct ipq)); + frag_kfree_s(qp, sizeof (struct ipq)); sti(); } - /* * Oops- a fragment queue timed out. Kill it and send an ICMP reply. */ @@ -209,11 +204,20 @@ */ ip_statistics.IpReasmTimeout++; - ip_statistics.IpReasmFails++; + ip_statistics.IpReasmFails++; /* This if is always true... shrug */ - if(qp->fragments!=NULL) - icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, - ICMP_EXC_FRAGTIME, 0, qp->dev); + if (qp->fragments != NULL) { + struct sk_buff *skb = qp->fragments->skb; + struct iphdr *iph = skb->ip_hdr; + + /* ICMP send engine expects skb->data to be just + * past IP header. + */ + skb_pull(skb, iph->ihl * 4); + + icmp_send(skb, ICMP_TIME_EXCEEDED, + ICMP_EXC_FRAGTIME, 0, qp->dev, 1); + } /* * Nuke the fragment queue. @@ -222,25 +226,24 @@ } /* - * Memory limiting on fragments. Evictor trashes the oldest + * Memory limiting on fragments. Evictor trashes the oldest * fragment queue until we are back under the low threshold */ - + static void ip_evictor(void) { - while(ip_frag_mem>IPFRAG_LOW_THRESH) - { - if(!ipqueue) + while (ip_frag_mem > IPFRAG_LOW_THRESH) { + if (!ipqueue) panic("ip_evictor: memcount"); ip_free(ipqueue); } } /* - * Add an entry to the 'ipq' queue for a newly received IP datagram. - * We will (hopefully :-) receive all other fragments of this datagram - * in time, so we just create a queue for this datagram, in which we - * will insert the received fragments at their respective positions. + * Add an entry to the 'ipq' queue for a newly received IP datagram. + * We will (hopefully :-) receive all other fragments of this datagram + * in time, so we just create a queue for this datagram, in which we + * will insert the received fragments at their respective positions. */ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev) @@ -248,13 +251,12 @@ struct ipq *qp; int ihlen; - qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC); - if (qp == NULL) - { + qp = (struct ipq *)frag_kmalloc(sizeof (struct ipq), GFP_ATOMIC); + if (qp == NULL) { NETDEBUG(printk("IP: create: no memory left !\n")); - return(NULL); + return NULL; } - memset(qp, 0, sizeof(struct ipq)); + memset(qp, 0, sizeof (struct ipq)); /* * Allocate memory for the IP header (plus 8 octets for ICMP). @@ -262,11 +264,10 @@ ihlen = iph->ihl * 4; qp->iph = (struct iphdr *) frag_kmalloc(64 + 8, GFP_ATOMIC); - if (qp->iph == NULL) - { + if (qp->iph == NULL) { NETDEBUG(printk("IP: create: no memory left !\n")); - frag_kfree_s(qp, sizeof(struct ipq)); - return(NULL); + frag_kfree_s(qp, sizeof (struct ipq)); + return NULL; } memcpy(qp->iph, iph, ihlen + 8); @@ -277,7 +278,7 @@ /* Start a timer for this entry. */ qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ - qp->timer.data = (unsigned long) qp; /* pointer to queue */ + qp->timer.data = (unsigned long)qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); @@ -289,10 +290,9 @@ qp->next->prev = qp; ipqueue = qp; sti(); - return(qp); + return qp; } - /* * See if a fragment queue is complete. */ @@ -304,30 +304,28 @@ /* Only possible if we received the final fragment. */ if (qp->len == 0) - return(0); + return 0; /* Check all fragment offsets to see if they connect. */ fp = qp->fragments; offset = 0; - while (fp != NULL) - { + while (fp != NULL) { if (fp->offset > offset) - return(0); /* fragment(s) missing */ + return 0; /* fragment(s) missing */ offset = fp->end; fp = fp->next; } /* All fragments are present. */ - return(1); + return 1; } - /* * Build a new IP datagram from all its fragments. * * FIXME: We copy here because we lack an effective way of handling lists * of bits on input. Until the new skb data handling is in I'm not going - * to touch this with a bargepole. + * to touch this with a bargepole. */ static struct sk_buff *ip_glue(struct ipq *qp) @@ -342,21 +340,20 @@ * Allocate a new buffer for the datagram. */ len = qp->ihlen + qp->len; - - if(len>65535) - { - NETDEBUG(printk("Oversized IP packet from %s.\n", in_ntoa(qp->iph->saddr))); + + if (len > 65535) { + NETDEBUG(printk("Oversized IP packet from %s.\n", + in_ntoa(qp->iph->saddr))); ip_statistics.IpReasmFails++; ip_free(qp); return NULL; } - - if ((skb = dev_alloc_skb(len)) == NULL) - { + + if ((skb = dev_alloc_skb(len)) == NULL) { ip_statistics.IpReasmFails++; NETDEBUG(printk("IP: queue_glue: no memory for gluing queue %p\n", qp)); ip_free(qp); - return(NULL); + return NULL; } /* Fill in the basic details. */ @@ -365,21 +362,19 @@ skb->free = 1; /* Copy the original IP headers into the new buffer. */ - ptr = (unsigned char *) skb->h.raw; - memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen); + ptr = (unsigned char *)skb->h.raw; + memcpy(ptr, ((unsigned char *)qp->iph), qp->ihlen); ptr += qp->ihlen; count = 0; /* Copy the data portions of all fragments into the new buffer. */ fp = qp->fragments; - while(fp != NULL) - { - if (fp->len < 0 || fp->offset+qp->ihlen+fp->len > skb->len) - { + while (fp != NULL) { + if (fp->len < 0 || fp->offset+qp->ihlen+fp->len > skb->len) { NETDEBUG(printk("Invalid fragment list: Fragment over size.\n")); ip_free(qp); - kfree_skb(skb,FREE_WRITE); + kfree_skb(skb, FREE_WRITE); ip_statistics.IpReasmFails++; return NULL; } @@ -400,10 +395,9 @@ skb->ip_hdr = iph; ip_statistics.IpReasmOKs++; - return(skb); + return skb; } - /* * Process an incoming IP datagram fragment. */ @@ -417,30 +411,30 @@ unsigned char *ptr; int flags, offset; int i, ihl, end; - + ip_statistics.IpReasmReqds++; /* * Start by cleaning up the memory */ - if(ip_frag_mem>IPFRAG_HIGH_THRESH) + if (ip_frag_mem > IPFRAG_HIGH_THRESH) ip_evictor(); - /* - * Find the entry of this IP datagram in the "incomplete datagrams" queue. + /* + * Find the entry of this IP datagram in the "incomplete + * datagrams" queue. */ - + qp = ip_find(iph); /* Is this a non-fragmented datagram? */ offset = ntohs(iph->frag_off); flags = offset & ~IP_OFFSET; offset &= IP_OFFSET; - if (((flags & IP_MF) == 0) && (offset == 0)) - { + if (((flags & IP_MF) == 0) && (offset == 0)) { if (qp != NULL) ip_free(qp); /* Fragmented frame replaced by full unfragmented copy */ - return(skb); + return skb; } offset <<= 3; /* offset is in 8-byte chunks */ @@ -452,48 +446,43 @@ * queue entry. */ - if (qp != NULL) - { + if (qp != NULL) { /* ANK. If the first fragment is received, * we should remember the correct IP header (with options) */ - if (offset == 0) - { + if (offset == 0) { qp->ihlen = ihl; - memcpy(qp->iph, iph, ihl+8); + memcpy(qp->iph, iph, ihl + 8); } del_timer(&qp->timer); qp->timer.expires = jiffies + IP_FRAG_TIME; /* about 30 seconds */ qp->timer.data = (unsigned long) qp; /* pointer to queue */ qp->timer.function = ip_expire; /* expire function */ add_timer(&qp->timer); - } - else - { + } else { /* * If we failed to create it, then discard the frame */ - if ((qp = ip_create(skb, iph, dev)) == NULL) - { + if ((qp = ip_create(skb, iph, dev)) == NULL) { skb->sk = NULL; kfree_skb(skb, FREE_READ); ip_statistics.IpReasmFails++; return NULL; } } - + /* * Attempt to construct an oversize packet. */ - - if(ntohs(iph->tot_len)+(int)offset>65535) - { + + if (ntohs(iph->tot_len) + (int)offset > 65535) { skb->sk = NULL; - NETDEBUG(printk("Oversized packet received from %s\n",in_ntoa(iph->saddr))); + NETDEBUG(printk("Oversized packet received from %s\n", + in_ntoa(iph->saddr))); kfree_skb(skb, FREE_READ); ip_statistics.IpReasmFails++; return NULL; - } + } /* * Determine the position of this fragment. @@ -515,26 +504,24 @@ qp->len = end; /* - * Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? + * Find out which fragments are in front and at the back of us + * in the chain of fragments so far. We must know where to put + * this fragment, right? */ prev = NULL; - for(next = qp->fragments; next != NULL; next = next->next) - { + for (next = qp->fragments; next != NULL; next = next->next) { if (next->offset >= offset) break; /* bingo! */ prev = next; } /* - * We found where to put this one. - * Check for overlap with preceding fragment, and, if needed, - * align things so that any overlaps are eliminated. + * We found where to put this one. + * Check for overlap with preceding fragment, and, if needed, + * align things so that any overlaps are eliminated. */ - if (prev != NULL && offset < prev->end) - { + if (prev != NULL && offset < prev->end) { i = prev->end - offset; offset += i; /* ptr into datagram */ ptr += i; /* ptr into fragment data */ @@ -545,15 +532,14 @@ * If we can merge fragments, do it. */ - for(tmp=next; tmp != NULL; tmp = tfp) - { + for (tmp = next; tmp != NULL; tmp = tfp) { tfp = tmp->next; if (tmp->offset >= end) break; /* no overlaps at all */ - i = end - next->offset; /* overlap is 'i' bytes */ - tmp->len -= i; /* so reduce size of */ - tmp->offset += i; /* next fragment */ + i = end - next->offset; /* overlap is 'i' bytes */ + tmp->len -= i; /* so reduce size of */ + tmp->offset += i; /* next fragment */ tmp->ptr += i; /* * If we get a frag size of <= 0, remove it and the packet @@ -562,8 +548,7 @@ * We never throw the new frag away, so the frag being * dumped has always been charged for. */ - if (tmp->len <= 0) - { + if (tmp->len <= 0) { if (tmp->prev != NULL) tmp->prev->next = tmp->next; else @@ -571,11 +556,11 @@ if (tmp->next != NULL) tmp->next->prev = tmp->prev; - - next=tfp; /* We have killed the original next frame */ - frag_kfree_skb(tmp->skb,FREE_READ); - frag_kfree_s(tmp, sizeof(struct ipfrag)); + next = tfp; /* We have killed the original next frame */ + + frag_kfree_skb(tmp->skb, FREE_READ); + frag_kfree_s(tmp, sizeof (struct ipfrag)); } } @@ -591,17 +576,16 @@ * failed the frag_create we haven't charged the queue. */ - if (!tfp) - { + if (!tfp) { skb->sk = NULL; kfree_skb(skb, FREE_READ); return NULL; } - + /* * From now on our buffer is charged to the queues. */ - + tfp->prev = prev; tfp->next = next; if (prev != NULL) @@ -613,32 +597,31 @@ next->prev = tfp; /* - * OK, so we inserted this new fragment into the chain. - * Check if we now have a full IP datagram which we can - * bump up to the IP layer... + * OK, so we inserted this new fragment into the chain. + * Check if we now have a full IP datagram which we can + * bump up to the IP layer... */ - if (ip_done(qp)) - { + if (ip_done(qp)) { skb2 = ip_glue(qp); /* glue together the fragments */ - return(skb2); + return skb2; } - return(NULL); + return NULL; } /* - * This IP datagram is too large to be sent in one piece. Break it up into - * smaller pieces (each of size equal to the MAC header plus IP header plus - * a block of the data of the original IP data part) that will yet fit in a - * single device frame, and queue such a frame for sending by calling the - * ip_queue_xmit(). Note that this is recursion, and bad things will happen - * if this function causes a loop... + * This IP datagram is too large to be sent in one piece. Break it up + * into smaller pieces (each of size equal to the MAC header plus IP + * header plus a block of the data of the original IP data part) that will + * yet fit in a single device frame, and queue such a frame for sending by + * calling the ip_queue_xmit(). Note that this is recursion, and bad + * things will happen if this function causes a loop... * * Yes this is inefficient, feel free to submit a quicker one. * */ - + void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag) { struct iphdr *iph; @@ -647,7 +630,7 @@ struct sk_buff *skb2; int left, mtu, hlen, len; int offset; - + unsigned short true_hard_header_len; /* @@ -656,7 +639,7 @@ raw = skb->data; #if 0 - iph = (struct iphdr *) (raw + dev->hard_header_len); + iph = (struct iphdr *) (raw + dev->hard_header_len); skb->ip_hdr = iph; #else iph = skb->ip_hdr; @@ -682,23 +665,22 @@ * Check for any "DF" flag. [DF means do not fragment] */ - if (iph->frag_off & htons(IP_DF)) - { + if (iph->frag_off & htons(IP_DF)) { ip_statistics.IpFragFails++; NETDEBUG(printk("ip_queue_xmit: frag needed\n")); return; } /* - * The protocol doesn't seem to say what to do in the case that the - * frame + options doesn't fit the mtu. As it used to fall down dead - * in this case we were fortunate it didn't happen + * The protocol doesn't seem to say what to do in the case that + * the frame + options doesn't fit the mtu. As it used to fall + * down dead in this case we were fortunate it didn't happen */ - if(mtu<8) - { + if (mtu < 8) { /* It's wrong but it's better than nothing */ - icmp_send(skb,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,htons(dev->mtu), dev); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htons(dev->mtu), dev, 1); ip_statistics.IpFragFails++; return; } @@ -717,30 +699,26 @@ else offset = 0; - /* * Keep copying data until we run out. */ - while(left > 0) - { + while (left > 0) { len = left; /* 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; + if (len < left) { + len /= 8; + len *= 8; } /* * Allocate buffer. */ - if ((skb2 = alloc_skb(len + hlen+15,GFP_ATOMIC)) == NULL) - { + if ((skb2 = alloc_skb(len + hlen + 15, GFP_ATOMIC)) == NULL) { NETDEBUG(printk("IP: frag: no memory for new fragment!\n")); ip_statistics.IpFragFails++; return; @@ -752,22 +730,22 @@ skb2->arp = skb->arp; skb2->protocol = htons(ETH_P_IP); /* Atleast PPP needs this */ -#if 0 - if(skb->free==0) - printk(KERN_ERR "IP fragmenter: BUG free!=1 in fragmenter\n"); -#endif +#if 0 + if (skb->free == 0) + printk(KERN_ERR + "IP fragmenter: BUG free!=1 in fragmenter\n"); +#endif skb2->free = 1; - skb_put(skb2,len + hlen); - skb2->h.raw=(char *) skb2->data; + skb_put(skb2, len + hlen); + skb2->h.raw = (char *) skb2->data; /* * Charge the memory for the fragment to any owner * it might possess */ - if (sk) - { + if (sk) { atomic_add(skb2->truesize, &sk->wmem_alloc); - skb2->sk=sk; + skb2->sk = sk; } skb2->raddr = skb->raddr; /* For rebuild_header - must be here */ @@ -783,7 +761,7 @@ memcpy(skb2->h.raw + hlen, ptr, len); left -= len; - skb2->h.raw+=true_hard_header_len; + skb2->h.raw += true_hard_header_len; /* * Fill in the new header fields. @@ -802,8 +780,8 @@ ip_options_fragment(skb); /* - * Added AC : If we are fragmenting a fragment that's not the - * last fragment then keep MF on each bit + * Added AC: If we are fragmenting a fragment that's not + * the last fragment then keep MF on each bit */ if (left > 0 || (is_frag & 1)) iph->frag_off |= htons(IP_MF); @@ -820,5 +798,3 @@ } ip_statistics.IpFragOKs++; } - - diff -urN linux-2.0.39/net/ipv4/ip_fw.c linux-2.0.40/net/ipv4/ip_fw.c --- linux-2.0.39/net/ipv4/ip_fw.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/net/ipv4/ip_fw.c 2004-02-07 23:13:01.000000000 -0800 @@ -80,7 +80,6 @@ * This software is provided ``AS IS'' without any warranties of any kind. */ -#include #include #include #include diff -urN linux-2.0.39/net/ipv4/ip_input.c linux-2.0.40/net/ipv4/ip_input.c --- linux-2.0.39/net/ipv4/ip_input.c 1998-11-15 10:33:21.000000000 -0800 +++ linux-2.0.40/net/ipv4/ip_input.c 2004-02-07 23:13:01.000000000 -0800 @@ -15,28 +15,34 @@ * Stefan Becker, * Jorge Cwik, * Arnt Gulbrandsen, - * + * * * Fixes: - * Alan Cox : Commented a couple of minor bits of surplus code - * Alan Cox : Undefining IP_FORWARD doesn't include the code + * Alan Cox : Commented a couple of minor bits of + * surplus code + * Alan Cox : Undefining IP_FORWARD doesn't include + * the code * (just stops a compiler warning). - * Alan Cox : Frames with >=MAX_ROUTE record routes, strict routes or loose routes - * are junked rather than corrupting things. - * Alan Cox : Frames to bad broadcast subnets are dumped - * We used to process them non broadcast and - * boy could that cause havoc. + * Alan Cox : Frames with >= MAX_ROUTE record routes, + * strict routes or loose routes are + * junked rather than corrupting things. + * Alan Cox : Frames to bad broadcast subnets + * are dumped + * We used to process them non broadcast + * and boy could that cause havoc. * Alan Cox : ip_forward sets the free flag on the * new frame it queues. Still crap because * it copies the frame but at least it * doesn't eat memory too. * Alan Cox : Generic queue code and memory fixes. - * Fred Van Kempen : IP fragment support (borrowed from NET2E) + * Fred Van Kempen : IP fragment support + * (borrowed from NET2E) * Gerhard Koerting: Forward fragmented frames correctly. - * Gerhard Koerting: Fixes to my fix of the above 8-). + * Gerhard Koerting: Fixes to my fix of the above 8-). * Gerhard Koerting: IP interface addressing fix. * Linus Torvalds : More robustness checks - * Alan Cox : Even more checks: Still not as robust as it ought to be + * Alan Cox : Even more checks: Still not as robust + * as it ought to be * Alan Cox : Save IP header pointer for later * Alan Cox : ip option setting * Alan Cox : Use ip_tos/ip_ttl settings @@ -55,13 +61,15 @@ * Alan Cox : BSD address rule semantics. Also see * UDP as there is a nasty checksum issue * if you do things the wrong way. - * Alan Cox : Always defrag, moved IP_FORWARD to the config.in file - * Alan Cox : IP options adjust sk->priority. + * Alan Cox : Always defrag, moved IP_FORWARD to the + * config.in file + * Alan Cox : IP options adjust sk->priority. * Pedro Roque : Fix mtu/length error in ip_forward. * Alan Cox : Avoid ip_chk_addr when possible. * Richard Underwood : IP multicasting. * Alan Cox : Cleaned up multicast handlers. - * Alan Cox : RAW sockets demultiplex in the BSD style. + * Alan Cox : RAW sockets demultiplex in the BSD + * style. * Gunther Mayer : Fix the SNMP reporting typo * Alan Cox : Always in group 224.0.0.1 * Pauline Middelink : Fast ip_checksum update when forwarding @@ -75,17 +83,22 @@ * Arnt Gulbrandsen : ip_build_xmit * Alan Cox : Per socket routing cache * Alan Cox : Fixed routing cache, added header cache. - * Alan Cox : Loopback didn't work right in original ip_build_xmit - fixed it. - * Alan Cox : Only send ICMP_REDIRECT if src/dest are the same net. + * Alan Cox : Loopback didn't work right in original + * ip_build_xmit - fixed it. + * Alan Cox : Only send ICMP_REDIRECT if src/dest are + * the same net. * Alan Cox : Incoming IP option handling. - * Alan Cox : Set saddr on raw output frames as per BSD. - * Alan Cox : Stopped broadcast source route explosions. + * Alan Cox : Set saddr on raw output frames as per + * BSD. + * Alan Cox : Stopped broadcast source route + * explosions. * Alan Cox : Can disable source routing * Takeshi Sone : Masquerading didn't work. * Dave Bonn,Alan Cox : Faster IP forwarding whenever possible. * Alan Cox : Memory leaks, tramples, misc debugging. * Alan Cox : Fixed multicast (by popular demand 8)) - * Alan Cox : Fixed forwarding (by even more popular demand 8)) + * Alan Cox : Fixed forwarding (by even more popular + * demand 8)) * Alan Cox : Fixed SNMP statistics [I think] * Gerhard Koerting : IP fragmentation forwarding fix * Alan Cox : Device lock against page fault. @@ -98,16 +111,19 @@ * Jos Vos : Do accounting *before* call_in_firewall * Willy Konynenberg : Transparent proxying support * - * + * * * To Fix: - * IP fragmentation wants rewriting cleanly. The RFC815 algorithm is much more efficient - * and could be made very efficient with the addition of some virtual memory hacks to permit - * the allocation of a buffer that can then be 'grown' by twiddling page tables. - * Output fragmentation wants updating along with the buffer management to use a single - * interleaved copy algorithm so that fragmenting has a one copy overhead. Actual packet - * output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause - * fragmentation anyway. + * IP fragmentation wants rewriting cleanly. The RFC815 algorithm + * is much more efficient and could be made very efficient with + * the addition of some virtual memory hacks to permit the + * allocation of a buffer that can then be 'grown' by twiddling + * page tables. + * Output fragmentation wants updating along with the buffer + * management to use a single interleaved copy algorithm so that + * fragmenting has a one copy overhead. Actual packet output + * should probably do its own fragmentation at the UDP/RAW layer. + * TCP shouldn't cause fragmentation anyway. * * FIXME: copy frag 0 iph to qp->iph * @@ -163,16 +179,16 @@ extern int last_retran; extern void sort_send(struct sock *sk); -#define min(a,b) ((a)<(b)?(a):(b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) /* * SNMP management statistics */ #ifdef CONFIG_IP_FORWARD -struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */ +struct ip_mib ip_statistics = {1, 64,}; /* Forwarding = Yes, Default TTL = 64 */ #else -struct ip_mib ip_statistics={2,64,}; /* Forwarding=No, Default TTL=64 */ +struct ip_mib ip_statistics = {2, 64,}; /* Forwarding = No, Default TTL = 64 */ #endif /* @@ -183,11 +199,7 @@ int ip_ioctl(struct sock *sk, int cmd, unsigned long arg) { - switch(cmd) - { - default: - return(-EINVAL); - } + return -EINVAL; } #ifdef CONFIG_IP_TRANSPARENT_PROXY @@ -207,8 +219,10 @@ case IPPROTO_UDP: return udp_chkaddr(skb); default: - return 0; + break; } + + return 0; } #endif @@ -227,30 +241,30 @@ unsigned char hash; unsigned char flag = 0; struct inet_protocol *ipprot; - int brd=IS_MYADDR; + int brd = IS_MYADDR; struct options * opt = NULL; - int is_frag=0; + int is_frag = 0; __u32 daddr; #ifdef CONFIG_FIREWALL int fwres; __u16 rport; -#endif +#endif #ifdef CONFIG_IP_MROUTE - int mroute_pkt=0; -#endif + int mroute_pkt = 0; +#endif #ifdef CONFIG_NET_IPV6 - /* - * Intercept IPv6 frames. We dump ST-II and invalid types just below.. + /* + * Intercept IPv6 frames. We dump ST-II and invalid types just + * below.. */ - - if(iph->version == 6) - return ipv6_rcv(skb,dev,pt); -#endif - ip_statistics.IpInReceives++; + if (iph->version == 6) + return ipv6_rcv(skb, dev, pt); +#endif + ip_statistics.IpInReceives++; /* * Tag the ip header of this packet so we can find it @@ -259,36 +273,40 @@ skb->ip_hdr = iph; /* - * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. - * RFC1122: 3.1.2.3 MUST discard a frame with invalid source address [NEEDS FIXING]. + * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails + * the checksum. + * RFC1122: 3.1.2.3 MUST discard a frame with invalid source + * address [NEEDS FIXING]. * * Is the datagram acceptable? * * 1. Length at least the size of an ip header * 2. Version of 4 - * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] + * 3. Checksums correctly. [Speed optimisation for later, + * skip loopback checksums] * 4. Doesn't have a bogus length - * (5. We ought to check for IP multicast addresses and undefined types.. does this matter ?) + * (5. We ought to check for IP multicast addresses and + * undefined types.. does this matter ?) */ - if (skb->lenihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0 - || skb->len < ntohs(iph->tot_len)) - { + if (skb->len < sizeof (struct iphdr) || + iph->ihl < 5 || iph->version != 4 || + ip_fast_csum((unsigned char *)iph, iph->ihl) != 0 || + skb->len < ntohs(iph->tot_len)) { ip_statistics.IpInHdrErrors++; kfree_skb(skb, FREE_WRITE); - return(0); + return 0; } /* - * Our transport medium may have padded the buffer out. Now we know it - * is IP we can trim to the true length of the frame. + * Our transport medium may have padded the buffer out. Now we + * know it is IP we can trim to the true length of the frame. * Note this now means skb->len holds ntohs(iph->tot_len). */ skb_trim(skb,ntohs(iph->tot_len)); - - if(skb->len < (iph->ihl<<2)) - { + + if (skb->len < (iph->ihl << 2)) { ip_statistics.IpInHdrErrors++; kfree_skb(skb, FREE_WRITE); return 0; @@ -302,39 +320,39 @@ */ #ifdef CONFIG_IP_ACCT - ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN); -#endif + ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_IN); +#endif /* * Try to select closest alias device, if any. - * net_alias_dev_rx32 returns main device if it + * net_alias_dev_rx32 returns main device if it * fails to found other. - * If successful, also incr. alias rx count. + * If successful, also incr. alias rx count. * * Only makes sense for unicasts - Thanks ANK. */ #ifdef CONFIG_NET_ALIAS - if (skb->pkt_type == PACKET_HOST && iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) { - skb->dev = dev = net_alias_dev_rx32(skb->dev, AF_INET, iph->saddr, iph->daddr); + if (skb->pkt_type == PACKET_HOST && + iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) { + skb->dev = dev = net_alias_dev_rx32(skb->dev, AF_INET, + iph->saddr, iph->daddr); } #endif - if (iph->ihl > 5) - { + if (iph->ihl > 5) { skb->ip_summed = 0; if (ip_options_compile(NULL, skb)) - return(0); + return 0; opt = (struct options*)skb->proto_priv; #ifdef CONFIG_IP_NOSR - if (opt->srr) - { + if (opt->srr) { kfree_skb(skb, FREE_READ); return -EINVAL; } -#endif +#endif } - + #if defined(CONFIG_IP_TRANSPARENT_PROXY) && !defined(CONFIG_IP_ALWAYS_DEFRAG) #define CONFIG_IP_ALWAYS_DEFRAG 1 #endif @@ -351,30 +369,28 @@ /* * See if the frame is fragmented. */ - - if(iph->frag_off) - { + + if (iph->frag_off) { if (iph->frag_off & htons(IP_MF)) - is_frag|=IPFWD_FRAGMENT; + is_frag |= IPFWD_FRAGMENT; /* - * Last fragment ? + * Last fragment? */ - + if (iph->frag_off & htons(IP_OFFSET)) - is_frag|=IPFWD_LASTFRAG; - + is_frag |= IPFWD_LASTFRAG; + /* * Reassemble IP fragments. */ - if(is_frag) - { + if (is_frag) { /* Defragment. Obtain the complete packet if there is one */ - skb=ip_defrag(iph,skb,dev); - if(skb==NULL) + skb = ip_defrag(iph, skb, dev); + if (skb == NULL) return 0; skb->dev = dev; - iph=skb->h.iph; + iph = skb->h.iph; is_frag = 0; /* * When the reassembled packet gets forwarded, the ip @@ -389,51 +405,51 @@ #endif /* - * See if the firewall wants to dispose of the packet. + * See if the firewall wants to dispose of the packet. */ - -#ifdef CONFIG_FIREWALL - if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport))dev, + iph, &rport)) < FW_ACCEPT) { + if (fwres == FW_REJECT) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, + 0, dev, 1); kfree_skb(skb, FREE_WRITE); - return 0; + return 0; } #ifdef CONFIG_IP_TRANSPARENT_PROXY - if (fwres==FW_REDIRECT) + if (fwres == FW_REDIRECT) skb->redirport = rport; else #endif skb->redirport = 0; #endif - + #ifndef CONFIG_IP_ALWAYS_DEFRAG /* * Remember if the frame is fragmented. */ - - if(iph->frag_off) - { + + if (iph->frag_off) { if (iph->frag_off & htons(IP_MF)) - is_frag|=IPFWD_FRAGMENT; + is_frag |= IPFWD_FRAGMENT; /* - * Last fragment ? + * Last fragment? */ - + if (iph->frag_off & htons(IP_OFFSET)) - is_frag|=IPFWD_LASTFRAG; + is_frag |= IPFWD_LASTFRAG; } - + #endif /* - * Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. + * Do any IP forwarding required. chk_addr() is expensive -- + * avoid it someday. * - * This is inefficient. While finding out if it is for us we could also compute - * the routing table entry. This is where the great unified cache theory comes - * in as and when someone implements it + * This is inefficient. While finding out if it is for us we could + * also compute the routing table entry. This is where the great + * unified cache theory comes in as and when someone implements it * * For most hosts over 99% of packets match the first conditional * and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at @@ -444,58 +460,54 @@ /* * ip_chksock adds still more overhead for forwarded traffic... */ - if ( iph->daddr == skb->dev->pa_addr || skb->redirport || (brd = ip_chk_addr(iph->daddr)) != 0 || ip_chksock(skb)) + if (iph->daddr == skb->dev->pa_addr || skb->redirport || + (brd = ip_chk_addr(iph->daddr)) != 0 || ip_chksock(skb)) { #else - if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0) + if (iph->daddr == skb->dev->pa_addr || + (brd = ip_chk_addr(iph->daddr)) != 0) { #endif - { - if (opt && opt->srr) - { + if (opt && opt->srr) { int srrspace, srrptr; __u32 nexthop; - unsigned char * optptr = ((unsigned char *)iph) + opt->srr; + unsigned char * optptr = ((unsigned char *)iph) + + opt->srr; - if (brd != IS_MYADDR || skb->pkt_type != PACKET_HOST) - { + if (brd != IS_MYADDR || skb->pkt_type != PACKET_HOST) { kfree_skb(skb, FREE_WRITE); return 0; } - for ( srrptr=optptr[2], srrspace = optptr[1]; - srrptr <= srrspace; - srrptr += 4 - ) - { + for (srrptr=optptr[2], srrspace = optptr[1]; + srrptr <= srrspace; srrptr += 4) { int brd2; - if (srrptr + 3 > srrspace) - { - icmp_send(skb, ICMP_PARAMETERPROB, 0, opt->srr+2, - skb->dev); + if (srrptr + 3 > srrspace) { + icmp_send(skb, ICMP_PARAMETERPROB, 0, + opt->srr + 2, skb->dev, 1); kfree_skb(skb, FREE_WRITE); return 0; } - memcpy(&nexthop, &optptr[srrptr-1], 4); + memcpy(&nexthop, &optptr[srrptr - 1], 4); if ((brd2 = ip_chk_addr(nexthop)) == 0) break; - if (brd2 != IS_MYADDR) - { - + if (brd2 != IS_MYADDR) { /* - * ANK: should we implement weak tunneling of multicasts? - * Are they obsolete? DVMRP specs (RFC-1075) is old enough... + * ANK: should we implement weak + * tunneling of multicasts? + * Are they obsolete? DVMRP specs + * (RFC-1075) is old enough... * [They are obsolete] */ kfree_skb(skb, FREE_WRITE); return -EINVAL; } - memcpy(&daddr, &optptr[srrptr-1], 4); + memcpy(&daddr, &optptr[srrptr - 1], 4); } - if (srrptr <= srrspace) - { + if (srrptr <= srrspace) { opt->srr_is_hit = 1; opt->is_changed = 1; if (sysctl_ip_forward) { - if (ip_forward(skb, dev, is_frag, nexthop)) + if (ip_forward(skb, dev, is_frag, + nexthop)) kfree_skb(skb, FREE_WRITE); } else { ip_statistics.IpInAddrErrors++; @@ -505,25 +517,23 @@ } } -#ifdef CONFIG_IP_MULTICAST - if(!(dev->flags&IFF_ALLMULTI) && brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK)) - { +#ifdef CONFIG_IP_MULTICAST + if (!(dev->flags & IFF_ALLMULTI) && brd == IS_MULTICAST && + iph->daddr != IGMP_ALL_HOSTS && + !(dev->flags & IFF_LOOPBACK)) { /* * Check it is for one of our groups */ struct ip_mc_list *ip_mc=dev->ip_mc_list; - do - { - if(ip_mc==NULL) - { + do { + if (ip_mc == NULL) { kfree_skb(skb, FREE_WRITE); return 0; } - if(ip_mc->multiaddr==iph->daddr) + if (ip_mc->multiaddr == iph->daddr) break; - ip_mc=ip_mc->next; - } - while(1); + ip_mc = ip_mc->next; + } while (1); } #endif @@ -532,14 +542,13 @@ * Reassemble IP fragments. */ - if(is_frag) - { + if (is_frag) { /* Defragment. Obtain the complete packet if there is one */ - skb=ip_defrag(iph,skb,dev); - if(skb==NULL) + skb = ip_defrag(iph,skb,dev); + if (skb == NULL) return 0; skb->dev = dev; - iph=skb->h.iph; + iph = skb->h.iph; } #endif @@ -555,10 +564,10 @@ return 0; } - if (ret) - { - struct iphdr *iph=skb->h.iph; - if (ip_forward(skb, dev, IPFWD_MASQUERADED, iph->daddr)) + if (ret) { + struct iphdr *iph = skb->h.iph; + if (ip_forward(skb, dev, IPFWD_MASQUERADED, + iph->daddr)) kfree_skb(skb, FREE_WRITE); return 0; } @@ -570,99 +579,109 @@ */ skb->ip_hdr = iph; - skb->h.raw += iph->ihl*4; + skb->h.raw += iph->ihl * 4; -#ifdef CONFIG_IP_MROUTE +#ifdef CONFIG_IP_MROUTE /* * Check the state on multicast routing (multicast and not 224.0.0.z) */ - - if(brd==IS_MULTICAST && (iph->daddr&htonl(0xFFFFFF00))!=htonl(0xE0000000)) - mroute_pkt=1; + + if (brd == IS_MULTICAST && + (iph->daddr & htonl(0xFFFFFF00)) != htonl(0xE0000000)) + mroute_pkt = 1; #endif /* - * Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies. + * Deliver to raw sockets. This is fun as to avoid copies + * we want to make no surplus copies. * - * RFC 1122: SHOULD pass TOS value up to the transport layer. + * RFC 1122: SHOULD pass TOS value up to the transport + * layer. + */ + + /* Note: See raw.c and net/raw.h, + * RAWV4_HTABLE_SIZE == MAX_INET_PROTOS */ - - /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ hash = iph->protocol & (MAX_INET_PROTOS - 1); - /* - * If there maybe a raw socket we must check - if not we don't care less + /* + * If there maybe a raw socket we must check - if not we + * don't care less */ - - if((raw_sk = raw_v4_htable[hash]) != NULL) { + + if ((raw_sk = raw_v4_htable[hash]) != NULL) { struct sock *sknext = NULL; struct sk_buff *skb1; raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr); - if(raw_sk) { /* Any raw sockets */ + if (raw_sk) { /* Any raw sockets */ do { /* Find the next */ sknext = raw_v4_lookup(raw_sk->next, iph->protocol, iph->saddr, iph->daddr); - if(sknext) - skb1 = skb_clone(skb, GFP_ATOMIC); + if (sknext) + skb1 = skb_clone(skb, + GFP_ATOMIC); else break; /* One pending raw socket left */ - if(skb1) - raw_rcv(raw_sk, skb1, dev, iph->saddr,daddr); + if (skb1) + raw_rcv(raw_sk, skb1, dev, + iph->saddr,daddr); raw_sk = sknext; - } while(raw_sk!=NULL); - + } while (raw_sk != NULL); + /* - * Here either raw_sk is the last raw socket, or NULL if none + * Here either raw_sk is the last raw + * socket, or NULL if none */ - + /* - * We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy + * We deliver to the last raw socket AFTER + * the protocol checks as it avoids a + * surplus copy */ } } - + /* * skb->h.raw now points at the protocol beyond the IP header. */ - - for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next) - { + + for (ipprot = (struct inet_protocol *)inet_protos[hash]; + ipprot != NULL; + ipprot = (struct inet_protocol *)ipprot->next) { struct sk_buff *skb2; - + if (ipprot->protocol != iph->protocol) continue; /* - * See if we need to make a copy of it. This will - * only be set if more than one protocol wants it. - * and then not for the last one. If there is a pending - * raw delivery wait for that + * See if we need to make a copy of it. This will + * only be set if more than one protocol wants it. + * and then not for the last one. If there is a + * pending raw delivery wait for that */ - + #ifdef CONFIG_IP_MROUTE - if (ipprot->copy || raw_sk || mroute_pkt) -#else - if (ipprot->copy || raw_sk) -#endif - { + if (ipprot->copy || raw_sk || mroute_pkt) { +#else + if (ipprot->copy || raw_sk) { +#endif skb2 = skb_clone(skb, GFP_ATOMIC); - if(skb2==NULL) + if (skb2 == NULL) continue; - } - else - { + } else { skb2 = skb; } flag = 1; /* - * Pass on the datagram to each protocol that wants it, - * based on the datagram protocol. We should really - * check the protocol handler's return values here... + * Pass on the datagram to each protocol that + * wants it, based on the datagram protocol. We + * should really check the protocol handler's + * return values here... */ ipprot->handler(skb2, dev, opt, daddr, @@ -672,58 +691,56 @@ /* * All protocols checked. - * If this packet was a broadcast, we may *not* reply to it, since that - * causes (proven, grin) ARP storms and a leakage of memory (i.e. all - * ICMP reply messages get queued up for transmission...) + * If this packet was a broadcast, we may *not* reply to + * it, since that causes (proven, grin) ARP storms and a + * leakage of memory (i.e. all ICMP reply messages get + * queued up for transmission...) */ -#ifdef CONFIG_IP_MROUTE +#ifdef CONFIG_IP_MROUTE /* * Forward the last copy to the multicast router. If * there is a pending raw delivery however make a copy * and forward that. */ - - if(mroute_pkt) - { - flag=1; - if(raw_sk==NULL) + + if (mroute_pkt) { + flag = 1; + if (raw_sk == NULL) ipmr_forward(skb, is_frag); - else - { - struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC); - if(skb2) - { - skb2->free=1; + else { + struct sk_buff *skb2 = skb_clone(skb, + GFP_ATOMIC); + if (skb2) { + skb2->free = 1; ipmr_forward(skb2, is_frag); } } } -#endif +#endif - if(raw_sk!=NULL) /* Shift to last raw user */ + if (raw_sk != NULL) /* Shift to last raw user */ raw_rcv(raw_sk, skb, dev, iph->saddr, daddr); - else if (!flag) /* Free and report errors */ - { - if (brd != IS_BROADCAST && brd!=IS_MULTICAST) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0, dev); + else if (!flag) { /* Free and report errors */ + if (brd != IS_BROADCAST && brd != IS_MULTICAST) + icmp_send(skb, ICMP_DEST_UNREACH, + ICMP_PROT_UNREACH, 0, dev, 1); kfree_skb(skb, FREE_WRITE); } - return(0); + return 0; } /* * Do any unicast IP forwarding required. */ - + /* * Don't forward multicast or broadcast frames. */ - if(skb->pkt_type!=PACKET_HOST || brd==IS_BROADCAST) - { - kfree_skb(skb,FREE_WRITE); + if (skb->pkt_type != PACKET_HOST || brd == IS_BROADCAST) { + kfree_skb(skb, FREE_WRITE); return 0; } @@ -732,21 +749,20 @@ */ if (sysctl_ip_forward) { - if (opt && opt->is_strictroute) - { - icmp_send(skb, ICMP_PARAMETERPROB, 0, 16, skb->dev); + if (opt && opt->is_strictroute) { + icmp_send(skb, ICMP_PARAMETERPROB, 0, 16, skb->dev, 1); kfree_skb(skb, FREE_WRITE); return -1; } if (ip_forward(skb, dev, is_frag, iph->daddr)) kfree_skb(skb, FREE_WRITE); } else { -/* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", - iph->saddr,iph->daddr);*/ +/* + printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n", + iph->saddr, iph->daddr); +*/ ip_statistics.IpInAddrErrors++; kfree_skb(skb, FREE_WRITE); } - return(0); + return 0; } - - diff -urN linux-2.0.39/net/ipv4/ip_masq_quake.c linux-2.0.40/net/ipv4/ip_masq_quake.c --- linux-2.0.39/net/ipv4/ip_masq_quake.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/net/ipv4/ip_masq_quake.c 2004-02-07 23:13:01.000000000 -0800 @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff -urN linux-2.0.39/net/ipv4/ip_options.c linux-2.0.40/net/ipv4/ip_options.c --- linux-2.0.39/net/ipv4/ip_options.c 1996-04-17 23:47:39.000000000 -0700 +++ linux-2.0.40/net/ipv4/ip_options.c 2004-02-07 23:13:01.000000000 -0800 @@ -6,7 +6,7 @@ * The options processing module for ip.c * * Authors: A.N.Kuznetsov - * + * */ #include @@ -18,7 +18,7 @@ #include #include -/* +/* * Write options to IP header, record destination address to * source route option, address of outgoing interface * (we should already know it, so that this function is allowed be @@ -26,118 +26,104 @@ * if we originate this datagram. */ -void ip_options_build(struct sk_buff * skb, struct options * opt, - __u32 daddr, __u32 saddr, - int is_frag) +void ip_options_build(struct sk_buff *skb, struct options *opt, + __u32 daddr, __u32 saddr, int is_frag) { - unsigned char * iph = (unsigned char*)skb->ip_hdr; + unsigned char *iph = (unsigned char *)skb->ip_hdr; - memcpy(skb->proto_priv, opt, sizeof(struct options)); - memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); - opt = (struct options*)skb->proto_priv; + memcpy(skb->proto_priv, opt, sizeof (struct options)); + memcpy(iph + sizeof (struct iphdr), opt->__data, opt->optlen); + opt = (struct options *)skb->proto_priv; opt->is_data = 0; if (opt->srr) - memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); + memcpy(iph + opt->srr + iph[opt->srr + 1] - 4, &daddr, 4); - if (!is_frag) - { + if (!is_frag) { if (opt->rr_needaddr) - memcpy(iph+opt->rr+iph[opt->rr+2]-5, &saddr, 4); + memcpy(iph + opt->rr + iph[opt->rr + 2] - 5, &saddr, 4); if (opt->ts_needaddr) - memcpy(iph+opt->ts+iph[opt->ts+2]-9, &saddr, 4); - if (opt->ts_needtime) - { + memcpy(iph + opt->ts + iph[opt->ts + 2] - 9, &saddr, 4); + if (opt->ts_needtime) { struct timeval tv; __u32 midtime; do_gettimeofday(&tv); midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); - memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); + memcpy(iph + opt->ts + iph[opt->ts + 2] - 5, &midtime, 4); } return; } - if (opt->rr) - { - memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]); + if (opt->rr) { + memset(iph + opt->rr, IPOPT_NOP, iph[opt->rr + 1]); opt->rr = 0; opt->rr_needaddr = 0; } - if (opt->ts) - { - memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]); + if (opt->ts) { + memset(iph + opt->ts, IPOPT_NOP, iph[opt->ts + 1]); opt->ts = 0; opt->ts_needaddr = opt->ts_needtime = 0; } } -int ip_options_echo(struct options * dopt, struct options * sopt, - __u32 daddr, __u32 saddr, - struct sk_buff * skb) +int ip_options_echo(struct options *dopt, struct options *sopt, + __u32 daddr, __u32 saddr, struct sk_buff *skb) { unsigned char *sptr, *dptr; int soffset, doffset; - int optlen; + int optlen; - memset(dopt, 0, sizeof(struct options)); + memset(dopt, 0, sizeof (struct options)); dopt->is_data = 1; if (!sopt) - sopt = (struct options*)skb->proto_priv; + sopt = (struct options *)skb->proto_priv; - if (sopt->optlen == 0) - { + if (sopt->optlen == 0) { dopt->optlen = 0; return 0; } - sptr = (sopt->is_data ? sopt->__data - sizeof(struct iphdr) : + sptr = (sopt->is_data ? sopt->__data - sizeof (struct iphdr) : (unsigned char *)skb->ip_hdr); dptr = dopt->__data; - if (sopt->rr) - { - optlen = sptr[sopt->rr+1]; - soffset = sptr[sopt->rr+2]; - dopt->rr = dopt->optlen + sizeof(struct iphdr); - memcpy(dptr, sptr+sopt->rr, optlen); + if (sopt->rr) { + optlen = sptr[sopt->rr + 1]; + soffset = sptr[sopt->rr + 2]; + dopt->rr = dopt->optlen + sizeof (struct iphdr); + memcpy(dptr, sptr + sopt->rr, optlen); if (sopt->rr_needaddr && soffset <= optlen) { if (soffset + 3 > optlen) return -EINVAL; dptr[2] = soffset + 4; dopt->rr_needaddr = 1; } - dptr += optlen; + dptr += optlen; dopt->optlen += optlen; } - if (sopt->ts) - { - optlen = sptr[sopt->ts+1]; - soffset = sptr[sopt->ts+2]; - dopt->ts = dopt->optlen + sizeof(struct iphdr); - memcpy(dptr, sptr+sopt->ts, optlen); - if (soffset <= optlen) - { - if (sopt->ts_needaddr) - { + if (sopt->ts) { + optlen = sptr[sopt->ts + 1]; + soffset = sptr[sopt->ts + 2]; + dopt->ts = dopt->optlen + sizeof (struct iphdr); + memcpy(dptr, sptr + sopt->ts, optlen); + if (soffset <= optlen) { + if (sopt->ts_needaddr) { if (soffset + 3 > optlen) return -EINVAL; dopt->ts_needaddr = 1; soffset += 4; } - if (sopt->ts_needtime) - { + if (sopt->ts_needtime) { if (soffset + 3 > optlen) return -EINVAL; dopt->ts_needtime = 1; soffset += 4; } - if (((struct timestamp*)(dptr+1))->flags == IPOPT_TS_PRESPEC) - { + if (((struct timestamp *)(dptr + 1))->flags == IPOPT_TS_PRESPEC) { __u32 addr; - memcpy(&addr, sptr+soffset-9, 4); - if (ip_chk_addr(addr) == 0) - { + memcpy(&addr, sptr + soffset - 9, 4); + if (ip_chk_addr(addr) == 0) { dopt->ts_needtime = 0; dopt->ts_needaddr = 0; soffset -= 8; @@ -148,9 +134,8 @@ dptr += optlen; dopt->optlen += optlen; } - if (sopt->srr) - { - unsigned char * start = sptr+sopt->srr; + if (sopt->srr) { + unsigned char *start = sptr + sopt->srr; __u32 faddr; optlen = start[1]; @@ -159,58 +144,55 @@ if (soffset > optlen) soffset = optlen + 1; soffset -= 4; - if (soffset > 3) - { - memcpy(&faddr, &start[soffset-1], 4); - for (soffset-=4, doffset=4; soffset > 3; soffset-=4, doffset+=4) - memcpy(&dptr[doffset-1], &start[soffset-1], 4); + if (soffset > 3) { + memcpy(&faddr, &start[soffset - 1], 4); + for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4) + memcpy(&dptr[doffset - 1], &start[soffset - 1], 4); /* * RFC1812 requires to fix illegal source routes. */ - if (memcmp(&saddr, &start[soffset+3], 4) == 0) + if (memcmp(&saddr, &start[soffset + 3], 4) == 0) doffset -= 4; } - if (doffset > 3) - { - memcpy(&start[doffset-1], &daddr, 4); + if (doffset > 3) { + memcpy(&start[doffset - 1], &daddr, 4); dopt->faddr = faddr; dptr[0] = start[0]; - dptr[1] = doffset+3; + dptr[1] = doffset + 3; dptr[2] = 4; - dptr += doffset+3; - dopt->srr = dopt->optlen + sizeof(struct iphdr); - dopt->optlen += doffset+3; + dptr += doffset + 3; + dopt->srr = dopt->optlen + sizeof (struct iphdr); + dopt->optlen += doffset + 3; dopt->is_strictroute = sopt->is_strictroute; } } - while (dopt->optlen & 3) - { + while (dopt->optlen & 3) { *dptr++ = IPOPT_END; dopt->optlen++; } return 0; } -void ip_options_fragment(struct sk_buff * skb) +void ip_options_fragment(struct sk_buff *skb) { - unsigned char * optptr = (unsigned char*)skb->ip_hdr; - struct options * opt = (struct options*)skb->proto_priv; + unsigned char *optptr = (unsigned char *)skb->ip_hdr; + struct options *opt = (struct options *)skb->proto_priv; int l = opt->optlen; int optlen; - while (l > 0) - { - switch (*optptr) - { - case IPOPT_END: + while (l > 0) { + switch (*optptr) { + case IPOPT_END: return; - case IPOPT_NOOP: + case IPOPT_NOOP: l--; optptr++; continue; + default: + break; } optlen = optptr[1]; - if (optlen<2 || optlen>l) + if (optlen < 2 || optlen > l) return; if (!(*optptr & 0x80)) memset(optptr, IPOPT_NOOP, optlen); @@ -231,114 +213,96 @@ * If opt == NULL, then skb->data should point to IP header. */ -int ip_options_compile(struct options * opt, struct sk_buff * skb) +int ip_options_compile(struct options *opt, struct sk_buff *skb) { int l; - unsigned char * iph; - unsigned char * optptr; + unsigned char *iph; + unsigned char *optptr; int optlen; - unsigned char * pp_ptr = NULL; + unsigned char *pp_ptr = NULL; - if (!opt) - { - opt = (struct options*)skb->proto_priv; - memset(opt, 0, sizeof(struct options)); - iph = (unsigned char*)skb->ip_hdr; - opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr); - optptr = iph + sizeof(struct iphdr); + if (!opt) { + opt = (struct options *)skb->proto_priv; + memset(opt, 0, sizeof (struct options)); + iph = (unsigned char *)skb->ip_hdr; + opt->optlen = ((struct iphdr *)iph)->ihl * 4 - sizeof (struct iphdr); + optptr = iph + sizeof (struct iphdr); opt->is_data = 0; - } - else - { - optptr = opt->is_data ? opt->__data : (unsigned char*)&skb->ip_hdr[1]; - iph = optptr - sizeof(struct iphdr); + } else { + optptr = opt->is_data ? opt->__data : (unsigned char *)&skb->ip_hdr[1]; + iph = optptr - sizeof (struct iphdr); } - for (l = opt->optlen; l > 0; ) - { - switch (*optptr) - { - case IPOPT_END: - for (optptr++, l--; l>0; l--) - { - if (*optptr != IPOPT_END) - { + for (l = opt->optlen; l > 0; ) { + switch (*optptr) { + case IPOPT_END: + for (optptr++, l--; l > 0; optptr++, l--) { + if (*optptr != IPOPT_END) { *optptr = IPOPT_END; opt->is_changed = 1; } } - goto eol; - case IPOPT_NOOP: + goto EOL; + case IPOPT_NOOP: l--; optptr++; continue; } optlen = optptr[1]; - if (optlen<2 || optlen>l) - { + if (optlen < 2 || optlen > l) { pp_ptr = optptr; - goto error; + goto ERROR; } - switch (*optptr) - { - case IPOPT_SSRR: - case IPOPT_LSRR: - if (optlen < 3) - { + switch (*optptr) { + case IPOPT_SSRR: + case IPOPT_LSRR: + if (optlen < 3) { pp_ptr = optptr + 1; - goto error; + goto ERROR; } - if (optptr[2] < 4) - { + if (optptr[2] < 4) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } /* NB: cf RFC-1812 5.2.4.1 */ - if (opt->srr) - { + if (opt->srr) { pp_ptr = optptr; - goto error; + goto ERROR; } - if (!skb) - { - if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) - { + if (!skb) { + if (optptr[2] != 4 || + optlen < 7 || ((optlen - 3) & 3)) { pp_ptr = optptr + 1; - goto error; + goto ERROR; } memcpy(&opt->faddr, &optptr[3], 4); if (optlen > 7) - memmove(&optptr[3], &optptr[7], optlen-7); + memmove(&optptr[3], &optptr[7], + optlen - 7); } opt->is_strictroute = (optptr[0] == IPOPT_SSRR); opt->srr = optptr - iph; break; - case IPOPT_RR: - if (opt->rr) - { + case IPOPT_RR: + if (opt->rr) { pp_ptr = optptr; - goto error; + goto ERROR; } - if (optlen < 3) - { + if (optlen < 3) { pp_ptr = optptr + 1; - goto error; + goto ERROR; } - if (optptr[2] < 4) - { + if (optptr[2] < 4) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } - if (optptr[2] <= optlen) - { - if (optptr[2]+3 > optlen) - { + if (optptr[2] <= optlen) { + if (optptr[2] + 3 > optlen) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } - if (skb) - { - memcpy(&optptr[optptr[2]-1], &skb->dev->pa_addr, 4); + if (skb) { + memcpy(&optptr[optptr[2] - 1], &skb->dev->pa_addr, 4); opt->is_changed = 1; } optptr[2] += 4; @@ -346,112 +310,97 @@ } opt->rr = optptr - iph; break; - case IPOPT_TIMESTAMP: - if (opt->ts) - { + case IPOPT_TIMESTAMP: + if (opt->ts) { pp_ptr = optptr; - goto error; + goto ERROR; } - if (optlen < 4) - { + if (optlen < 4) { pp_ptr = optptr + 1; - goto error; + goto ERROR; } - if (optptr[2] < 5) - { + if (optptr[2] < 5) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } - if (optptr[2] <= optlen) - { - struct timestamp * ts = (struct timestamp*)(optptr+1); - __u32 * timeptr = NULL; - if (ts->ptr+3 > ts->len) - { + if (optptr[2] <= optlen) { + struct timestamp *ts = (struct timestamp *)(optptr + 1); + __u32 *timeptr = NULL; + if (ts->ptr + 3 > ts->len) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } - switch (ts->flags) - { - case IPOPT_TS_TSONLY: + switch (ts->flags) { + case IPOPT_TS_TSONLY: opt->ts = optptr - iph; - if (skb) - timeptr = (__u32*)&optptr[ts->ptr-1]; + if (skb) + timeptr = (__u32 *)&optptr[ts->ptr - 1]; opt->ts_needtime = 1; ts->ptr += 4; break; - case IPOPT_TS_TSANDADDR: - if (ts->ptr+7 > ts->len) - { + case IPOPT_TS_TSANDADDR: + if (ts->ptr + 7 > ts->len) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } opt->ts = optptr - iph; - if (skb) - { - memcpy(&optptr[ts->ptr-1], &skb->dev->pa_addr, 4); - timeptr = (__u32*)&optptr[ts->ptr+3]; + if (skb) { + memcpy(&optptr[ts->ptr - 1], &skb->dev->pa_addr, 4); + timeptr = (__u32 *)&optptr[ts->ptr + 3]; } opt->ts_needaddr = 1; opt->ts_needtime = 1; ts->ptr += 8; break; - case IPOPT_TS_PRESPEC: - if (ts->ptr+7 > ts->len) - { + case IPOPT_TS_PRESPEC: + if (ts->ptr + 7 > ts->len) { pp_ptr = optptr + 2; - goto error; + goto ERROR; } opt->ts = optptr - iph; { __u32 addr; - memcpy(&addr, &optptr[ts->ptr-1], 4); + memcpy(&addr, &optptr[ts->ptr - 1], 4); if (ip_chk_addr(addr) == 0) break; if (skb) - timeptr = (__u32*)&optptr[ts->ptr+3]; + timeptr = (__u32 *)&optptr[ts->ptr + 3]; } opt->ts_needaddr = 1; opt->ts_needtime = 1; ts->ptr += 8; break; - default: + default: pp_ptr = optptr + 3; - goto error; + goto ERROR; } - if (timeptr) - { + if (timeptr) { struct timeval tv; - __u32 midtime; + __u32 midtime; do_gettimeofday(&tv); midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000); - memcpy(timeptr, &midtime, sizeof(__u32)); + memcpy(timeptr, &midtime, sizeof (__u32)); opt->is_changed = 1; } - } - else - { - struct timestamp * ts = (struct timestamp*)(optptr+1); - if (ts->overflow == 15) - { + } else { + struct timestamp *ts = (struct timestamp *)(optptr + 1); + if (ts->overflow == 15) { pp_ptr = optptr + 3; - goto error; + goto ERROR; } opt->ts = optptr - iph; - if (skb) - { + if (skb) { ts->overflow++; opt->is_changed = 1; } } break; - case IPOPT_SEC: - case IPOPT_SID: - default: - if (!skb) - { + case IPOPT_SEC: + case IPOPT_SID: + default: + if (!skb) { pp_ptr = optptr; - goto error; + goto ERROR; } break; } @@ -459,16 +408,15 @@ optptr += optlen; } -eol: +EOL: if (!pp_ptr) return 0; -error: - if (skb) - { - icmp_send(skb, ICMP_PARAMETERPROB, 0, pp_ptr-iph, skb->dev); +ERROR: + if (skb) { + icmp_send(skb, ICMP_PARAMETERPROB, 0, + pp_ptr - iph, skb->dev, 1); kfree_skb(skb, FREE_READ); } return -EINVAL; } - diff -urN linux-2.0.39/net/ipv4/tcp.c linux-2.0.40/net/ipv4/tcp.c --- linux-2.0.39/net/ipv4/tcp.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/net/ipv4/tcp.c 2004-02-07 23:13:01.000000000 -0800 @@ -206,6 +206,7 @@ * David S. Miller : New socket lookup architecture for ISS. * This code is dedicated to John Dyson. * Elliot Poger : Added support for SO_BINDTODEVICE. + * Michael Deutschmann : Added some IS_SKBs in tcp_recvmsg. * * To Fix: * Fast path the code. Two things here - fix the window calculation @@ -1652,9 +1653,11 @@ current->state = TASK_INTERRUPTIBLE; + IS_SKB_HEAD((struct sk_buff *)&sk->receive_queue); skb = sk->receive_queue.next; while (skb != (struct sk_buff *)&sk->receive_queue) { + IS_SKB_LINKED(skb); if (before(*seq, skb->seq)) break; offset = *seq - skb->seq; diff -urN linux-2.0.39/net/ipv4/tcp_input.c linux-2.0.40/net/ipv4/tcp_input.c --- linux-2.0.39/net/ipv4/tcp_input.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/net/ipv4/tcp_input.c 2004-02-07 23:13:01.000000000 -0800 @@ -46,6 +46,7 @@ * * George Baeslack : SIGIO delivery on accept() bug that * affected sun jdk. + * Michael Deutschmann : Added IS_SKBs to tcp_insert_skb */ #include @@ -1897,6 +1898,8 @@ struct sk_buff * prev, * next; u32 seq; + IS_SKB_UNLINKED(skb); + /* * Find where the new skb goes.. (This goes backwards, * on the assumption that we get the packets in order) @@ -1904,7 +1907,9 @@ seq = skb->seq; prev = list->prev; next = (struct sk_buff *) list; + IS_SKB_HEAD(next); for (;;) { + IS_SKB_LINKED(prev); if (prev == (struct sk_buff *) list || !after(prev->seq, seq)) break; next = prev; diff -urN linux-2.0.39/net/ipv4/udp.c linux-2.0.40/net/ipv4/udp.c --- linux-2.0.39/net/ipv4/udp.c 1997-12-10 09:14:01.000000000 -0800 +++ linux-2.0.40/net/ipv4/udp.c 2004-02-07 23:13:01.000000000 -0800 @@ -14,35 +14,41 @@ * * Fixes: * Alan Cox : verify_area() calls - * Alan Cox : stopped close while in use off icmp + * Alan Cox : stopped close while in use off icmp * messages. Not a fix but a botch that * for udp at least is 'valid'. * Alan Cox : Fixed icmp handling properly - * Alan Cox : Correct error for oversized datagrams - * Alan Cox : Tidied select() semantics. - * Alan Cox : udp_err() fixed properly, also now + * Alan Cox : Correct error for oversized datagrams + * Alan Cox : Tidied select() semantics. + * Alan Cox : udp_err() fixed properly, also now * select and read wake correctly on errors - * Alan Cox : udp_send verify_area moved to avoid mem leak + * Alan Cox : udp_send verify_area moved to avoid mem + * leak * Alan Cox : UDP can count its memory * Alan Cox : send to an unknown connection causes * an ECONNREFUSED off the icmp, but * does NOT close. - * Alan Cox : Switched to new sk_buff handlers. No more backlog! - * Alan Cox : Using generic datagram code. Even smaller and the PEEK - * bug no longer crashes it. - * Fred Van Kempen : Net2e support for sk->broadcast. + * Alan Cox : Switched to new sk_buff handlers. No + * more backlog! + * Alan Cox : Using generic datagram code. Even + * smaller and the PEEK bug no longer + * crashes it. + * Fred Van Kempen : Net2e support for sk->broadcast. * Alan Cox : Uses skb_free_datagram * Alan Cox : Added get/set sockopt support. - * Alan Cox : Broadcasting without option set returns EACCES. - * Alan Cox : No wakeup calls. Instead we now use the callbacks. + * Alan Cox : Broadcasting without option set returns + * EACCES. + * Alan Cox : No wakeup calls. Instead we now use the + * callbacks. * Alan Cox : Use ip_tos and ip_ttl * Alan Cox : SNMP Mibs * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. * Matt Dillon : UDP length checks. * Alan Cox : Smarter af_inet used properly. * Alan Cox : Use new kernel side addressing. - * Alan Cox : Incorrect return on truncated datagram receive. - * Arnt Gulbrandsen : New udp_send and stuff + * Alan Cox : Incorrect return on truncated datagram + * receive. + * Arnt Gulbrandsen : New udp_send and stuff * Alan Cox : Cache last socket * Alan Cox : Route cache * Jon Peatfield : Minor efficiency fix to sendto(). @@ -63,10 +69,10 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - + /* RFC1122 Status: 4.1.3.1 (Ports): - SHOULD send ICMP_PORT_UNREACHABLE in response to datagrams to + SHOULD send ICMP_PORT_UNREACHABLE in response to datagrams to an un-listened port. (OK) 4.1.3.2 (IP Options) MUST pass IP options from IP -> application (OK) @@ -81,12 +87,14 @@ 4.1.3.5 (UDP Multihoming) MUST allow application to specify source address (OK) SHOULD be able to communicate the chosen src addr up to application - when application doesn't choose (NOT YET - doesn't seem to be in the BSD API) + when application doesn't choose (NOT YET - doesn't seem to be in the BSD + API) [Does opening a SOCK_PACKET and snooping your output count 8)] 4.1.3.6 (Invalid Addresses) MUST discard invalid source addresses (NOT YET -- will be implemented in IP, so UDP will eventually be OK. Right now it's a violation.) - MUST only send datagrams with one of our addresses (NOT YET - ought to be OK ) + MUST only send datagrams with one of our addresses (NOT YET - ought to be + OK) 950728 -- MS */ @@ -120,7 +128,7 @@ * Snmp MIB for the UDP layer */ -struct udp_mib udp_statistics; +struct udp_mib udp_statistics; struct sock *udp_hash[UDP_HTABLE_SIZE]; @@ -130,8 +138,9 @@ int retval = 0, sk_reuse = sk->reuse; SOCKHASH_LOCK(); - for(sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; sk2 = sk2->next) { - if((sk2->num == snum) && (sk2 != sk)) { + for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + sk2 != NULL; sk2 = sk2->next) { + if ((sk2->num == snum) && (sk2 != sk)) { int sk2_reuse = sk2->reuse; /* Two sockets can be bound to the same port if they're @@ -139,13 +148,13 @@ if (sk->bound_device != sk2->bound_device) continue; - if(!sk2->rcv_saddr || !sk->rcv_saddr) { - if((!sk2_reuse) || (!sk_reuse)) { + if (!sk2->rcv_saddr || !sk->rcv_saddr) { + if ((!sk2_reuse) || (!sk_reuse)) { retval = 1; break; } - } else if(sk2->rcv_saddr == sk->rcv_saddr) { - if((!sk_reuse) || (!sk2_reuse)) { + } else if (sk2->rcv_saddr == sk->rcv_saddr) { + if ((!sk_reuse) || (!sk2_reuse)) { retval = 1; break; } @@ -160,8 +169,8 @@ { struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)]; - for(; sk != NULL; sk = sk->next) { - if(sk->num == num) + for (; sk != NULL; sk = sk->next) { + if (sk->num == num) return 1; } return 0; @@ -193,9 +202,9 @@ /* Is this one better than our best so far? */ size = 0; do { - if(++size >= best_size_so_far) + if (++size >= best_size_so_far) goto next; - } while((sk = sk->next) != NULL); + } while ((sk = sk->next) != NULL); best_size_so_far = size; best = result; next: @@ -234,8 +243,8 @@ skp = &udp_hash[num]; SOCKHASH_LOCK(); - while(*skp != NULL) { - if(*skp == sk) { + while (*skp != NULL) { + if (*skp == sk) { *skp = sk->next; break; } @@ -254,8 +263,8 @@ skp = &udp_hash[oldnum]; SOCKHASH_LOCK(); - while(*skp != NULL) { - if(*skp == sk) { + while (*skp != NULL) { + if (*skp == sk) { *skp = sk->next; break; } @@ -270,28 +279,29 @@ /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ -__inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, - struct device *dev) +__inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev) { struct sock *sk, *result = NULL; unsigned short hnum = ntohs(dport); int badness = -1; - for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { - if((sk->num == hnum) && !(sk->dead && (sk->state == TCP_CLOSE))) { + for (sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; + sk != NULL; sk = sk->next) { + if ((sk->num == hnum) && !(sk->dead && + (sk->state == TCP_CLOSE))) { int score = 0; - if(sk->rcv_saddr) { - if(sk->rcv_saddr != daddr) + if (sk->rcv_saddr) { + if (sk->rcv_saddr != daddr) continue; score++; } - if(sk->daddr) { - if(sk->daddr != saddr) + if (sk->daddr) { + if (sk->daddr != saddr) continue; score++; } - if(sk->dummy_th.dest) { - if(sk->dummy_th.dest != sport) + if (sk->dummy_th.dest) { + if (sk->dummy_th.dest != sport) continue; score++; } @@ -303,10 +313,10 @@ else continue; /* mismatch--not this sock */ } - if(score == 4) { + if (score == 4) { result = sk; break; - } else if(score > badness) { + } else if (score > badness) { result = sk; badness = score; } @@ -329,38 +339,38 @@ hh[0] = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; hh[1] = udp_hash[hpnum & (UDP_HTABLE_SIZE - 1)]; for (i = 0; i < 2; i++) { - for(sk = hh[i]; sk != NULL; sk = sk->next) { - if(sk->num == hnum || sk->num == hpnum) { + for (sk = hh[i]; sk != NULL; sk = sk->next) { + if (sk->num == hnum || sk->num == hpnum) { int score = 0; - if(sk->dead && (sk->state == TCP_CLOSE)) + if (sk->dead && (sk->state == TCP_CLOSE)) continue; - if(sk->rcv_saddr) { - if((sk->num != hpnum || sk->rcv_saddr != paddr) && + if (sk->rcv_saddr) { + if ((sk->num != hpnum || sk->rcv_saddr != paddr) && (sk->num != hnum || sk->rcv_saddr != daddr)) continue; score++; } - if(sk->daddr) { - if(sk->daddr != saddr) + if (sk->daddr) { + if (sk->daddr != saddr) continue; score++; } - if(sk->dummy_th.dest) { - if(sk->dummy_th.dest != sport) + if (sk->dummy_th.dest) { + if (sk->dummy_th.dest != sport) continue; score++; } /* If this socket is bound to a particular interface, * did the packet come in on it? */ - if(sk->bound_device) { + if (sk->bound_device) { if (sk->bound_device != dev) continue; score++; } - if(score == 4 && sk->num == hnum) { + if (score == 4 && sk->num == hnum) { result = sk; break; - } else if(score > badness && (sk->num == hpnum || sk->rcv_saddr)) { + } else if (score > badness && (sk->num == hpnum || sk->rcv_saddr)) { result = sk; badness = score; } @@ -381,27 +391,27 @@ { struct sock *s = sk; unsigned short hnum = ntohs(num); - for(; s; s = s->next) { - if ((s->num != hnum) || - (s->dead && (s->state == TCP_CLOSE)) || - (s->daddr && s->daddr!=raddr) || + for (; s; s = s->next) { + if ((s->num != hnum) || + (s->dead && (s->state == TCP_CLOSE)) || + (s->daddr && s->daddr != raddr) || (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) || - ((s->bound_device) && (s->bound_device!=dev)) || - (s->rcv_saddr && s->rcv_saddr != laddr)) + ((s->bound_device) && (s->bound_device!=dev)) || + (s->rcv_saddr && s->rcv_saddr != laddr)) continue; break; - } - return s; + } + return s; } -#define min(a,b) ((a)<(b)?(a):(b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) /* * This routine is called by the ICMP module when it gets some * sort of error condition. If err < 0 then the socket should * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. + * it's just the icmp type << 8 | icmp code. * Header points to the ip header of the error packet. We move * on past this. Then (as it used to claim before adjustment) * header points to the first 8 bytes of the udp header. We need @@ -416,50 +426,47 @@ /* * Find the 8 bytes of post IP header ICMP included for us - */ - - if(lendest, saddr, uh->source, NULL); - if (sk == NULL) - return; /* No socket for error */ - - if (type == ICMP_SOURCE_QUENCH) - { /* Slow down! */ - if (sk->cong_window > 1) + if (sk == NULL) + return; /* No socket for error */ + + if (type == ICMP_SOURCE_QUENCH) { /* Slow down! */ + if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2; return; } - if (type == ICMP_PARAMETERPROB) - { + if (type == ICMP_PARAMETERPROB) { sk->err = EPROTO; sk->error_report(sk); return; } - + /* - * Various people wanted BSD UDP semantics. Well they've come + * Various people wanted BSD UDP semantics. Well they've come * back out because they slow down response to stuff like dead * or unreachable name servers and they screw term users something - * chronic. Oh and it violates RFC1122. So basically fix your + * chronic. Oh and it violates RFC1122. So basically fix your * client code people. */ - + /* RFC1122: OK. Passes ICMP errors back to application, as per */ /* 4.1.3.3. */ /* After the comment above, that should be no surprise. */ - if(code<=NR_ICMP_UNREACH && icmp_err_convert[code].fatal) - { + if (code <= NR_ICMP_UNREACH && icmp_err_convert[code].fatal) { /* * 4.x BSD compatibility item. Break RFC1122 to * get BSD socket semantics. */ - if(sk->bsdism && sk->state!=TCP_ESTABLISHED) + if (sk->bsdism && sk->state != TCP_ESTABLISHED) return; sk->err = icmp_err_convert[code].errno; sk->error_report(sk); @@ -469,10 +476,10 @@ static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base) { - return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); + return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base); } -struct udpfakehdr +struct udpfakehdr { struct udphdr uh; __u32 daddr; @@ -482,73 +489,68 @@ }; /* - * Copy and checksum a UDP packet from user space into a buffer. We still have to do the planning to - * get ip_build_xmit to spot direct transfer to network card and provide an additional callback mode - * for direct user->board I/O transfers. That one will be fun. + * Copy and checksum a UDP packet from user space into a buffer. We still + * have to do the planning to get ip_build_xmit to spot direct transfer to + * network card and provide an additional callback mode for direct + * user->board I/O transfers. That one will be fun. */ - -static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) + +static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; const char *src; char *dst; unsigned int len; - if (offset) - { + if (offset) { len = fraglen; - src = ufh->from+(offset-sizeof(struct udphdr)); - dst = to; - } - else - { - len = fraglen-sizeof(struct udphdr); - src = ufh->from; - dst = to+sizeof(struct udphdr); + src = ufh->from + (offset - sizeof (struct udphdr)); + dst = to; + } else { + len = fraglen - sizeof (struct udphdr); + src = ufh->from; + dst = to + sizeof (struct udphdr); } ufh->wcheck = csum_partial_copy_fromuser(src, dst, len, ufh->wcheck); - if (offset == 0) - { - ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr), - ufh->wcheck); - ufh->uh.check = csum_tcpudp_magic(saddr, ufh->daddr, - ntohs(ufh->uh.len), - IPPROTO_UDP, ufh->wcheck); + if (offset == 0) { + ufh->wcheck = csum_partial((char *)ufh, sizeof (struct udphdr), + ufh->wcheck); + ufh->uh.check = csum_tcpudp_magic(saddr, ufh->daddr, + ntohs(ufh->uh.len), + IPPROTO_UDP, ufh->wcheck); if (ufh->uh.check == 0) ufh->uh.check = -1; - memcpy(to, ufh, sizeof(struct udphdr)); + memcpy(to, ufh, sizeof (struct udphdr)); } } /* - * Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing - * that we use two routines for this for speed. Probably we ought to have a CONFIG_FAST_NET - * set for >10Mb/second boards to activate this sort of coding. Timing needed to verify if - * this is a valid decision. + * Unchecksummed UDP is sufficiently critical to stuff like ATM video + * conferencing that we use two routines for this for speed. Probably we + * ought to have a CONFIG_FAST_NET set for >10Mb/second boards to activate + * this sort of coding. Timing needed to verify if this is a valid + * decision. */ - -static void udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) + +static void udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; const char *src; char *dst; unsigned int len; - if (offset) - { + if (offset) { len = fraglen; - src = ufh->from+(offset-sizeof(struct udphdr)); - dst = to; - } - else - { - len = fraglen-sizeof(struct udphdr); - src = ufh->from; - dst = to+sizeof(struct udphdr); - } - memcpy_fromfs(dst,src,len); - if (offset == 0) - memcpy(to, ufh, sizeof(struct udphdr)); + src = ufh->from + (offset - sizeof (struct udphdr)); + dst = to; + } else { + len = fraglen - sizeof (struct udphdr); + src = ufh->from; + dst = to + sizeof (struct udphdr); + } + memcpy_fromfs(dst, src, len); + if (offset == 0) + memcpy(to, ufh, sizeof (struct udphdr)); } @@ -558,13 +560,13 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin, const unsigned char *from, int len, int rt, - __u32 saddr, int noblock) + __u32 saddr, int noblock) { - int ulen = len + sizeof(struct udphdr); + int ulen = len + sizeof (struct udphdr); int a; struct udpfakehdr ufh; - - if(ulen>65535-sizeof(struct iphdr)) + + if (ulen > 65535 - sizeof (struct iphdr)) return -EMSGSIZE; ufh.uh.source = sk->dummy_th.source; @@ -586,14 +588,14 @@ * easily, without adding system calls. */ struct sockaddr_in *sinfrom = - (struct sockaddr_in *) sin->sin_zero; + (struct sockaddr_in *)sin->sin_zero; if (!suser()) - return(-EPERM); + return -EPERM; if (sinfrom->sin_family && sinfrom->sin_family != AF_INET) - return(-EINVAL); + return -EINVAL; if (sinfrom->sin_port == 0) - return(-EINVAL); + return -EINVAL; saddr = sinfrom->sin_addr.s_addr; ufh.uh.source = sinfrom->sin_port; } @@ -604,13 +606,15 @@ /* (MAY) and it defaults to on (MUST). Almost makes up for the */ /* violation above. -- MS */ - if(sk->no_check) - a = ip_build_xmit(sk, udp_getfrag_nosum, &ufh, ulen, - sin->sin_addr.s_addr, saddr, sk->opt, rt, IPPROTO_UDP, noblock); + if (sk->no_check) + a = ip_build_xmit(sk, udp_getfrag_nosum, &ufh, ulen, + sin->sin_addr.s_addr, saddr, sk->opt, rt, + IPPROTO_UDP, noblock); else - a = ip_build_xmit(sk, udp_getfrag, &ufh, ulen, - sin->sin_addr.s_addr, saddr, sk->opt, rt, IPPROTO_UDP, noblock); - if(a<0) + a = ip_build_xmit(sk, udp_getfrag, &ufh, ulen, + sin->sin_addr.s_addr, saddr, sk->opt, rt, + IPPROTO_UDP, noblock); + if (a < 0) return a; udp_statistics.UdpOutDatagrams++; return len; @@ -622,51 +626,48 @@ { struct sockaddr_in sin; int tmp; - __u32 saddr=0; + __u32 saddr = 0; - /* + /* * Check the flags. We support no flags for UDP sending */ #ifdef CONFIG_IP_TRANSPARENT_PROXY - if (flags&~(MSG_DONTROUTE|MSG_PROXY)) + if (flags & ~(MSG_DONTROUTE | MSG_PROXY)) #else - if (flags&~MSG_DONTROUTE) + if (flags & ~MSG_DONTROUTE) #endif - return(-EINVAL); + return -EINVAL; /* - * Get and verify the address. + * Get and verify the address. */ - - if (usin) - { - if (addr_len < sizeof(sin)) - return(-EINVAL); - if (usin->sin_family && usin->sin_family != AF_INET) - return(-EINVAL); - if (usin->sin_port == 0) - return(-EINVAL); - } - else - { + + if (usin) { + if (addr_len < sizeof (sin)) + return -EINVAL; + if (usin->sin_family && usin->sin_family != AF_INET) + return -EINVAL; + if (usin->sin_port == 0) + return -EINVAL; + } else { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* We need to provide a sockaddr_in when using MSG_PROXY. */ - if (flags&MSG_PROXY) - return(-EINVAL); + if (flags & MSG_PROXY) + return -EINVAL; #endif - if (sk->state != TCP_ESTABLISHED) - return(-EINVAL); + if (sk->state != TCP_ESTABLISHED) + return -EINVAL; sin.sin_family = AF_INET; sin.sin_port = sk->dummy_th.dest; sin.sin_addr.s_addr = sk->daddr; usin = &sin; - } - - /* - * BSD socket semantics. You must set SO_BROADCAST to permit - * broadcasting of data. - */ - + } + + /* + * BSD socket semantics. You must set SO_BROADCAST to permit + * broadcasting of data. + */ + /* RFC1122: OK. Allows the application to select the specific */ /* source address for an outgoing packet (MUST) as per 4.1.3.5. */ /* Optional addition: a mechanism for telling the application what */ @@ -677,11 +678,12 @@ /* af_inet.c checks these. It does need work to allow BSD style */ /* bind to multicast as is done by xntpd */ - if(usin->sin_addr.s_addr==INADDR_ANY) - usin->sin_addr.s_addr=ip_my_addr(); - - if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) - return -EACCES; /* Must turn broadcast on first */ + if (usin->sin_addr.s_addr == INADDR_ANY) + usin->sin_addr.s_addr = ip_my_addr(); + + if (!sk->broadcast && + ip_chk_addr(usin->sin_addr.s_addr) == IS_BROADCAST) + return -EACCES; /* Must turn broadcast on first */ lock_sock(sk); @@ -690,40 +692,40 @@ /* The datagram has been sent off. Release the socket. */ release_sock(sk); - return(tmp); + return tmp; } /* * Temporary */ - -static int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, - int flags) + +static int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, int flags) { - if(msg->msg_iovlen==1) - return udp_sendto(sk,msg->msg_iov[0].iov_base,len, noblock, flags, msg->msg_name, msg->msg_namelen); - else - { + if (msg->msg_iovlen == 1) + return udp_sendto(sk, msg->msg_iov[0].iov_base, len, noblock, + flags, msg->msg_name, msg->msg_namelen); + else { /* * For awkward cases we linearise the buffer first. In theory this is only frames * whose iovec's don't split on 4 byte boundaries, and soon encrypted stuff (to keep * skip happy). We are a bit more general about it. */ - + unsigned char *buf; int fs; int err; - if(len>65515) + if (len > 65515) return -EMSGSIZE; - buf=kmalloc(len, GFP_KERNEL); - if(buf==NULL) + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) return -ENOBUFS; memcpy_fromiovec(buf, msg->msg_iov, len); - fs=get_fs(); + fs = get_fs(); set_fs(get_ds()); - err=udp_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen); + err = udp_sendto(sk, buf, len, noblock, flags, msg->msg_name, + msg->msg_namelen); set_fs(fs); - kfree_s(buf,len); + kfree_s(buf, len); return err; } } @@ -731,106 +733,105 @@ /* * IOCTL requests applicable to the UDP protocol */ - + int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) { int err; - switch(cmd) + switch (cmd) { + case TIOCOUTQ: { - case TIOCOUTQ: - { - unsigned long amount; - - if (sk->state == TCP_LISTEN) return(-EINVAL); - amount = sock_wspace(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return(err); - put_fs_long(amount,(unsigned long *)arg); - return(0); - } + unsigned long amount; - case TIOCINQ: - { - struct sk_buff *skb; - unsigned long amount; - - if (sk->state == TCP_LISTEN) return(-EINVAL); - amount = 0; - skb = skb_peek(&sk->receive_queue); - if (skb != NULL) { - /* - * We will only return the amount - * of this packet since that is all - * that will be read. - */ - amount = skb->len-sizeof(struct udphdr); - } - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); - if(err) - return(err); - put_fs_long(amount,(unsigned long *)arg); - return(0); + if (sk->state == TCP_LISTEN) + return -EINVAL; + amount = sock_wspace(sk); + err = verify_area(VERIFY_WRITE, (void *)arg, + sizeof (unsigned long)); + if (err) + return err; + put_fs_long(amount, (unsigned long *)arg); + return 0; + } + + case TIOCINQ: + { + struct sk_buff *skb; + unsigned long amount; + + if (sk->state == TCP_LISTEN) + return -EINVAL; + amount = 0; + skb = skb_peek(&sk->receive_queue); + if (skb != NULL) { + /* + * We will only return the amount + * of this packet since that is all + * that will be read. + */ + amount = skb->len - sizeof (struct udphdr); } + err = verify_area(VERIFY_WRITE, (void *)arg, + sizeof (unsigned long)); + if (err) + return err; + put_fs_long(amount, (unsigned long *)arg); + return 0; + } - default: - return(-EINVAL); + default: + return -EINVAL; } - return(0); + return 0; } - /* - * This should be easy, if there is something there we\ - * return it, otherwise we block. + * This should be easy, if there is something there we\ + * return it, otherwise we block. */ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, - int noblock, int flags,int *addr_len) + int noblock, int flags, int *addr_len) { - int copied = 0; - int truesize; - struct sk_buff *skb; - int er; - struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name; + int copied = 0; + int truesize; + struct sk_buff *skb; + int er; + struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; /* * Check any passed addresses */ - - if (addr_len) - *addr_len=sizeof(*sin); - + + if (addr_len) + *addr_len = sizeof (*sin); + /* * From here the generic datagram does a lot of the work. Come * the finished NET3, it will do _ALL_ the work! */ - - skb=skb_recv_datagram(sk,flags,noblock,&er); - if(skb==NULL) - return er; - - truesize = skb->len - sizeof(struct udphdr); - copied = min(len, truesize); - - /* - * FIXME : should use udp header size info value - */ - - skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied); - sk->stamp=skb->stamp; + + skb = skb_recv_datagram(sk, flags, noblock, &er); + if (skb == NULL) + return er; + + truesize = skb->len - sizeof (struct udphdr); + copied = min(len, truesize); + + /* + * FIXME : should use udp header size info value + */ + + skb_copy_datagram_iovec(skb, sizeof (struct udphdr), + msg->msg_iov, copied); + sk->stamp = skb->stamp; /* Copy the address. */ - if (sin) - { + if (sin) { sin->sin_family = AF_INET; sin->sin_port = skb->h.uh->source; sin->sin_addr.s_addr = skb->daddr; #ifdef CONFIG_IP_TRANSPARENT_PROXY - if (flags&MSG_PROXY) - { + if (flags&MSG_PROXY) { /* * We map the first 8 bytes of a second sockaddr_in * into the last 8 (unused) bytes of a sockaddr_in. @@ -838,39 +839,41 @@ * easily, without adding system calls. */ struct sockaddr_in *sinto = - (struct sockaddr_in *) sin->sin_zero; + (struct sockaddr_in *)sin->sin_zero; sinto->sin_family = AF_INET; sinto->sin_port = skb->h.uh->dest; sinto->sin_addr.s_addr = skb->saddr; } #endif - } - - skb_free_datagram(sk, skb); - return(copied); + } + + skb_free_datagram(sk, skb); + return copied; } int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) { struct rtable *rt; - if (addr_len < sizeof(*usin)) - return(-EINVAL); + if (addr_len < sizeof (*usin)) + return -EINVAL; - if (usin->sin_family && usin->sin_family != AF_INET) - return(-EAFNOSUPPORT); - if (usin->sin_addr.s_addr==INADDR_ANY) - usin->sin_addr.s_addr=ip_my_addr(); - - if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST) - return -EACCES; /* Must turn broadcast on first */ - - rt=ip_rt_route((__u32)usin->sin_addr.s_addr, sk->localroute, sk->bound_device); - if (rt==NULL) - return -ENETUNREACH; - if(!sk->saddr) - sk->saddr = rt->rt_src; /* Update source address */ - if(!sk->rcv_saddr) + if (usin->sin_family && usin->sin_family != AF_INET) + return -EAFNOSUPPORT; + if (usin->sin_addr.s_addr == INADDR_ANY) + usin->sin_addr.s_addr = ip_my_addr(); + + if (!sk->broadcast && + ip_chk_addr(usin->sin_addr.s_addr) == IS_BROADCAST) + return -EACCES; /* Must turn broadcast on first */ + + rt = ip_rt_route((__u32)usin->sin_addr.s_addr, + sk->localroute, sk->bound_device); + if (rt == NULL) + return -ENETUNREACH; + if (!sk->saddr) + sk->saddr = rt->rt_src; /* Update source address */ + if (!sk->rcv_saddr) sk->rcv_saddr = rt->rt_src; sk->daddr = usin->sin_addr.s_addr; sk->dummy_th.dest = usin->sin_port; @@ -878,7 +881,7 @@ if (sk->ip_route_cache) ip_rt_put(sk->ip_route_cache); sk->ip_route_cache = rt; - return(0); + return 0; } @@ -901,7 +904,7 @@ /* I assume this includes the IP options, as per RFC1122 (4.1.3.2). */ /* If not, please let me know. -- MS */ - if (__sock_queue_rcv_skb(sk,skb)<0) { + if (__sock_queue_rcv_skb(sk, skb) < 0) { udp_statistics.UdpInErrors++; ip_statistics.IpInDiscards++; ip_statistics.IpInDelivers--; @@ -959,8 +962,9 @@ SOCKHASH_LOCK(); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; - sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, daddr, skb->dev); - if(sk) { + sk = udp_v4_mcast_next(sk, uh->dest, saddr, uh->source, + daddr, skb->dev); + if (sk) { struct sock *sknext = NULL; do { @@ -968,32 +972,32 @@ sknext = udp_v4_mcast_next(sk->next, uh->dest, saddr, uh->source, daddr, skb->dev); - if(sknext) + if (sknext) skb1 = skb_clone(skb, GFP_ATOMIC); - if(skb1) + if (skb1) udp_deliver(sk, skb1); sk = sknext; - } while(sknext); + } while (sknext); given = 1; } SOCKHASH_UNLOCK(); - if(!given) + if (!given) kfree_skb(skb, FREE_READ); return 0; } #endif /* - * All we need to do is get the socket, and then do a checksum. + * All we need to do is get the socket, and then do a checksum. */ - + int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, __u32 daddr, unsigned short len, __u32 saddr, int redo, struct inet_protocol *protocol) { - struct sock *sk; - struct udphdr *uh; + struct sock *sk; + struct udphdr *uh; unsigned short ulen; int addr_type; @@ -1012,29 +1016,28 @@ */ addr_type = IS_MYADDR; - if(!dev || dev->pa_addr!=daddr) - addr_type=ip_chk_addr(daddr); - + if (!dev || dev->pa_addr != daddr) + addr_type = ip_chk_addr(daddr); + /* * Get the header. */ - - uh = (struct udphdr *) skb->h.uh; - - ip_statistics.IpInDelivers++; + + uh = (struct udphdr *)skb->h.uh; + + ip_statistics.IpInDelivers++; /* * Validate the packet and the UDP length. */ - + ulen = ntohs(uh->len); - - if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh)) - { + + if (ulen > len || len < sizeof (*uh) || ulen < sizeof (*uh)) { NETDEBUG(printk("UDP: short packet: %d/%d\n", ulen, len)); udp_statistics.UdpInErrors++; kfree_skb(skb, FREE_WRITE); - return(0); + return 0; } /* RFC1122 warning: According to 4.1.3.6, we MUST discard any */ @@ -1044,13 +1047,13 @@ /* FIXME list for IP, though, so I wouldn't worry about it. */ /* (That's the Right Place to do it, IMHO.) -- MS */ - if (uh->check && ( - ( (skb->ip_summed == CHECKSUM_HW) && udp_check(uh, len, saddr, daddr, skb->csum ) ) || - ( (skb->ip_summed == CHECKSUM_NONE) && udp_check(uh, len, saddr, daddr,csum_partial((char*)uh, len, 0))) - /* skip if CHECKSUM_UNNECESSARY */ - ) - ) - { + /* Skip csum_partial if CHECKSUM_UNNECESSARY */ + if (uh->check && + (((skb->ip_summed == CHECKSUM_HW) && + udp_check(uh, len, saddr, daddr, skb->csum)) || + ((skb->ip_summed == CHECKSUM_NONE) && + udp_check(uh, len, saddr, daddr, + csum_partial((char *)uh, len, 0))))) { /* wants to know, who sent it, to go and stomp on the garbage sender... */ @@ -1058,44 +1061,43 @@ /* the network is concerned, anyway) as per 4.1.3.4 (MUST). */ NETDEBUG(printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n", - ntohl(saddr),ntohs(uh->source), - ntohl(daddr),ntohs(uh->dest), - ulen)); + ntohl(saddr), ntohs(uh->source), + ntohl(daddr), ntohs(uh->dest), + ulen)); udp_statistics.UdpInErrors++; kfree_skb(skb, FREE_WRITE); - return(0); + return 0; } /* - * These are supposed to be switched. + * These are supposed to be switched. */ - + skb->daddr = saddr; skb->saddr = daddr; - len=ulen; + len = ulen; skb->dev = dev; - skb_trim(skb,len); + skb_trim(skb, len); #ifdef CONFIG_IP_MULTICAST - if (addr_type==IS_BROADCAST || addr_type==IS_MULTICAST) + if (addr_type == IS_BROADCAST || addr_type == IS_MULTICAST) return udp_v4_mcast_deliver(skb, uh, saddr, daddr); #endif #ifdef CONFIG_IP_TRANSPARENT_PROXY - if(skb->redirport) + if (skb->redirport) sk = udp_v4_proxy_lookup(saddr, uh->source, daddr, uh->dest, dev->pa_addr, skb->redirport, dev); else #endif sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, dev); - - if (sk == NULL) - { - udp_statistics.UdpNoPorts++; - if (addr_type != IS_BROADCAST && addr_type != IS_MULTICAST) - { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev); + + if (sk == NULL) { + udp_statistics.UdpNoPorts++; + if (addr_type != IS_BROADCAST && addr_type != IS_MULTICAST) { + icmp_send(skb, ICMP_DEST_UNREACH, + ICMP_PORT_UNREACH, 0, dev, 0); } /* * Hmm. We got an UDP broadcast to a port to which we @@ -1103,8 +1105,8 @@ */ skb->sk = NULL; kfree_skb(skb, FREE_WRITE); - return(0); - } + return 0; + } udp_deliver(sk, skb); return 0; } diff -urN linux-2.0.39/net/netrom/af_netrom.c linux-2.0.40/net/netrom/af_netrom.c --- linux-2.0.39/net/netrom/af_netrom.c 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/net/netrom/af_netrom.c 2004-02-07 23:13:01.000000000 -0800 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff -urN linux-2.0.39/net/netsyms.c linux-2.0.40/net/netsyms.c --- linux-2.0.39/net/netsyms.c 1999-06-13 10:21:04.000000000 -0700 +++ linux-2.0.40/net/netsyms.c 2004-02-07 23:13:01.000000000 -0800 @@ -166,6 +166,7 @@ X(kfree_skb), X(skb_clone), X(skb_copy), + X(skb_pad), X(dev_alloc_skb), X(dev_kfree_skb), X(skb_device_unlock), diff -urN linux-2.0.39/net/rose/af_rose.c linux-2.0.40/net/rose/af_rose.c --- linux-2.0.39/net/rose/af_rose.c 1998-11-15 10:33:22.000000000 -0800 +++ linux-2.0.40/net/rose/af_rose.c 2004-02-07 23:13:01.000000000 -0800 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff -urN linux-2.0.39/net/unix/af_unix.c linux-2.0.40/net/unix/af_unix.c --- linux-2.0.39/net/unix/af_unix.c 2001-01-09 13:29:20.000000000 -0800 +++ linux-2.0.40/net/unix/af_unix.c 2004-02-07 23:13:01.000000000 -0800 @@ -4,7 +4,7 @@ * Authors: Alan Cox, * * Currently this contains all but the file descriptor passing code. - * Before that goes in the odd bugs in the iovec handlers need + * Before that goes in the odd bugs in the iovec handlers need * fixing, and this bit testing. BSD fd passing is not a trivial part * of the exercise it turns out. Anyone like writing garbage collectors. * @@ -31,6 +31,11 @@ * Alan Cox : Shutdown() bug * Michael Deutschmann : release was writing to the socket * structure after freeing it. + * Jon Nelson, + * Alan Cox, + * David Weinehall : Fix possible memory-leaks + * Michael Deutschmann : Fix fd-passing semantics to + * match what OpenSSH expects. * * Known differences from reference BSD that was tested: * @@ -63,7 +68,6 @@ #include #include #include -#include #include #include #include @@ -794,7 +798,10 @@ fp = (struct file **)(skb->h.filp+sizeof(long)); if (cmnum > fdnum) + { cmnum = fdnum; + cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(int) * fdnum; + } /* * Copy those that fit @@ -861,7 +868,7 @@ int sent=0; struct file *fp[UNIX_MAX_FD]; /* number of fds waiting to be passed, 0 means either - * no fds to pass or they've already been passed + * no fds to pass or they've already been passed */ int fpnum=0; @@ -974,7 +981,11 @@ { int err=unix_attach_fds(fpnum,fp,skb); if(err) + { + unix_fd_free(sk, fp, fpnum); + kfree(skb); return err; + } fpnum=0; } else @@ -1080,20 +1091,15 @@ { cm=unix_copyrights(msg->msg_control, msg->msg_controllen); - if(cm==NULL || msg->msg_controllencmsg_type!=SCM_RIGHTS || - cm->cmsg_level!=SOL_SOCKET || - msg->msg_controllen!=cm->cmsg_len -#endif - ) + if(cm==NULL || msg->msg_controllencmsg_type = SCM_RIGHTS; + cm->cmsg_level = SOL_SOCKET; + cm->cmsg_len = msg->msg_controllen; } down(&sk->protinfo.af_unix.readsem); /* Lock the socket */ diff -urN linux-2.0.39/net/unix/garbage.c linux-2.0.40/net/unix/garbage.c --- linux-2.0.39/net/unix/garbage.c 1998-11-15 10:33:23.000000000 -0800 +++ linux-2.0.40/net/unix/garbage.c 2004-02-07 23:13:01.000000000 -0800 @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include diff -urN linux-2.0.39/scripts/checkconfig.pl linux-2.0.40/scripts/checkconfig.pl --- linux-2.0.39/scripts/checkconfig.pl 1998-11-15 10:33:23.000000000 -0800 +++ linux-2.0.40/scripts/checkconfig.pl 2004-02-07 23:13:01.000000000 -0800 @@ -14,6 +14,7 @@ # Initialize variables. my $fInComment = 0; + my $fInString = 0; my $fUseConfig = 0; my $iLinuxConfig = 0; my %configList = (); @@ -25,12 +26,23 @@ m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1))); # Pick up definitions. - if ( m/^#/o ) + if ( m/^\s*#/o ) { - $iLinuxConfig = $. if m/^#\s*include\s*/o; - $configList{uc $1} = 1 if m/^#\s*include\s*/o; - $configList{$1} = 1 if m/^#\s*define\s+CONFIG_(\w*)/o; - $configList{$1} = 1 if m/^#\s*undef\s+CONFIG_(\w*)/o; + $iLinuxConfig = $. if m/^\s*#\s*include\s*"linux\/config\.h"/o; + $configList{uc $1} = 1 if m/^\s*#\s*include\s*"config\/(\S*)\.h"/o; + } + + # Strip strings. + $fInString && (s+^.*?"+ +o ? ($fInString = 0) : next); + m+"+o && (s+".*?"+ +go, (s+".*$+ +o && ($fInString = 1))); + + # Pick up definitions. + if ( m/^\s*#/o ) + { + $iLinuxConfig = $. if m/^\s*#\s*include\s*/o; + $configList{uc $1} = 1 if m/^\s*#\s*include\s*/o; + $configList{$1} = 1 if m/^\s*#\s*define\s+CONFIG_(\w*)/o; + $configList{$1} = 1 if m/^\s*#\s*undef\s+CONFIG_(\w*)/o; } # Look for usages. @@ -47,7 +59,7 @@ # Report superfluous includes. if ( $iLinuxConfig && ! $fUseConfig ) - { print "$file: $iLinuxConfig: not needed.\n"; } + { print "$file: $iLinuxConfig: linux/config.h not needed.\n"; } close(FILE); } diff -urN linux-2.0.39/scripts/checkhelp.pl linux-2.0.40/scripts/checkhelp.pl --- linux-2.0.39/scripts/checkhelp.pl 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.0.40/scripts/checkhelp.pl 2004-02-07 23:13:01.000000000 -0800 @@ -0,0 +1,30 @@ +#!/usr/bin/perl +# checkhelp.pl - finds configuration options that have no +# corresponding section in the help file +# +# made by Meelis Roos (mroos@tartu.cyber.ee) + +# read the help file +@options=split /\n/, `grep '^CONFIG' Documentation/Configure.help`; +die "Can't read Documentation/Configure.help\n" if $#options == -1; + +#read all the files +foreach $file (@ARGV) +{ + open (FILE, $file) || die "Can't open $file: $!\n"; + while () { + # repeat until no CONFIG_* are left + while (/^\s*(bool|tristate|dep_tristate|string|int|hex).*' *(.*)'.*(CONFIG_\w*)/) { + $what=$3; + $name=$2; + s/$3//; + @found = grep (/$what$/, @options); + if ($#found == -1) { + next if $nohelp{$what}; + print "$name\n$what\n No help for $what\n\n"; + $nohelp{$what}=1; + } + } + } + close (FILE); +} diff -urN linux-2.0.39/scripts/checkincludes.pl linux-2.0.40/scripts/checkincludes.pl --- linux-2.0.39/scripts/checkincludes.pl 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.0.40/scripts/checkincludes.pl 2004-02-07 23:13:01.000000000 -0800 @@ -0,0 +1,24 @@ +#!/usr/bin/perl +# +# checkincludes: Find files included more than once in (other) files. +# Copyright abandoned, 2000, Niels Kristian Bech Jensen . + +foreach $file (@ARGV) { + open(FILE, $file) or die "Cannot open $file: $!.\n"; + + my %includedfiles = (); + + while () { + if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) { + ++$includedfiles{$1}; + } + } + + foreach $filename (keys %includedfiles) { + if ($includedfiles{$filename} > 1) { + print "$file: $filename is included more than once.\n"; + } + } + + close(FILE); +} diff -urN linux-2.0.39/scripts/lxdialog/menubox.c linux-2.0.40/scripts/lxdialog/menubox.c --- linux-2.0.39/scripts/lxdialog/menubox.c 1998-11-15 10:33:24.000000000 -0800 +++ linux-2.0.40/scripts/lxdialog/menubox.c 2004-02-07 23:13:01.000000000 -0800 @@ -29,7 +29,7 @@ static void print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey) { - int i, j; + int j; char menu_item[menu_width+1]; strncpy(menu_item, item, menu_width); @@ -40,8 +40,11 @@ wattrset (win, menubox_attr); wmove (win, choice, 0); #if OLD_NCURSES - for (i = 0; i < menu_width; i++) - waddch (win, ' '); + { + int i; + for (i = 0; i < menu_width; i++) + waddch (win, ' '); + } #else wclrtoeol(win); #endif diff -urN linux-2.0.39/scripts/lxdialog/textbox.c linux-2.0.40/scripts/lxdialog/textbox.c --- linux-2.0.39/scripts/lxdialog/textbox.c 1998-11-15 10:33:24.000000000 -0800 +++ linux-2.0.40/scripts/lxdialog/textbox.c 2004-02-07 23:13:01.000000000 -0800 @@ -451,7 +451,7 @@ static void print_line (WINDOW * win, int row, int width) { - int i, y, x; + int y, x; char *line; line = get_line (); @@ -463,8 +463,11 @@ getyx (win, y, x); /* Clear 'residue' of previous line */ #if OLD_NCURSES - for (i = 0; i < width - x; i++) - waddch (win, ' '); + { + int i; + for (i = 0; i < width - x; i++) + waddch (win, ' '); + } #else wclrtoeol(win); #endif diff -urN linux-2.0.39/scripts/mkdep.c linux-2.0.40/scripts/mkdep.c --- linux-2.0.39/scripts/mkdep.c 1996-10-08 09:33:56.000000000 -0700 +++ linux-2.0.40/scripts/mkdep.c 2004-02-07 23:13:01.000000000 -0800 @@ -65,17 +65,17 @@ #endif #define GETNEXT { \ +if (next == end) \ + break; \ next_byte(__buf); \ if (!__nrbuf) { \ __buf = *(unsigned long *) next; \ __nrbuf = sizeof(unsigned long); \ - if (!__buf) \ - break; \ } next++; __nrbuf--; } #define CASE(c,label) if (current == c) goto label #define NOTCASE(c,label) if (current != c) goto label -static void state_machine(register char *next) +static void state_machine(register char *next, register char *end) { for(;;) { register unsigned long __buf = 0; @@ -244,7 +244,7 @@ return; } close(fd); - state_machine(map); + state_machine(map, map + st.st_size); munmap(map, mapsize); if (hasdep) puts(command);