diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-12-28 04:06:37 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-12-28 04:06:37 -0800 |
| commit | fb7d196b9a65a800e5d841c2543267383e6bf3cd (patch) | |
| tree | 7c2b2ab6d9439ce64384f7542fd5e2da817ea306 | |
| parent | 339d617ff03e2cc4326526f6ff395947b41d920b (diff) | |
| parent | 8b3c4cbfc0e727c76b53e55f22610d814e44dc97 (diff) | |
Merge
392 files changed, 15489 insertions, 5923 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index a57fca2015c2..8df1075acfe8 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -52,7 +52,7 @@ o Gnu C 2.95.3 # gcc --version o Gnu make 3.78 # make --version o binutils 2.9.5.0.25 # ld -v o util-linux 2.10o # fdformat --version -o modutils 2.4.2 # insmod -V +o module-init-tools 0.9 # rmmod -V o e2fsprogs 1.29 # tune2fs o jfsutils 1.0.14 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs @@ -141,14 +141,11 @@ If the unthinkable happens and your kernel oopses, you'll need a 2.4 version of ksymoops to decode the report; see REPORTING-BUGS in the root of the Linux source for more information. -Modutils +Module-Init-Tools -------- -Upgrade to recent modutils to fix various outstanding bugs which are -seen more frequently under 2.4.x, and to enable auto-loading of USB -modules. In addition, the layout of modules under -/lib/modules/`uname -r`/ has been made more sane. This change also -requires that you upgrade to a recent modutils. +A new module loader is now in the kernel that requires module-init-tools +to use. It is backward compatible with the 2.4.x series kernels. Mkinitrd -------- @@ -306,7 +303,7 @@ o <ftp://ftp.kernel.org/pub/linux/utils/kernel/ksymoops/v2.4/> Modutils -------- -o <ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.4/> +o <ftp://ftp.kernel.org/pub/linux/kernel/people/rusty/modules/> Mkinitrd -------- diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 12b0086b75ea..b3c00ed92451 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -213,7 +213,7 @@ The top Makefile exports the following variables: $(GENKSYMS) contains the command used to generate kernel symbol signatures when CONFIG_MODVERSIONS is enabled. The genksyms - command comes from the modutils package. + command comes from the module-init-tools package. CROSS_COMPILE diff --git a/Documentation/modules.txt b/Documentation/modules.txt index 833a05804052..e30516d41121 100644 --- a/Documentation/modules.txt +++ b/Documentation/modules.txt @@ -3,12 +3,11 @@ in the Linux kernel. This is not a technical description on the internals of module, but mostly a sample of how to compile and use modules. -Note: You should ensure that the modutils-X.Y.Z.tar.gz you are using -is the most up to date one for this kernel. The "X.Y.Z" will reflect -the kernel version at the time of the release of the modules package. -Some older modules packages aren't aware of some of the newer modular -features that the kernel now supports. The current required version -is listed in the file linux/Documentation/Changes. +Note: You should ensure that the module-init-tools-X.Y.Z.tar.gz you +are using is the most up to date one for this kernel. Some older +modules packages aren't aware of some of the newer modular features +that the kernel now supports. The current required version is listed +in the file linux/Documentation/Changes. * * * NOTE * * * The kernel has been changed to remove kerneld support and use @@ -124,7 +123,8 @@ And, yes, there _are_ man-pages for all this... To use modprobe successfully, you generally place the following command in your /etc/rc.d/rc.S script. (Read more about this in the -"rc.hints" file in the module utilities package, "modutils-x.y.z.tar.gz".) +"rc.hints" file in the module utilities package, +"module-init-tools-x.y.z.tar.gz".) /sbin/depmod -a diff --git a/Documentation/networking/z8530drv.txt b/Documentation/networking/z8530drv.txt index 60f453d18f89..2206abbc3e1b 100644 --- a/Documentation/networking/z8530drv.txt +++ b/Documentation/networking/z8530drv.txt @@ -54,7 +54,7 @@ Before you can use a module, you'll have to load it with insmod scc.o -please read 'man insmod' that comes with modutils. +please read 'man insmod' that comes with module-init-tools. You should include the insmod in one of the /etc/rc.d/rc.* files, and don't forget to insert a call of sccinit after that. It diff --git a/Documentation/sound/oss/Introduction b/Documentation/sound/oss/Introduction index 0b7fdc9593a4..90b41f8c3b4c 100644 --- a/Documentation/sound/oss/Introduction +++ b/Documentation/sound/oss/Introduction @@ -119,9 +119,9 @@ the README takes precedence. 6. Make the modules and install them (make modules; make modules_install). -Note, for 2.4.x kernels, make sure you have the newer modutils -loaded or modules will not be loaded properly. 2.4.x changed the -layout of /lib/modules/2.4.x and requires an updated modutils. +Note, for 2.5.x kernels, make sure you have the newer module-init-tools +installed or modules will not be loaded properly. 2.5.x requires an +updated module-init-tools. Plug and Play (PnP: diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index ac873ad4ce6e..424ccd9f7c45 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -286,9 +286,9 @@ can be ORed together: 1 - A module with a non-GPL license has been loaded, this includes modules with no license. - Set by modutils >= 2.4.9. + Set by modutils >= 2.4.9 and module-init-tools. 2 - A module was force loaded by insmod -f. - Set by modutils >= 2.4.9. + Set by modutils >= 2.4.9 and module-init-tools. 4 - Unsafe SMP processors: SMP with CPUs not designed for SMP. ============================================================== diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt new file mode 100644 index 000000000000..2950ab0012bf --- /dev/null +++ b/Documentation/uml/UserModeLinux-HOWTO.txt @@ -0,0 +1,4686 @@ + User Mode Linux HOWTO + User Mode Linux Core Team + Mon Nov 18 14:16:16 EST 2002 + + This document describes the use and abuse of Jeff Dike's User Mode + Linux: a port of the Linux kernel as a normal Intel Linux process. + ______________________________________________________________________ + + Table of Contents + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1. Introduction + + 1.1 How is User Mode Linux Different? + 1.2 Why Would I Want User Mode Linux? + + 2. Compiling the kernel and modules + + 2.1 Compiling the kernel + 2.2 Compiling and installing kernel modules + 2.3 Compiling and installing uml_utilities + + 3. Running UML and logging in + + 3.1 Running UML + 3.2 Logging in + 3.3 Examples + + 4. UML on 2G/2G hosts + + 4.1 Introduction + 4.2 The problem + 4.3 The solution + + 5. Setting up serial lines and consoles + + 5.1 Specifying the device + 5.2 Specifying the channel + 5.3 Examples + + 6. Setting up the network + + 6.1 General setup + 6.2 Userspace daemons + 6.3 Specifying ethernet addresses + 6.4 UML interface setup + 6.5 Multicast + 6.6 TUN/TAP with the uml_net helper + 6.7 TUN/TAP with a preconfigured tap device + 6.8 Ethertap + 6.9 The switch daemon + 6.10 Slip + 6.11 Slirp + 6.12 pcap + 6.13 Setting up the host yourself + + 7. Sharing Filesystems between Virtual Machines + + 7.1 A warning + 7.2 Using layered block devices + 7.3 Note! + 7.4 Another warning + 7.5 uml_moo : Merging a COW file with its backing file + + 8. Creating filesystems + + 8.1 Create the filesystem file + 8.2 Assign the file to a UML device + 8.3 Creating and mounting the filesystem + + 9. Host file access + + 9.1 Using hostfs + 9.2 hostfs as the root filesystem + 9.3 Building hostfs + + 10. The Management Console + 10.1 version + 10.2 halt and reboot + 10.3 config + 10.4 remove + 10.5 sysrq + 10.6 help + 10.7 cad + 10.8 stop + 10.9 go + + 11. Kernel debugging + + 11.1 Starting the kernel under gdb + 11.2 Examining sleeping processes + 11.3 Running ddd on UML + 11.4 Debugging modules + 11.5 Attaching gdb to the kernel + 11.6 Using alternate debuggers + + 12. Kernel debugging examples + + 12.1 The case of the hung fsck + 12.2 Episode 2: The case of the hung fsck + + 13. What to do when UML doesn't work + + 13.1 Strange compilation errors when you build from source + 13.2 UML hangs on boot after mounting devfs + 13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem + 13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid' + 13.5 UML doesn't work when /tmp is an NFS filesystem + 13.6 UML hangs on boot when compiled with gprof support + 13.7 syslogd dies with a SIGTERM on startup + 13.8 TUN/TAP networking doesn't work on a 2.4 host + 13.9 You can network to the host but not to other machines on the net + 13.10 I have no root and I want to scream + 13.11 UML build conflict between ptrace.h and ucontext.h + 13.12 The UML BogoMips is exactly half the host's BogoMips + 13.13 When you run UML, it immediately segfaults + 13.14 xterms appear, then immediately disappear + 13.15 Any other panic, hang, or strange behavior + + 14. Diagnosing Problems + + 14.1 Case 1 : Normal kernel panics + 14.2 Case 2 : Tracing thread panics + 14.3 Case 3 : Tracing thread panics caused by other threads + 14.4 Case 4 : Hangs + + 15. Thanks + + 15.1 Code and Documentation + 15.2 Flushing out bugs + 15.3 Buglets and clean-ups + 15.4 Case Studies + 15.5 Other contributions + + + ______________________________________________________________________ + + 11.. IInnttrroodduuccttiioonn + + Welcome to User Mode Linux. It's going to be fun. + + + + 11..11.. HHooww iiss UUsseerr MMooddee LLiinnuuxx DDiiffffeerreenntt?? + + Normally, the Linux Kernel talks straight to your hardware (video + card, keyboard, hard drives, etc), and any programs which run ask the + kernel to operate the hardware, like so: + + + + +-----------+-----------+----+ + | Process 1 | Process 2 | ...| + +-----------+-----------+----+ + | Linux Kernel | + +----------------------------+ + | Hardware | + +----------------------------+ + + + + + The User Mode Linux Kernel is different; instead of talking to the + hardware, it talks to a `real' Linux kernel (called the `host kernel' + from now on), like any other program. Programs can then run inside + User-Mode Linux as if they were running under a normal kernel, like + so: + + + + +----------------+ + | Process 2 | ...| + +-----------+----------------+ + | Process 1 | User-Mode Linux| + +----------------------------+ + | Linux Kernel | + +----------------------------+ + | Hardware | + +----------------------------+ + + + + + + 11..22.. WWhhyy WWoouulldd II WWaanntt UUsseerr MMooddee LLiinnuuxx?? + + + 1. If User Mode Linux crashes, your host kernel is still fine. + + 2. You can run a usermode kernel as a non-root user. + + 3. You can debug the User Mode Linux like any normal process. + + 4. You can run gprof (profiling) and gcov (coverage testing). + + 5. You can play with your kernel without breaking things. + + 6. You can use it as a sandbox for testing new apps. + + 7. You can try new development kernels safely. + + 8. You can run different distributions simultaneously. + + 9. It's extremely fun. + + + + + + 22.. CCoommppiilliinngg tthhee kkeerrnneell aanndd mmoodduulleess + + + + + 22..11.. CCoommppiilliinngg tthhee kkeerrnneell + + + Compiling the user mode kernel is just like compiling any other + kernel. Let's go through the steps, using 2.4.0-prerelease (current + as of this writing) as an example: + + + 1. Download the latest UML patch from + + the download page <http://user-mode-linux.sourceforge.net/dl- + sf.html> + + In this example, the file is uml-patch-2.4.0-prerelease.bz2. + + + 2. Download the matching kernel from your favourite kernel mirror, + such as: + + ftp://ftp.ca.kernel.org/pub/kernel/v2.4/linux-2.4.0-prerelease.tar.bz2 + <ftp://ftp.ca.kernel.org/pub/kernel/v2.4/linux-2.4.0-prerelease.tar.bz2> + . + + + 3. Make a directory and unpack the kernel into it. + + + + host% + mkdir ~/uml + + + + + + + host% + cd ~/uml + + + + + + + host% + tar -xzvf linux-2.4.0-prerelease.tar.bz2 + + + + + + + 4. Apply the patch using + + + + host% + cd ~/uml/linux + + + + host% + bzcat uml-patch-2.4.0-prerelease.bz2 | patch -p1 + + + + + + + 5. Run your favorite config; `make xconfig ARCH=um' is the most + convenient. `make config ARCH=um' and 'make menuconfig ARCH=um' + will work as well. The defaults will give you a useful kernel. If + you want to change something, go ahead, it probably won't hurt + anything. + + + Note: If the host is configured with a 2G/2G address space split + rather than the usual 3G/1G split, then the packaged UML binaries + will not run. They will immediately segfault. See ``UML on 2G/2G + hosts'' for the scoop on running UML on your system. + + + + 6. Finish with `make linux ARCH=um': the result is a file called + `linux' in the top directory of your source tree. + + Make sure that you don't build this kernel in /usr/src/linux. On some + distributions, /usr/include/asm is a link into this pool. The user- + mode build changes the other end of that link, and things that include + <asm/anything.h> stop compiling. + + The sources are also available from cvs at the project's cvs page, + which has directions on getting the sources. You can also browse the + CVS pool from there. + + If you get the CVS sources, you will have to check them out into an + empty directory. You will then have to copy each file into the + corresponding directory in the appropriate kernel pool. + + If you don't have the latest kernel pool, you can get the + corresponding user-mode sources with + + + host% cvs co -r v_2_3_x linux + + + + + where 'x' is the version in your pool. Note that you will not get the + bug fixes and enhancements that have gone into subsequent releases. + + + If you build your own kernel, and want to boot it from one of the + filesystems distributed from this site, then, in nearly all cases, + devfs must be compiled into the kernel and mounted at boot time. The + exception is the SuSE filesystem. For this, devfs must either not be + in the kernel at all, or "devfs=nomount" must be on the kernel command + line. Any disagreement between the kernel and the filesystem being + booted about whether devfs is being used will result in the boot + getting no further than single-user mode. + + + If you don't want to use devfs, you can remove the need for it from a + filesystem by copying /dev from someplace, making a bunch of /dev/ubd + devices: + + + UML# for i in 0 1 2 3 4 5 6 7; do mknod ubd$i b 98 $i; done + + + + + and changing /etc/fstab and /etc/inittab to refer to the non-devfs + devices. + + + + 22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess + + UML modules are built in the same way as the native kernel (with the + exception of the 'ARCH=um' that you always need for UML): + + + host% make modules ARCH=um + + + + + Any modules that you want to load into this kernel need to be built in + the user-mode pool. Modules from the native kernel won't work. + + You can install them by using ftp or something to copy them into the + virtual machine and dropping them into /lib/modules/`uname -r`. + + You can also get the kernel build process to install them as follows: + + 1. with the kernel not booted, mount the root filesystem in the top + level of the kernel pool: + + + host% mount root_fs mnt -o loop + + + + + + + 2. run + + + host% + make modules_install INSTALL_MOD_PATH=`pwd`/mnt ARCH=um + + + + + + + 3. unmount the filesystem + + + host% umount mnt + + + + + + + 4. boot the kernel on it + + + When the system is booted, you can use insmod as usual to get the + modules into the kernel. A number of things have been loaded into UML + as modules, especially filesystems and network protocols and filters, + so most symbols which need to be exported probably already are. + However, if you do find symbols that need exporting, let us + <http://user-mode-linux.sourceforge.net/contacts.html> know, and + they'll be "taken care of". + + + + 22..33.. CCoommppiilliinngg aanndd iinnssttaalllliinngg uummll__uuttiilliittiieess + + Many features of the UML kernel require a user-space helper program, + so a uml_utilities package is distributed separately from the kernel + patch which provides these helpers. Included within this is: + + +o port-helper - Used by consoles which connect to xterms or ports + + +o tunctl - Configuration tool to create and delete tap devices + + +o uml_net - Setuid binary for automatic tap device configuration + + +o uml_switch - User-space virtual switch required for daemon + transport + + The uml_utilities tree is compiled with: + + + host# + make && make install + + + + + Note that UML kernel patches may require a specific version of the + uml_utilities distribution. If you don't keep up with the mailing + lists, ensure that you have the latest release of uml_utilities if you + are experiencing problems with your UML kernel, particularly when + dealing with consoles or command-line switches to the helper programs + + + + + + + + + 33.. RRuunnnniinngg UUMMLL aanndd llooggggiinngg iinn + + + + 33..11.. RRuunnnniinngg UUMMLL + + It runs on 2.2.15 or later, and all 2.4 kernels. + + + Booting UML is straightforward. Simply run 'linux': it will try to + mount the file `root_fs' in the current directory. You do not need to + run it as root. If your root filesystem is not named `root_fs', then + you need to put a `ubd0=root_fs_whatever' switch on the linux command + line. + + + You will need a filesystem to boot UML from. There are a number + available for download from here <http://user-mode- + linux.sourceforge.net/dl-sf.html> . There are also several tools + <http://user-mode-linux.sourceforge.net/fs_making.html> which can be + used to generate UML-compatible filesystem images from media. + The kernel will boot up and present you with a login prompt. + + + Note: If the host is configured with a 2G/2G address space split + rather than the usual 3G/1G split, then the packaged UML binaries will + not run. They will immediately segfault. See ``UML on 2G/2G hosts'' + for the scoop on running UML on your system. + + + + 33..22.. LLooggggiinngg iinn + + + + The prepackaged filesystems have a root account with password 'root' + and a user account with password 'user'. The login banner will + generally tell you how to log in. So, you log in and you will find + yourself inside a little virtual machine. Our filesystems have a + variety of commands and utilities installed (and it is fairly easy to + add more), so you will have a lot of tools with which to poke around + the system. + + There are a couple of other ways to log in: + + +o On a virtual console + + + + Each virtual console that is configured (i.e. the device exists in + /dev and /etc/inittab runs a getty on it) will come up in its own + xterm. If you get tired of the xterms, read ``Setting up serial + lines and consoles'' to see how to attach the consoles to + something else, like host ptys. + + + + +o Over the serial line + + + In the boot output, find a line that looks like: + + + + serial line 0 assigned pty /dev/ptyp1 + + + + + Attach your favorite terminal program to the corresponding tty. I.e. + for minicom, the command would be + + + host% minicom -o -p /dev/ttyp1 + + + + + + + +o Over the net + + + If the network is running, then you can telnet to the virtual + machine and log in to it. See ``Setting up the network'' to learn + about setting up a virtual network. + + When you're done using it, run halt, and the kernel will bring itself + down and the process will exit. + + + 33..33.. EExxaammpplleess + + Here are some examples of UML in action: + + +o A login session <http://user-mode-linux.sourceforge.net/login.html> + + +o A virtual network <http://user-mode-linux.sourceforge.net/net.html> + + + + + + + + 44.. UUMMLL oonn 22GG//22GG hhoossttss + + + + + 44..11.. IInnttrroodduuccttiioonn + + + Most Linux machines are configured so that the kernel occupies the + upper 1G (0xc0000000 - 0xffffffff) of the 4G address space and + processes use the lower 3G (0x00000000 - 0xbfffffff). However, some + machine are configured with a 2G/2G split, with the kernel occupying + the upper 2G (0x80000000 - 0xffffffff) and processes using the lower + 2G (0x00000000 - 0x7fffffff). + + + + + 44..22.. TThhee pprroobblleemm + + + The prebuilt UML binaries on this site will not run on 2G/2G hosts + because UML occupies the upper .5G of the 3G process address space + (0xa0000000 - 0xbfffffff). Obviously, on 2G/2G hosts, this is right + in the middle of the kernel address space, so UML won't even load - it + will immediately segfault. + + + + + 44..33.. TThhee ssoolluuttiioonn + + + The fix for this is to rebuild UML from source after enabling + CONFIG_HOST_2G_2G (under 'General Setup'). This will cause UML to + load itself in the top .5G of that smaller process address space, + where it will run fine. See ``Compiling the kernel and modules'' if + you need help building UML from source. + + + + + + + + + + + 55.. SSeettttiinngg uupp sseerriiaall lliinneess aanndd ccoonnssoolleess + + + It is possible to attach UML serial lines and consoles to many types + of host I/O channels by specifying them on the command line. + + + You can attach them to host ptys, ttys, file descriptors, and ports. + This allows you to do things like + + +o have a UML console appear on an unused host console, + + +o hook two virtual machines together by having one attach to a pty + and having the other attach to the corresponding tty + + +o make a virtual machine accessible from the net by attaching a + console to a port on the host. + + + The general format of the command line option is device=channel. + + + + 55..11.. SSppeecciiffyyiinngg tthhee ddeevviiccee + + Devices are specified with "con" or "ssl" (console or serial line, + respectively), optionally with a device number if you are talking + about a specific device. + + + Using just "con" or "ssl" describes all of the consoles or serial + lines. If you want to talk about console #3 or serial line #10, they + would be "con3" and "ssl10", respectively. + + + A specific device name will override a less general "con=" or "ssl=". + So, for example, you can assign a pty to each of the serial lines + except for the first two like this: + + + ssl=pty ssl0=tty:/dev/tty0 ssl1=tty:/dev/tty1 + + + + + The specificity of the device name is all that matters; order on the + command line is irrelevant. + + + + 55..22.. SSppeecciiffyyiinngg tthhee cchhaannnneell + + There are a number of different types of channels to attach a UML + device to, each with a different way of specifying exactly what to + attach to. + + +o pseudo-terminals - device=pty pts terminals - device=pts + + + This will cause UML to allocate a free host pseudo-terminal for the + device. The terminal that it got will be announced in the boot + log. You access it by attaching a terminal program to the + corresponding tty: + + +o screen /dev/pts/n + + +o screen /dev/ttyxx + + +o minicom -o -p /dev/ttyxx - minicom seems not able to handle pts + devices + + +o kermit - start it up, 'open' the device, then 'connect' + + + + + + +o terminals - device=tty:tty device file + + + This will make UML attach the device to the specified tty (i.e + + + con1=tty:/dev/tty3 + + + + + will attach UML's console 1 to the host's /dev/tty3). If the tty that + you specify is the slave end of a tty/pty pair, something else must + have already opened the corresponding pty in order for this to work. + + + + + + +o xterms - device=xterm + + + UML will run an xterm and the device will be attached to it. + + + + + + +o Port - device=port:port number + + + This will attach the UML devices to the specified host port. + Attaching console 1 to the host's port 9000 would be done like + this: + + + con1=port:9000 + + + + + Attaching all the serial lines to that port would be done similarly: + + + ssl=port:9000 + + + + + You access these devices by telnetting to that port. Each active tel- + net session gets a different device. If there are more telnets to a + port than UML devices attached to it, then the extra telnet sessions + will block until an existing telnet detaches, or until another device + becomes active (i.e. by being activated in /etc/inittab). + + This channel has the advantage that you can both attach multiple UML + devices to it and know how to access them without reading the UML boot + log. It is also unique in allowing access to a UML from remote + machines without requiring that the UML be networked. This could be + useful in allowing public access to UMLs because they would be + accessible from the net, but wouldn't need any kind of network + filtering or access control because they would have no network access. + + + If you attach the main console to a portal, then the UML boot will + appear to hang. In reality, it's waiting for a telnet to connect, at + which point the boot will proceed. + + + + + + +o already-existing file descriptors - device=file descriptor + + + If you set up a file descriptor on the UML command line, you can + attach a UML device to it. This is most commonly used to put the + main console back on stdin and stdout after assigning all the other + consoles to something else: + + + con0=fd:0,fd:1 con=pts + + + + + + + + + +o Nothing - device=null + + + This allows the device to be opened, in contrast to 'none', but + reads will block, and writes will succeed and the data will be + thrown out. + + + + + + +o None - device=none + + + This causes the device to disappear. If you are using devfs, the + device will not appear in /dev. If not, then attempts to open it + will return -ENODEV. + + + + You can also specify different input and output channels for a device + by putting a comma between them: + + + ssl3=tty:/dev/tty2,xterm + + + + + will cause serial line 3 to accept input on the host's /dev/tty3 and + display output on an xterm. That's a silly example - the most common + use of this syntax is to reattach the main console to stdin and stdout + as shown above. + + + If you decide to move the main console away from stdin/stdout, the + initial boot output will appear in the terminal that you're running + UML in. However, once the console driver has been officially + initialized, then the boot output will start appearing wherever you + specified that console 0 should be. That device will receive all + subsequent output. + + + + 55..33.. EExxaammpplleess + + There are a number of interesting things you can do with this + capability. + + + First, this is how you get rid of those bleeding console xterms by + attaching them to host ptys: + + + con=pty con0=fd:0,fd:1 + + + + + This will make a UML console take over an unused host virtual console, + so that when you switch to it, you will see the UML login prompt + rather than the host login prompt: + + + con1=tty:/dev/tty6 + + + + + You can attach two virtual machines together with what amounts to a + serial line as follows: + + Run one UML with a serial line attached to a pty - + + + ssl1=pty + + + + + Look at the boot log to see what pty it got (this example will assume + that it got /dev/ptyp1). + + Boot the other UML with a serial line attached to the corresponding + tty - + + + ssl1=tty:/dev/ttyp1 + + + + + Log in, make sure that it has no getty on that serial line, attach a + terminal program like minicom to it, and you should see the login + prompt of the other virtual machine. + + + 66.. SSeettttiinngg uupp tthhee nneettwwoorrkk + + + + This page describes how to set up the various transports and to + provide a UML instance with network access to the host, other machines + on the local net, and the rest of the net. + + + As of 2.4.5, UML networking has been completely redone to make it much + easier to set up, fix bugs, and add new features. + + + There is a new helper, uml_net, which does the host setup that + requires root privileges. + + + There are currently five transport types available for a UML virtual + machine to exchange packets with other hosts: + + +o ethertap + + +o TUN/TAP + + +o Multicast + + +o a switch daemon + + +o slip + + +o slirp + + +o pcap + + The TUN/TAP, ethertap, slip, and slirp transports allow a UML + instance to exchange packets with the host. They may be directed + to the host or the host may just act as a router to provide access + to other physical or virtual machines. + + + The pcap transport is a synthetic read-only interface, using the + libpcap binary to collect packets from interfaces on the host and + filter them. This is useful for building preconfigured traffic + monitors or sniffers. + + + The daemon and multicast transports provide a completely virtual + network to other virtual machines. This network is completely + disconnected from the physical network unless one of the virtual + machines on it is acting as a gateway. + + + With so many host transports, which one should you use? Here's when + you should use each one: + + +o ethertap - if you want access to the host networking and it is + running 2.2 + + +o TUN/TAP - if you want access to the host networking and it is + running 2.4. Also, the TUN/TAP transport is able to use a + preconfigured device, allowing it to avoid using the setuid uml_net + helper, which is a security advantage. + + +o Multicast - if you want a purely virtual network and you don't want + to set up anything but the UML + + +o a switch daemon - if you want a purely virtual network and you + don't mind running the daemon in order to get somewhat better + performance + + +o slip - there is no particular reason to run the slip backend unless + ethertap and TUN/TAP are just not available for some reason + + +o slirp - if you don't have root access on the host to setup + networking, or if you don't want to allocate an IP to your UML + + +o pcap - not much use for actual network connectivity, but great for + monitoring traffic on the host + + Ethertap is available on 2.4 and works fine. TUN/TAP is preferred + to it because it has better performance and ethertap is officially + considered obsolete in 2.4. Also, the root helper only needs to + run occasionally for TUN/TAP, rather than handling every packet, as + it does with ethertap. This is a slight security advantage since + it provides fewer opportunities for a nasty UML user to somehow + exploit the helper's root privileges. + + + 66..11.. GGeenneerraall sseettuupp + + First, you must have the virtual network enabled in your UML. If are + running a prebuilt kernel from this site, everything is already + enabled. If you build the kernel yourself, under the "Network device + support" menu, enable "Network device support", and then the three + transports. + + + The next step is to provide a network device to the virtual machine. + This is done by describing it on the kernel command line. + + The general format is + + + eth <n> = <transport> , <transport args> + + + + + For example, a virtual ethernet device may be attached to a host + ethertap device as follows: + + + eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 + + + + + This sets up eth0 inside the virtual machine to attach itself to the + host /dev/tap0, assigns it an ethernet address, and assigns the host + tap0 interface an IP address. + + + + Note that the IP address you assign to the host end of the tap device + must be different than the IP you assign to the eth device inside UML. + If you are short on IPs and don't want to comsume two per UML, then + you can reuse the host's eth IP address for the host ends of the tap + devices. Internally, the UMLs must still get unique IPs for their eth + devices. You can also give the UMLs non-routable IPs (192.168.x.x or + 10.x.x.x) and have the host masquerade them. This will let outgoing + connections work, but incoming connections won't without more work, + such as port forwarding from the host. + Also note that when you configure the host side of an interface, it is + only acting as a gateway. It will respond to pings sent to it + locally, but is not useful to do that since it's a host interface. + You are not talking to the UML when you ping that interface and get a + response. + + + You can also add devices to a UML and remove them at runtime. See the + ``The Management Console'' page for details. + + + The sections below describe this in more detail. + + + Once you've decided how you're going to set up the devices, you boot + UML, log in, configure the UML side of the devices, and set up routes + to the outside world. At that point, you will be able to talk to any + other machines, physical or virtual, on the net. + + + If ifconfig inside UML fails and the network refuses to come up, run + tell you what went wrong. + + + + 66..22.. UUsseerrssppaaccee ddaaeemmoonnss + + You will likely need the setuid helper, or the switch daemon, or both. + They are both installed with the RPM and deb, so if you've installed + either, you can skip the rest of this section. + + + If not, then you need to check them out of CVS, build them, and + install them. The helper is uml_net, in CVS /tools/uml_net, and the + daemon is uml_switch, in CVS /tools/uml_router. They are both built + with a plain 'make'. Both need to be installed in a directory that's + in your path - /usr/bin is recommend. On top of that, uml_net needs + to be setuid root. + + + + 66..33.. SSppeecciiffyyiinngg eetthheerrnneett aaddddrreesssseess + + Below, you will see that the TUN/TAP, ethertap, and daemon interfaces + allow you to specify hardware addresses for the virtual ethernet + devices. This is generally not necessary. If you don't have a + specific reason to do it, you probably shouldn't. If one is not + specified on the command line, the driver will assign one based on the + device IP address. It will provide the address fe:fd:nn:nn:nn:nn + where nn.nn.nn.nn is the device IP address. This is nearly always + sufficient to guarantee a unique hardware address for the device. A + couple of exceptions are: + + +o Another set of virtual ethernet devices are on the same network and + they are assigned hardware addresses using a different scheme which + may conflict with the UML IP address-based scheme + + +o You aren't going to use the device for IP networking, so you don't + assign the device an IP address + + If you let the driver provide the hardware address, you should make + sure that the device IP address is known before the interface is + brought up. So, inside UML, this will guarantee that: + + + + UML# + ifconfig eth0 192.168.0.250 up + + + + + If you decide to assign the hardware address yourself, make sure that + the first byte of the address is even. Addresses with an odd first + byte are broadcast addresses, which you don't want assigned to a + device. + + + + 66..44.. UUMMLL iinntteerrffaaccee sseettuupp + + Once the network devices have been described on the command line, you + should boot UML and log in. + + + The first thing to do is bring the interface up: + + + UML# ifconfig ethn ip-address up + + + + + You should be able to ping the host at this point. + + + To reach the rest of the world, you should set a default route to the + host: + + + UML# route add default gw host ip + + + + + Again, with host ip of 192.168.0.4: + + + UML# route add default gw 192.168.0.4 + + + + + This page used to recommend setting a network route to your local net. + This is wrong, because it will cause UML to try to figure out hardware + addresses of the local machines by arping on the interface to the + host. Since that interface is basically a single strand of ethernet + with two nodes on it (UML and the host) and arp requests don't cross + networks, they will fail to elicit any responses. So, what you want + is for UML to just blindly throw all packets at the host and let it + figure out what to do with them, which is what leaving out the network + route and adding the default route does. + + + Note: If you can't communicate with other hosts on your physical + ethernet, it's probably because of a network route that's + automatically set up. If you run 'route -n' and see a route that + looks like this: + + + + + Destination Gateway Genmask Flags Metric Ref Use Iface + 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 + + + + + with a mask that's not 255.255.255.255, then replace it with a route + to your host: + + + UML# + route del -net 192.168.0.0 dev eth0 netmask 255.255.255.0 + + + + + + + UML# + route add -host 192.168.0.4 dev eth0 + + + + + This, plus the default route to the host, will allow UML to exchange + packets with any machine on your ethernet. + + + + 66..55.. MMuullttiiccaasstt + + The simplest way to set up a virtual network between multiple UMLs is + to use the mcast transport. This was written by Harald Welte and is + present in UML version 2.4.5-5um and later. Your system must have + multicast enabled in the kernel and there must be a multicast-capable + network device on the host. Normally, this is eth0, but if there is + no ethernet card on the host, then you will likely get strange error + messages when you bring the device up inside UML. + + + To use it, run two UMLs with + + + eth0=mcast + + + + + on their command lines. Log in, configure the ethernet device in each + machine with different IP addresses: + + + UML1# ifconfig eth0 192.168.0.254 + + + + + + + UML2# ifconfig eth0 192.168.0.253 + + + + + and they should be able to talk to each other. + + The full set of command line options for this transport are + + + + ethn=mcast,ethernet address,multicast + address,multicast port,ttl + + + + + Harald's original README is here <http://user-mode-linux.source- + forge.net/text/mcast.txt> and explains these in detail, as well as + some other issues. + + + + 66..66.. TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr + + TUN/TAP is the preferred mechanism on 2.4 to exchange packets with the + host. The TUN/TAP backend has been in UML since 2.4.9-3um. + + + The easiest way to get up and running is to let the setuid uml_net + helper do the host setup for you. This involves insmod-ing the tun.o + module if necessary, configuring the device, and setting up IP + forwarding, routing, and proxy arp. If you are new to UML networking, + do this first. If you're concerned about the security implications of + the setuid helper, use it to get up and running, then read the next + section to see how to have UML use a preconfigured tap device, which + avoids the use of uml_net. + + + If you specify an IP address for the host side of the device, the + uml_net helper will do all necessary setup on the host - the only + requirement is that TUN/TAP be available, either built in to the host + kernel or as the tun.o module. + + The format of the command line switch to attach a device to a TUN/TAP + device is + + + eth <n> =tuntap,,, <IP address> + + + + + For example, this argument will attach the UML's eth0 to the next + available tap device and assign an ethernet address to it based on its + IP address + + + eth0=tuntap,,,192.168.0.254 + + + + + + + Note that the IP address that must be used for the eth device inside + UML is fixed by the routing and proxy arp that is set up on the + TUN/TAP device on the host. You can use a different one, but it won't + work because reply packets won't reach the UML. This is a feature. + It prevents a nasty UML user from doing things like setting the UML IP + to the same as the network's nameserver or mail server. + + + There are a couple potential problems with running the TUN/TAP + transport on a 2.4 host kernel + + +o TUN/TAP seems not to work on 2.4.3 and earlier. Upgrade the host + kernel or use the ethertap transport. + + +o With an upgraded kernel, TUN/TAP may fail with + + + File descriptor in bad state + + + + + This is due to a header mismatch between the upgraded kernel and the + kernel that was originally installed on the machine. The fix is to + make sure that /usr/src/linux points to the headers for the running + kernel. + + These were pointed out by Tim Robinson <timro at trkr dot net> in + <http://www.geocrawler.com/lists/3/SourceForge/597/0/> name="this uml- + user post"> . + + + + 66..77.. TTUUNN//TTAAPP wwiitthh aa pprreeccoonnffiigguurreedd ttaapp ddeevviiccee + + If you prefer not to have UML use uml_net (which is somewhat + insecure), with UML 2.4.17-11, you can set up a TUN/TAP device + beforehand. The setup needs to be done as root, but once that's done, + there is no need for root assistance. Setting up the device is done + as follows: + + +o Create the device with tunctl (available from the UML utilities + tarball) + + + + + host# tunctl -u uid + + + + + where uid is the user id or username that UML will be run as. This + will tell you what device was created. + + +o Configure the device IP (change IP addresses and device name to + suit) + + + + + host# ifconfig tap0 192.168.0.254 up + + + + + + +o Set up routing and arping if desired - this is my recipe, there are + other ways of doing the same thing + + + host# + bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' + + host# + route add -host 192.168.0.253 dev tap0 + + + + + + + host# + bash -c 'echo 1 > /proc/sys/net/ipv4/conf/tap0/proxy_arp' + + + + + + + host# + arp -Ds 192.168.0.253 eth0 pub + + + + + Note that this must be done every time the host boots - this configu- + ration is not stored across host reboots. So, it's probably a good + idea to stick it in an rc file. An even better idea would be a little + utility which reads the information from a config file and sets up + devices at boot time. + + +o Rather than using up two IPs and ARPing for one of them, you can + also provide direct access to your LAN by the UML by using a + bridge. + + + host# + brctl addbr br0 + + + + + + + host# + ifconfig eth0 0.0.0.0 promisc up + + + + + + + host# + ifconfig tap0 0.0.0.0 promisc up + + + + + + + host# + ifconfig br0 192.168.0.1 netmask 255.255.255.0 up + + + + + + + + host# + brctl stp br0 off + + + + + + + host# + brctl setfd br0 1 + + + + + + + host# + brctl sethello br0 1 + + + + + + + host# + brctl addif br0 eth0 + + + + + + + host# + brctl addif br0 tap0 + + + + + Note that 'br0' should be setup using ifconfig with the existing IP + address of eth0, as eth0 no longer has its own IP. + + +o + + + Also, the /dev/net/tun device must be writable by the user running + UML in order for the UML to use the device that's been configured + for it. The simplest thing to do is + + + host# chmod 666 /dev/net/tun + + + + + Making it world-writeable looks bad, but it seems not to be + exploitable as a security hole. However, it does allow anyone to cre- + ate useless tap devices (useless because they can't configure them), + which is a DOS attack. A somewhat more secure alternative would to be + to create a group containing all the users who have preconfigured tap + devices and chgrp /dev/net/tun to that group with mode 664 or 660. + + + +o Once the device is set up, run UML with 'eth0=tuntap,device name' + (i.e. 'eth0=tuntap,tap0') on the command line (or do it with the + mconsole config command). + + +o Bring the eth device up in UML and you're in business. + + If you don't want that tap device any more, you can make it non- + persistent with + + + host# tunctl -d tap device + + + + + Finally, tunctl has a -b (for brief mode) switch which causes it to + output only the name of the tap device it created. This makes it + suitable for capture by a script: + + + host# TAP=`tunctl -u 1000 -b` + + + + + + + 66..88.. EEtthheerrttaapp + + Ethertap is the general mechanism on 2.2 for userspace processes to + exchange packets with the kernel. + + + + To use this transport, you need to describe the virtual network device + on the UML command line. The general format for this is + + + eth <n> =ethertap, <device> , <ethernet address> , <tap IP address> + + + + + So, the previous example + + + eth0=ethertap,tap0,fe:fd:0:0:0:1,192.168.0.254 + + + + + attaches the UML eth0 device to the host /dev/tap0, assigns it the + ethernet address fe:fd:0:0:0:1, and assigns the IP address + 192.168.0.254 to the tap device. + + + + The tap device is mandatory, but the others are optional. If the + ethernet address is omitted, one will be assigned to it. + + + The presence of the tap IP address will cause the helper to run and do + whatever host setup is needed to allow the virtual machine to + communicate with the outside world. If you're not sure you know what + you're doing, this is the way to go. + + + If it is absent, then you must configure the tap device and whatever + arping and routing you will need on the host. However, even in this + case, the uml_net helper still needs to be in your path and it must be + setuid root if you're not running UML as root. This is because the + tap device doesn't support SIGIO, which UML needs in order to use + something as a source of input. So, the helper is used as a + convenient asynchronous IO thread. + + If you're using the uml_net helper, you can ignore the following host + setup - uml_net will do it for you. You just need to make sure you + have ethertap available, either built in to the host kernel or + available as a module. + + + If you want to set things up yourself, you need to make sure that the + appropriate /dev entry exists. If it doesn't, become root and create + it as follows: + + + mknod /dev/tap <minor> c 36 <minor> + 16 + + + + + For example, this is how to create /dev/tap0: + + + mknod /dev/tap0 c 36 0 + 16 + + + + + You also need to make sure that the host kernel has ethertap support. + If ethertap is enabled as a module, you apparently need to insmod + ethertap once for each ethertap device you want to enable. So, + + + host# + insmod ethertap + + + + + will give you the tap0 interface. To get the tap1 interface, you need + to run + + + host# + insmod ethertap unit=1 -o ethertap1 + + + + + + + + 66..99.. TThhee sswwiittcchh ddaaeemmoonn + + NNoottee: This is the daemon formerly known as uml_router, but which was + renamed so the network weenies of the world would stop growling at me. + + + The switch daemon, uml_switch, provides a mechanism for creating a + totally virtual network. By default, it provides no connection to the + host network (but see -tap, below). + + + The first thing you need to do is run the daemon. Running it with no + arguments will make it listen on a default pair of unix domain + sockets. + + + If you want it to listen on a different pair of sockets, use + + + -unix control socket data socket + + + + + + If you want it to act as a hub rather than a switch, use + + + -hub + + + + + + If you want the switch to be connected to host networking (allowing + the umls to get access to the outside world through the host), use + + + -tap tap0 + + + + + + Note that the tap device must be preconfigured (see "TUN/TAP with a + preconfigured tap device", above). If you're using a different tap + device than tap0, specify that instead of tap0. + + + uml_switch can be backgrounded as follows + + + host% + uml_switch [ options ] < /dev/null > /dev/null + + + + + The reason it doesn't background by default is that it listens to + stdin for EOF. When it sees that, it exits. + + + The general format of the kernel command line switch is + + + + ethn=daemon,ethernet address,socket + type,control socket,data socket + + + + + You can leave off everything except the 'daemon'. You only need to + specify the ethernet address if the one that will be assigned to it + isn't acceptable for some reason. The rest of the arguments describe + how to communicate with the daemon. You should only specify them if + you told the daemon to use different sockets than the default. So, if + you ran the daemon with no arguments, running the UML on the same + machine with + eth0=daemon + + + + + will cause the eth0 driver to attach itself to the daemon correctly. + + + + 66..1100.. SSlliipp + + Slip is another, less general, mechanism for a process to communicate + with the host networking. In contrast to the ethertap interface, + which exchanges ethernet frames with the host and can be used to + transport any higher-level protocol, it can only be used to transport + IP. + + + The general format of the command line switch is + + + + ethn=slip,slip IP + + + + + The slip IP argument is the IP address that will be assigned to the + host end of the slip device. If it is specified, the helper will run + and will set up the host so that the virtual machine can reach it and + the rest of the network. + + + There are some oddities with this interface that you should be aware + of. You should only specify one slip device on a given virtual + machine, and its name inside UML will be 'umn', not 'eth0' or whatever + you specified on the command line. These problems will be fixed at + some point. + + + + 66..1111.. SSlliirrpp + + slirp uses an external program, usually /usr/bin/slirp, to provide IP + only networking connectivity through the host. This is similar to IP + masquerading with a firewall, although the translation is performed in + user-space, rather than by the kernel. As slirp does not set up any + interfaces on the host, or changes routing, slirp does not require + root access or setuid binaries on the host. + + + The general format of the command line switch for slirp is: + + + + ethn=slirp,ethernet address,slirp path + + + + + The ethernet address is optional, as UML will set up the interface + with an ethernet address based upon the initial IP address of the + interface. The slirp path is generally /usr/bin/slirp, although it + will depend on distribution. + + + The slirp program can have a number of options passed to the command + line and we can't add them to the UML command line, as they will be + parsed incorrectly. Instead, a wrapper shell script can be written or + the options inserted into the /.slirprc file. More information on + all of the slirp options can be found in its man pages. + + + The eth0 interface on UML should be set up with the IP 10.2.0.15, + although you can use anything as long as it is not used by a network + you will be connecting to. The default route on UML should be set to + use + + + UML# + route add default dev eth0 + + + + + slirp provides a number of useful IP addresses which can be used by + UML, such as 10.0.2.3 which is an alias for the DNS server specified + in /etc/resolv.conf on the host or the IP given in the 'dns' option + for slirp. + + + Even with a baudrate setting higher than 115200, the slirp connection + is limited to 115200. If you need it to go faster, the slirp binary + needs to be compiled with FULL_BOLT defined in config.h. + + + + 66..1122.. ppccaapp + + The pcap transport is attached to a UML ethernet device on the command + line or with uml_mconsole with the following syntax: + + + + ethn=pcap,host interface,filter + expression,option1,option2 + + + + + The expression and options are optional. + + + The interface is whatever network device on the host you want to + sniff. The expression is a pcap filter expression, which is also what + tcpdump uses, so if you know how to specify tcpdump filters, you will + use the same expressions here. The options are up to two of + 'promisc', control whether pcap puts the host interface into + promiscuous mode. 'optimize' and 'nooptimize' control whether the pcap + expression optimizer is used. + + + Example: + + + + eth0=pcap,eth0,tcp + + eth1=pcap,eth0,!tcp + + + + will cause the UML eth0 to emit all tcp packets on the host eth0 and + the UML eth1 to emit all non-tcp packets on the host eth0. + + + + 66..1133.. SSeettttiinngg uupp tthhee hhoosstt yyoouurrsseellff + + If you don't specify an address for the host side of the ethertap or + slip device, UML won't do any setup on the host. So this is what is + needed to get things working (the examples use a host-side IP of + 192.168.0.251 and a UML-side IP of 192.168.0.250 - adjust to suit your + own network): + + +o The device needs to be configured with its IP address. Tap devices + are also configured with an mtu of 1484. Slip devices are + configured with a point-to-point address pointing at the UML ip + address. + + + host# ifconfig tap0 arp mtu 1484 192.168.0.251 up + + + + + + + host# + ifconfig sl0 192.168.0.251 pointopoint 192.168.0.250 up + + + + + + +o If a tap device is being set up, a route is set to the UML IP. + + + UML# route add -host 192.168.0.250 gw 192.168.0.251 + + + + + + +o To allow other hosts on your network to see the virtual machine, + proxy arp is set up for it. + + + host# arp -Ds 192.168.0.250 eth0 pub + + + + + + +o Finally, the host is set up to route packets. + + + host# echo 1 > /proc/sys/net/ipv4/ip_forward + + + + + + + + + + + 77.. SShhaarriinngg FFiilleessyysstteemmss bbeettwweeeenn VViirrttuuaall MMaacchhiinneess + + + + + 77..11.. AA wwaarrnniinngg + + Don't attempt to share filesystems simply by booting two UMLs from the + same file. That's the same thing as booting two physical machines + from a shared disk. It will result in filesystem corruption. + + + + 77..22.. UUssiinngg llaayyeerreedd bblloocckk ddeevviicceess + + The way to share a filesystem between two virtual machines is to use + the copy-on-write (COW) layering capability of the ubd block driver. + As of 2.4.6-2um, the driver supports layering a read-write private + device over a read-only shared device. A machine's writes are stored + in the private device, while reads come from either device - the + private one if the requested block is valid in it, the shared one if + not. Using this scheme, the majority of data which is unchanged is + shared between an arbitrary number of virtual machines, each of which + has a much smaller file containing the changes that it has made. With + a large number of UMLs booting from a large root filesystem, this + leads to a huge disk space saving. It will also help performance, + since the host will be able to cache the shared data using a much + smaller amount of memory, so UML disk requests will be served from the + host's memory rather than its disks. + + + + + To add a copy-on-write layer to an existing block device file, simply + add the name of the COW file to the appropriate ubd switch: + + + ubd0=root_fs_cow,root_fs_debian_22 + + + + + where 'root_fs_cow' is the private COW file and 'root_fs_debian_22' is + the existing shared filesystem. The COW file need not exist. If it + doesn't, the driver will create and initialize it. Once the COW file + has been initialized, it can be used on its own on the command line: + + + ubd0=root_fs_cow + + + + + The name of the backing file is stored in the COW file header, so it + would be redundant to continue specifying it on the command line. + + + + 77..33.. NNoottee!! + + When checking the size of the COW file in order to see the gobs of + space that you're saving, make sure you use 'ls -ls' to see the actual + disk consumption rather than the length of the file. The COW file is + sparse, so the length will be very different from the disk usage. + Here is a 'ls -l' of a COW file and backing file from one boot and + shutdown: + host% ls -l cow.debian debian2.2 + -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian + -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 + + + + + Doesn't look like much saved space, does it? Well, here's 'ls -ls': + + + host% ls -ls cow.debian debian2.2 + 880 -rw-r--r-- 1 jdike jdike 492504064 Aug 6 21:16 cow.debian + 525832 -rwxrw-rw- 1 jdike jdike 537919488 Aug 6 20:42 debian2.2 + + + + + Now, you can see that the COW file has less than a meg of disk, rather + than 492 meg. + + + + 77..44.. AAnnootthheerr wwaarrnniinngg + + Once a filesystem is being used as a readonly backing file for a COW + file, do not boot directly from it or modify it in any way. Doing so + will invalidate any COW files that are using it. The mtime and size + of the backing file are stored in the COW file header at its creation, + and they must continue to match. If they don't, the driver will + refuse to use the COW file. + + + + + If you attempt to evade this restriction by changing either the + backing file or the COW header by hand, you will get a corrupted + filesystem. + + + + + Among other things, this means that upgrading the distribution in a + backing file and expecting that all of the COW files using it will see + the upgrade will not work. + + + + + 77..55.. uummll__mmoooo :: MMeerrggiinngg aa CCOOWW ffiillee wwiitthh iittss bbaacckkiinngg ffiillee + + Depending on how you use UML and COW devices, it may be advisable to + merge the changes in the COW file into the backing file every once in + a while. + + + + + The utility that does this is uml_moo. Its usage is + + + host% uml_moo COW file new backing file + + + + + There's no need to specify the backing file since that information is + already in the COW file header. If you're paranoid, boot the new + merged file, and if you're happy with it, move it over the old backing + file. + + + + + uml_moo creates a new backing file by default as a safety measure. It + also has a destructive merge option which will merge the COW file + directly into its current backing file. This is really only usable + when the backing file only has one COW file associated with it. If + there are multiple COWs associated with a backing file, a -d merge of + one of them will invalidate all of the others. However, it is + convenient if you're short of disk space, and it should also be + noticably faster than a non-destructive merge. + + + + + uml_moo is installed with the UML deb and RPM. If you didn't install + UML from one of those packages, you can also get it from the UML + utilities <http://user-mode-linux.sourceforge.net/dl-sf.html#UML + utilities> tar file in tools/moo. + + + + + + + + + 88.. CCrreeaattiinngg ffiilleessyysstteemmss + + + You may want to create and mount new UML filesystems, either because + your root filesystem isn't large enough or because you want to use a + filesystem other than ext2. + + + This was written on the occasion of reiserfs being included in the + 2.4.1 kernel pool, and therefore the 2.4.1 UML, so the examples will + talk about reiserfs. This information is generic, and the examples + should be easy to translate to the filesystem of your choice. + + + 88..11.. CCrreeaattee tthhee ffiilleessyysstteemm ffiillee + + dd is your friend. All you need to do is tell dd to create an empty + file of the appropriate size. I usually make it sparse to save time + and to avoid allocating disk space until it's actually used. For + example, the following command will create a sparse 100 meg file full + of zeroes. + + + host% + dd if=/dev/zero of=new_filesystem seek=100 count=1 bs=1M + + + + + + + 88..22.. AAssssiiggnn tthhee ffiillee ttoo aa UUMMLL ddeevviiccee + + Add an argument like the following to the UML command line: + + ubd4=new_filesystem + + + + + making sure that you use an unassigned ubd device number. + + + + 88..33.. CCrreeaattiinngg aanndd mmoouunnttiinngg tthhee ffiilleessyysstteemm + + Make sure that the filesystem is available, either by being built into + the kernel, or available as a module, then boot up UML and log in. If + the root filesystem doesn't have the filesystem utilities (mkfs, fsck, + etc), then get them into UML by way of the net or hostfs. + + + Make the new filesystem on the device assigned to the new file: + + + host# mkreiserfs /dev/ubd/4 + + + <----------- MKREISERFSv2 -----------> + + ReiserFS version 3.6.25 + Block size 4096 bytes + Block count 25856 + Used blocks 8212 + Journal - 8192 blocks (18-8209), journal header is in block 8210 + Bitmaps: 17 + Root block 8211 + Hash function "r5" + ATTENTION: ALL DATA WILL BE LOST ON '/dev/ubd/4'! (y/n)y + journal size 8192 (from 18) + Initializing journal - 0%....20%....40%....60%....80%....100% + Syncing..done. + + + + + Now, mount it: + + + UML# + mount /dev/ubd/4 /mnt + + + + + and you're in business. + + + + + + + + + + 99.. HHoosstt ffiillee aacccceessss + + + If you want to access files on the host machine from inside UML, you + can treat it as a separate machine and either nfs mount directories + from the host or copy files into the virtual machine with scp or rcp. + However, since UML is running on the the host, it can access those + files just like any other process and make them available inside the + virtual machine without needing to use the network. + + + This is now possible with the hostfs virtual filesystem. With it, you + can mount a host directory into the UML filesystem and access the + files contained in it just as you would on the host. + + + 99..11.. UUssiinngg hhoossttffss + + To begin with, make sure that hostfs is available inside the virtual + machine with + + + UML# cat /proc/filesystems + + + + . hostfs should be listed. If it's not, either rebuild the kernel + with hostfs configured into it or make sure that hostfs is built as a + module and available inside the virtual machine, and insmod it. + + + Now all you need to do is run mount: + + + UML# mount none /mnt/host -t hostfs + + + + + will mount the host's / on the virtual machine's /mnt/host. + + + If you don't want to mount the host root directory, then you can + specify a subdirectory to mount with the -o switch to mount: + + + UML# mount none /mnt/home -t hostfs -o /home + + + + + will mount the hosts's /home on the virtual machine's /mnt/home. + + + + 99..22.. hhoossttffss aass tthhee rroooott ffiilleessyysstteemm + + It's possible to boot from a directory hierarchy on the host using + hostfs rather than using the standard filesystem in a file. + + To start, you need that hierarchy. The easiest way is to loop mount + an existing root_fs file: + + + host# mount root_fs uml_root_dir -o loop + + + + + You need to change the filesystem type of / in etc/fstab to be + 'hostfs', so that line looks like this: + + /dev/ubd/0 / hostfs defaults 1 1 + + + + + Then you need to chown to yourself all the files in that directory + that are owned by root. This worked for me: + + + host# find . -uid 0 -exec chown jdike {} \; + + + + + Next, make sure that your UML kernel has hostfs compiled in, not as a + module. Then run UML with the boot device pointing at that directory: + + + ubd0=/path/to/uml/root/directory + + + + + UML should then boot as it does normally. + + + 99..33.. BBuuiillddiinngg hhoossttffss + + If you need to build hostfs because it's not in your kernel, you have + two choices: + + + + +o Compiling hostfs into the kernel: + + + Reconfigure the kernel and set the 'Host filesystem' option under + + + +o Compiling hostfs as a module: + + + Reconfigure the kernel and set the 'Host filesystem' option under + be in arch/um/fs/hostfs/hostfs.o. Install that in + /lib/modules/`uname -r`/fs in the virtual machine, boot it up, and + + + UML# insmod hostfs + + + + + + + + + + + + + 1100.. TThhee MMaannaaggeemmeenntt CCoonnssoollee + + + + The UML management console is a low-level interface to the kernel, + somewhat like the i386 SysRq interface. Since there is a full-blown + operating system under UML, there is much greater flexibility possible + than with the SysRq mechanism. + + + There are a number of things you can do with the mconsole interface: + + +o get the kernel version + + +o add and remove devices + + +o halt or reboot the machine + + +o Send SysRq commands + + +o Pause and resume the UML + + + You need the mconsole client (uml_mconsole) which is present in CVS + (/tools/mconsole) in 2.4.5-9um and later, and will be in the RPM in + 2.4.6. + + + You also need CONFIG_MCONSOLE (under 'General Setup') enabled in UML. + When you boot UML, you'll see a line like: + + + mconsole initialized on /home/jdike/.uml/umlNJ32yL/mconsole + + + + + If you specify a unique machine id one the UML command line, i.e. + + + umid=debian + + + + + you'll see this + + + mconsole initialized on /home/jdike/.uml/debian/mconsole + + + + + That file is the socket that uml_mconsole will use to communicate with + UML. Run it with either the umid or the full path as its argument: + + + host% uml_mconsole debian + + + + + or + + + host% uml_mconsole /home/jdike/.uml/debian/mconsole + + + + + You'll get a prompt, at which you can run one of these commands: + + +o version + + +o halt + + +o reboot + + +o config + + +o remove + + +o sysrq + + +o help + + +o cad + + +o stop + + +o go + + + 1100..11.. vveerrssiioonn + + This takes no arguments. It prints the UML version. + + + (mconsole) version + OK Linux usermode 2.4.5-9um #1 Wed Jun 20 22:47:08 EDT 2001 i686 + + + + + There are a couple actual uses for this. It's a simple no-op which + can be used to check that a UML is running. It's also a way of + sending an interrupt to the UML. This is sometimes useful on SMP + hosts, where there's a bug which causes signals to UML to be lost, + often causing it to appear to hang. Sending such a UML the mconsole + version command is a good way to 'wake it up' before networking has + been enabled, as it does not do anything to the function of the UML. + + + + 1100..22.. hhaalltt aanndd rreebboooott + + These take no arguments. They shut the machine down immediately, with + no syncing of disks and no clean shutdown of userspace. So, they are + pretty close to crashing the machine. + + + (mconsole) halt + OK + + + + + + + 1100..33.. ccoonnffiigg + + "config" adds a new device to the virtual machine. Currently the ubd + and network drivers support this. It takes one argument, which is the + device to add, with the same syntax as the kernel command line. + + + + + (mconsole) + config ubd3=/home/jdike/incoming/roots/root_fs_debian22 + + OK + (mconsole) config eth1=mcast + OK + + + + + + + 1100..44.. rreemmoovvee + + "remove" deletes a device from the system. Its argument is just the + name of the device to be removed. The device must be idle in whatever + sense the driver considers necessary. In the case of the ubd driver, + the removed block device must not be mounted, swapped on, or otherwise + open, and in the case of the network driver, the device must be down. + + + (mconsole) remove ubd3 + OK + (mconsole) remove eth1 + OK + + + + + + + 1100..55.. ssyyssrrqq + + This takes one argument, which is a single letter. It calls the + generic kernel's SysRq driver, which does whatever is called for by + that argument. See the SysRq documentation in Documentation/sysrq.txt + in your favorite kernel tree to see what letters are valid and what + they do. + + + + 1100..66.. hheellpp + + "help" returns a string listing the valid commands and what each one + does. + + + + 1100..77.. ccaadd + + This invokes the Ctl-Alt-Del action on init. What exactly this ends + up doing is up to /etc/inittab. Normally, it reboots the machine. + With UML, this is usually not desired, so if a halt would be better, + then find the section of inittab that looks like this + + + # What to do when CTRL-ALT-DEL is pressed. + ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now + + + + + and change the command to halt. + + + + 1100..88.. ssttoopp + + This puts the UML in a loop reading mconsole requests until a 'go' + mconsole command is recieved. This is very useful for making backups + of UML filesystems, as the UML can be stopped, then synced via 'sysrq + s', so that everything is written to the filesystem. You can then copy + the filesystem and then send the UML 'go' via mconsole. + + + Note that a UML running with more than one CPU will have problems + after you send the 'stop' command, as only one CPU will be held in a + mconsole loop and all others will continue as normal. This is a bug, + and will be fixed. + + + + 1100..99.. ggoo + + This resumes a UML after being paused by a 'stop' command. Note that + when the UML has resumed, TCP connections may have timed out and if + the UML is paused for a long period of time, crond might go a little + crazy, running all the jobs it didn't do earlier. + + + + + + + + + 1111.. KKeerrnneell ddeebbuuggggiinngg + + + NNoottee:: The interface that makes debugging, as described here, possible + is present in 2.4.0-test6 kernels and later. + + + Since the user-mode kernel runs as a normal Linux process, it is + possible to debug it with gdb almost like any other process. It is + slightly different because the kernel's threads are already being + ptraced for system call interception, so gdb can't ptrace them. + However, a mechanism has been added to work around that problem. + + + In order to debug the kernel, you need build it from source. See + ``Compiling the kernel and modules'' for information on doing that. + Make sure that you enable CONFIG_DEBUGSYM and CONFIG_PT_PROXY during + the config. These will compile the kernel with -g, and enable the + ptrace proxy so that gdb works with UML, respectively. + + + + + 1111..11.. SSttaarrttiinngg tthhee kkeerrnneell uunnddeerr ggddbb + + You can have the kernel running under the control of gdb from the + beginning by putting 'debug' on the command line. You will get an + xterm with gdb running inside it. The kernel will send some commands + to gdb which will leave it stopped at the beginning of start_kernel. + At this point, you can get things going with 'next', 'step', or + 'cont'. + + + There is a transcript of a debugging session here <debug- + session.html> , with breakpoints being set in the scheduler and in an + interrupt handler. + 1111..22.. EExxaammiinniinngg sslleeeeppiinngg pprroocceesssseess + + Not every bug is evident in the currently running process. Sometimes, + processes hang in the kernel when they shouldn't because they've + deadlocked on a semaphore or something similar. In this case, when + you ^C gdb and get a backtrace, you will see the idle thread, which + isn't very relevant. + + + What you want is the stack of whatever process is sleeping when it + shouldn't be. You need to figure out which process that is, which is + generally fairly easy. Then you need to get its host process id, + which you can do either by looking at ps on the host or at + task.thread.extern_pid in gdb. + + + Now what you do is this: + + +o detach from the current thread + + + (UML gdb) det + + + + + + +o attach to the thread you are interested in + + + (UML gdb) att <host pid> + + + + + + +o look at its stack and anything else of interest + + + (UML gdb) bt + + + + + Note that you can't do anything at this point that requires that a + process execute, e.g. calling a function + + +o when you're done looking at that process, reattach to the current + thread and continue it + + + (UML gdb) + att 1 + + + + + + + (UML gdb) + c + + + + + Here, specifying any pid which is not the process id of a UML thread + will cause gdb to reattach to the current thread. I commonly use 1, + but any other invalid pid would work. + + + + 1111..33.. RRuunnnniinngg dddddd oonn UUMMLL + + ddd works on UML, but requires a special kludge. The process goes + like this: + + +o Start ddd + + + host% ddd linux + + + + + + +o With ps, get the pid of the gdb that ddd started. You can ask the + gdb to tell you, but for some reason that confuses things and + causes a hang. + + +o run UML with 'debug=parent gdb-pid=<pid>' added to the command line + - it will just sit there after you hit return + + +o type 'att 1' to the ddd gdb and you will see something like + + + 0xa013dc51 in __kill () + + + (gdb) + + + + + + +o At this point, type 'c', UML will boot up, and you can use ddd just + as you do on any other process. + + + + 1111..44.. DDeebbuuggggiinngg mmoodduulleess + + gdb has support for debugging code which is dynamically loaded into + the process. This support is what is needed to debug kernel modules + under UML. + + + Using that support is somewhat complicated. You have to tell gdb what + object file you just loaded into UML and where in memory it is. Then, + it can read the symbol table, and figure out where all the symbols are + from the load address that you provided. It gets more interesting + when you load the module again (i.e. after an rmmod). You have to + tell gdb to forget about all its symbols, including the main UML ones + for some reason, then load then all back in again. + + + There's an easy way and a hard way to do this. The easy way is to use + the umlgdb expect script written by Chandan Kudige. It basically + automates the process for you. + + + First, you must tell it where your modules are. There is a list in + the script that looks like this: + set MODULE_PATHS { + "fat" "/usr/src/uml/linux-2.4.18/fs/fat/fat.o" + "isofs" "/usr/src/uml/linux-2.4.18/fs/isofs/isofs.o" + "minix" "/usr/src/uml/linux-2.4.18/fs/minix/minix.o" + } + + + + + You change that to list the names and paths of the modules that you + are going to debug. Then you run it from the toplevel directory of + your UML pool and it basically tells you what to do: + + + + + ******** GDB pid is 21903 ******** + Start UML as: ./linux <kernel switches> debug gdb-pid=21903 + + + + GNU gdb 5.0rh-5 Red Hat Linux 7.1 + Copyright 2001 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + (gdb) b sys_init_module + Breakpoint 1 at 0xa0011923: file module.c, line 349. + (gdb) att 1 + + + + + After you run UML and it sits there doing nothing, you hit return at + the 'att 1' and continue it: + + + Attaching to program: /home/jdike/linux/2.4/um/./linux, process 1 + 0xa00f4221 in __kill () + (UML gdb) c + Continuing. + + + + + At this point, you debug normally. When you insmod something, the + expect magic will kick in and you'll see something like: + + + + + + + + + + + + + + + + + + *** Module hostfs loaded *** + Breakpoint 1, sys_init_module (name_user=0x805abb0 "hostfs", + mod_user=0x8070e00) at module.c:349 + 349 char *name, *n_name, *name_tmp = NULL; + (UML gdb) finish + Run till exit from #0 sys_init_module (name_user=0x805abb0 "hostfs", + mod_user=0x8070e00) at module.c:349 + 0xa00e2e23 in execute_syscall (r=0xa8140284) at syscall_kern.c:411 + 411 else res = EXECUTE_SYSCALL(syscall, regs); + Value returned is $1 = 0 + (UML gdb) + p/x (int)module_list + module_list->size_of_struct + + $2 = 0xa9021054 + (UML gdb) symbol-file ./linux + Load new symbol table from "./linux"? (y or n) y + Reading symbols from ./linux... + done. + (UML gdb) + add-symbol-file /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o 0xa9021054 + + add symbol table from file "/home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o" at + .text_addr = 0xa9021054 + (y or n) y + + Reading symbols from /home/jdike/linux/2.4/um/arch/um/fs/hostfs/hostfs.o... + done. + (UML gdb) p *module_list + $1 = {size_of_struct = 84, next = 0xa0178720, name = 0xa9022de0 "hostfs", + size = 9016, uc = {usecount = {counter = 0}, pad = 0}, flags = 1, + nsyms = 57, ndeps = 0, syms = 0xa9023170, deps = 0x0, refs = 0x0, + init = 0xa90221f0 <init_hostfs>, cleanup = 0xa902222c <exit_hostfs>, + ex_table_start = 0x0, ex_table_end = 0x0, persist_start = 0x0, + persist_end = 0x0, can_unload = 0, runsize = 0, kallsyms_start = 0x0, + kallsyms_end = 0x0, + archdata_start = 0x1b855 <Address 0x1b855 out of bounds>, + archdata_end = 0xe5890000 <Address 0xe5890000 out of bounds>, + kernel_data = 0xf689c35d <Address 0xf689c35d out of bounds>} + >> Finished loading symbols for hostfs ... + + + + + That's the easy way. It's highly recommended. The hard way is + described below in case you're interested in what's going on. + + + Boot the kernel under the debugger and load the module with insmod or + modprobe. With gdb, do: + + + (UML gdb) p module_list + + + + + This is a list of modules that have been loaded into the kernel, with + the most recently loaded module first. Normally, the module you want + is at module_list. If it's not, walk down the next links, looking at + the name fields until find the module you want to debug. Take the + address of that structure, and add module.size_of_struct (which in + 2.4.10 kernels is 96 (0x60)) to it. Gdb can make this hard addition + for you :-): + + + + (UML gdb) + printf "%#x\n", (int)module_list module_list->size_of_struct + + + + + The offset from the module start occasionally changes (before 2.4.0, + it was module.size_of_struct + 4), so it's a good idea to check the + init and cleanup addresses once in a while, as describe below. Now + do: + + + (UML gdb) + add-symbol-file /path/to/module/on/host that_address + + + + + Tell gdb you really want to do it, and you're in business. + + + If there's any doubt that you got the offset right, like breakpoints + appear not to work, or they're appearing in the wrong place, you can + check it by looking at the module structure. The init and cleanup + fields should look like: + + + init = 0x588066b0 <init_hostfs>, cleanup = 0x588066c0 <exit_hostfs> + + + + + with no offsets on the symbol names. If the names are right, but they + are offset, then the offset tells you how much you need to add to the + address you gave to add-symbol-file. + + + When you want to load in a new version of the module, you need to get + gdb to forget about the old one. The only way I've found to do that + is to tell gdb to forget about all symbols that it knows about: + + + (UML gdb) symbol-file + + + + + Then reload the symbols from the kernel binary: + + + (UML gdb) symbol-file /path/to/kernel + + + + + and repeat the process above. You'll also need to re-enable break- + points. They were disabled when you dumped all the symbols because + gdb couldn't figure out where they should go. + + + + 1111..55.. AAttttaacchhiinngg ggddbb ttoo tthhee kkeerrnneell + + If you don't have the kernel running under gdb, you can attach gdb to + it later by sending the tracing thread a SIGUSR1. The first line of + the console output identifies its pid: + tracing thread pid = 20093 + + + + + When you send it the signal: + + + host% kill -USR1 20093 + + + + + you will get an xterm with gdb running in it. + + + If you have the mconsole compiled into UML, then the mconsole client + can be used to start gdb: + + + (mconsole) (mconsole) config gdb=xterm + + + + + will fire up an xterm with gdb running in it. + + + + 1111..66.. UUssiinngg aalltteerrnnaattee ddeebbuuggggeerrss + + UML has support for attaching to an already running debugger rather + than starting gdb itself. This is present in CVS as of 17 Apr 2001. + I sent it to Alan for inclusion in the ac tree, and it will be in my + 2.4.4 release. + + + This is useful when gdb is a subprocess of some UI, such as emacs or + ddd. It can also be used to run debuggers other than gdb on UML. + Below is an example of using strace as an alternate debugger. + + + To do this, you need to get the pid of the debugger and pass it in + with the + + + If you are using gdb under some UI, then tell it to 'att 1', and + you'll find yourself attached to UML. + + + If you are using something other than gdb as your debugger, then + you'll need to get it to do the equivalent of 'att 1' if it doesn't do + it automatically. + + + An example of an alternate debugger is strace. You can strace the + actual kernel as follows: + + +o Run the following in a shell + + + host% + sh -c 'echo pid=$$; echo -n hit return; read x; exec strace -p 1 -o strace.out' + + + + +o Run UML with 'debug' and 'gdb-pid=<pid>' with the pid printed out + by the previous command + + +o Hit return in the shell, and UML will start running, and strace + output will start accumulating in the output file. + + Note that this is different from running + + + host% strace ./linux + + + + + That will strace only the main UML thread, the tracing thread, which + doesn't do any of the actual kernel work. It just oversees the vir- + tual machine. In contrast, using strace as described above will show + you the low-level activity of the virtual machine. + + + + + + 1122.. KKeerrnneell ddeebbuuggggiinngg eexxaammpplleess + + 1122..11.. TThhee ccaassee ooff tthhee hhuunngg ffsscckk + + When booting up the kernel, fsck failed, and dropped me into a shell + to fix things up. I ran fsck -y, which hung: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Setting hostname uml [ OK ] + Checking root filesystem + /dev/fhd0 was not cleanly unmounted, check forced. + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. + + /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. + (i.e., without -a or -p options) + [ FAILED ] + + *** An error occurred during the file system check. + *** Dropping you to a shell; the system will reboot + *** when you leave the shell. + Give root password for maintenance + (or type Control-D for normal startup): + + [root@uml /root]# fsck -y /dev/fhd0 + fsck -y /dev/fhd0 + Parallelizing fsck version 1.14 (9-Jan-1999) + e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 + /dev/fhd0 contains a file system with errors, check forced. + Pass 1: Checking inodes, blocks, and sizes + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes + + Inode 19780, i_blocks is 1548, should be 540. Fix? yes + + Pass 2: Checking directory structure + Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes + + Directory inode 11858, block 0, offset 0: directory corrupted + Salvage? yes + + Missing '.' in directory inode 11858. + Fix? yes + + Missing '..' in directory inode 11858. + Fix? yes + + + + + + The standard drill in this sort of situation is to fire up gdb on the + signal thread, which, in this case, was pid 1935. In another window, + I run gdb and attach pid 1935. + + + + + ~/linux/2.3.26/um 1016: gdb linux + GNU gdb 4.17.0.11 with Linux support + Copyright 1998 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + + (gdb) att 1935 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1935 + 0x100756d9 in __wait4 () + + + + + + + Let's see what's currently running: + + + + (gdb) p current_task.pid + $1 = 0 + + + + + + It's the idle thread, which means that fsck went to sleep for some + reason and never woke up. + + + Let's guess that the last process in the process list is fsck: + + + + (gdb) p current_task.prev_task.comm + $13 = "fsck.ext2\000\000\000\000\000\000" + + + + + + It is, so let's see what it thinks it's up to: + + + + (gdb) p current_task.prev_task.thread + $14 = {extern_pid = 1980, tracing = 0, want_tracing = 0, forking = 0, + kernel_stack_page = 0, signal_stack = 1342627840, syscall = {id = 4, args = { + 3, 134973440, 1024, 0, 1024}, have_result = 0, result = 50590720}, + request = {op = 2, u = {exec = {ip = 1350467584, sp = 2952789424}, fork = { + regs = {1350467584, 2952789424, 0 <repeats 15 times>}, sigstack = 0, + pid = 0}, switch_to = 0x507e8000, thread = {proc = 0x507e8000, + arg = 0xaffffdb0, flags = 0, new_pid = 0}, input_request = { + op = 1350467584, fd = -1342177872, proc = 0, pid = 0}}}} + + + + + + The interesting things here are the fact that its .thread.syscall.id + is __NR_write (see the big switch in arch/um/kernel/syscall_kern.c or + the defines in include/asm-um/arch/unistd.h), and that it never + returned. Also, its .request.op is OP_SWITCH (see + arch/um/include/user_util.h). These mean that it went into a write, + and, for some reason, called schedule(). + + + The fact that it never returned from write means that its stack should + be fairly interesting. Its pid is 1980 (.thread.extern_pid). That + process is being ptraced by the signal thread, so it must be detached + before gdb can attach it: + + + + + + + + + + + (gdb) call detach(1980) + + Program received signal SIGSEGV, Segmentation fault. + <function called from gdb> + The program being debugged stopped while in a function called from GDB. + When the function (detach) is done executing, GDB will silently + stop (instead of continuing to evaluate the expression containing + the function call). + (gdb) call detach(1980) + $15 = 0 + + + + + + The first detach segfaults for some reason, and the second one + succeeds. + + + Now I detach from the signal thread, attach to the fsck thread, and + look at its stack: + + + (gdb) det + Detaching from program: /home/dike/linux/2.3.26/um/linux Pid 1935 + (gdb) att 1980 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 1980 + 0x10070451 in __kill () + (gdb) bt + #0 0x10070451 in __kill () + #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 + #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) + at process_kern.c:156 + #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) + at process_kern.c:161 + #4 0x10001d12 in schedule () at sched.c:777 + #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 + #6 0x1006aa10 in __down_failed () at semaphore.c:157 + #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 + #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + #9 <signal handler called> + #10 0x10155404 in errno () + #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 + #12 0x1006c5d8 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + #13 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + #14 <signal handler called> + #15 0xc0fd in ?? () + #16 0x10016647 in sys_write (fd=3, + buf=0x80b8800 <Address 0x80b8800 out of bounds>, count=1024) + at read_write.c:159 + #17 0x1006d5b3 in execute_syscall (syscall=4, args=0x5006ef08) + at syscall_kern.c:254 + #18 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 + #19 <signal handler called> + #20 0x400dc8b0 in ?? () + + + + + + The interesting things here are : + + +o There are two segfaults on this stack (frames 9 and 14) + + +o The first faulting address (frame 11) is 0x50000800 + + (gdb) p (void *)1342179328 + $16 = (void *) 0x50000800 + + + + + + The initial faulting address is interesting because it is on the idle + thread's stack. I had been seeing the idle thread segfault for no + apparent reason, and the cause looked like stack corruption. In hopes + of catching the culprit in the act, I had turned off all protections + to that stack while the idle thread wasn't running. This apparently + tripped that trap. + + + However, the more immediate problem is that second segfault and I'm + going to concentrate on that. First, I want to see where the fault + happened, so I have to go look at the sigcontent struct in frame 8: + + + + (gdb) up + #1 0x10068ccd in usr1_pid (pid=1980) at process.c:30 + 30 kill(pid, SIGUSR1); + (gdb) + #2 0x1006a03f in _switch_to (prev=0x50072000, next=0x507e8000) + at process_kern.c:156 + 156 usr1_pid(getpid()); + (gdb) + #3 0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000) + at process_kern.c:161 + 161 _switch_to(prev, next); + (gdb) + #4 0x10001d12 in schedule () at sched.c:777 + 777 switch_to(prev, next, prev); + (gdb) + #5 0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71 + 71 schedule(); + (gdb) + #6 0x1006aa10 in __down_failed () at semaphore.c:157 + 157 } + (gdb) + #7 0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174 + 174 segv(sc->cr2, sc->err & 2); + (gdb) + #8 0x1006c5ec in kern_segv_handler (sig=11) at trap_user.c:182 + 182 segv_handler(sc); + (gdb) p *sc + Cannot access memory at address 0x0. + + + + + That's not very useful, so I'll try a more manual method: + + + (gdb) p *((struct sigcontext *) (&sig + 1)) + $19 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, + __dsh = 0, edi = 1342179328, esi = 1350378548, ebp = 1342630440, + esp = 1342630420, ebx = 1348150624, edx = 1280, ecx = 0, eax = 0, + trapno = 14, err = 4, eip = 268480945, cs = 35, __csh = 0, eflags = 66118, + esp_at_signal = 1342630420, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, + cr2 = 1280} + + + + The ip is in handle_mm_fault: + + + (gdb) p (void *)268480945 + $20 = (void *) 0x1000b1b1 + (gdb) i sym $20 + handle_mm_fault + 57 in section .text + + + + + + Specifically, it's in pte_alloc: + + + (gdb) i line *$20 + Line 124 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1b1 <handle_mm_fault+57> + and ends at 0x1000b1b7 <handle_mm_fault+63>. + + + + + + To find where in handle_mm_fault this is, I'll jump forward in the + code until I see an address in that procedure: + + + + (gdb) i line *0x1000b1c0 + Line 126 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1b7 <handle_mm_fault+63> + and ends at 0x1000b1c3 <handle_mm_fault+75>. + (gdb) i line *0x1000b1d0 + Line 131 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1d0 <handle_mm_fault+88> + and ends at 0x1000b1da <handle_mm_fault+98>. + (gdb) i line *0x1000b1e0 + Line 61 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1da <handle_mm_fault+98> + and ends at 0x1000b1e1 <handle_mm_fault+105>. + (gdb) i line *0x1000b1f0 + Line 134 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b1f0 <handle_mm_fault+120> + and ends at 0x1000b200 <handle_mm_fault+136>. + (gdb) i line *0x1000b200 + Line 135 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b200 <handle_mm_fault+136> + and ends at 0x1000b208 <handle_mm_fault+144>. + (gdb) i line *0x1000b210 + Line 139 of "/home/dike/linux/2.3.26/um/include/asm/pgalloc.h" + starts at address 0x1000b210 <handle_mm_fault+152> + and ends at 0x1000b219 <handle_mm_fault+161>. + (gdb) i line *0x1000b220 + Line 1168 of "memory.c" starts at address 0x1000b21e <handle_mm_fault+166> + and ends at 0x1000b222 <handle_mm_fault+170>. + + + + + + Something is apparently wrong with the page tables or vma_structs, so + lets go back to frame 11 and have a look at them: + + + + #11 0x1006c0aa in segv (address=1342179328, is_write=2) at trap_kern.c:50 + 50 handle_mm_fault(current, vma, address, is_write); + (gdb) call pgd_offset_proc(vma->vm_mm, address) + $22 = (pgd_t *) 0x80a548c + + + + + + That's pretty bogus. Page tables aren't supposed to be in process + text or data areas. Let's see what's in the vma: + + + (gdb) p *vma + $23 = {vm_mm = 0x507d2434, vm_start = 0, vm_end = 134512640, + vm_next = 0x80a4f8c, vm_page_prot = {pgprot = 0}, vm_flags = 31200, + vm_avl_height = 2058, vm_avl_left = 0x80a8c94, vm_avl_right = 0x80d1000, + vm_next_share = 0xaffffdb0, vm_pprev_share = 0xaffffe63, + vm_ops = 0xaffffe7a, vm_pgoff = 2952789626, vm_file = 0xafffffec, + vm_private_data = 0x62} + (gdb) p *vma.vm_mm + $24 = {mmap = 0x507d2434, mmap_avl = 0x0, mmap_cache = 0x8048000, + pgd = 0x80a4f8c, mm_users = {counter = 0}, mm_count = {counter = 134904288}, + map_count = 134909076, mmap_sem = {count = {counter = 135073792}, + sleepers = -1342177872, wait = {lock = <optimized out or zero length>, + task_list = {next = 0xaffffe63, prev = 0xaffffe7a}, + __magic = -1342177670, __creator = -1342177300}, __magic = 98}, + page_table_lock = {}, context = 138, start_code = 0, end_code = 0, + start_data = 0, end_data = 0, start_brk = 0, brk = 0, start_stack = 0, + arg_start = 0, arg_end = 0, env_start = 0, env_end = 0, rss = 1350381536, + total_vm = 0, locked_vm = 0, def_flags = 0, cpu_vm_mask = 0, swap_cnt = 0, + swap_address = 0, segments = 0x0} + + + + + + This also pretty bogus. With all of the 0x80xxxxx and 0xaffffxxx + addresses, this is looking like a stack was plonked down on top of + these structures. Maybe it's a stack overflow from the next page: + + + + (gdb) p vma + $25 = (struct vm_area_struct *) 0x507d2434 + + + + + + That's towards the lower quarter of the page, so that would have to + have been pretty heavy stack overflow: + + + + + + + + + + + + + + + (gdb) x/100x $25 + 0x507d2434: 0x507d2434 0x00000000 0x08048000 0x080a4f8c + 0x507d2444: 0x00000000 0x080a79e0 0x080a8c94 0x080d1000 + 0x507d2454: 0xaffffdb0 0xaffffe63 0xaffffe7a 0xaffffe7a + 0x507d2464: 0xafffffec 0x00000062 0x0000008a 0x00000000 + 0x507d2474: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2484: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2494: 0x00000000 0x00000000 0x507d2fe0 0x00000000 + 0x507d24a4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24b4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24c4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24d4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24e4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d24f4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2504: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2514: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2524: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2534: 0x00000000 0x00000000 0x507d25dc 0x00000000 + 0x507d2544: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2554: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2564: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2574: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2584: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d2594: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d25a4: 0x00000000 0x00000000 0x00000000 0x00000000 + 0x507d25b4: 0x00000000 0x00000000 0x00000000 0x00000000 + + + + + + It's not stack overflow. The only "stack-like" piece of this data is + the vma_struct itself. + + + At this point, I don't see any avenues to pursue, so I just have to + admit that I have no idea what's going on. What I will do, though, is + stick a trap on the segfault handler which will stop if it sees any + writes to the idle thread's stack. That was the thing that happened + first, and it may be that if I can catch it immediately, what's going + on will be somewhat clearer. + + + 1122..22.. EEppiissooddee 22:: TThhee ccaassee ooff tthhee hhuunngg ffsscckk + + After setting a trap in the SEGV handler for accesses to the signal + thread's stack, I reran the kernel. + + + fsck hung again, this time by hitting the trap: + + + + + + + + + + + + + + + + + Setting hostname uml [ OK ] + Checking root filesystem + /dev/fhd0 contains a file system with errors, check forced. + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. + + /dev/fhd0: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. + (i.e., without -a or -p options) + [ FAILED ] + + *** An error occurred during the file system check. + *** Dropping you to a shell; the system will reboot + *** when you leave the shell. + Give root password for maintenance + (or type Control-D for normal startup): + + [root@uml /root]# fsck -y /dev/fhd0 + fsck -y /dev/fhd0 + Parallelizing fsck version 1.14 (9-Jan-1999) + e2fsck 1.14, 9-Jan-1999 for EXT2 FS 0.5b, 95/08/09 + /dev/fhd0 contains a file system with errors, check forced. + Pass 1: Checking inodes, blocks, and sizes + Error reading block 86894 (Attempt to read block from filesystem resulted in short read) while reading indirect blocks of inode 19780. Ignore error? yes + + Pass 2: Checking directory structure + Error reading block 49405 (Attempt to read block from filesystem resulted in short read). Ignore error? yes + + Directory inode 11858, block 0, offset 0: directory corrupted + Salvage? yes + + Missing '.' in directory inode 11858. + Fix? yes + + Missing '..' in directory inode 11858. + Fix? yes + + Untested (4127) [100fe44c]: trap_kern.c line 31 + + + + + + I need to get the signal thread to detach from pid 4127 so that I can + attach to it with gdb. This is done by sending it a SIGUSR1, which is + caught by the signal thread, which detaches the process: + + + kill -USR1 4127 + + + + + + Now I can run gdb on it: + + + + + + + + + + + + + + ~/linux/2.3.26/um 1034: gdb linux + GNU gdb 4.17.0.11 with Linux support + Copyright 1998 Free Software Foundation, Inc. + GDB is free software, covered by the GNU General Public License, and you are + welcome to change it and/or distribute copies of it under certain conditions. + Type "show copying" to see the conditions. + There is absolutely no warranty for GDB. Type "show warranty" for details. + This GDB was configured as "i386-redhat-linux"... + (gdb) att 4127 + Attaching to program `/home/dike/linux/2.3.26/um/linux', Pid 4127 + 0x10075891 in __libc_nanosleep () + + + + + + The backtrace shows that it was in a write and that the fault address + (address in frame 3) is 0x50000800, which is right in the middle of + the signal thread's stack page: + + + (gdb) bt + #0 0x10075891 in __libc_nanosleep () + #1 0x1007584d in __sleep (seconds=1000000) + at ../sysdeps/unix/sysv/linux/sleep.c:78 + #2 0x1006ce9a in stop () at user_util.c:191 + #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 + #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + #5 0x1006c63c in kern_segv_handler (sig=11) at trap_user.c:182 + #6 <signal handler called> + #7 0xc0fd in ?? () + #8 0x10016647 in sys_write (fd=3, buf=0x80b8800 "R.", count=1024) + at read_write.c:159 + #9 0x1006d603 in execute_syscall (syscall=4, args=0x5006ef08) + at syscall_kern.c:254 + #10 0x1006af87 in really_do_syscall (sig=12) at syscall_user.c:35 + #11 <signal handler called> + #12 0x400dc8b0 in ?? () + #13 <signal handler called> + #14 0x400dc8b0 in ?? () + #15 0x80545fd in ?? () + #16 0x804daae in ?? () + #17 0x8054334 in ?? () + #18 0x804d23e in ?? () + #19 0x8049632 in ?? () + #20 0x80491d2 in ?? () + #21 0x80596b5 in ?? () + (gdb) p (void *)1342179328 + $3 = (void *) 0x50000800 + + + + + + Going up the stack to the segv_handler frame and looking at where in + the code the access happened shows that it happened near line 110 of + block_dev.c: + + + + + + + + + + (gdb) up + #1 0x1007584d in __sleep (seconds=1000000) + at ../sysdeps/unix/sysv/linux/sleep.c:78 + ../sysdeps/unix/sysv/linux/sleep.c:78: No such file or directory. + (gdb) + #2 0x1006ce9a in stop () at user_util.c:191 + 191 while(1) sleep(1000000); + (gdb) + #3 0x1006bf88 in segv (address=1342179328, is_write=2) at trap_kern.c:31 + 31 KERN_UNTESTED(); + (gdb) + #4 0x1006c628 in segv_handler (sc=0x5006eaf8) at trap_user.c:174 + 174 segv(sc->cr2, sc->err & 2); + (gdb) p *sc + $1 = {gs = 0, __gsh = 0, fs = 0, __fsh = 0, es = 43, __esh = 0, ds = 43, + __dsh = 0, edi = 1342179328, esi = 134973440, ebp = 1342631484, + esp = 1342630864, ebx = 256, edx = 0, ecx = 256, eax = 1024, trapno = 14, + err = 6, eip = 268550834, cs = 35, __csh = 0, eflags = 66070, + esp_at_signal = 1342630864, ss = 43, __ssh = 0, fpstate = 0x0, oldmask = 0, + cr2 = 1342179328} + (gdb) p (void *)268550834 + $2 = (void *) 0x1001c2b2 + (gdb) i sym $2 + block_write + 1090 in section .text + (gdb) i line *$2 + Line 209 of "/home/dike/linux/2.3.26/um/include/asm/arch/string.h" + starts at address 0x1001c2a1 <block_write+1073> + and ends at 0x1001c2bf <block_write+1103>. + (gdb) i line *0x1001c2c0 + Line 110 of "block_dev.c" starts at address 0x1001c2bf <block_write+1103> + and ends at 0x1001c2e3 <block_write+1139>. + + + + + + Looking at the source shows that the fault happened during a call to + copy_to_user to copy the data into the kernel: + + + 107 count -= chars; + 108 copy_from_user(p,buf,chars); + 109 p += chars; + 110 buf += chars; + + + + + + p is the pointer which must contain 0x50000800, since buf contains + 0x80b8800 (frame 8 above). It is defined as: + + + p = offset + bh->b_data; + + + + + + I need to figure out what bh is, and it just so happens that bh is + passed as an argument to mark_buffer_uptodate and mark_buffer_dirty a + few lines later, so I do a little disassembly: + + + + + (gdb) disas 0x1001c2bf 0x1001c2e0 + Dump of assembler code from 0x1001c2bf to 0x1001c2d0: + 0x1001c2bf <block_write+1103>: addl %eax,0xc(%ebp) + 0x1001c2c2 <block_write+1106>: movl 0xfffffdd4(%ebp),%edx + 0x1001c2c8 <block_write+1112>: btsl $0x0,0x18(%edx) + 0x1001c2cd <block_write+1117>: btsl $0x1,0x18(%edx) + 0x1001c2d2 <block_write+1122>: sbbl %ecx,%ecx + 0x1001c2d4 <block_write+1124>: testl %ecx,%ecx + 0x1001c2d6 <block_write+1126>: jne 0x1001c2e3 <block_write+1139> + 0x1001c2d8 <block_write+1128>: pushl $0x0 + 0x1001c2da <block_write+1130>: pushl %edx + 0x1001c2db <block_write+1131>: call 0x1001819c <__mark_buffer_dirty> + End of assembler dump. + + + + + + At that point, bh is in %edx (address 0x1001c2da), which is calculated + at 0x1001c2c2 as %ebp + 0xfffffdd4, so I figure exactly what that is, + taking %ebp from the sigcontext_struct above: + + + (gdb) p (void *)1342631484 + $5 = (void *) 0x5006ee3c + (gdb) p 0x5006ee3c+0xfffffdd4 + $6 = 1342630928 + (gdb) p (void *)$6 + $7 = (void *) 0x5006ec10 + (gdb) p *((void **)$7) + $8 = (void *) 0x50100200 + + + + + + Now, I look at the structure to see what's in it, and particularly, + what its b_data field contains: + + + (gdb) p *((struct buffer_head *)0x50100200) + $13 = {b_next = 0x50289380, b_blocknr = 49405, b_size = 1024, b_list = 0, + b_dev = 15872, b_count = {counter = 1}, b_rdev = 15872, b_state = 24, + b_flushtime = 0, b_next_free = 0x501001a0, b_prev_free = 0x50100260, + b_this_page = 0x501001a0, b_reqnext = 0x0, b_pprev = 0x507fcf58, + b_data = 0x50000800 "", b_page = 0x50004000, + b_end_io = 0x10017f60 <end_buffer_io_sync>, b_dev_id = 0x0, + b_rsector = 98810, b_wait = {lock = <optimized out or zero length>, + task_list = {next = 0x50100248, prev = 0x50100248}, __magic = 1343226448, + __creator = 0}, b_kiobuf = 0x0} + + + + + + The b_data field is indeed 0x50000800, so the question becomes how + that happened. The rest of the structure looks fine, so this probably + is not a case of data corruption. It happened on purpose somehow. + + + The b_page field is a pointer to the page_struct representing the + 0x50000000 page. Looking at it shows the kernel's idea of the state + of that page: + + + + (gdb) p *$13.b_page + $17 = {list = {next = 0x50004a5c, prev = 0x100c5174}, mapping = 0x0, + index = 0, next_hash = 0x0, count = {counter = 1}, flags = 132, lru = { + next = 0x50008460, prev = 0x50019350}, wait = { + lock = <optimized out or zero length>, task_list = {next = 0x50004024, + prev = 0x50004024}, __magic = 1342193708, __creator = 0}, + pprev_hash = 0x0, buffers = 0x501002c0, virtual = 1342177280, + zone = 0x100c5160} + + + + + + Some sanity-checking: the virtual field shows the "virtual" address of + this page, which in this kernel is the same as its "physical" address, + and the page_struct itself should be mem_map[0], since it represents + the first page of memory: + + + + (gdb) p (void *)1342177280 + $18 = (void *) 0x50000000 + (gdb) p mem_map + $19 = (mem_map_t *) 0x50004000 + + + + + + These check out fine. + + + Now to check out the page_struct itself. In particular, the flags + field shows whether the page is considered free or not: + + + (gdb) p (void *)132 + $21 = (void *) 0x84 + + + + + + The "reserved" bit is the high bit, which is definitely not set, so + the kernel considers the signal stack page to be free and available to + be used. + + + At this point, I jump to conclusions and start looking at my early + boot code, because that's where that page is supposed to be reserved. + + + In my setup_arch procedure, I have the following code which looks just + fine: + + + + bootmap_size = init_bootmem(start_pfn, end_pfn - start_pfn); + free_bootmem(__pa(low_physmem) + bootmap_size, high_physmem - low_physmem); + + + + + + Two stack pages have already been allocated, and low_physmem points to + the third page, which is the beginning of free memory. + The init_bootmem call declares the entire memory to the boot memory + manager, which marks it all reserved. The free_bootmem call frees up + all of it, except for the first two pages. This looks correct to me. + + + So, I decide to see init_bootmem run and make sure that it is marking + those first two pages as reserved. I never get that far. + + + Stepping into init_bootmem, and looking at bootmem_map before looking + at what it contains shows the following: + + + + (gdb) p bootmem_map + $3 = (void *) 0x50000000 + + + + + + Aha! The light dawns. That first page is doing double duty as a + stack and as the boot memory map. The last thing that the boot memory + manager does is to free the pages used by its memory map, so this page + is getting freed even its marked as reserved. + + + The fix was to initialize the boot memory manager before allocating + those two stack pages, and then allocate them through the boot memory + manager. After doing this, and fixing a couple of subsequent buglets, + the stack corruption problem disappeared. + + + + + + 1133.. WWhhaatt ttoo ddoo wwhheenn UUMMLL ddooeessnn''tt wwoorrkk + + + + + 1133..11.. SSttrraannggee ccoommppiillaattiioonn eerrrroorrss wwhheenn yyoouu bbuuiilldd ffrroomm ssoouurrccee + + As of test11, it is necessary to have "ARCH=um" in the environment or + on the make command line for all steps in building UML, including + clean, distclean, or mrproper, config, menuconfig, or xconfig, dep, + and linux. If you forget for any of them, the i386 build seems to + contaminate the UML build. If this happens, start from scratch with + + + host% + make mrproper ARCH=um + + + + + and repeat the build process with ARCH=um on all the steps. + + + See ``Compiling the kernel and modules'' for more details. + + + Another cause of strange compilation errors is building UML in + /usr/src/linux. If you do this, the first thing you need to do is + clean up the mess you made. The /usr/src/linux/asm link will now + point to /usr/src/linux/asm-um. Make it point back to + /usr/src/linux/asm-i386. Then, move your UML pool someplace else and + build it there. Also see below, where a more specific set of symptoms + is described. + + + + 1133..22.. UUMMLL hhaannggss oonn bboooott aafftteerr mmoouunnttiinngg ddeevvffss + + The boot looks like this: + + + VFS: Mounted root (ext2 filesystem) readonly. + Mounted devfs on /dev + + + + + You're probably running a recent distribution on an old machine. I + saw this with the RH7.1 filesystem running on a Pentium. The shared + library loader, ld.so, was executing an instruction (cmove) which the + Pentium didn't support. That instruction was apparently added later. + If you run UML under the debugger, you'll see the hang caused by one + instruction causing an infinite SIGILL stream. + + + The fix is to boot UML on an older filesystem. + + + + 1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss-- + tteemm + + I saw this on reiserfs 3.5.21 and it seems to be fixed in 3.5.27. + Panics preceded by + + + Detaching pid nnnn + + + + are diagnostic of this problem. This is a reiserfs bug which causes a + thread to occasionally read stale data from a mmapped page shared with + another thread. The fix is to upgrade the filesystem or to have /tmp + be an ext2 filesystem. + + + + 1133..44.. TThhee ccoommppiillee ffaaiillss wwiitthh eerrrroorrss aabboouutt ccoonnfflliiccttiinngg ttyyppeess ffoorr + ''ooppeenn'',, ''dduupp'',, aanndd ''wwaaiittppiidd'' + + This happens when you build in /usr/src/linux. The UML build makes + the include/asm link point to include/asm-um. /usr/include/asm points + to /usr/src/linux/include/asm, so when that link gets moved, files + which need to include the asm-i386 versions of headers get the + incompatible asm-um versions. The fix is to move the include/asm link + back to include/asm-i386 and to do UML builds someplace else. + + + + 1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm + + This seems to be a similar situation with the resierfs problem above. + Some versions of NFS seems not to handle mmap correctly, which UML + depends on. The workaround is have /tmp be non-NFS directory. + + + 1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt + + If you build UML with gprof support and, early in the boot, it does + this + + + kernel BUG at page_alloc.c:100! + + + + + you have a buggy gcc. You can work around the problem by removing + UM_FASTCALL from CFLAGS in arch/um/Makefile-i386. This will open up + another bug, but that one is fairly hard to reproduce. + + + + 1133..77.. ssyyssllooggdd ddiieess wwiitthh aa SSIIGGTTEERRMM oonn ssttaarrttuupp + + The exact boot error depends on the distribution that you're booting, + but Debian produces this: + + + /etc/rc2.d/S10sysklogd: line 49: 93 Terminated + start-stop-daemon --start --quiet --exec /sbin/syslogd -- $SYSLOGD + + + + + This is a syslogd bug. There's a race between a parent process + installing a signal handler and its child sending the signal. See + this uml-devel post <http://www.geocrawler.com/lists/3/Source- + Forge/709/0/6612801> for the details. + + + + 1133..88.. TTUUNN//TTAAPP nneettwwoorrkkiinngg ddooeessnn''tt wwoorrkk oonn aa 22..44 hhoosstt + + There are a couple of problems which were + <http://www.geocrawler.com/lists/3/SourceForge/597/0/> name="pointed + out"> by Tim Robinson <timro at trkr dot net> + + +o It doesn't work on hosts running 2.4.7 (or thereabouts) or earlier. + The fix is to upgrade to something more recent and then read the + next item. + + +o If you see + + + File descriptor in bad state + + + + when you bring up the device inside UML, you have a header mismatch + between the original kernel and the upgraded one. Make /usr/src/linux + point at the new headers. This will only be a problem if you build + uml_net yourself. + + + + 1133..99.. YYoouu ccaann nneettwwoorrkk ttoo tthhee hhoosstt bbuutt nnoott ttoo ootthheerr mmaacchhiinneess oonn tthhee + nneett + + If you can connect to the host, and the host can connect to UML, but + you can not connect to any other machines, then you may need to enable + IP Masquerading on the host. Usually this is only experienced when + using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML + networking, rather than the public address space that your host is + connected to. UML does not enable IP Masquerading, so you will need + to create a static rule to enable it: + + + host% + iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + + + + + Replace eth0 with the interface that you use to talk to the rest of + the world. + + + Documentation on IP Masquerading, and SNAT, can be found at + www.netfilter.org <http://www.netfilter.org> . + + + If you can reach the local net, but not the outside Internet, then + that is usually a routing problem. The UML needs a default route: + + + UML# + route add default gw gateway IP + + + + + The gateway IP can be any machine on the local net that knows how to + reach the outside world. Usually, this is the host or the local net- + work's gateway. + + + Occasionally, we hear from someone who can reach some machines, but + not others on the same net, or who can reach some ports on other + machines, but not others. These are usually caused by strange + firewalling somewhere between the UML and the other box. You track + this down by running tcpdump on every interface the packets travel + over and see where they disappear. When you find a machine that takes + the packets in, but does not send them onward, that's the culprit. + + + + 1133..1100.. II hhaavvee nnoo rroooott aanndd II wwaanntt ttoo ssccrreeaamm + + Thanks to Birgit Wahlich for telling me about this strange one. It + turns out that there's a limit of six environment variables on the + kernel command line. When that limit is reached or exceeded, argument + processing stops, which means that the 'root=' argument that UML + usually adds is not seen. So, the filesystem has no idea what the + root device is, so it panics. + + + The fix is to put less stuff on the command line. Glomming all your + setup variables into one is probably the best way to go. + + + + 1133..1111.. UUMMLL bbuuiilldd ccoonnfflliicctt bbeettwweeeenn ppttrraaccee..hh aanndd uuccoonntteexxtt..hh + + On some older systems, /usr/include/asm/ptrace.h and + /usr/include/sys/ucontext.h define the same names. So, when they're + included together, the defines from one completely mess up the parsing + of the other, producing errors like: + /usr/include/sys/ucontext.h:47: parse error before + `10' + + + + + plus a pile of warnings. + + + This is a libc botch, which has since been fixed, and I don't see any + way around it besides upgrading. + + + + 1133..1122.. TThhee UUMMLL BBooggooMMiippss iiss eexxaaccttllyy hhaallff tthhee hhoosstt''ss BBooggooMMiippss + + On i386 kernels, there are two ways of running the loop that is used + to calculate the BogoMips rating, using the TSC if it's there or using + a one-instruction loop. The TSC produces twice the BogoMips as the + loop. UML uses the loop, since it has nothing resembling a TSC, and + will get almost exactly the same BogoMips as a host using the loop. + However, on a host with a TSC, its BogoMips will be double the loop + BogoMips, and therefore double the UML BogoMips. + + + + 1133..1133.. WWhheenn yyoouu rruunn UUMMLL,, iitt iimmmmeeddiiaatteellyy sseeggffaauullttss + + If the host is configured with the 2G/2G address space split, that's + why. See ``UML on 2G/2G hosts'' for the details on getting UML to + run on your host. + + + + 1133..1144.. xxtteerrmmss aappppeeaarr,, tthheenn iimmmmeeddiiaatteellyy ddiissaappppeeaarr + + If you're running an up to date kernel with an old release of + uml_utilities, the port-helper program will not work properly, so + xterms will exit straight after they appear. The solution is to + upgrade to the latest release of uml_utilities. Usually this problem + occurs when you have installed a packaged release of UML then compiled + your own development kernel without upgrading the uml_utilities from + the source distribution. + + + + 1133..1155.. AAnnyy ootthheerr ppaanniicc,, hhaanngg,, oorr ssttrraannggee bbeehhaavviioorr + + If you're seeing truly strange behavior, such as hangs or panics that + happen in random places, or you try running the debugger to see what's + happening and it acts strangely, then it could be a problem in the + host kernel. If you're not running a stock Linus or -ac kernel, then + try that. An early version of the preemption patch and a 2.4.10 SuSE + kernel have caused very strange problems in UML. + + + Otherwise, let me know about it. Send a message to one of the UML + mailing lists - either the developer list - user-mode-linux-devel at + lists dot sourceforge dot net (subscription info) or the user list - + user-mode-linux-user at lists dot sourceforge do net (subscription + info), whichever you prefer. Don't assume that everyone knows about + it and that a fix is imminent. + + + If you want to be super-helpful, read ``Diagnosing Problems'' and + follow the instructions contained therein. + 1144.. DDiiaaggnnoossiinngg PPrroobblleemmss + + + If you get UML to crash, hang, or otherwise misbehave, you should + report this on one of the project mailing lists, either the developer + list - user-mode-linux-devel at lists dot sourceforge dot net + (subscription info) or the user list - user-mode-linux-user at lists + dot sourceforge dot net (subscription info). When you do, it is + likely that I will want more information. So, it would be helpful to + read the stuff below, do whatever is applicable in your case, and + report the results to the list. + + + For any diagnosis, you're going to need to build a debugging kernel. + The binaries from this site aren't debuggable. If you haven't done + this before, read about ``Compiling the kernel and modules'' and + ``Kernel debugging'' UML first. + + + 1144..11.. CCaassee 11 :: NNoorrmmaall kkeerrnneell ppaanniiccss + + The most common case is for a normal thread to panic. To debug this, + you will need to run it under the debugger (add 'debug' to the command + line). An xterm will start up with gdb running inside it. Continue + it when it stops in start_kernel and make it crash. Now ^C gdb and + + + If the panic was a "Kernel mode fault", then there will be a segv + frame on the stack and I'm going to want some more information. The + stack might look something like this: + + + (UML gdb) backtrace + #0 0x1009bf76 in __sigprocmask (how=1, set=0x5f347940, oset=0x0) + at ../sysdeps/unix/sysv/linux/sigprocmask.c:49 + #1 0x10091411 in change_sig (signal=10, on=1) at process.c:218 + #2 0x10094785 in timer_handler (sig=26) at time_kern.c:32 + #3 0x1009bf38 in __restore () + at ../sysdeps/unix/sysv/linux/i386/sigaction.c:125 + #4 0x1009534c in segv (address=8, ip=268849158, is_write=2, is_user=0) + at trap_kern.c:66 + #5 0x10095c04 in segv_handler (sig=11) at trap_user.c:285 + #6 0x1009bf38 in __restore () + + + + + I'm going to want to see the symbol and line information for the value + of ip in the segv frame. In this case, you would do the following: + + + (UML gdb) i sym 268849158 + + + + + and + + + (UML gdb) i line *268849158 + + + + + The reason for this is the __restore frame right above the segv_han- + dler frame is hiding the frame that actually segfaulted. So, I have + to get that information from the faulting ip. + + + 1144..22.. CCaassee 22 :: TTrraacciinngg tthhrreeaadd ppaanniiccss + + The less common and more painful case is when the tracing thread + panics. In this case, the kernel debugger will be useless because it + needs a healthy tracing thread in order to work. The first thing to + do is get a backtrace from the tracing thread. This is done by + figuring out what its pid is, firing up gdb, and attaching it to that + pid. You can figure out the tracing thread pid by looking at the + first line of the console output, which will look like this: + + + tracing thread pid = 15851 + + + + + or by running ps on the host and finding the line that looks like + this: + + + jdike 15851 4.5 0.4 132568 1104 pts/0 S 21:34 0:05 ./linux [(tracing thread)] + + + + + If the panic was 'segfault in signals', then follow the instructions + above for collecting information about the location of the seg fault. + + + If the tracing thread flaked out all by itself, then send that + backtrace in and wait for our crack debugging team to fix the problem. + + + 1144..33.. CCaassee 33 :: TTrraacciinngg tthhrreeaadd ppaanniiccss ccaauusseedd bbyy ootthheerr tthhrreeaaddss + + However, there are cases where the misbehavior of another thread + caused the problem. The most common panic of this type is: + + + wait_for_stop failed to wait for <pid> to stop with <signal number> + + + + + In this case, you'll need to get a backtrace from the process men- + tioned in the panic, which is complicated by the fact that the kernel + debugger is defunct and without some fancy footwork, another gdb can't + attach to it. So, this is how the fancy footwork goes: + + In a shell: + + + host% kill -STOP pid + + + + + Run gdb on the tracing thread as described in case 2 and do: + + + (host gdb) call detach(pid) + + + If you get a segfault, do it again. It always works the second time. + + Detach from the tracing thread and attach to that other thread: + + + (host gdb) detach + + + + + + + (host gdb) attach pid + + + + + If gdb hangs when attaching to that process, go back to a shell and + do: + + + host% + kill -CONT pid + + + + + And then get the backtrace: + + + (host gdb) backtrace + + + + + + 1144..44.. CCaassee 44 :: HHaannggss + + Hangs seem to be fairly rare, but they sometimes happen. When a hang + happens, we need a backtrace from the offending process. Run the + kernel debugger as described in case 1 and get a backtrace. If the + current process is not the idle thread, then send in the backtrace. + You can tell that it's the idle thread if the stack looks like this: + + + #0 0x100b1401 in __libc_nanosleep () + #1 0x100a2885 in idle_sleep (secs=10) at time.c:122 + #2 0x100a546f in do_idle () at process_kern.c:445 + #3 0x100a5508 in cpu_idle () at process_kern.c:471 + #4 0x100ec18f in start_kernel () at init/main.c:592 + #5 0x100a3e10 in start_kernel_proc (unused=0x0) at um_arch.c:71 + #6 0x100a383f in signal_tramp (arg=0x100a3dd8) at trap_user.c:50 + + + + + If this is the case, then some other process is at fault, and went to + sleep when it shouldn't have. Run ps on the host and figure out which + process should not have gone to sleep and stayed asleep. Then attach + to it with gdb and get a backtrace as described in case 3. + + + + + + + 1155.. TThhaannkkss + + + A number of people have helped this project in various ways, and this + page gives recognition where recognition is due. + + + If you're listed here and you would prefer a real link on your name, + or no link at all, instead of the despammed email address pseudo-link, + let me know. + + + If you're not listed here and you think maybe you should be, please + let me know that as well. I try to get everyone, but sometimes my + bookkeeping lapses and I forget about contributions. + + + 1155..11.. CCooddee aanndd DDooccuummeennttaattiioonn + + Rusty Russell <rusty at linuxcare.com.au> - + + +o wrote the HOWTO <http://user-mode- + linux.sourceforge.net/UserModeLinux-HOWTO.html> + + +o prodded me into making this project official and putting it on + SourceForge + + +o came up with the way cool UML logo <http://user-mode- + linux.sourceforge.net/uml-small.png> + + +o redid the config process + + + Peter Moulder <reiter at netspace.net.au> - Fixed my config and build + processes, and added some useful code to the block driver + + + Bill Stearns <wstearns at pobox.com> - + + +o HOWTO updates + + +o lots of bug reports + + +o lots of testing + + +o dedicated a box (uml.ists.dartmouth.edu) to support UML development + + +o wrote the mkrootfs script, which allows bootable filesystems of + RPM-based distributions to be cranked out + + +o cranked out a large number of filesystems with said script + + + Jim Leu <jleu at mindspring.com> - Wrote the virtual ethernet driver + and associated usermode tools + + Lars Brinkhoff <http://lars.nocrew.org/> - Contributed the ptrace + proxy from his own project <http://a386.nocrew.org/> to allow easier + kernel debugging + + + Andrea Arcangeli <andrea at suse.de> - Redid some of the early boot + code so that it would work on machines with Large File Support + + + Chris Emerson <http://www.chiark.greenend.org.uk/~cemerson/> - Did + the first UML port to Linux/ppc + + + Harald Welte <laforge at gnumonks.org> - Wrote the multicast + transport for the network driver + + + Jorgen Cederlof - Added special file support to hostfs + + + Greg Lonnon <glonnon at ridgerun dot com> - Changed the ubd driver + to allow it to layer a COW file on a shared read-only filesystem and + wrote the iomem emulation support + + + Henrik Nordstrom <http://hem.passagen.se/hno/> - Provided a variety + of patches, fixes, and clues + + + Lennert Buytenhek - Contributed various patches, a rewrite of the + network driver, the first implementation of the mconsole driver, and + did the bulk of the work needed to get SMP working again. + + + Yon Uriarte - Fixed the TUN/TAP network backend while I slept. + + + Adam Heath - Made a bunch of nice cleanups to the initialization code, + plus various other small patches. + + + Matt Zimmerman - Matt volunteered to be the UML Debian maintainer and + is doing a real nice job of it. He also noticed and fixed a number of + actually and potentially exploitable security holes in uml_net. Plus + the occasional patch. I like patches. + + + James McMechan - James seems to have taken over maintenance of the ubd + driver and is doing a nice job of it. + + + Chandan Kudige - wrote the umlgdb script which automates the reloading + of module symbols. + + + Steve Schmidtke - wrote the UML slirp transport and hostaudio drivers, + enabling UML processes to access audio devices on the host. He also + submitted patches for the slip transport and lots of other things. + + + David Coulson <http://davidcoulson.net> - + + +o Set up the usermodelinux.org <http://usermodelinux.org> site, + which is a great way of keeping the UML user community on top of + UML goings-on. + + +o Site documentation and updates + + +o Nifty little UML management daemon UMLd + <http://uml.openconsultancy.com/umld/> + + +o Lots of testing and bug reports + + + + + 1155..22.. FFlluusshhiinngg oouutt bbuuggss + + + + +o Yuri Pudgorodsky + + +o Gerald Britton + + +o Ian Wehrman + + +o Gord Lamb + + +o Eugene Koontz + + +o John H. Hartman + + +o Anders Karlsson + + +o Daniel Phillips + + +o John Fremlin + + +o Rainer Burgstaller + + +o James Stevenson + + +o Matt Clay + + +o Cliff Jefferies + + +o Geoff Hoff + + +o Lennert Buytenhek + + +o Al Viro + + +o Frank Klingenhoefer + + +o Livio Baldini Soares + + +o Jon Burgess + + +o Petru Paler + + +o Paul + + +o Chris Reahard + + +o Sverker Nilsson + + +o Gong Su + + +o johan verrept + + +o Bjorn Eriksson + + +o Lorenzo Allegrucci + + +o Muli Ben-Yehuda + + +o David Mansfield + + +o Howard Goff + + +o Mike Anderson + + +o John Byrne + + +o Sapan J. Batia + + +o Iris Huang + + +o Jan Hudec + + +o Voluspa + + + + + 1155..33.. BBuugglleettss aanndd cclleeaann--uuppss + + + + +o Dave Zarzycki + + +o Adam Lazur + + +o Boria Feigin + + +o Brian J. Murrell + + +o JS + + +o Roman Zippel + + +o Wil Cooley + + +o Ayelet Shemesh + + +o Will Dyson + + +o Sverker Nilsson + + +o dvorak + + +o v.naga srinivas + + +o Shlomi Fish + + +o Roger Binns + + +o johan verrept + + +o MrChuoi + + +o Peter Cleve + + +o Vincent Guffens + + +o Nathan Scott + + +o Patrick Caulfield + + +o jbearce + + +o Catalin Marinas + + +o Shane Spencer + + +o Zou Min + + + +o Ryan Boder + + +o Lorenzo Colitti + + +o Gwendal Grignou + + +o Andre' Breiler + + +o Tsutomu Yasuda + + + + 1155..44.. CCaassee SSttuuddiieess + + + +o Jon Wright + + +o William McEwan + + +o Michael Richardson + + + + 1155..55.. OOtthheerr ccoonnttrriibbuuttiioonnss + + + Bill Carr <Bill.Carr at compaq.com> made the Red Hat mkrootfs script + work with RH 6.2. + + Michael Jennings <mikejen at hevanet.com> sent in some material which + is now gracing the top of the index page <http://user-mode- + linux.sourceforge.net/index.html> of this site. + + SGI <http://www.sgi.com> (and more specifically Ralf Baechle <ralf at + uni-koblenz.de> ) gave me an account on oss.sgi.com + <http://www.oss.sgi.com> . The bandwidth there made it possible to + produce most of the filesystems available on the project download + page. + + Laurent Bonnaud <Laurent.Bonnaud at inpg.fr> took the old grotty + Debian filesystem that I've been distributing and updated it to 2.2. + It is now available by itself here. + + Rik van Riel gave me some ftp space on ftp.nl.linux.org so I can make + releases even when Sourceforge is broken. + + Rodrigo de Castro looked at my broken pte code and told me what was + wrong with it, letting me fix a long-standing (several weeks) and + serious set of bugs. + + Chris Reahard built a specialized root filesystem for running a DNS + server jailed inside UML. It's available from the download + <http://user-mode-linux.sourceforge.net/dl-sf.html> page in the Jail + Filesysems section. + + + + + + + + + + + + diff --git a/Documentation/usb/hotplug.txt b/Documentation/usb/hotplug.txt index 9e3b8fe50405..62d5860f324e 100644 --- a/Documentation/usb/hotplug.txt +++ b/Documentation/usb/hotplug.txt @@ -5,8 +5,8 @@ into the bus with power on. In most cases, users expect the devices to become immediately usable. That means the system must do many things, including: - Find a driver that can handle the device. That may involve - loading a kernel module; newer drivers can use modutils to - publish their device (and class) support to user utilities. + loading a kernel module; newer drivers can use module-init-tools + to publish their device (and class) support to user utilities. - Bind a driver to that device. Bus frameworks do that using a device driver's probe() routine. @@ -76,15 +76,15 @@ user mode daemon to detect changes in system configuration. Currently available policy agent implementations can load drivers for modules, and can invoke driver-specific setup scripts. The newest ones -leverage USB modutils support. Later agents might unload drivers. +leverage USB module-init-tools support. Later agents might unload drivers. USB MODUTILS SUPPORT -Current versions of modutils will create a "modules.usbmap" file which -contains the entries from each driver's MODULE_DEVICE_TABLE. Such files -can be used by various user mode policy agents to make sure all the right -driver modules get loaded, either at boot time or later. +Current versions of module-init-tools will create a "modules.usbmap" file +which contains the entries from each driver's MODULE_DEVICE_TABLE. Such +files can be used by various user mode policy agents to make sure all the +right driver modules get loaded, either at boot time or later. See <linux/usb.h> for full information about such table entries; or look at existing drivers. Each table entry describes one or more criteria to diff --git a/Documentation/video4linux/README.cpia b/Documentation/video4linux/README.cpia index 521ef795a647..c95e7bbc0fdf 100644 --- a/Documentation/video4linux/README.cpia +++ b/Documentation/video4linux/README.cpia @@ -51,9 +51,9 @@ CONFIG_VIDEO_DEV=m CONFIG_VIDEO_CPIA=m CONFIG_VIDEO_CPIA_PP=m -For autoloading of all those modules you need to tell modutils some -stuff. Add the following line to your modutils config-file -(e.g. /etc/modules.conf or wherever your distribution does store that +For autoloading of all those modules you need to tell module-init-tools +some stuff. Add the following line to your module-init-tools config-file +(e.g. /etc/modprobe.conf or wherever your distribution does store that stuff): options parport_pc io=0x378 irq=7 dma=3 diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index b8510c8addb2..9aff927ee623 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -167,6 +167,13 @@ config MK7 some extended instructions, and passes appropriate optimization flags to GCC. +config MK8 + bool "Opteron/Athlon64/Hammer/K8" + help + Select this for an AMD Opteron or Athlon64 Hammer-family processor. Enables + use of some extended instructions, and passes appropriate optimization + flags to GCC. + config MELAN bool "Elan" @@ -227,7 +234,7 @@ config X86_L1_CACHE_SHIFT int default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || M686 || M586MMX || M586TSC || M586 default "4" if MELAN || M486 || M386 - default "6" if MK7 + default "6" if MK7 || MK8 default "7" if MPENTIUM4 config RWSEM_GENERIC_SPINLOCK @@ -282,7 +289,7 @@ config X86_ALIGNMENT_16 config X86_GOOD_APIC bool - depends on MK7 || MPENTIUM4 || MPENTIUMIII || M686 || M586MMX + depends on MK7 || MPENTIUM4 || MPENTIUMIII || M686 || M586MMX || MK8 default y config X86_INTEL_USERCOPY @@ -292,7 +299,7 @@ config X86_INTEL_USERCOPY config X86_USE_PPRO_CHECKSUM bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || M686 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || M686 || MK8 default y config X86_USE_3DNOW @@ -305,6 +312,16 @@ config X86_OOSTORE depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 default y +config X86_PREFETCH + bool + depends on MPENTIUMIII || MP4 + default y + +config X86_SSE2 + bool + depends on MK8 || MPENTIUM4 + default y + config HUGETLB_PAGE bool "Huge TLB Page Support" help diff --git a/arch/i386/Makefile b/arch/i386/Makefile index ef293556b96c..6277bdd05469 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -38,6 +38,7 @@ cflags-$(CONFIG_MPENTIUMIII) += $(call check_gcc,-march=pentium3,-march=i686) cflags-$(CONFIG_MPENTIUM4) += $(call check_gcc,-march=pentium4,-march=i686) cflags-$(CONFIG_MK6) += $(call check_gcc,-march=k6,-march=i586) cflags-$(CONFIG_MK7) += $(call check_gcc,-march=athlon,-march=i686 -malign-functions=4) +cflags-$(CONFIG_MK8) += $(call check_gcc,-march=k8,$(call check_gcc,-march=athlon,-march=i686 -malign-functions=4)) cflags-$(CONFIG_MCRUSOE) += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0 cflags-$(CONFIG_MWINCHIPC6) += $(call check_gcc,-march=winchip-c6,-march=i586) cflags-$(CONFIG_MWINCHIP2) += $(call check_gcc,-march=winchip2,-march=i586) diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 98936e86c9b8..73d1bbdbf43c 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -614,7 +614,8 @@ static int __init detect_init_APIC (void) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) + if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) || + (boot_cpu_data.x86 == 15)) break; goto no_apic; case X86_VENDOR_INTEL: diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c index 294c78c9b534..1df54f5a7087 100644 --- a/arch/i386/kernel/cpu/mcheck/k7.c +++ b/arch/i386/kernel/cpu/mcheck/k7.c @@ -1,5 +1,5 @@ /* - * Athlon specific Machine Check Exception Reporting + * Athlon/Hammer specific Machine Check Exception Reporting */ #include <linux/init.h> @@ -82,6 +82,9 @@ void __init amd_mcheck_init(struct cpuinfo_x86 *c) nr_mce_banks = l & 0xff; for (i=0; i<nr_mce_banks; i++) { + /* Don't enable northbridge MCE by default on Hammer */ + if (boot_cpu_data.x86_model == 15 && i == 4) + continue; wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff); wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0); } diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 46caa93519aa..5b82d52983db 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -574,7 +574,7 @@ static int __init mtrr_init(void) query the width (in bits) of the physical addressable memory on the Hammer family. */ - if (boot_cpu_data.x86 >= 7 + if (boot_cpu_data.x86 == 15 && (cpuid_eax(0x80000000) >= 0x80000008)) { u32 phys_addr; phys_addr = cpuid_eax(0x80000008) & 0xff; diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index fbae2c8deeaf..9eeaca1be2a1 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -123,7 +123,7 @@ static int __init setup_nmi_watchdog(char *str) nmi_watchdog = nmi; if ((nmi == NMI_LOCAL_APIC) && (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && - (boot_cpu_data.x86 == 6)) + (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15)) nmi_watchdog = nmi; /* * We can enable the IO-APIC watchdog @@ -294,7 +294,7 @@ void __pminit setup_apic_nmi_watchdog (void) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 != 6) + if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15) return; setup_k7_watchdog(); break; diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index 45c65d3a4efa..f33880c8f87b 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -233,6 +233,7 @@ int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu) *cpu = OPROFILE_CPU_ATHLON; break; +#ifndef CONFIG_X86_64 case X86_VENDOR_INTEL: /* Less than a P6-class processor */ if (family != 6) @@ -248,6 +249,7 @@ int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu) model = &op_ppro_spec; break; +#endif default: return 0; diff --git a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c index b4aabede5531..722353a5b7ff 100644 --- a/arch/i386/oprofile/op_model_athlon.c +++ b/arch/i386/oprofile/op_model_athlon.c @@ -99,7 +99,7 @@ static int athlon_check_ctrs(unsigned int const cpu, for (i = 0 ; i < NUM_COUNTERS; ++i) { CTR_READ(low, high, msrs, i); if (CTR_OVERFLOWED(low)) { - oprofile_add_sample(regs->eip, i, cpu); + oprofile_add_sample(instruction_pointer(regs), i, cpu); CTR_WRITE(reset_value[i], msrs, i); return 1; } diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c index 0f00c4d1e924..cff299fb1461 100644 --- a/arch/i386/oprofile/op_model_ppro.c +++ b/arch/i386/oprofile/op_model_ppro.c @@ -94,7 +94,7 @@ static int ppro_check_ctrs(unsigned int const cpu, for (i = 0 ; i < NUM_COUNTERS; ++i) { CTR_READ(low, high, msrs, i); if (CTR_OVERFLOWED(low)) { - oprofile_add_sample(regs->eip, i, cpu); + oprofile_add_sample(instruction_pointer(regs), i, cpu); CTR_WRITE(reset_value[i], msrs, i); return 1; } diff --git a/arch/i386/oprofile/timer_int.c b/arch/i386/oprofile/timer_int.c index 1159b7597eef..d4f0c24d89d9 100644 --- a/arch/i386/oprofile/timer_int.c +++ b/arch/i386/oprofile/timer_int.c @@ -21,7 +21,7 @@ static int timer_notify(struct notifier_block * self, unsigned long val, void * struct pt_regs * regs = (struct pt_regs *)data; int cpu = smp_processor_id(); - oprofile_add_sample(regs->eip, 0, cpu); + oprofile_add_sample(instruction_pointer(regs), 0, cpu); return 0; } diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 59e449a9187f..82fb20e2b639 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -2070,48 +2070,6 @@ config HPDCA If you want to use the internal "DCA" serial ports on an HP300 machine, say Y here. -config SUN3X_ZS - bool "Sun3/3x builtin serial support" - depends on SUN3 || SUN3X - help - ZS refers to a type of asynchronous serial port built in to the Sun3 - and Sun3x workstations; if you have a Sun 3, you probably have - these. Say 'Y' to support ZS ports directly. This option must be - enabled in order to support the - keyboard and mouse ports. - -config SUN_KEYBOARD - bool - depends on SUN3X_ZS - default y - help - Say Y here to support the keyboard found on Sun 3 and 3x - workstations. It can also be used support Sun Type-5 keyboards - through an adaptor. See - <http://www.suse.cz/development/input/adapters.html> and - <http://sourceforge.net/projects/linuxconsole/> for details on the - latter. - -config SUN_MOUSE - bool - depends on SUN3X_ZS - default y - -config SBUS - bool - depends on SUN3X_ZS - default y - -config SBUSCHAR - bool - depends on SUN3X_ZS - default y - -config SUN_SERIAL - bool - depends on SUN3X_ZS - default y - config MVME147_SCC bool "SCC support for MVME147 serial ports" depends on MVME147 @@ -2148,7 +2106,7 @@ config DN_SERIAL config SERIAL_CONSOLE bool "Support for serial port console" - depends on (AMIGA || ATARI || MAC || HP300 || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || HPDCA=y || SUN3X_ZS || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL) + depends on (AMIGA || ATARI || MAC || HP300 || SUN3 || SUN3X || VME || APOLLO) && (ATARI_MFPSER=y || ATARI_SCC=y || ATARI_MIDI=y || MAC_SCC=y || AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y || HPDCA=y || SERIAL=y || MVME147_SCC || SERIAL167 || MVME162_SCC || BVME6000_SCC || DN_SERIAL) ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 31cff1fde9c5..8bf52e30794c 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m) # override top level makefile AS += -m68020 LDFLAGS := -m m68kelf +LDFLAGS_BLOB := --format binary --oformat elf32-m68k ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries CROSS_COMPILE = m68k-linux- diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index bebb2d4b171c..bceff2e4c7c4 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -17,6 +17,7 @@ #include <linux/kernel_stat.h> #include <linux/init.h> #include <linux/seq_file.h> +#include <linux/interrupt.h> #include <asm/irq.h> #include <asm/amigahw.h> diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 5abf761945ac..49e2b36659c9 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -21,6 +21,7 @@ #include <linux/rtc.h> #include <linux/init.h> #include <linux/vt_kern.h> +#include <linux/interrupt.h> #ifdef CONFIG_ZORRO #include <linux/zorro.h> #endif diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c index 54f4d43d1ed3..5dae74f908f3 100644 --- a/arch/m68k/apollo/config.c +++ b/arch/m68k/apollo/config.c @@ -6,6 +6,7 @@ #include <linux/console.h> #include <linux/rtc.h> #include <linux/vt_kern.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/bootinfo.h> diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 8fc840c0bafc..80c45418188c 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -168,7 +168,7 @@ asmlinkage void IRQ_NAME(n); \ void atari_slow_irq_##n##_dummy (void) { \ __asm__ (__ALIGN_STR "\n" \ "atari_slow_irq_" #n "_handler:\t" \ -" addql #1,%5\n" /* local_irq_count++ */ \ +" addl %6,%5\n" /* preempt_count() += HARDIRQ_OFFSET */ \ SAVE_ALL_INT "\n" \ GET_CURRENT(%%d0) "\n" \ " andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ @@ -194,7 +194,7 @@ __asm__ (__ALIGN_STR "\n" \ "n" (PT_OFF_SR), "n" (n), \ "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \ - "m" (local_irq_count(0)) \ + "m" (preempt_count()), "di" (HARDIRQ_OFFSET) \ ); \ for (;;); /* fake noreturn */ \ } @@ -276,7 +276,7 @@ __asm__ (__ALIGN_STR "\n" "atari_fast_irq_handler: orw #0x700,%%sr /* disable all interrupts */ atari_prio_irq_handler:\t - addql #1,%2\n" /* local_irq_count++ */ + addl %3,%2\n" /* preempt_count() += HARDIRQ_OFFSET */ SAVE_ALL_INT "\n" GET_CURRENT(%%d0) " /* get vector number from stack frame and convert to source */ @@ -297,7 +297,7 @@ atari_prio_irq_handler:\t addql #4,%%sp jbra ret_from_interrupt" : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC), - "m" (local_irq_count(0)) + "m" (preempt_count()), "di" (HARDIRQ_OFFSET) ); for (;;); } @@ -481,8 +481,7 @@ int atari_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r irq_node_t *node; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); if (irq_handler[irq].handler != atari_call_irq_list) { /* Only one handler yet, make a node for this first one */ @@ -507,7 +506,7 @@ int atari_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r node->next = irq_handler[irq].dev_id; irq_handler[irq].dev_id = node; - restore_flags(flags); + local_irq_restore(flags); return 0; } else { printk ("%s: Irq %d allocated by other type int (call from %s)\n", @@ -531,13 +530,12 @@ void atari_free_irq(unsigned int irq, void *dev_id) if (vectors[vector] == bad_interrupt) goto not_found; - save_flags(flags); - cli(); + local_irq_save(flags); if (irq_handler[irq].handler != atari_call_irq_list) { /* It's the only handler for the interrupt */ if (irq_handler[irq].dev_id != dev_id) { - restore_flags(flags); + local_irq_restore(flags); goto not_found; } irq_handler[irq].handler = NULL; @@ -548,7 +546,7 @@ void atari_free_irq(unsigned int irq, void *dev_id) atari_disable_irq(irq); atari_turnoff_irq(irq); - restore_flags(flags); + local_irq_restore(flags); return; } @@ -557,7 +555,7 @@ void atari_free_irq(unsigned int irq, void *dev_id) if ((*list)->dev_id == dev_id) break; } if (!*list) { - restore_flags(flags); + local_irq_restore(flags); goto not_found; } @@ -574,7 +572,7 @@ void atari_free_irq(unsigned int irq, void *dev_id) node->handler = NULL; /* Mark it as free for reallocation */ } - restore_flags(flags); + local_irq_restore(flags); return; not_found: diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c index 7b401d17fef9..d3a60be60069 100644 --- a/arch/m68k/atari/atasound.c +++ b/arch/m68k/atari/atasound.c @@ -58,8 +58,7 @@ void atari_mksound (unsigned int hz, unsigned int ticks) unsigned char tmp; int period; - save_flags(flags); - cli(); + local_irq_save(flags); /* Disable generator A in mixer control. */ @@ -106,5 +105,5 @@ void atari_mksound (unsigned int hz, unsigned int ticks) tmp &= ~1; sound_ym.wd_data = tmp; } - restore_flags(flags); + local_irq_restore(flags); } diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 035bb3e264dc..8fa786dbd982 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -509,12 +509,11 @@ static void atari_heartbeat( int on ) if (atari_dont_touch_floppy_select) return; - save_flags(flags); - cli(); + local_irq_save(flags); sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); - restore_flags(flags); + local_irq_restore(flags); } #endif @@ -569,7 +568,7 @@ static void atari_reset (void) /* processor independent: turn off interrupts and reset the VBR; * the caches must be left enabled, else prefetching the final jump * instruction doesn't work. */ - cli(); + local_irq_disable(); __asm__ __volatile__ ("moveq #0,%/d0\n\t" "movec %/d0,%/vbr" diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 1aff226be34b..ec7230628c76 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -33,6 +33,7 @@ #include <linux/genhd.h> #include <linux/sched.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/atari_stdma.h> #include <asm/atariints.h> @@ -75,10 +76,9 @@ static void stdma_int (int irq, void *dummy, struct pt_regs *fp); void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data) { - unsigned long oldflags; + unsigned long flags; - save_flags(oldflags); - cli(); /* protect lock */ + local_irq_save(flags); /* protect lock */ while(stdma_locked) /* Since the DMA is used for file system purposes, we @@ -89,7 +89,7 @@ void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data) stdma_locked = 1; stdma_isr = handler; stdma_isr_data = data; - restore_flags(oldflags); + local_irq_restore(flags); } @@ -106,17 +106,16 @@ void stdma_lock(void (*handler)(int, void *, struct pt_regs *), void *data) void stdma_release(void) { - unsigned long oldflags; + unsigned long flags; + + local_irq_save(flags); - save_flags(oldflags); - cli(); - stdma_locked = 0; stdma_isr = NULL; stdma_isr_data = NULL; wake_up(&stdma_wait); - restore_flags(oldflags); + local_irq_restore(flags); } diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index 1c9268b5ed4f..cc1586d87845 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -765,7 +765,7 @@ static int unswap_by_read(unsigned short *map, unsigned long max, return -ENOMEM; } read_lock(&tasklist_lock); - for_each_task(p) + for_each_process(p) unswap_process(p->mm, entry, page); read_unlock(&tasklist_lock); shmem_unuse(entry, page); @@ -984,7 +984,7 @@ static void do_stram_request(request_queue_t *q) unsigned long len = req->current_nr_sectors << 9; if ((start + len) > swap_end) { printk( KERN_ERR "stram: bad access beyond end of device: " - "block=%ld, count=%ld\n", + "block=%ld, count=%d\n", req->sector, req->current_nr_sectors ); end_request(req, 0); diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index b57a80594a9a..98e344a0111c 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -216,8 +216,7 @@ int atari_tt_hwclk( int op, struct rtc_time *t ) schedule_timeout(HWCLK_POLL_INTERVAL); } - save_flags(flags); - cli(); + local_irq_save(flags); RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); if (!op) { sec = RTC_READ( RTC_SECONDS ); @@ -238,7 +237,7 @@ int atari_tt_hwclk( int op, struct rtc_time *t ) if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); } RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); - restore_flags(flags); + local_irq_restore(flags); if (!op) { /* read: adjust values */ diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index eff77830e92c..58771d3367be 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -24,6 +24,7 @@ #include <linux/major.h> #include <linux/genhd.h> #include <linux/rtc.h> +#include <linux/interrupt.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -358,8 +359,7 @@ int bvme6000_set_clock_mmss (unsigned long nowtime) ? real_minutes - rtc_minutes : rtc_minutes - real_minutes) < 30) { - save_flags(flags); - cli(); + local_irq_save(flags); rtc_tenms = rtc->bcd_tenms; while (rtc_tenms == rtc->bcd_tenms) ; @@ -367,7 +367,7 @@ int bvme6000_set_clock_mmss (unsigned long nowtime) ; rtc->bcd_min = bin2bcd(real_minutes); rtc->bcd_sec = bin2bcd(real_seconds); - restore_flags(flags); + local_irq_restore(flags); } else retval = -1; diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c index 071771d0182b..e9fe8968fb5f 100644 --- a/arch/m68k/bvme6000/rtc.c +++ b/arch/m68k/bvme6000/rtc.c @@ -49,8 +49,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, switch (cmd) { case RTC_RD_TIME: /* Read the time/date from RTC */ { - save_flags(flags); - cli(); + local_irq_save(flags); /* Ensure clock and real-time-mode-register are accessible */ msr = rtc->msr & 0xc0; rtc->msr = 0x40; @@ -66,7 +65,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1; } while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec)); rtc->msr = msr; - restore_flags(flags); + local_irq_restore(flags); return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } @@ -106,8 +105,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (yrs >= 2070) return -EINVAL; - save_flags(flags); - cli(); + local_irq_save(flags); /* Ensure clock and real-time-mode-register are accessible */ msr = rtc->msr & 0xc0; rtc->msr = 0x40; @@ -125,7 +123,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, rtc->t0cr_rtmr = yrs%4 | 0x08; rtc->msr = msr; - restore_flags(flags); + local_irq_restore(flags); return 0; } default: @@ -179,7 +177,6 @@ int __init rtc_DP8570A_init(void) return -ENODEV; printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION); - misc_register(&rtc_dev); - return 0; + return misc_register(&rtc_dev); } diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 6e371c61c727..1faabadaf569 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -552,10 +552,10 @@ sys_call_table: .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_create_module + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module - .long sys_get_kernel_syms /* 130 */ + .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ .long sys_quotactl .long sys_getpgid .long sys_fchdir @@ -592,7 +592,7 @@ sys_call_table: .long sys_setresuid16 .long sys_getresuid16 /* 165 */ .long sys_getpagesize - .long sys_query_module + .long sys_ni_syscall /* old sys_query_module */ .long sys_poll .long sys_nfsservctl .long sys_setresgid16 /* 170 */ diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index bcaba1d0d973..bccb3147ee81 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -21,7 +21,7 @@ ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with ** Magnum- and FX-alternate ram ** 98/04/25 Phil Blundell: added HP300 support -** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures +** 1998/08/30 David Kilzer: Added support for font_desc structures ** for linux-2.1.115 ** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01) ** @@ -130,7 +130,7 @@ * * mmu_engage * ---------- - * Thanks to a small helping routine enabling the mmu got quiet simple + * Thanks to a small helping routine enabling the mmu got quite simple * and there is only one way left. mmu_engage makes a complete a new mapping * that only includes the absolute necessary to be able to jump to the final * postion and to restore the original mapping. @@ -238,7 +238,7 @@ * In theory these could be determined at run time or handed * over by the booter. But, let's be real, it's a fine hard * coded value. (But, you will notice the code is run-time - * flexible!) A pointer to the font's struct fbcon_font_desc + * flexible!) A pointer to the font's struct font_desc * is kept locally in Lconsole_font. It is used to determine * font size information dynamically. * @@ -1202,7 +1202,7 @@ L(not6000): * * Map the kernel (that's already done), * Map the I/O (on most machines that's the - * 0x5000.0000 ... 0x5200.0000 range, + * 0x5000.0000 ... 0x5300.0000 range, * Map the video frame buffer using as few pages * as absolutely (this requirement mostly stems from * the fact that when the frame buffer is at @@ -1246,10 +1246,11 @@ L(mmu_init_mac): andl L(mac_videobase),%d0 mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3 - mmu_map_eq #0x40800000,#0x02000000,%d3 /* rom ? */ - mmu_map_eq #0x50000000,#0x02000000,%d3 - mmu_map_eq #0x60000000,#0x00400000,%d3 - mmu_map_eq #0x9c000000,#0x00400000,%d3 + /* The ROM starts at 4000 0000 */ + mmu_map_eq #0x40000000,#0x02000000,%d3 + /* IO devices */ + mmu_map_eq #0x50000000,#0x03000000,%d3 + /* NuBus slot space */ mmu_map_tt #1,#0xf8000000,#0x08000000,%d3 jbra L(mmu_init_done) @@ -1461,6 +1462,9 @@ L(mmu_fixup_done): andl L(mac_videobase),%d0 addl #VIDEOMEMBASE,%d0 movel %d0,L(mac_videobase) +#ifdef MAC_SERIAL_DEBUG + orl #0x50000000,L(mac_sccbase) +#endif 1: #endif @@ -3032,10 +3036,6 @@ func_start serial_putc,%d0/%d1/%a0/%a1 #ifdef CONFIG_MAC is_not_mac(5f) -#ifdef CONSOLE - console_putc %d0 -#endif /* CONSOLE */ - #ifdef MAC_SERIAL_DEBUG #ifdef MAC_USE_SCC_A @@ -3371,7 +3371,7 @@ console_clear_loop: * a1 = address of Lconsole_font pointer */ lea %pc@(L(console_font)),%a1 - movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in Lconsole_font */ + movel %a0,%a1@ /* store pointer to struct font_desc in Lconsole_font */ tstl %a0 jeq 1f @@ -3383,10 +3383,10 @@ console_clear_loop: */ /* ASSERT: a0 = contents of Lconsole_font */ movel %d3,%d0 /* screen width in pixels */ - divul %a0@(FBCON_FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ + divul %a0@(FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ movel %d4,%d1 /* screen height in pixels */ - divul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ + divul %a0@(FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ movel %d0,%a2@(Lconsole_struct_num_columns) movel %d1,%a2@(Lconsole_struct_num_rows) @@ -3430,6 +3430,10 @@ L(console_put_stats): putn %pc@(L(cputype)) putc '\n' +#ifdef MAC_SERIAL_DEBUG + putn %pc@(L(mac_sccbase)) + putc '\n' +#endif # if defined(MMU_PRINT) jbsr mmu_print_machine_cpu_types # endif /* MMU_PRINT */ @@ -3489,7 +3493,7 @@ console_scroll: movel %pc@(L(console_font)),%a0 tstl %a0 jeq 1f - mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */ + mulul %a0@(FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */ addal %d5,%a2 /* @@ -3508,7 +3512,7 @@ console_scroll: lea %pc@(L(mac_rowbytes)),%a0 movel %a0@,%d6 movel %pc@(L(console_font)),%a0 - subl %a0@(FBCON_FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */ + subl %a0@(FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */ mulul %d4,%d6 /* scan line bytes x num scan lines */ divul #32,%d6 /* we'll move 8 longs at a time */ subq #1,%d6 @@ -3527,7 +3531,7 @@ console_scroll_loop: lea %pc@(L(mac_rowbytes)),%a0 movel %a0@,%d6 movel %pc@(L(console_font)),%a0 - mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */ + mulul %a0@(FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */ divul #32,%d6 /* we'll move 8 words at a time */ subq #1,%d6 @@ -3606,19 +3610,19 @@ console_not_home: movel %a0@(Lconsole_struct_num_columns),%d1 cmpl %d1,%d0 jcs 1f - putc '\n' /* recursion is OK! */ + console_putc #'\n' /* recursion is OK! */ 1: movel %a0@(Lconsole_struct_cur_row),%d1 /* * At this point we make a shift in register usage - * a0 = address of pointer to font data (fbcon_font_desc) + * a0 = address of pointer to font data (font_desc) */ movel %pc@(L(console_font)),%a0 - movel %a0@(FBCON_FONT_DESC_DATA),%a1 /* Load fbcon_font_desc.data into a1 */ + movel %a0@(FONT_DESC_DATA),%a1 /* Load font_desc.data into a1 */ andl #0x000000ff,%d7 /* ASSERT: a0 = contents of Lconsole_font */ - mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */ + mulul %a0@(FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */ addl %d7,%a1 /* a1 = points to char image */ /* @@ -3631,15 +3635,15 @@ console_not_home: * d7 = count down for the font's pixel count in height */ /* ASSERT: a0 = contents of Lconsole_font */ - mulul %a0@(FBCON_FONT_DESC_WIDTH),%d0 - mulul %a0@(FBCON_FONT_DESC_HEIGHT),%d1 - movel %a0@(FBCON_FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */ + mulul %a0@(FONT_DESC_WIDTH),%d0 + mulul %a0@(FONT_DESC_HEIGHT),%d1 + movel %a0@(FONT_DESC_HEIGHT),%d7 /* Load font_desc.height into d7 */ subq #1,%d7 console_read_char_scanline: moveb %a1@+,%d3 /* ASSERT: a0 = contents of Lconsole_font */ - movel %a0@(FBCON_FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */ + movel %a0@(FONT_DESC_WIDTH),%d6 /* Load font_desc.width into d6 */ subql #1,%d6 console_do_font_scanline: @@ -3650,7 +3654,7 @@ console_do_font_scanline: dbra %d6,console_do_font_scanline /* ASSERT: a0 = contents of Lconsole_font */ - subl %a0@(FBCON_FONT_DESC_WIDTH),%d0 + subl %a0@(FONT_DESC_WIDTH),%d0 addq #1,%d1 dbra %d7,console_read_char_scanline @@ -3848,7 +3852,7 @@ L(console_globals): .long 0 /* left edge */ .long 0 /* mac putc */ L(console_font): - .long 0 /* pointer to console font (struct fbcon_font_desc) */ + .long 0 /* pointer to console font (struct font_desc) */ #endif /* CONSOLE */ #if defined(MMU_PRINT) diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c index 55a386813236..4dd235d15b29 100644 --- a/arch/m68k/kernel/m68k_defs.c +++ b/arch/m68k/kernel/m68k_defs.c @@ -78,13 +78,13 @@ int main(void) DEFINE(BIR_SIZE, offsetof(struct bi_record, size)); DEFINE(BIR_DATA, offsetof(struct bi_record, data)); - /* offsets into fbcon_font_desc (video/font.h) */ - DEFINE(FBCON_FONT_DESC_IDX, offsetof(struct fbcon_font_desc, idx)); - DEFINE(FBCON_FONT_DESC_NAME, offsetof(struct fbcon_font_desc, name)); - DEFINE(FBCON_FONT_DESC_WIDTH, offsetof(struct fbcon_font_desc, width)); - DEFINE(FBCON_FONT_DESC_HEIGHT, offsetof(struct fbcon_font_desc, height)); - DEFINE(FBCON_FONT_DESC_DATA, offsetof(struct fbcon_font_desc, data)); - DEFINE(FBCON_FONT_DESC_PREF, offsetof(struct fbcon_font_desc, pref)); + /* offsets into font_desc (drivers/video/console/font.h) */ + DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx)); + DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name)); + DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width)); + DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height)); + DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data)); + DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref)); /* signal defines */ DEFINE(SIGSEGV, SIGSEGV); diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 15b76c74ba60..ad8aebdfd0e5 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -26,7 +26,6 @@ asmlinkage long long __muldi3 (long long, long long); extern char m68k_debug_device[]; extern void dump_thread(struct pt_regs *, struct user *); -extern int dump_fpu(elf_fpregset_t *); /* platform dependent support */ diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 5c50d1f142a2..4d19c1c3979b 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -202,14 +202,15 @@ void flush_thread(void) asmlinkage int m68k_fork(struct pt_regs *regs) { struct task_struct *p; - p = do_fork(SIGCHLD, rdusp(), regs, 0, NULL); + p = do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } asmlinkage int m68k_vfork(struct pt_regs *regs) { struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, + NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -218,15 +219,17 @@ asmlinkage int m68k_clone(struct pt_regs *regs) unsigned long clone_flags; unsigned long newsp; struct task_struct *p; - int *user_tid; + int *parent_tidptr, *child_tidptr; /* syscall2 puts clone_flags in d1 and usp in d2 */ clone_flags = regs->d1; newsp = regs->d2; - user_tid = (int *)regs->d3; + parent_tidptr = (int *)regs->d3; + child_tidptr = (int *)regs->d4; if (!newsp) newsp = rdusp(); - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, user_tid); + p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, + parent_tidptr, child_tidptr); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index bf1d0ab11f52..ba0ea7d6361c 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -380,9 +380,6 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_SUN3X if (MACH_IS_SUN3X) { dvma_init(); -#ifdef CONFIG_SUN3X_ZS - sun_serial_setup(); -#endif } #endif diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index e45e7441d1a3..908785fd123f 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -1101,7 +1101,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: - if (do_coredump(signr, regs)) + if (do_coredump(signr, exit_code, regs)) exit_code |= 0x80; /* FALLTHRU */ diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 4343116eef4e..ad20bedba50c 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -820,32 +820,43 @@ asmlinkage void buserr_c(struct frame *fp) static int kstack_depth_to_print = 48; -extern struct module kernel_module; + +extern char _stext, _etext; + +#ifdef CONFIG_MODULES + +/* FIXME: Accessed without a lock --RR */ +extern struct list_head modules; static inline int kernel_text_address(unsigned long addr) { -#ifdef CONFIG_MODULES struct module *mod; -#endif - extern char _stext, _etext; if (addr >= (unsigned long) &_stext && addr <= (unsigned long) &_etext) return 1; -#ifdef CONFIG_MODULES - for (mod = module_list; mod != &kernel_module; mod = mod->next) { + list_for_each_entry(mod, &modules, list) { /* mod_bound tests for addr being inside the vmalloc'ed * module area. Of course it'd be better to test only * for the .text subset... */ - if (mod_bound(addr, 0, mod)) + if (mod_bound((void *)addr, 0, mod)) return 1; } -#endif return 0; } +#else // !CONFIG_MODULES + +static inline int kernel_text_address(unsigned long addr) +{ + return (addr >= (unsigned long) &_stext && + addr <= (unsigned long) &_etext); +} + +#endif // !CONFIG_MODULES + void show_trace(unsigned long *stack) { unsigned long *endstack; diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index b30459aedb31..17ce0248fbfe 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -90,7 +90,7 @@ static void mac_get_model(char *str); void mac_bang(int irq, void *vector, struct pt_regs *p) { - printk("Resetting ...\n"); + printk(KERN_INFO "Resetting ...\n"); mac_reset(); } @@ -181,17 +181,16 @@ int __init mac_parse_bootinfo(const struct bi_record *record) static void mac_cache_card_flush(int writeback) { - unsigned long cpu_flags; - save_flags(cpu_flags); - cli(); + unsigned long flags; + local_irq_save(flags); via_flush_cache(); - restore_flags(cpu_flags); + local_irq_restore(flags); } void __init config_mac(void) { if (!MACH_IS_MAC) { - printk("ERROR: no Mac, but config_mac() called!! \n"); + printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); } mach_sched_init = mac_sched_init; @@ -326,13 +325,14 @@ static struct mac_model mac_data_table[]= */ { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_Q605_ACC, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, /* The Q700 does have a NS Sonic */ - { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, + { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_MACE, MAC_NUBUS}, + { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC, MAC_ETHER_MACE, MAC_NUBUS}, { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, @@ -345,8 +345,8 @@ static struct mac_model mac_data_table[]= { MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, /* These have the comm slot, and therefore the possibility of SONIC ethernet */ + { MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_P588, "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_TV, "TV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_P600, "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, @@ -358,7 +358,7 @@ static struct mac_model mac_data_table[]= /* The C610 may or may not have SONIC. We probe to make sure */ { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS}, + { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC, MAC_ETHER_MACE, MAC_NUBUS}, /* * The PowerBooks all the same "Combo" custom IC for SCSI and SCC @@ -411,7 +411,7 @@ void mac_identify(void) /* no bootinfo model id -> NetBSD booter was used! */ /* XXX FIXME: breaks for model > 31 */ model=(mac_bi_data.cpuid>>2)&63; - printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); + printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); } macintosh_config = mac_data_table; @@ -429,22 +429,22 @@ void mac_identify(void) iop_preinit(); mac_debug_init(); - printk ("Detected Macintosh model: %d \n", model); + printk (KERN_INFO "Detected Macintosh model: %d \n", model); /* * Report booter data: */ - printk (" Penguin bootinfo data:\n"); - printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", + printk (KERN_DEBUG " Penguin bootinfo data:\n"); + printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", mac_bi_data.videoaddr, mac_bi_data.videorow, mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, mac_bi_data.dimensions >> 16); - printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", + printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", mac_bi_data.videological, mac_orig_videoaddr, mac_bi_data.sccbase); - printk (" Boottime: 0x%lx GMTBias: 0x%lx \n", + printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", mac_bi_data.boottime, mac_bi_data.gmtbias); - printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", + printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); #if 0 printk ("Ramdisk: addr 0x%lx size 0x%lx\n", @@ -467,7 +467,7 @@ void mac_identify(void) MACHW_SET(MAC_SCSI_96_2); break; default: - printk("config.c: wtf: unknown scsi, using 53c80\n"); + printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); MACHW_SET(MAC_SCSI_80); break; @@ -481,7 +481,7 @@ void mac_identify(void) void mac_report_hardware(void) { - printk("Apple Macintosh %s\n", macintosh_config->name); + printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name); } static void mac_get_model(char *str) diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index 627a7580fa01..737037841835 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c @@ -111,6 +111,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/proc_fs.h> +#include <linux/interrupt.h> #include <asm/bootinfo.h> #include <asm/macintosh.h> @@ -212,20 +213,19 @@ static int iop_alive(volatile struct mac_iop *iop) static struct iop_msg *iop_alloc_msg(void) { int i; - ulong cpu_flags; + unsigned long flags; - save_flags(cpu_flags); - cli(); + local_irq_save(flags); for (i = 0 ; i < NUM_IOP_MSGS ; i++) { if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) { iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING; - restore_flags(cpu_flags); + local_irq_restore(flags); return &iop_msg_pool[i]; } } - restore_flags(cpu_flags); + local_irq_restore(flags); return NULL; } diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c index 4ef9220463e2..b9f73f9e76d0 100644 --- a/arch/m68k/mac/macboing.c +++ b/arch/m68k/mac/macboing.c @@ -187,8 +187,7 @@ void mac_mksound( unsigned int freq, unsigned int length ) return; } - save_flags( flags ); - cli(); + local_irq_save(flags); del_timer( &mac_sound_timer ); @@ -210,7 +209,7 @@ void mac_mksound( unsigned int freq, unsigned int length ) mac_sound_timer.expires = jiffies + length; add_timer( &mac_sound_timer ); - restore_flags( flags ); + local_irq_restore(flags); } /* @@ -240,8 +239,7 @@ static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsig mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec; /* this is reasonably big for small frequencies */ - save_flags( flags ); - cli(); + local_irq_save(flags); /* set the volume */ mac_asc_regs[ 0x806 ] = volume; @@ -263,7 +261,7 @@ static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsig mac_sound_timer.expires = jiffies + 1; add_timer( &mac_sound_timer ); - restore_flags( flags ); + local_irq_restore(flags); } /* @@ -283,8 +281,7 @@ static void mac_quadra_ring_bell( unsigned long ignored ) * ...and the possibility to use a real sample (a boingy noise, maybe...) */ - save_flags( flags ); - cli(); + local_irq_save(flags); del_timer( &mac_sound_timer ); @@ -301,7 +298,7 @@ static void mac_quadra_ring_bell( unsigned long ignored ) else mac_asc_regs[ 0x801 ] = 0; - restore_flags( flags ); + local_irq_restore(flags); } /* diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index 40938c05f60c..4f8ea17f57ac 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -276,15 +276,14 @@ void mac_init_IRQ(void) static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node) { - unsigned long cpu_flags; + unsigned long flags; irq_node_t *cur; if (!node->dev_id) printk("%s: Warning: dev_id of %s is zero\n", __FUNCTION__, node->devname); - save_flags(cpu_flags); - cli(); + local_irq_save(flags); cur = *list; @@ -309,27 +308,26 @@ static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node) node->next = cur; *list = node; - restore_flags(cpu_flags); + local_irq_restore(flags); } static inline void mac_delete_irq(irq_node_t **list, void *dev_id) { - unsigned long cpu_flags; + unsigned long flags; irq_node_t *node; - save_flags(cpu_flags); - cli(); + local_irq_save(flags); for (node = *list; node; list = &node->next, node = *list) { if (node->dev_id == dev_id) { *list = node->next; /* Mark it as free. */ node->handler = NULL; - restore_flags(cpu_flags); + local_irq_restore(flags); return; } } - restore_flags(cpu_flags); + local_irq_restore(flags); printk ("%s: tried to remove invalid irq\n", __FUNCTION__); } @@ -343,7 +341,7 @@ static inline void mac_delete_irq(irq_node_t **list, void *dev_id) void mac_do_irq_list(int irq, struct pt_regs *fp) { irq_node_t *node, *slow_nodes; - unsigned long cpu_flags; + unsigned long flags; kstat_cpu(0).irqs[irq]++; @@ -360,8 +358,8 @@ void mac_do_irq_list(int irq, struct pt_regs *fp) node = node->next) node->handler(irq, node->dev_id, fp); if (!node) return; - save_flags(cpu_flags); - restore_flags((cpu_flags & ~0x0700) | (fp->sr & 0x0700)); + local_save_flags(flags); + local_irq_restore((flags & ~0x0700) | (fp->sr & 0x0700)); /* if slow handlers exists, serve them now */ slow_nodes = node; for (; node; node = node->next) { @@ -735,15 +733,15 @@ void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs) { volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2; unsigned char reg; - unsigned long cpu_flags; + unsigned long flags; /* Read RR3 from the chip. Always do this on channel A */ /* This must be an atomic operation so disable irqs. */ - save_flags(cpu_flags); cli(); + local_irq_save(flags); *scc = 3; reg = *scc; - restore_flags(cpu_flags); + local_irq_restore(flags); /* Now dispatch. Bits 0-2 are for channel B and */ /* bits 3-5 are for channel A. We can safely */ diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index 04fc953d271c..61f41a8026a8 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -165,11 +165,10 @@ static void via_pram_writebyte(__u8 data) static void via_pram_command(int command, __u8 *data) { - unsigned long cpu_flags; + unsigned long flags; int is_read; - save_flags(cpu_flags); - cli(); + local_irq_save(flags); /* Enable the RTC and make sure the strobe line is high */ @@ -193,7 +192,7 @@ static void via_pram_command(int command, __u8 *data) via1[vBufB] |= VIA1B_vRTCEnb; - restore_flags(cpu_flags); + local_irq_restore(flags); } static __u8 via_read_pram(int offset) @@ -405,7 +404,7 @@ void mac_poweroff(void) pmu_shutdown(); #endif } - sti(); + local_irq_enable(); printk("It is now safe to turn off your Macintosh.\n"); while(1); } @@ -413,7 +412,7 @@ void mac_poweroff(void) void mac_reset(void) { if (macintosh_config->adb_type == MAC_ADB_II) { - unsigned long cpu_flags; + unsigned long flags; /* need ROMBASE in booter */ /* indeed, plus need to MAP THE ROM !! */ @@ -429,12 +428,11 @@ void mac_reset(void) * MSch: Machines known to crash on ROM reset ... */ } else { - save_flags(cpu_flags); - cli(); + local_irq_save(flags); rom_reset(); - restore_flags(cpu_flags); + local_irq_restore(flags); } #ifdef CONFIG_ADB_CUDA } else if (macintosh_config->adb_type == MAC_ADB_CUDA) { @@ -459,7 +457,7 @@ void mac_reset(void) unsigned long virt = (unsigned long) mac_reset; unsigned long phys = virt_to_phys(mac_reset); unsigned long offset = phys-virt; - cli(); /* lets not screw this up, ok? */ + local_irq_disable(); /* lets not screw this up, ok? */ __asm__ __volatile__(".chip 68030\n\t" "pmove %0,%/tt0\n\t" ".chip 68k" @@ -495,7 +493,7 @@ void mac_reset(void) } /* should never get here */ - sti(); + local_irq_enable(); printk ("Restart failed. Please restart manually.\n"); while(1); } diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 4c453339112b..53b448deb37a 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -137,15 +137,15 @@ void __init via_init(void) panic("UNKNOWN VIA TYPE"); } - printk("VIA1 at %p is a 6522 or clone\n", via1); + printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1); - printk("VIA2 at %p is ", via2); + printk(KERN_INFO "VIA2 at %p is ", via2); if (rbv_present) { - printk("an RBV\n"); + printk(KERN_INFO "an RBV\n"); } else if (oss_present) { - printk("an OSS\n"); + printk(KERN_INFO "an OSS\n"); } else { - printk("a 6522 or clone\n"); + printk(KERN_INFO "a 6522 or clone\n"); } #ifdef DEBUG_VIA @@ -291,22 +291,22 @@ void __init via_register_interrupts(void) void via_debug_dump(void) { - printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", + printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", (uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]); - printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", + printk(KERN_DEBUG " PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", (uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]); if (oss_present) { - printk("VIA2: <OSS>\n"); + printk(KERN_DEBUG "VIA2: <OSS>\n"); } else if (rbv_present) { - printk("VIA2: IFR = 0x%02X IER = 0x%02X\n", + printk(KERN_DEBUG "VIA2: IFR = 0x%02X IER = 0x%02X\n", (uint) via2[rIFR], (uint) via2[rIER]); - printk(" SIFR = 0x%02X SIER = 0x%02X\n", + printk(KERN_DEBUG " SIFR = 0x%02X SIER = 0x%02X\n", (uint) via2[rSIFR], (uint) via2[rSIER]); } else { - printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", + printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n", (uint) via2[vDirA], (uint) via2[vDirB], (uint) via2[vACR]); - printk(" PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", + printk(KERN_DEBUG " PCR = 0x%02X IFR = 0x%02X IER = 0x%02X\n", (uint) via2[vPCR], (uint) via2[vIFR], (uint) via2[vIER]); } @@ -374,7 +374,10 @@ void __init via_nubus_init(void) if (!rbv_present) { /* set the line to be an output on non-RBV machines */ - via2[vDirB] |= 0x02; + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { + via2[vDirB] |= 0x02; + } } /* this seems to be an ADB bit on PMU machines */ @@ -390,8 +393,23 @@ void __init via_nubus_init(void) via2[rSIER] = 0x7F; via2[rSIER] = nubus_active | 0x80; } else { - via2[vBufA] = 0xFF; - via2[vDirA] = ~nubus_active; + /* These are ADB bits on PMU */ + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { + switch(macintosh_config->ident) + { + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_SE30: + via2[vBufA] |= 0x3F; + via2[vDirA] = ~nubus_active | 0xc0; + break; + default: + via2[vBufA] = 0xFF; + via2[vDirA] = ~nubus_active; + } + } } } @@ -481,7 +499,7 @@ void via_irq_enable(int irq) { int irq_bit = 1 << irq_idx; #ifdef DEBUG_IRQUSE - printk("via_irq_enable(%d)\n", irq); + printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); #endif if (irq_src == 1) { @@ -508,7 +526,21 @@ void via_irq_enable(int irq) { via2[rSIER] = IER_SET_BIT(irq_idx); } else { /* Make sure the bit is an input, to enable the irq */ - via2[vDirA] &= ~irq_bit; + /* But not on PowerBooks, that's ADB... */ + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { + switch(macintosh_config->ident) + { + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_SE30: + via2[vDirA] &= (~irq_bit | 0xc0); + break; + default: + via2[vDirA] &= ~irq_bit; + } + } } nubus_active |= irq_bit; } @@ -520,7 +552,7 @@ void via_irq_disable(int irq) { int irq_bit = 1 << irq_idx; #ifdef DEBUG_IRQUSE - printk("via_irq_disable(%d)\n", irq); + printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); #endif if (irq_src == 1) { @@ -533,7 +565,11 @@ void via_irq_disable(int irq) { via2[rSIER] = IER_CLR_BIT(irq_idx); } else { /* disable the nubus irq by changing dir to output */ - via2[vDirA] |= irq_bit; + /* except on PMU */ + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { + via2[vDirA] |= irq_bit; + } } nubus_active &= ~irq_bit; } diff --git a/arch/m68k/mm/extable.c b/arch/m68k/mm/extable.c index 1f8d9e8c3323..bb854b6e92e9 100644 --- a/arch/m68k/mm/extable.c +++ b/arch/m68k/mm/extable.c @@ -33,23 +33,29 @@ search_one_table(const struct exception_table_entry *first, unsigned long search_exception_table(unsigned long addr) { - unsigned long ret; + unsigned long ret = 0; #ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); - if (ret) return ret; + return ret; #else + unsigned long flags; + struct list_head *i; + /* The kernel is the last "module" -- no need to treat it special. */ - struct module *mp; - for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) + spin_lock_irqsave(&modlist_lock, flags); + list_for_each(i, &extables) { + struct exception_table *ex + = list_entry(i, struct exception_table, list); + if (ex->num_entries == 0) continue; - ret = search_one_table(mp->ex_table_start, - mp->ex_table_end-1, addr); - if (ret) return ret; + ret = search_one_table(ex->entry, + ex->entry + ex->num_entries - 1, addr); + if (ret) + break; } + spin_unlock_irqrestore(&modlist_lock, flags); + return ret; #endif - - return 0; } diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c index dd3411170472..a1dcc2ed06aa 100644 --- a/arch/m68k/mm/sun3mmu.c +++ b/arch/m68k/mm/sun3mmu.c @@ -83,7 +83,7 @@ void __init paging_init(void) /* now change pg_table to kernel virtual addresses */ pg_table = (pte_t *) __va ((unsigned long) pg_table); for (i=0; i<PTRS_PER_PTE; ++i, ++pg_table) { - pte_t pte = __mk_pte(address, PAGE_INIT); + pte_t pte = pfn_pte(virt_to_pfn(address), PAGE_INIT); if (address >= (unsigned long)high_memory) pte_val (pte) = 0; set_pte (pg_table, pte); diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 25c324c036f4..5f5342a2a67f 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -23,6 +23,7 @@ #include <linux/major.h> #include <linux/genhd.h> #include <linux/rtc.h> +#include <linux/interrupt.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -209,10 +210,9 @@ static void scc_write (char ch) void m147_scc_write (struct console *co, const char *str, unsigned count) { - unsigned long flags; + unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); while (count--) { @@ -220,7 +220,7 @@ void m147_scc_write (struct console *co, const char *str, unsigned count) scc_write ('\r'); scc_write (*str++); } - restore_flags(flags); + local_irq_restore(flags); } void mvme147_init_console_port (struct console *co, int cflag) diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index cf42754a0980..713c18b54c7e 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -24,6 +24,7 @@ #include <linux/major.h> #include <linux/genhd.h> #include <linux/rtc.h> +#include <linux/interrupt.h> #include <asm/bootinfo.h> #include <asm/system.h> diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c index 6f88e9d2bbd7..ec79bfc53d34 100644 --- a/arch/m68k/mvme16x/rtc.c +++ b/arch/m68k/mvme16x/rtc.c @@ -48,8 +48,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, switch (cmd) { case RTC_RD_TIME: /* Read the time/date from RTC */ { - save_flags(flags); - cli(); + local_irq_save(flags); /* Ensure clock and real-time-mode-register are accessible */ rtc->ctrl = RTC_READ; wtime.tm_sec = BCD2BIN(rtc->bcd_sec); @@ -62,7 +61,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, wtime.tm_year += 100; wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1; rtc->ctrl = 0; - restore_flags(flags); + local_irq_restore(flags); return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } @@ -102,8 +101,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (yrs >= 2070) return -EINVAL; - save_flags(flags); - cli(); + local_irq_save(flags); rtc->ctrl = RTC_WRITE; rtc->bcd_sec = BIN2BCD(sec); @@ -114,7 +112,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, rtc->bcd_year = BIN2BCD(yrs%100); rtc->ctrl = 0; - restore_flags(flags); + local_irq_restore(flags); return 0; } default: @@ -168,7 +166,6 @@ int __init rtc_MK48T08_init(void) return -ENODEV; printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION); - misc_register(&rtc_dev); - return 0; + return misc_register(&rtc_dev); } diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 54fe9303cbd4..da640dfb0bbd 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -18,6 +18,7 @@ #include <linux/string.h> #include <linux/sched.h> #include <linux/seq_file.h> +#include <linux/interrupt.h> #include <asm/rtc.h> #include <asm/ptrace.h> @@ -374,7 +375,7 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp) } if ( irq_tab[irq].state & IRQ_INPROGRESS ) { - /* some handlers do sti() for irq latency reasons, */ + /* some handlers do local_irq_enable() for irq latency reasons, */ /* however reentering an active irq handler is not permitted */ #ifdef IP_USE_DISABLE /* in theory this is the better way to do it because it still */ diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index 3aaa166f5612..2c21cfb5337f 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -42,7 +42,6 @@ extern void sun3_get_model (char* model); extern void idprom_init (void); extern int sun3_hwclk(int set, struct rtc_time *t); -extern void sun_serial_setup(void); volatile char* clock_va; extern volatile unsigned char* sun3_intreg; extern unsigned long availmem; @@ -173,10 +172,6 @@ void __init config_sun3(void) m68k_memory[0].size=*(romvec->pv_sun3mem); sun3_bootmem_alloc(memory_start, memory_end); - -#ifdef CONFIG_SUN3X_ZS - sun_serial_setup(); -#endif } void __init sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) diff --git a/arch/m68k/sun3/dvma.c b/arch/m68k/sun3/dvma.c index 1c47cc14415c..af1b60199455 100644 --- a/arch/m68k/sun3/dvma.c +++ b/arch/m68k/sun3/dvma.c @@ -1,5 +1,11 @@ - -/* dvma support routines */ +/* + * linux/arch/m68k/sun3/dvma.c + * + * Written by Sam Creasey + * + * Sun3 IOMMU routines used for dvma accesses. + * + */ #include <linux/kernel.h> #include <linux/mm.h> @@ -22,7 +28,7 @@ inline unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr) j = *(volatile unsigned long *)kaddr; *(volatile unsigned long *)kaddr = j; - ptep = __mk_pte(kaddr, PAGE_KERNEL); + ptep = pfn_pte(virt_to_pfn(kaddr), PAGE_KERNEL); pte = pte_val(ptep); // printk("dvma_remap: addr %lx -> %lx pte %08lx len %x\n", // kaddr, vaddr, pte, len); diff --git a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c index 1015f247ae7e..fce7e6f03172 100644 --- a/arch/m68k/sun3/intersil.c +++ b/arch/m68k/sun3/intersil.c @@ -40,7 +40,7 @@ int sun3_hwclk(int set, struct rtc_time *t) todintersil = (struct intersil_dt *) &intersil_clock->counter; - save_and_cli(flags); + local_irq_save(flags); intersil_clock->cmd_reg = STOP_VAL; @@ -68,7 +68,7 @@ int sun3_hwclk(int set, struct rtc_time *t) intersil_clock->cmd_reg = START_VAL; - restore_flags(flags); + local_irq_restore(flags); return 0; diff --git a/arch/m68k/sun3/prom/console.c b/arch/m68k/sun3/prom/console.c index 5ec12de10fbd..52c1427863de 100644 --- a/arch/m68k/sun3/prom/console.c +++ b/arch/m68k/sun3/prom/console.c @@ -22,9 +22,9 @@ prom_nbgetchar(void) int i = -1; unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); i = (*(romvec->pv_nbgetchar))(); - restore_flags(flags); + local_irq_restore(flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ } @@ -37,9 +37,9 @@ prom_nbputchar(char c) unsigned long flags; int i = -1; - save_flags(flags); cli(); + local_irq_save(flags); i = (*(romvec->pv_nbputchar))(c); - restore_flags(flags); + local_irq_restore(flags); return i; /* Ugh, we could spin forever on unsupported proms ;( */ } @@ -83,12 +83,12 @@ prom_query_input_device() }; case PROM_V3: case PROM_P1275: - save_flags(flags); cli(); + local_irq_save(flags); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r" (¤t_set[smp_processor_id()]) : "memory"); - restore_flags(flags); + local_irq_restore(flags); if(prom_node_has_property(st_p, "keyboard")) return PROMDEV_IKBD; prom_getproperty(st_p, "device_type", propb, sizeof(propb)); @@ -133,12 +133,12 @@ prom_query_output_device() case PROM_V2: case PROM_V3: case PROM_P1275: - save_flags(flags); cli(); + local_irq_save(flags); st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r" (¤t_set[smp_processor_id()]) : "memory"); - restore_flags(flags); + local_irq_restore(flags); propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); if (propl >= 0 && propl == sizeof("display") && strncmp("display", propb, sizeof("display")) == 0) diff --git a/arch/m68k/sun3/prom/misc.c b/arch/m68k/sun3/prom/misc.c index 1d19e8d49b91..b88716f2c68c 100644 --- a/arch/m68k/sun3/prom/misc.c +++ b/arch/m68k/sun3/prom/misc.c @@ -19,9 +19,9 @@ void prom_reboot(char *bcommand) { unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); (*(romvec->pv_reboot))(bcommand); - restore_flags(flags); + local_irq_restore(flags); } /* Drop into the prom, with the chance to continue with the 'go' @@ -40,9 +40,9 @@ prom_halt(void) { unsigned long flags; again: - save_flags(flags); cli(); + local_irq_save(flags); (*(romvec->pv_halt))(); - restore_flags(flags); + local_irq_restore(flags); goto again; /* PROM is out to get me -DaveM */ } diff --git a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c index fe148907acd8..52a39cb28b97 100644 --- a/arch/m68k/sun3/sbus.c +++ b/arch/m68k/sun3/sbus.c @@ -12,13 +12,9 @@ #include <linux/types.h> #include <linux/init.h> -extern void rs_init(void); - -void __init sbus_init(void) +int __init sbus_init(void) { - - rs_init(); - + return 0; } void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, @@ -27,3 +23,4 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, return (void *)address; } +subsys_initcall(sbus_init); diff --git a/arch/m68k/sun3x/dvma.c b/arch/m68k/sun3x/dvma.c index 3f28e3565235..4fc997c9b2ef 100644 --- a/arch/m68k/sun3x/dvma.c +++ b/arch/m68k/sun3x/dvma.c @@ -102,7 +102,7 @@ inline int dvma_map_cpu(unsigned long kaddr, pmd_t *pmd; unsigned long end2; - if((pmd = pmd_alloc_kernel(pgd, vaddr)) == NULL) { + if((pmd = pmd_alloc(&init_mm, pgd, vaddr)) == NULL) { ret = -ENOMEM; goto out; } @@ -116,7 +116,7 @@ inline int dvma_map_cpu(unsigned long kaddr, pte_t *pte; unsigned long end3; - if((pte = pte_alloc_kernel(pmd, vaddr)) == NULL) { + if((pte = pte_alloc_kernel(&init_mm, pmd, vaddr)) == NULL) { ret = -ENOMEM; goto out; } @@ -131,7 +131,8 @@ inline int dvma_map_cpu(unsigned long kaddr, printk("mapping %08lx phys to %08lx\n", __pa(kaddr), vaddr); #endif - set_pte(pte, __mk_pte(kaddr, PAGE_KERNEL)); + set_pte(pte, pfn_pte(virt_to_pfn(kaddr), + PAGE_KERNEL)); pte++; kaddr += PAGE_SIZE; vaddr += PAGE_SIZE; diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c index d738e0536a34..93dd64576e1a 100644 --- a/arch/m68k/sun3x/prom.c +++ b/arch/m68k/sun3x/prom.c @@ -37,9 +37,9 @@ extern e_vector vectors[256]; /* arch/m68k/kernel/traps.c */ void sun3x_halt(void) { unsigned long flags; - + /* Disable interrupts while we mess with things */ - save_flags(flags); cli(); + local_irq_save(flags); /* Restore prom vbr */ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); @@ -56,13 +56,13 @@ void sun3x_halt(void) sun3_enable_irq(5); __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); - restore_flags(flags); + local_irq_restore(flags); } void sun3x_reboot(void) { /* This never returns, don't bother saving things */ - cli(); + local_irq_disable(); /* Restore prom vbr */ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c index b72f3c2eb65d..683a34e815d4 100644 --- a/arch/m68k/sun3x/time.c +++ b/arch/m68k/sun3x/time.c @@ -45,7 +45,7 @@ int sun3x_hwclk(int set, struct rtc_time *t) (struct mostek_dt *)(SUN3X_EEPROM+M_CONTROL); unsigned long flags; - save_and_cli(flags); + local_irq_save(flags); if(set) { h->csr |= C_WRITE; @@ -69,7 +69,7 @@ int sun3x_hwclk(int set, struct rtc_time *t) h->csr &= ~C_READ; } - restore_flags(flags); + local_irq_restore(flags); return 0; } diff --git a/arch/m68k/vmlinux-std.lds b/arch/m68k/vmlinux-std.lds index c0ac0012d92d..c31bc1da259b 100644 --- a/arch/m68k/vmlinux-std.lds +++ b/arch/m68k/vmlinux-std.lds @@ -47,6 +47,9 @@ SECTIONS __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; + __start___param = .; + __param : { *(__param) } + __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) @@ -59,6 +62,10 @@ SECTIONS } __initcall_end = .; . = ALIGN(8192); + __initramfs_start = .; + .init.ramfs : { *(.init.ramfs) } + __initramfs_end = .; + . = ALIGN(8192); __init_end = .; .data.init_task : { *(.data.init_task) } /* The initial task and kernel stack */ diff --git a/arch/m68k/vmlinux-sun3.lds b/arch/m68k/vmlinux-sun3.lds index 83aa0185079c..9ce55a8120c0 100644 --- a/arch/m68k/vmlinux-sun3.lds +++ b/arch/m68k/vmlinux-sun3.lds @@ -43,6 +43,9 @@ __init_begin = .; __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; + __start___param = .; + __param : { *(__param) } + __stop___param = .; __initcall_start = .; .initcall.init : { *(.initcall1.init) @@ -55,6 +58,10 @@ __init_begin = .; } __initcall_end = .; . = ALIGN(8192); + __initramfs_start = .; + .init.ramfs : { *(.init.ramfs) } + __initramfs_end = .; + . = ALIGN(8192); __init_end = .; .init.task : { *(init_task) } diff --git a/arch/um/Kconfig b/arch/um/Kconfig index f7e8005ebf38..cb59d60d0fff 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -30,6 +30,13 @@ config RWSEM_GENERIC_SPINLOCK bool default y +config MODE_TT + bool + default y + +config MODE_SKAS + bool + default y menu "Code maturity level options" @@ -64,9 +71,41 @@ config BINFMT_MISC config HOSTFS tristate "Host filesystem" + help + While the User-Mode Linux port uses its own root file system for + booting and normal file access, this module lets the UML user + access files stored on the host. It does not require any + network connection between the Host and UML. An example use of + this might be: + + mount none /tmp/fromhost -t hostfs -o /tmp/umlshare + + where /tmp/fromhost is an empty directory inside UML and + /tmp/umlshare is a directory on the host with files the UML user + wishes to access. + + For more information, see + <http://user-mode-linux.sourceforge.net/hostfs.html>. + + If you'd like to be able to work with files stored on the host, + say Y or M here; otherwise say N. + config MCONSOLE bool "Management console" + help + The user mode linux management console is a low-level interface to + the kernel, somewhat like the i386 SysRq interface. Since there is + a full-blown operating system running under every user mode linux + instance, there is much greater flexibility possible than with the + SysRq mechanism. + + If you answer 'Y' to this option, to use this feature, you need the + mconsole client (called uml_mconsole) which is present in CVS in + 2.4.5-9um and later (path /tools/mconsole), and is also in the + distribution RPM package in 2.4.6 and later. + + It is safe to say 'Y' here. config MAGIC_SYSRQ bool "Magic SysRq key" @@ -77,6 +116,16 @@ config HOST_2G_2G config UML_SMP bool "Symmetric multi-processing support" + help + This option enables UML SMP support. UML implements virtual SMP by + allowing as many processes to run simultaneously on the host as + there are virtual processors configured. Obviously, if the host is + a uniprocessor, those processes will timeshare, but, inside UML, + will appear to be running simultaneously. If the host is a + multiprocessor, then UML processes may run simultaneously, depending + on the host scheduler. + CONFIG_SMP will be set to whatever this option is set to. + It is safe to leave this unchanged. config SMP bool @@ -90,10 +139,27 @@ config NR_CPUS config NEST_LEVEL int "Nesting level" default "0" + help + This is set to the number of layers of UMLs that this UML will be run + in. Normally, this is zero, meaning that it will run directly on the + host. Setting it to one will build a UML that can run inside a UML + that is running on the host. Generally, if you intend this UML to run + inside another UML, set CONFIG_NEST_LEVEL to one more than the host + UML. + + Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to + greater than one, then the guest UML should have its CONFIG_NEST_LEVEL + set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. + Only change this if you are running nested UMLs. config KERNEL_HALF_GIGS int "Kernel address space size (in .5G units)" default "1" + help + This determines the amount of address space that UML will allocate for + its own, measured in half Gigabyte units. The default is 1. + Change this only if you need to boot UML with an unusually large amount + of physical memory. config HIGHMEM bool "Highmem support" @@ -128,6 +194,7 @@ source "net/Kconfig" source "fs/Kconfig" +source "lib/Kconfig" menu "SCSI support" @@ -156,6 +223,14 @@ config DEBUG_SLAB config DEBUGSYM bool "Enable kernel debugging symbols" + help + When this is enabled, the User-Mode Linux binary will include + debugging symbols. This enlarges the binary by a few megabytes, + but aids in tracking down kernel problems in UML. It is required + if you intend to do any kernel development. + + If you're truly short on disk space or don't expect to report any + bugs back to the UML developers, say N, otherwise say Y. config PT_PROXY bool "Enable ptrace proxy" @@ -164,10 +239,28 @@ config PT_PROXY config GPROF bool "Enable gprof support" depends on DEBUGSYM + help + This allows profiling of a User-Mode Linux kernel with the gprof + utility. + + See <http://user-mode-linux.sourceforge.net/gprof.html> for more + details. + + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. config GCOV bool "Enable gcov support" depends on DEBUGSYM + help + This option allows developers to retrieve coverage data from a UML + session. + + See <http://user-mode-linux.sourceforge.net/gcov.html> for more + details. + + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. endmenu diff --git a/arch/um/Kconfig_block b/arch/um/Kconfig_block index 542627172e92..fba53d9bb983 100644 --- a/arch/um/Kconfig_block +++ b/arch/um/Kconfig_block @@ -3,10 +3,31 @@ menu "Block Devices" config BLK_DEV_UBD bool "Virtual block device" + help + The User-Mode Linux port includes a driver called UBD which will let + you access arbitrary files on the host computer as block devices. + Unless you know that you do not need such virtual block devices say + Y here. config BLK_DEV_UBD_SYNC bool "Always do synchronous disk IO for UBD" depends on BLK_DEV_UBD + help + Writes to the virtual block device are not immediately written to the + host's disk; this may cause problems if, for example, the + User-Mode Linux 'Virtual Machine' uses a journalling filesystem and + the host computer crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to + turn on synchronous operation by default for all block devices. + + If you're running a journalling file system (like reiserfs, for + example) in your virtual machine, you will want to say Y here. If + you care for the safety of the data in your virtual machine, Y is a + wise choice too. In all other cases (for example, if you're just + playing around with User-Mode Linux) you can choose N. config BLK_DEV_LOOP tristate "Loopback device support" @@ -29,6 +50,19 @@ config BLK_DEV_INITRD config MMAPPER tristate "Example IO memory driver" + help + The User-Mode Linux port can provide support for IO Memory + emulation with this option. This allows a host file to be + specified as an I/O region on the kernel command line. That file + will be mapped into UML's kernel address space where a driver can + locate it and do whatever it wants with the memory, including + providing an interface to it for UML processes to use. + + For more information, see + <http://user-mode-linux.sourceforge.net/iomem.html>. + + If you'd like to be able to provide a simulated IO port space for + User-Mode Linux processes, say Y. If unsure, say N. endmenu diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char index 8a3367c10310..a21cbbc7efde 100644 --- a/arch/um/Kconfig_char +++ b/arch/um/Kconfig_char @@ -7,36 +7,104 @@ config STDIO_CONSOLE config SSL bool "Virtual serial line" + help + The User-Mode Linux environment allows you to create virtual serial + lines on the UML that are usually made to show up on the host as + ttys or ptys. + + See <http://user-mode-linux.sourceforge.net/input.html> for more + information and command line examples of how to use this facility. + + Unless you have a specific reason for disabling this, say Y. config FD_CHAN bool "file descriptor channel support" + help + This option enables support for attaching UML consoles and serial + lines to already set up file descriptors. Generally, the main + console is attached to file descriptors 0 and 1 (stdin and stdout), + so it would be wise to leave this enabled unless you intend to + attach it to some other host device. config NULL_CHAN bool "null channel support" + help + This option enables support for attaching UML consoles and serial + lines to a device similar to /dev/null. Data written to it disappears + and there is never any data to be read. config PORT_CHAN bool "port channel support" + help + This option enables support for attaching UML consoles and serial + lines to host portals. They may be accessed with 'telnet <host> + <port number>'. Any number of consoles and serial lines may be + attached to a single portal, although what UML device you get when + you telnet to that portal will be unpredictable. + It is safe to say 'Y' here. config PTY_CHAN bool "pty channel support" + help + This option enables support for attaching UML consoles and serial + lines to host pseudo-terminals. Access to both traditional + pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled + with this option. The assignment of UML devices to host devices + will be announced in the kernel message log. + It is safe to say 'Y' here. config TTY_CHAN bool "tty channel support" + help + This option enables support for attaching UML consoles and serial + lines to host terminals. Access to both virtual consoles + (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and + /dev/pts/*) are controlled by this option. + It is safe to say 'Y' here. config XTERM_CHAN bool "xterm channel support" + help + This option enables support for attaching UML consoles and serial + lines to xterms. Each UML device so assigned will be brought up in + its own xterm. + If you disable this option, then CONFIG_PT_PROXY will be disabled as + well, since UML's gdb currently requires an xterm. + It is safe to say 'Y' here. config CON_ZERO_CHAN string "Default main console channel initialization" default "fd:0,fd:1" + help + This is the string describing the channel to which the main console + will be attached by default. This value can be overridden from the + command line. The default value is "fd:0,fd:1", which attaches the + main console to stdin and stdout. + It is safe to leave this unchanged. config CON_CHAN string "Default console channel initialization" default "xterm" + help + This is the string describing the channel to which all consoles + except the main console will be attached by default. This value can + be overridden from the command line. The default value is "xterm", + which brings them up in xterms. + It is safe to leave this unchanged, although you may wish to change + this if you expect the UML that you build to be run in environments + which don't have X or xterm available. config SSL_CHAN string "Default serial line channel initialization" default "pty" + help + This is the string describing the channel to which the serial lines + will be attached by default. This value can be overridden from the + command line. The default value is "pty", which attaches them to + traditional pseudo-terminals. + It is safe to leave this unchanged, although you may wish to change + this if you expect the UML that you build to be run in environments + which don't have a set of /dev/pty* devices. config UNIX98_PTYS bool "Unix98 PTY support" @@ -63,6 +131,11 @@ config UML_WATCHDOG config UML_SOUND tristate "Sound support" + help + This option enables UML sound support. If enabled, it will pull in + soundcore and the UML hostaudio relay, which acts as a intermediary + between the host's dsp and mixer devices and the UML sound system. + It is safe to say 'Y' here. config SOUND tristate @@ -72,8 +145,5 @@ config HOSTAUDIO tristate default UML_SOUND -config TTY_LOG - bool "Enable tty logging" - endmenu diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net index ba311513abc3..443a74bd622d 100644 --- a/arch/um/Kconfig_net +++ b/arch/um/Kconfig_net @@ -5,30 +5,177 @@ menu "Network Devices" # UML virtual driver config UML_NET bool "Virtual network device" + help + While the User-Mode port cannot directly talk to any physical + hardware devices, this choice and the following transport options + provide one or more virtual network devices through which the UML + kernels can talk to each other, the host, and with the host's help, + machines on the outside world. + + For more information, including explanations of the networking and + sample configurations, see + <http://user-mode-linux.sourceforge.net/networking.html>. + + If you'd like to be able to enable networking in the User-Mode + linux environment, say Y; otherwise say N. Note that you must + enable at least one of the following transport options to actually + make use of UML networking. config UML_NET_ETHERTAP bool "Ethertap transport" depends on UML_NET + help + The Ethertap User-Mode Linux network transport allows a single + running UML to exchange packets with its host over one of the + host's Ethertap devices, such as /dev/tap0. Additional running + UMLs can use additional Ethertap devices, one per running UML. + While the UML believes it's on a (multi-device, broadcast) virtual + Ethernet network, it's in fact communicating over a point-to-point + link with the host. + + To use this, your host kernel must have support for Ethertap + devices. Also, if your host kernel is 2.4.x, it must have + CONFIG_NETLINK_DEV configured as Y or M. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable Ethertap + networking. + + If you'd like to set up an IP network with the host and/or the + outside world, say Y to this, the Daemon Transport and/or the + Slip Transport. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. config UML_NET_TUNTAP bool "TUN/TAP transport" depends on UML_NET + help + The UML TUN/TAP network transport allows a UML instance to exchange + packets with the host over a TUN/TAP device. This option will only + work with a 2.4 host, unless you've applied the TUN/TAP patch to + your 2.2 host kernel. + + To use this transport, your host kernel must have support for TUN/TAP + devices, either built-in or as a module. config UML_NET_SLIP bool "SLIP transport" depends on UML_NET + help + The slip User-Mode Linux network transport allows a running UML to + network with its host over a point-to-point link. Unlike Ethertap, + which can carry any Ethernet frame (and hence even non-IP packets), + the slip transport can only carry IP packets. + + To use this, your host must support slip devices. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html>. That site + has examples of the UML command line to use to enable slip + networking, and details of a few quirks with it. + + The Ethertap Transport is preferred over slip because of its + limitations. If you prefer slip, however, say Y here. Otherwise + choose the Multicast transport (to network multiple UMLs on + multiple hosts), Ethertap (to network with the host and the + outside world), and/or the Daemon transport (to network multiple + UMLs on a single host). You may choose more than one without + conflict. If you don't need UML networking, say N. config UML_NET_DAEMON bool "Daemon transport" depends on UML_NET + help + This User-Mode Linux network transport allows one or more running + UMLs on a single host to communicate with each other, but not to + the host. + + To use this form of networking, you'll need to run the UML + networking daemon on the host. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable Daemon + networking. + + If you'd like to set up a network with other UMLs on a single host, + say Y. If you need a network between UMLs on multiple physical + hosts, choose the Multicast Transport. To set up a network with + the host and/or other IP machines, say Y to the Ethertap or Slip + transports. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. config UML_NET_MCAST bool "Multicast transport" depends on UML_NET + help + This Multicast User-Mode Linux network transport allows multiple + UMLs (even ones running on different host machines!) to talk to + each other over a virtual ethernet network. However, it requires + at least one UML with one of the other transports to act as a + bridge if any of them need to be able to talk to their hosts or any + other IP machines. + + To use this, your host kernel(s) must support IP Multicasting. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable Multicast + networking, and notes about the security of this approach. + + If you need UMLs on multiple physical hosts to communicate as if + they shared an Ethernet network, say Y. If you need to communicate + with other IP machines, make sure you select one of the other + transports (possibly in addition to Multicast; they're not + exclusive). If you don't need to network UMLs say N to each of + the transports. config UML_NET_PCAP bool "pcap transport" depends on UML_NET + help + The pcap transport makes a pcap packet stream on the host look + like an ethernet device inside UML. This is useful for making + UML act as a network monitor for the host. You must have libcap + installed in order to build the pcap transport into UML. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable this option. + + If you intend to use UML as a network monitor for the host, say + Y here. Otherwise, say N. + +config UML_NET_SLIRP + bool "SLiRP transport" + depends on UML_NET + help + The SLiRP User-Mode Linux network transport allows a running UML + to network by invoking a program that can handle SLIP encapsulated + packets. This is commonly (but not limited to) the application + known as SLiRP, a program that can re-socket IP packets back onto + the host on which it is run. Only IP packets are supported, + unlike other network transports that can handle all Ethernet + frames. In general, slirp allows the UML the same IP connectivity + to the outside world that the host user is permitted, and unlike + other transports, SLiRP works without the need of root level + privleges, setuid binaries, or SLIP devices on the host. This + also means not every type of connection is possible, but most + situations can be accomodated with carefully crafted slirp + commands that can be passed along as part of the network device's + setup string. The effect of this transport on the UML is similar + that of a host behind a firewall that masquerades all network + connections passing through it (but is less secure). + + To use this you should first have slirp compiled somewhere + accessible on the host, and have read its documentation. If you + don't need UML networking, say N. + + Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" + # Below are hardware-independent drivers mirrored from # drivers/net/Config.in. It would be nice if Linux diff --git a/arch/um/Makefile b/arch/um/Makefile index e4ad81702045..6fd0df8cd4e3 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -1,3 +1,8 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + ARCH_DIR = arch/um OS := $(shell uname -s) @@ -11,37 +16,31 @@ include/linux/version.h: arch/$(ARCH)/Makefile # EXTRAVERSION... MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) -MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot - ifeq ($(CONFIG_DEBUGSYM),y) -DEBUG = -g CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) endif -ifeq ($(CONFIG_GCOV),y) -CFLAGS += -fprofile-arcs -ftest-coverage -endif - -ifeq ($(CONFIG_GPROF), y) -PROFILE += -pg -DPROFILING -LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup -endif +CFLAGS-$(CONFIG_DEBUGSYM) += -g +CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage +CFLAGS-$(CONFIG_GPROF) += $(PROFILE) +LINK-$(CONFIG_GPROF) += $(PROFILE) -Wl,--wrap,__monstartup core-y += $(ARCH_DIR)/kernel/ \ $(ARCH_DIR)/drivers/ \ $(ARCH_DIR)/sys-$(SUBARCH)/ -core-$(CONFIG_PT_PROXY) += $(ARCH_DIR)/ptproxy/ - -ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include +ARCH_INCLUDE = -I$(ARCH_DIR)/include +MODE_INCLUDE = -I$(ARCH_DIR)/kernel/tt/include \ + -I$(ARCH_DIR)/kernel/skas/include # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common # in CFLAGS. Otherwise, it would cause ld to complain about the two different # errnos. -CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ - -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno +CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ + -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ + $(MODE_INCLUDE) LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc @@ -51,10 +50,16 @@ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ include/asm-um/sigcontext.h include/asm-um/processor.h \ include/asm-um/ptrace.h include/asm-um/arch-signal.h -ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \ - $(SYMLINK_HEADERS) +ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \ + $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h + +ifeq ($(CONFIG_MODE_SKAS), y) +GEN_HEADERS = $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h -GEN_HEADERS = $(ARCH_DIR)/include/task.h +$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h +endif + +GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h include $(ARCH_DIR)/Makefile-$(SUBARCH) include $(ARCH_DIR)/Makefile-os-$(OS) @@ -62,9 +67,9 @@ include $(ARCH_DIR)/Makefile-os-$(OS) $(ARCH_DIR)/vmlinux.lds.S : touch $@ -prepare: $(ARCH_SYMLINKS) $(GEN_HEADERS) +prepare: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) -LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o +LDFLAGS_vmlinux = -r vmlinux: $(ARCH_DIR)/main.o @@ -74,18 +79,21 @@ $(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S scripts FORCE AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ -DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum -linux: arch/um/uml.lds.s vmlinux - $(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \ - $(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil +linux: $(ARCH_DIR)/uml.lds.s vmlinux + $(CC) -Wl,-T,$(ARCH_DIR)/uml.lds.s -static $(LINK-y) $(LINK_WRAPS) \ + -o linux $(ARCH_DIR)/main.o vmlinux -L/usr/lib -lutil USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) -USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE) +USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ + $(MODE_INCLUDE) # To get a definition of F_SETSIG USER_CFLAGS += -D_GNU_SOURCE +CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) + $(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< @@ -106,11 +114,9 @@ archclean: sysclean find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ -o -name '*.gcov' \) -type f -print | xargs rm -f rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS) - @$(MAKEBOOT) clean archdep: for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done - @$(MAKEBOOT) dep $(SYMLINK_HEADERS): cd $(TOPDIR)/$(dir $@) ; \ @@ -119,18 +125,28 @@ $(SYMLINK_HEADERS): include/asm-um/arch: cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch -arch/um/include/sysdep: - cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep +$(ARCH_DIR)/include/sysdep: + cd $(ARCH_DIR)/include && ln -sf sysdep-$(SUBARCH) sysdep -arch/um/os: +$(ARCH_DIR)/os: cd $(ARCH_DIR) && ln -sf os-$(OS) os +$(ARCH_DIR)/include/uml-config.h : + ln -sf $(TOPDIR)/include/linux/autoconf.h $@ + $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task $< > $@ -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util FORCE ; +$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants + $< > $@ + +$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \ + $(ARCH_DIR)/util FORCE ; $(ARCH_DIR)/util: FORCE @$(call descend,$@,) +$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : + $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h + export SUBARCH USER_CFLAGS OS diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index e4a66c4fbacf..3bd90fbdb7e0 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -21,13 +21,13 @@ prepare: $(SYS_HEADERS) $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc $< > $@ -$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread +$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread $< > $@ $(SYS_UTIL_DIR)/mk_sc: FORCE ; @$(call descend,$(SYS_UTIL_DIR),$@) -$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) FORCE ; +$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; @$(call descend,$(SYS_UTIL_DIR),$@) $(SYS_UTIL_DIR): include/asm FORCE diff --git a/arch/um/boot/Makefile b/arch/um/boot/Makefile deleted file mode 100644 index f5dc182a5fb4..000000000000 --- a/arch/um/boot/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -dep: - -clean: diff --git a/arch/um/config_block.in b/arch/um/config_block.in deleted file mode 100644 index 419bb713354a..000000000000 --- a/arch/um/config_block.in +++ /dev/null @@ -1,16 +0,0 @@ -mainmenu_option next_comment -comment 'Block Devices' - -bool 'Virtual block device' CONFIG_BLK_DEV_UBD -dep_bool ' Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD -tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP -dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET -tristate 'RAM disk support' CONFIG_BLK_DEV_RAM -if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then - int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 -fi -dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM - -tristate 'Example IO memory driver' CONFIG_MMAPPER - -endmenu diff --git a/arch/um/config_char.in b/arch/um/config_char.in deleted file mode 100644 index dfb87d66b8de..000000000000 --- a/arch/um/config_char.in +++ /dev/null @@ -1,37 +0,0 @@ -mainmenu_option next_comment -comment 'Character Devices' - -define_bool CONFIG_STDIO_CONSOLE y - -bool 'Virtual serial line' CONFIG_SSL - -bool 'file descriptor channel support' CONFIG_FD_CHAN -bool 'null channel support' CONFIG_NULL_CHAN -bool 'port channel support' CONFIG_PORT_CHAN -bool 'pty channel support' CONFIG_PTY_CHAN -bool 'tty channel support' CONFIG_TTY_CHAN -bool 'xterm channel support' CONFIG_XTERM_CHAN -string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \ - "fd:0,fd:1" -string 'Default console channel initialization' CONFIG_CON_CHAN "xterm" -string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty" - - -bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS -if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 -fi - -bool 'Watchdog Timer Support' CONFIG_WATCHDOG -dep_bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \ - $CONFIG_WATCHDOG -dep_tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG -dep_tristate ' UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG - -tristate 'Sound support' CONFIG_UML_SOUND -define_tristate CONFIG_SOUND $CONFIG_UML_SOUND -define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND - -bool 'Enable tty logging' CONFIG_TTY_LOG - -endmenu diff --git a/arch/um/config_net.in b/arch/um/config_net.in deleted file mode 100644 index f1f6a6e9b13f..000000000000 --- a/arch/um/config_net.in +++ /dev/null @@ -1,46 +0,0 @@ -mainmenu_option next_comment -comment 'Network Devices' - -# UML virtual driver -bool 'Virtual network device' CONFIG_UML_NET - -dep_bool ' Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET -dep_bool ' TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET -dep_bool ' SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET -dep_bool ' Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET -dep_bool ' Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET -dep_bool ' pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET - -# Below are hardware-independent drivers mirrored from -# drivers/net/Config.in. It would be nice if Linux -# had HW independent drivers separated from the other -# but it does not. Until then each non-ISA/PCI arch -# needs to provide it's own menu of network drivers - -tristate 'Dummy net driver support' CONFIG_DUMMY -tristate 'Bonding driver support' CONFIG_BONDING -tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER -tristate 'Universal TUN/TAP device driver support' CONFIG_TUN -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK" = "y" ]; then - tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP - fi -fi - -tristate 'PPP (point-to-point protocol) support' CONFIG_PPP -if [ ! "$CONFIG_PPP" = "n" ]; then - dep_bool ' PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL - dep_bool ' PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER - dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP - dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP - dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP - dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP - dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL -fi - -tristate 'SLIP (serial line) support' CONFIG_SLIP -dep_bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP -dep_bool ' Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP -dep_bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP - -endmenu diff --git a/arch/um/config_scsi.in b/arch/um/config_scsi.in deleted file mode 100644 index ed363965b73f..000000000000 --- a/arch/um/config_scsi.in +++ /dev/null @@ -1,30 +0,0 @@ -comment 'SCSI support type (disk, tape, CD-ROM)' - -dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI - -if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then - int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 -fi - -dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - -dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI - -if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR - int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 -fi -dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI - -comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - -#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES -#fi - -bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN - -bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS -bool ' SCSI logging facility' CONFIG_SCSI_LOGGING - -dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index bd963ccdc7e8..8e72f9032ab6 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -5,23 +5,14 @@ CHAN_OBJS := chan_kern.o chan_user.o line.o -# This nonsense is due to kbuild. In the 2.4 build, I stick -lpcap in -# pcap-objs, and that is just included in the link command. The 2.5 kbuild -# filters out everything from pcap-objs which are not in the built-in.o -# dependencies, which are $(obj-y). So, -lpcap must be in $(obj-y), too. -# However, make magically expands -lfoo prerequisites into /usr/lib/libfoo.a -# file names. This causes the kbuild filtering to filter the -lpcap from -# pcap-objs, causing the link to fail. -# So, what this does is figure out by hand (crudely) what file -lpcap really -# is and just use it. - -PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.a; do \ - [ -f $$f ] && echo $$f ; done | head -1) +# pcap is broken in 2.5 because kbuild doesn't allow pcap.a to be linked +# in to pcap.o slip-objs := slip_kern.o slip_user.o +slirp-objs := slirp_kern.o slirp_user.o daemon-objs := daemon_kern.o daemon_user.o mcast-objs := mcast_kern.o mcast_user.o -pcap-objs := pcap_kern.o pcap_user.o $(PCAP) +#pcap-objs := pcap_kern.o pcap_user.o $(PCAP) net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o hostaudio-objs := hostaudio_kern.o hostaudio_user.o @@ -34,9 +25,10 @@ export-objs := mconsole_kern.o obj-y = obj-$(CONFIG_SSL) += ssl.o obj-$(CONFIG_UML_NET_SLIP) += slip.o +obj-$(CONFIG_UML_NET_SLIRP) += slirp.o obj-$(CONFIG_UML_NET_DAEMON) += daemon.o obj-$(CONFIG_UML_NET_MCAST) += mcast.o -obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP) +#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP) obj-$(CONFIG_UML_NET) += net.o obj-$(CONFIG_MCONSOLE) += mconsole.o obj-$(CONFIG_MMAPPER) += mmapper_kern.o @@ -50,8 +42,6 @@ obj-$(CONFIG_TTY_CHAN) += tty.o obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o -CFLAGS_pcap_user.o = -I/usr/include/pcap - obj-y += stdio_console.o $(CHAN_OBJS) USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) @@ -61,7 +51,7 @@ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \ USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file)) $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean: diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 46a84e8e916c..119cce1bb689 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -24,7 +24,8 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) return(NULL); } -static int not_configged_open(int input, int output, int primary, void *data) +static int not_configged_open(int input, int output, int primary, void *data, + char **dev_out) { printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); @@ -112,7 +113,8 @@ static int open_one_chan(struct chan *chan, int input, int output, int primary) if(chan->opened) return(0); if(chan->ops->open == NULL) fd = 0; - else fd = (*chan->ops->open)(input, output, primary, chan->data); + else fd = (*chan->ops->open)(input, output, primary, chan->data, + &chan->dev); if(fd < 0) return(fd); chan->fd = fd; @@ -258,6 +260,66 @@ void free_chan(struct list_head *chans) } } +static int one_chan_config_string(struct chan *chan, char *str, int size, + char **error_out) +{ + int n = 0; + + CONFIG_CHUNK(str, size, n, chan->ops->type, 0); + + if(chan->dev == NULL){ + CONFIG_CHUNK(str, size, n, "", 1); + return(n); + } + + CONFIG_CHUNK(str, size, n, ":", 0); + CONFIG_CHUNK(str, size, n, chan->dev, 0); + + return(n); +} + +static int chan_pair_config_string(struct chan *in, struct chan *out, + char *str, int size, char **error_out) +{ + int n; + + n = one_chan_config_string(in, str, size, error_out); + str += n; + size -= n; + + if(in == out){ + CONFIG_CHUNK(str, size, n, "", 1); + return(n); + } + + CONFIG_CHUNK(str, size, n, ",", 1); + n = one_chan_config_string(out, str, size, error_out); + str += n; + size -= n; + CONFIG_CHUNK(str, size, n, "", 1); + + return(n); +} + +int chan_config_string(struct list_head *chans, char *str, int size, + char **error_out) +{ + struct list_head *ele; + struct chan *chan, *in = NULL, *out = NULL; + + list_for_each(ele, chans){ + chan = list_entry(ele, struct chan, list); + if(!chan->primary) + continue; + if(chan->input) + in = chan; + if(chan->output) + out = chan; + } + + return(chan_pair_config_string(in, out, str, size, error_out)); +} + struct chan_type { char *key; struct chan_ops *ops; diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 79879f30aef5..e06f20a14877 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -19,6 +19,8 @@ #include "user.h" #include "helper.h" #include "os.h" +#include "choose-mode.h" +#include "mode.h" void generic_close(int fd, void *unused) { @@ -144,32 +146,6 @@ static int winch_thread(void *arg) } } -static int tracer_winch[2]; - -static void tracer_winch_handler(int sig) -{ - char c = 1; - - if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) - printk("tracer_winch_handler - write failed, errno = %d\n", - errno); -} - -/* Called only by the tracing thread during initialization */ - -void setup_tracer_winch(void) -{ - int err; - - err = os_pipe(tracer_winch, 1, 1); - if(err){ - printk("setup_tracer_winch : os_pipe failed, errno = %d\n", - -err); - return; - } - signal(SIGWINCH, tracer_winch_handler); -} - static int winch_tramp(int fd, void *device_data, int *fd_out) { struct winch_data data; @@ -212,9 +188,8 @@ void register_winch(int fd, void *device_data) if(!isatty(fd)) return; pid = tcgetpgrp(fd); - if(pid == tracing_pid) - register_winch_irq(tracer_winch[0], fd, -1, device_data); - else if(pid == -1){ + if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && + (pid == -1)){ thread = winch_tramp(fd, device_data, &thread_fd); if(fd != -1){ register_winch_irq(thread_fd, fd, thread, device_data); diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index e31620d15a77..60fc63adce4a 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -15,6 +15,7 @@ struct fd_chan { int fd; int raw; struct termios tt; + char str[sizeof("1234567890\0")]; }; void *fd_init(char *str, int device, struct chan_opts *opts) @@ -30,7 +31,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts) } str++; n = strtoul(str, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == str)){ printk("fd_init : couldn't parse file descriptor '%s'\n", str); return(NULL); } @@ -40,7 +41,7 @@ void *fd_init(char *str, int device, struct chan_opts *opts) return(data); } -int fd_open(int input, int output, int primary, void *d) +int fd_open(int input, int output, int primary, void *d, char **dev_out) { struct fd_chan *data = d; @@ -48,6 +49,8 @@ int fd_open(int input, int output, int primary, void *d) tcgetattr(data->fd, &data->tt); raw(data->fd, 0); } + sprintf(data->str, "%d", data->fd); + *dev_out = data->str; return(data->fd); } @@ -69,6 +72,7 @@ int fd_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops fd_ops = { + type: "fd", init: fd_init, open: fd_open, close: fd_close, diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 837c07f41669..576f3f655a04 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -8,11 +8,13 @@ #include "linux/list.h" #include "linux/devfs_fs_kernel.h" #include "asm/irq.h" +#include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" #include "line.h" #include "kern.h" #include "user_util.h" +#include "kern_util.h" #include "os.h" #define LINE_BUFSIZE 4096 @@ -87,15 +89,26 @@ static int flush_buffer(struct line *line) return(line->head == line->tail); } -int line_write(struct line *lines, struct tty_struct *tty, const char *buf, - int len) +int line_write(struct line *lines, struct tty_struct *tty, int from_user, + const char *buf, int len) { struct line *line; + char *new; unsigned long flags; int n, err, i; if(tty->stopped) return 0; + if(from_user){ + new = kmalloc(len, GFP_KERNEL); + if(new == NULL) + return(0); + n = copy_from_user(new, buf, len); + if(n == len) + return(-EFAULT); + buf = new; + } + i = minor(tty->device) - tty->driver.minor_start; line = &lines[i]; @@ -281,7 +294,7 @@ void close_lines(struct line *lines, int nlines) close_chan(&lines[i].chan_list); } -void line_setup(struct line *lines, int num, char *init) +int line_setup(struct line *lines, int num, char *init, int all_allowed) { int i, n; char *end; @@ -292,12 +305,36 @@ void line_setup(struct line *lines, int num, char *init) if(*end != '='){ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", init); - return; + return(1); } init = end; } init++; - if(n == -1){ + if((n >= 0) && (n >= num)){ + printk("line_setup - %d out of range ((0 ... %d) allowed)\n", + n, num); + return(1); + } + else if(n >= 0){ + if(lines[n].count > 0){ + printk("line_setup - device %d is open\n", n); + return(1); + } + if(lines[n].init_pri <= INIT_ONE){ + lines[n].init_pri = INIT_ONE; + if(!strcmp(init, "none")) lines[n].valid = 0; + else { + lines[n].init_str = init; + lines[n].valid = 1; + } + } + } + else if(!all_allowed){ + printk("line_setup - can't configure all devices from " + "mconsole\n"); + return(1); + } + else { for(i = 0; i < num; i++){ if(lines[i].init_pri <= INIT_ALL){ lines[i].init_pri = INIT_ALL; @@ -309,14 +346,57 @@ void line_setup(struct line *lines, int num, char *init) } } } - else if(lines[n].init_pri <= INIT_ONE){ - lines[n].init_pri = INIT_ONE; - if(!strcmp(init, "none")) lines[n].valid = 0; - else { - lines[n].init_str = init; - lines[n].valid = 1; - } + return(0); +} + +int line_config(struct line *lines, int num, char *str) +{ + char *new = uml_strdup(str); + + if(new == NULL){ + printk("line_config - uml_strdup failed\n"); + return(-ENOMEM); } + return(line_setup(lines, num, new, 0)); +} + +int line_get_config(char *name, struct line *lines, int num, char *str, + int size, char **error_out) +{ + struct line *line; + char *end; + int dev, n = 0; + + dev = simple_strtoul(name, &end, 0); + if((*end != '\0') || (end == name)){ + *error_out = "line_setup failed to parse device number"; + return(0); + } + + if((dev < 0) || (dev >= num)){ + *error_out = "device number of of range"; + return(0); + } + + line = &lines[dev]; + down(&line->sem); + + if(!line->valid) + CONFIG_CHUNK(str, size, n, "none", 1); + else if(line->count == 0) + CONFIG_CHUNK(str, size, n, line->init_str, 1); + else n = chan_config_string(&line->chan_list, str, size, error_out); + + up(&line->sem); + return(n); +} + +int line_remove(struct line *lines, int num, char *str) +{ + char config[sizeof("conxxxx=none\0")]; + + sprintf(config, "%s=none", str); + return(line_setup(lines, num, config, 0)); } void line_register_devfs(struct lines *set, struct line_driver *line_driver, @@ -366,6 +446,8 @@ void line_register_devfs(struct lines *set, struct line_driver *line_driver, if(!lines[i].valid) tty_unregister_devfs(driver, driver->minor_start + i); } + + mconsole_register_dev(&line_driver->mc); } void lines_init(struct line *lines, int nlines) @@ -451,7 +533,7 @@ static void winch_cleanup(void) list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); close(winch->fd); - if(winch->pid != -1) os_kill_process(winch->pid); + if(winch->pid != -1) os_kill_process(winch->pid, 0); } } diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index 25158ba650c2..a0cbc72b8cd3 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -92,7 +92,7 @@ int mcast_setup(char *str, char **mac_out, void *data) if(port_str != NULL){ n = simple_strtoul(port_str, &last, 10); - if(*last != '\0'){ + if((*last != '\0') || (last == port_str)){ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", port_str); return(0); @@ -102,7 +102,7 @@ int mcast_setup(char *str, char **mac_out, void *data) if(ttl_str != NULL){ init->ttl = simple_strtoul(ttl_str, &last, 10); - if(*last != '\0'){ + if((*last != '\0') || (last == ttl_str)){ printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", ttl_str); return(0); diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 49c1773e0c9b..8ba898759587 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -108,6 +108,7 @@ void mconsole_version(struct mc_request *req) reboot - Reboot UML config <dev>=<config> - Add a new device to UML; same syntax as command line + config <dev> - Query the configuration of a device remove <dev> - Remove a device from UML sysrq <letter> - Performs the SysRq action controlled by the letter cad - invoke the Ctl-Alt-Del handler @@ -181,10 +182,56 @@ static struct mc_device *mconsole_find_dev(char *name) return(NULL); } +#define CONFIG_BUF_SIZE 64 + +static void mconsole_get_config(int (*get_config)(char *, char *, int, + char **), + struct mc_request *req, char *name) +{ + char default_buf[CONFIG_BUF_SIZE], *error, *buf; + int n, size; + + if(get_config == NULL){ + mconsole_reply(req, "No get_config routine defined", 1, 0); + return; + } + + error = NULL; + size = sizeof(default_buf)/sizeof(default_buf[0]); + buf = default_buf; + + while(1){ + n = (*get_config)(name, buf, size, &error); + if(error != NULL){ + mconsole_reply(req, error, 1, 0); + goto out; + } + + if(n <= size){ + mconsole_reply(req, buf, 0, 0); + goto out; + } + + if(buf != default_buf) + kfree(buf); + + size = n; + buf = kmalloc(size, GFP_KERNEL); + if(buf == NULL){ + mconsole_reply(req, "Failed to allocate buffer", 1, 0); + return; + } + } + out: + if(buf != default_buf) + kfree(buf); + +} + void mconsole_config(struct mc_request *req) { struct mc_device *dev; - char *ptr = req->request.data; + char *ptr = req->request.data, *name; int err; ptr += strlen("config"); @@ -194,8 +241,17 @@ void mconsole_config(struct mc_request *req) mconsole_reply(req, "Bad configuration option", 1, 0); return; } - err = (*dev->config)(&ptr[strlen(dev->name)]); - mconsole_reply(req, "", err, 0); + + name = &ptr[strlen(dev->name)]; + ptr = name; + while((*ptr != '=') && (*ptr != '\0')) + ptr++; + + if(*ptr == '='){ + err = (*dev->config)(name); + mconsole_reply(req, "", err, 0); + } + else mconsole_get_config(dev->get_config, req, name); } void mconsole_remove(struct mc_request *req) diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index deef1a0a75e3..f6bda1b3b1fe 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -39,7 +39,6 @@ static int uml_net_rx(struct net_device *dev) /* If we can't allocate memory, try again next round. */ if ((skb = dev_alloc_skb(dev->mtu)) == NULL) { lp->stats.rx_dropped++; - reactivate_fd(lp->fd, UM_ETH_IRQ); return 0; } @@ -48,7 +47,6 @@ static int uml_net_rx(struct net_device *dev) skb->mac.raw = skb->data; pkt_len = (*lp->read)(lp->fd, &skb, lp); - reactivate_fd(lp->fd, UM_ETH_IRQ); if (pkt_len > 0) { skb_trim(skb, pkt_len); skb->protocol = (*lp->protocol)(skb); @@ -69,18 +67,22 @@ void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct uml_net_private *lp = dev->priv; int err; - if (netif_running(dev)) { - spin_lock(&lp->lock); - while((err = uml_net_rx(dev)) > 0) ; - if(err < 0) { - printk(KERN_ERR - "Device '%s' read returned %d, shutting it " - "down\n", dev->name, err); - dev->flags &= ~IFF_UP; - dev_close(dev); - } - spin_unlock(&lp->lock); + if(!netif_running(dev)) + return; + + spin_lock(&lp->lock); + while((err = uml_net_rx(dev)) > 0) ; + if(err < 0) { + printk(KERN_ERR + "Device '%s' read returned %d, shutting it down\n", + dev->name, err); + dev_close(dev); + goto out; } + reactivate_fd(lp->fd, UM_ETH_IRQ); + + out: + spin_unlock(&lp->lock); } static int uml_net_open(struct net_device *dev) @@ -250,6 +252,37 @@ void uml_net_user_timer_expire(unsigned long _conn) #endif } +/* + * default do nothing hard header packet routines for struct net_device init. + * real ethernet transports will overwrite with real routines. + */ +static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + return(0); /* no change */ +} + +static int uml_net_rebuild_header(struct sk_buff *skb) +{ + return(0); /* ignore */ +} + +static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + return(-1); /* fail */ +} + +static void uml_net_header_cache_update(struct hh_cache *hh, + struct net_device *dev, unsigned char * haddr) +{ + /* ignore */ +} + +static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + return(0); /* nothing */ +} + static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static struct list_head devices = LIST_HEAD_INIT(devices); @@ -261,21 +294,25 @@ static int eth_configure(int n, void *init, char *mac, struct uml_net_private *lp; int save, err, size; + size = transport->private_size + sizeof(struct uml_net_private) + + sizeof(((struct uml_net_private *) 0)->user); + device = kmalloc(sizeof(*device), GFP_KERNEL); if(device == NULL){ printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); return(1); } + *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list), + .dev = NULL, + .index = n, + .mac = { [ 0 ... 5 ] = 0 }, + .have_mac = 0 }); + spin_lock(&devices_lock); list_add(&device->list, &devices); spin_unlock(&devices_lock); - device->index = n; - - size = transport->private_size + sizeof(struct uml_net_private) + - sizeof(((struct uml_net_private *) 0)->user); - if(setup_etheraddr(mac, device->mac)) device->have_mac = 1; @@ -290,10 +327,18 @@ static int eth_configure(int n, void *init, char *mac, printk(KERN_ERR "eth_configure: failed to allocate device\n"); return(1); } + memset(dev, 0, sizeof(*dev) + size); + snprintf(dev->name, sizeof(dev->name), "eth%d", n); dev->priv = (void *) &dev[1]; device->dev = dev; + dev->hard_header = uml_net_hard_header; + dev->rebuild_header = uml_net_rebuild_header; + dev->hard_header_cache = uml_net_header_cache; + dev->header_cache_update= uml_net_header_cache_update; + dev->hard_header_parse = uml_net_header_parse; + (*transport->kern->init)(dev, init); dev->mtu = transport->user->max_packet; @@ -308,32 +353,6 @@ static int eth_configure(int n, void *init, char *mac, dev->do_ioctl = uml_net_ioctl; dev->watchdog_timeo = (HZ >> 1); dev->irq = UM_ETH_IRQ; - dev->init = NULL; - dev->master = NULL; - dev->neigh_setup = NULL; - dev->owner = NULL; - dev->state = 0; - dev->next_sched = 0; - dev->get_wireless_stats = 0; - dev->wireless_handlers = 0; - dev->gflags = 0; - dev->mc_list = NULL; - dev->mc_count = 0; - dev->promiscuity = 0; - dev->atalk_ptr = NULL; - dev->ip_ptr = NULL; - dev->dn_ptr = NULL; - dev->ip6_ptr = NULL; - dev->ec_ptr = NULL; - atomic_set(&dev->refcnt, 0); - dev->features = 0; - dev->uninit = NULL; - dev->destructor = NULL; - dev->set_config = NULL; - dev->accept_fastpath = 0; - dev->br_port = 0; - dev->mem_start = 0; - dev->mem_end = 0; rtnl_lock(); err = register_netdevice(dev); @@ -372,6 +391,7 @@ static int eth_configure(int n, void *init, char *mac, if(transport->user->init) (*transport->user->init)(&lp->user, dev); + if(device->have_mac) set_ether_mac(dev, device->mac); return(0); @@ -486,7 +506,6 @@ void register_transport(struct transport *new) kfree(init); } list_del(ð->list); - return; } } @@ -580,7 +599,7 @@ static int net_remove(char *str) int n; n = simple_strtoul(str, &end, 0); - if(*end != '\0') + if((*end != '\0') || (end == str)) return(-1); device = find_device(n); diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 08cc7b0a165e..6a41c213e0d6 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include <stdlib.h> #include <errno.h> #include <fcntl.h> #include "chan_user.h" @@ -15,8 +16,9 @@ void *null_init(char *str, int device, struct chan_opts *opts) return(&null_chan); } -int null_open(int input, int output, int primary, void *d) +int null_open(int input, int output, int primary, void *d, char **dev_out) { + *dev_out = NULL; return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0)); } @@ -30,6 +32,7 @@ void null_free(void *data) } struct chan_ops null_ops = { + type: "null", init: null_init, open: null_open, close: generic_close, diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 25a1c47c116f..15ce4f90ab95 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -32,8 +32,8 @@ struct port_list { struct port_dev { struct port_list *port; int fd; - int helper_pid; - int telnetd_pid; + int helper_pid; + int telnetd_pid; }; struct connection { @@ -50,7 +50,7 @@ static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) struct connection *conn = data; int fd; - fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); + fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); if(fd < 0){ if(fd == -EAGAIN) return; @@ -99,14 +99,13 @@ static int port_accept(struct port_list *port) } list_add(&conn->list, &port->pending); - ret = 1; - goto out; + return(1); out_free: kfree(conn); out_close: os_close_file(fd); - if(pid != -1) os_kill_process(pid); + if(pid != -1) os_kill_process(pid, 0); out: return(ret); } @@ -191,9 +190,9 @@ void *port_data(int port_num) goto out; } - *dev = ((struct port_dev) { port : port, - fd : -1, - helper_pid : -1 }); + *dev = ((struct port_dev) { port : port, + fd : -1, + helper_pid : -1 }); goto out; out_free: @@ -210,9 +209,9 @@ void port_remove_dev(void *d) struct port_dev *dev = d; if(dev->helper_pid != -1) - os_kill_process(dev->helper_pid); + os_kill_process(dev->helper_pid, 0); if(dev->telnetd_pid != -1) - os_kill_process(dev->telnetd_pid); + os_kill_process(dev->telnetd_pid, 0); dev->helper_pid = -1; } @@ -275,8 +274,8 @@ void port_kern_free(void *d) { struct port_dev *dev = d; - if(dev->helper_pid != -1) os_kill_process(dev->telnetd_pid); - if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid); + if(dev->helper_pid != -1) os_kill_process(dev->helper_pid, 0); + if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid, 0); kfree(dev); } diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 35f163da9d32..3e0d3950ac1c 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -3,11 +3,12 @@ * Licensed under the GPL */ +#include <stdio.h> #include <stddef.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include <unistd.h> -#include <string.h> #include <termios.h> #include <sys/socket.h> #include <sys/un.h> @@ -24,6 +25,7 @@ struct port_chan { int raw; struct termios tt; void *kernel_data; + char dev[sizeof("32768\0")]; }; void *port_init(char *str, int device, struct chan_opts *opts) @@ -40,7 +42,7 @@ void *port_init(char *str, int device, struct chan_opts *opts) } str++; port = strtoul(str, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == str)){ printk("port_init : couldn't parse port '%s'\n", str); return(NULL); } @@ -50,11 +52,12 @@ void *port_init(char *str, int device, struct chan_opts *opts) if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); *data = ((struct port_chan) { raw : opts->raw, kernel_data : kern_data }); + sprintf(data->dev, "%d", port); return(data); } -int port_open(int input, int output, int primary, void *d) +int port_open(int input, int output, int primary, void *d, char **dev_out) { struct port_chan *data = d; int fd; @@ -64,6 +67,7 @@ int port_open(int input, int output, int primary, void *d) tcgetattr(fd, &data->tt); raw(fd, 0); } + *dev_out = data->dev; return(fd); } @@ -91,6 +95,7 @@ void port_free(void *d) } struct chan_ops port_ops = { + type: "port", init: port_init, open: port_open, close: port_close, @@ -129,42 +134,6 @@ int port_listen_fd(int port) return(err); } -int port_rcv_fd(int fd) -{ - int new, n; - char buf[CMSG_SPACE(sizeof(new))]; - struct msghdr msg; - struct cmsghdr *cmsg; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = NULL; - msg.msg_iovlen = 0; - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - msg.msg_flags = 0; - - n = recvmsg(fd, &msg, 0); - if(n < 0){ - printk("rcv_fd : recvmsg failed - errno = %d\n", errno); - return(-1); - } - - cmsg = CMSG_FIRSTHDR(&msg); - if(cmsg == NULL){ - printk("rcv_fd didn't receive anything, error = %d\n", errno); - return(-1); - } - if((cmsg->cmsg_level != SOL_SOCKET) || - (cmsg->cmsg_type != SCM_RIGHTS)){ - printk("rcv_fd didn't receive a descriptor\n"); - return(-1); - } - - new = ((int *) CMSG_DATA(cmsg))[0]; - return(new); -} - struct port_pre_exec_data { int sock_fd; int pipe_fd; diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index 6054dd6aa9ac..213b35d1dcfc 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -19,6 +19,7 @@ struct pty_chan { int dev; int raw; struct termios tt; + char dev_name[sizeof("/dev/pts/0123456\0")]; }; void *pty_chan_init(char *str, int device, struct chan_opts *opts) @@ -32,9 +33,10 @@ void *pty_chan_init(char *str, int device, struct chan_opts *opts) return(data); } -int pts_open(int input, int output, int primary, void *d) +int pts_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; + char *dev; int fd; if((fd = get_pty()) < 0){ @@ -45,7 +47,11 @@ int pts_open(int input, int output, int primary, void *d) tcgetattr(fd, &data->tt); raw(fd, 0); } - if(data->announce) (*data->announce)(ptsname(fd), data->dev); + + dev = ptsname(fd); + sprintf(data->dev_name, "%s", dev); + *dev_out = data->dev_name; + if(data->announce) (*data->announce)(dev, data->dev); return(fd); } @@ -94,7 +100,7 @@ static void grantpt_cb(void *arg) info->err = errno; } -int pty_open(int input, int output, int primary, void *d) +int pty_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; int fd; @@ -105,11 +111,14 @@ int pty_open(int input, int output, int primary, void *d) if(fd < 0) return(-errno); info.fd = fd; - tracing_cb(grantpt_cb, &info); + initial_thread_cb(grantpt_cb, &info); unlockpt(fd); if(data->raw) raw(fd, 0); if(data->announce) (*data->announce)(dev, data->dev); + + sprintf(data->dev_name, "%s", dev); + *dev_out = data->dev_name; return(fd); } @@ -121,6 +130,7 @@ int pty_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops pty_ops = { + type: "pty", init: pty_chan_init, open: pty_open, close: generic_close, @@ -133,6 +143,7 @@ struct chan_ops pty_ops = { }; struct chan_ops pts_ops = { + type: "pts", init: pty_chan_init, open: pts_open, close: generic_close, diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h index 6fe5588e8a21..495f2f1b1420 100644 --- a/arch/um/drivers/slip.h +++ b/arch/um/drivers/slip.h @@ -2,6 +2,9 @@ #define __UM_SLIP_H #define BUF_SIZE 1500 + /* two bytes each for a (pathological) max packet of escaped chars + * + * terminating END char + initial END char */ +#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) struct slip_data { void *dev; @@ -9,10 +12,9 @@ struct slip_data { char *addr; char *gate_addr; int slave; - /* two bytes each for a (pathological) max packet of escaped chars + - * terminating END char + inital END char - */ - char buf[2 * BUF_SIZE + 2]; + char ibuf[ENC_BUF_SIZE]; + char obuf[ENC_BUF_SIZE]; + int more; /* more data: do not read fd until ibuf has been drained */ int pos; int esc; }; diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index 1ca56f563757..f498a83d9db5 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -1,3 +1,4 @@ +#include "linux/config.h" #include "linux/kernel.h" #include "linux/stddef.h" #include "linux/init.h" @@ -24,21 +25,19 @@ void slip_init(struct net_device *dev, void *data) { name : { '\0' }, addr: NULL, gate_addr : init->gate_addr, - slave : 0, - buf : { '\0' }, + slave : -1, + ibuf : { '\0' }, + obuf : { '\0' }, pos : 0, esc : 0, dev : dev }); - strncpy(dev->name, "umn", IFNAMSIZ); dev->init = NULL; dev->hard_header_len = 0; dev->addr_len = 4; dev->type = ARPHRD_ETHER; dev->tx_queue_len = 256; dev->flags = IFF_NOARP; - if(register_netdev(dev)) - printk(KERN_ERR "Couldn't initialize umn\n"); printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr); } diff --git a/arch/um/drivers/slip_proto.h b/arch/um/drivers/slip_proto.h new file mode 100644 index 000000000000..7206361ace45 --- /dev/null +++ b/arch/um/drivers/slip_proto.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __UM_SLIP_PROTO_H__ +#define __UM_SLIP_PROTO_H__ + +/* SLIP protocol characters. */ +#define SLIP_END 0300 /* indicates end of frame */ +#define SLIP_ESC 0333 /* indicates byte stuffing */ +#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc) +{ + int ret; + + switch(c){ + case SLIP_END: + *esc = 0; + ret=*pos; + *pos=0; + return(ret); + case SLIP_ESC: + *esc = 1; + return(0); + case SLIP_ESC_ESC: + if(*esc){ + *esc = 0; + c = SLIP_ESC; + } + break; + case SLIP_ESC_END: + if(*esc){ + *esc = 0; + c = SLIP_END; + } + break; + } + buf[(*pos)++] = c; + return(0); +} + +static inline int slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = SLIP_END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch(c = *s++) { + case SLIP_END: + *ptr++ = SLIP_ESC; + *ptr++ = SLIP_ESC_END; + break; + case SLIP_ESC: + *ptr++ = SLIP_ESC; + *ptr++ = SLIP_ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = SLIP_END; + return (ptr - d); +} + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index d8cd43c2f555..e36e8213671b 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -15,6 +15,7 @@ #include "user.h" #include "net_user.h" #include "slip.h" +#include "slip_proto.h" #include "helper.h" #include "os.h" @@ -66,7 +67,7 @@ static void slip_pre_exec(void *arg) if(data->stdin != -1) dup2(data->stdin, 0); dup2(data->stdout, 1); - close(data->close_me); + if(data->close_me != -1) close(data->close_me); } static int slip_tramp(char **argv, int fd) @@ -156,7 +157,7 @@ static int slip_open(void *data) } sencap = 0; if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){ - printk("Failed to sett slip encapsulation - " + printk("Failed to set slip encapsulation - " "errno = %d\n", errno); return(-errno); } @@ -186,103 +187,48 @@ static void slip_close(int fd, void *data) pri->slave = -1; } -/* SLIP protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - -static int slip_unesc(struct slip_data *sl, unsigned char c) -{ - int ret; - - switch(c){ - case END: - sl->esc = 0; - ret = sl->pos; - sl->pos = 0; - return(ret); - case ESC: - sl->esc = 1; - return(0); - case ESC_ESC: - if(sl->esc){ - sl->esc = 0; - c = ESC; - } - break; - case ESC_END: - if(sl->esc){ - sl->esc = 0; - c = END; - } - break; - } - sl->buf[sl->pos++] = c; - return(0); -} - int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) { int i, n, size, start; - n = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos); + if(pri->more>0) { + i = 0; + while(i < pri->more) { + size = slip_unesc(pri->ibuf[i++], + pri->ibuf, &pri->pos, &pri->esc); + if(size){ + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); + pri->more=pri->more-i; + return(size); + } + } + pri->more=0; + } + + n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); if(n <= 0) return(n); start = pri->pos; for(i = 0; i < n; i++){ - size = slip_unesc(pri, pri->buf[start + i]); + size = slip_unesc(pri->ibuf[start + i], + pri->ibuf, &pri->pos, &pri->esc); if(size){ - memcpy(buf, pri->buf, size); + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); + pri->more=n-(i+1); return(size); } } return(0); } -static int slip_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - *ptr++ = END; - - /* - * For each byte in the packet, send the appropriate - * character sequence, according to the SLIP protocol. - */ - - while (len-- > 0) { - switch(c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } - *ptr++ = END; - return (ptr - d); -} - int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) { int actual, n; - actual = slip_esc(buf, pri->buf, len); - n = net_write(fd, pri->buf, actual); + actual = slip_esc(buf, pri->obuf, len); + n = net_write(fd, pri->obuf, actual); if(n < 0) return(n); else return(len); } diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h new file mode 100644 index 000000000000..04e407d1e44a --- /dev/null +++ b/arch/um/drivers/slirp.h @@ -0,0 +1,51 @@ +#ifndef __UM_SLIRP_H +#define __UM_SLIRP_H + +#define BUF_SIZE 1500 + /* two bytes each for a (pathological) max packet of escaped chars + * + * terminating END char + initial END char */ +#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) + +#define SLIRP_MAX_ARGS 100 +/* + * XXX this next definition is here because I don't understand why this + * initializer doesn't work in slirp_kern.c: + * + * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] }, + * + * or why I can't typecast like this: + * + * argv : (char* [SLIRP_MAX_ARGS])(init->argv), + */ +struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; }; + +struct slirp_data { + void *dev; + struct arg_list_dummy_wrapper argw; + int pid; + int slave; + char ibuf[ENC_BUF_SIZE]; + char obuf[ENC_BUF_SIZE]; + int more; /* more data: do not read fd until ibuf has been drained */ + int pos; + int esc; +}; + +extern struct net_user_info slirp_user_info; + +extern int set_umn_addr(int fd, char *addr, char *ptp_addr); +extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri); +extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri); + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c new file mode 100644 index 000000000000..1a459dd94d76 --- /dev/null +++ b/arch/um/drivers/slirp_kern.c @@ -0,0 +1,132 @@ +#include "linux/kernel.h" +#include "linux/stddef.h" +#include "linux/init.h" +#include "linux/netdevice.h" +#include "linux/if_arp.h" +#include "net_kern.h" +#include "net_user.h" +#include "kern.h" +#include "slirp.h" + +struct slirp_init { + struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */ +}; + +void slirp_init(struct net_device *dev, void *data) +{ + struct uml_net_private *private; + struct slirp_data *spri; + struct slirp_init *init = data; + int i; + + private = dev->priv; + spri = (struct slirp_data *) private->user; + *spri = ((struct slirp_data) + { argw : init->argw, + pid : -1, + slave : -1, + ibuf : { '\0' }, + obuf : { '\0' }, + pos : 0, + esc : 0, + dev : dev }); + + dev->init = NULL; + dev->hard_header_len = 0; + dev->addr_len = 4; + dev->type = ARPHRD_ETHER; + dev->tx_queue_len = 256; + dev->flags = IFF_NOARP; + printk("SLIRP backend - command line:"); + for(i=0;spri->argw.argv[i]!=NULL;i++) { + printk(" '%s'",spri->argw.argv[i]); + } + printk("\n"); +} + +static unsigned short slirp_protocol(struct sk_buff *skbuff) +{ + return(htons(ETH_P_IP)); +} + +static int slirp_read(int fd, struct sk_buff **skb, + struct uml_net_private *lp) +{ + return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, + (struct slirp_data *) &lp->user)); +} + +static int slirp_write(int fd, struct sk_buff **skb, + struct uml_net_private *lp) +{ + return(slirp_user_write(fd, (*skb)->data, (*skb)->len, + (struct slirp_data *) &lp->user)); +} + +struct net_kern_info slirp_kern_info = { + init: slirp_init, + protocol: slirp_protocol, + read: slirp_read, + write: slirp_write, +}; + +static int slirp_setup(char *str, char **mac_out, void *data) +{ + struct slirp_init *init = data; + int i=0; + + *init = ((struct slirp_init) + { argw : { { "slirp", NULL } } }); + + str = split_if_spec(str, mac_out, NULL); + + if(str == NULL) { /* no command line given after MAC addr */ + return(1); + } + + do { + if(i>=SLIRP_MAX_ARGS-1) { + printk("slirp_setup: truncating slirp arguments\n"); + break; + } + init->argw.argv[i++] = str; + while(*str && *str!=',') { + if(*str=='_') *str=' '; + str++; + } + if(*str!=',') + break; + *str++='\0'; + } while(1); + init->argw.argv[i]=NULL; + return(1); +} + +static struct transport slirp_transport = { + list : LIST_HEAD_INIT(slirp_transport.list), + name : "slirp", + setup : slirp_setup, + user : &slirp_user_info, + kern : &slirp_kern_info, + private_size : sizeof(struct slirp_data), + setup_size : sizeof(struct slirp_init), +}; + +static int register_slirp(void) +{ + register_transport(&slirp_transport); + return(1); +} + +__initcall(register_slirp); + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c new file mode 100644 index 000000000000..bba76df0f33d --- /dev/null +++ b/arch/um/drivers/slirp_user.c @@ -0,0 +1,202 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sched.h> +#include <string.h> +#include <sys/fcntl.h> +#include <sys/errno.h> +#include <sys/wait.h> +#include <sys/signal.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "net_user.h" +#include "slirp.h" +#include "slip_proto.h" +#include "helper.h" +#include "os.h" + +void slirp_user_init(void *data, void *dev) +{ + struct slirp_data *pri = data; + + pri->dev = dev; +} + +struct slirp_pre_exec_data { + int stdin; + int stdout; +}; + +static void slirp_pre_exec(void *arg) +{ + struct slirp_pre_exec_data *data = arg; + + if(data->stdin != -1) dup2(data->stdin, 0); + if(data->stdout != -1) dup2(data->stdout, 1); +} + +static int slirp_tramp(char **argv, int fd) +{ + struct slirp_pre_exec_data pe_data; + int pid; + + pe_data.stdin = fd; + pe_data.stdout = fd; + pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL); + + return(pid); +} + +static int slirp_datachan(int *mfd, int *sfd) +{ + int fds[2], err; + + err = os_pipe(fds, 1, 1); + if(err){ + printk("slirp_datachan: Failed to open pipe, errno = %d\n", + -err); + return(err); + } + + *mfd = fds[0]; + *sfd = fds[1]; + return(0); +} + +static int slirp_open(void *data) +{ + struct slirp_data *pri = data; + int sfd, mfd, pid, err; + + err = slirp_datachan(&mfd, &sfd); + if(err) + return(err); + + pid = slirp_tramp(pri->argw.argv, sfd); + + if(pid < 0){ + printk("slirp_tramp failed - errno = %d\n", pid); + os_close_file(sfd); + os_close_file(mfd); + return(pid); + } + + pri->slave = sfd; + pri->pos = 0; + pri->esc = 0; + + pri->pid = pid; + + return(mfd); +} + +static void slirp_close(int fd, void *data) +{ + struct slirp_data *pri = data; + int status,err; + + close(fd); + close(pri->slave); + + pri->slave = -1; + + if(pri->pid<1) { + printk("slirp_close: no child process to shut down\n"); + return; + } + +#if 0 + if(kill(pri->pid, SIGHUP)<0) { + printk("slirp_close: sending hangup to %d failed (%d)\n", + pri->pid, errno); + } +#endif + + err = waitpid(pri->pid, &status, WNOHANG); + if(err<0) { + printk("slirp_close: waitpid returned %d\n", errno); + return; + } + + if(err==0) { + printk("slirp_close: process %d has not exited\n"); + return; + } + + pri->pid = -1; +} + +int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri) +{ + int i, n, size, start; + + if(pri->more>0) { + i = 0; + while(i < pri->more) { + size = slip_unesc(pri->ibuf[i++], + pri->ibuf,&pri->pos,&pri->esc); + if(size){ + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); + pri->more=pri->more-i; + return(size); + } + } + pri->more=0; + } + + n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); + if(n <= 0) return(n); + + start = pri->pos; + for(i = 0; i < n; i++){ + size = slip_unesc(pri->ibuf[start + i], + pri->ibuf,&pri->pos,&pri->esc); + if(size){ + memcpy(buf, pri->ibuf, size); + memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); + pri->more=n-(i+1); + return(size); + } + } + return(0); +} + +int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri) +{ + int actual, n; + + actual = slip_esc(buf, pri->obuf, len); + n = net_write(fd, pri->obuf, actual); + if(n < 0) return(n); + else return(len); +} + +static int slirp_set_mtu(int mtu, void *data) +{ + return(mtu); +} + +struct net_user_info slirp_user_info = { + init: slirp_user_init, + open: slirp_open, + close: slirp_close, + remove: NULL, + set_mtu: slirp_set_mtu, + add_address: NULL, + delete_address: NULL, + max_packet: BUF_SIZE +}; + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index c0cd826d9d8b..4f0b772a4f88 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -20,6 +20,7 @@ #include "kern.h" #include "init.h" #include "irq_user.h" +#include "mconsole_kern.h" #include "2_5compat.h" static int ssl_version = 1; @@ -47,6 +48,10 @@ static struct chan_opts opts = { in_kernel : 1, }; +static int ssl_config(char *str); +static int ssl_get_config(char *dev, char *str, int size, char **error_out); +static int ssl_remove(char *str); + static struct line_driver driver = { name : "UML serial line", devfs_name : "tts/%d", @@ -60,6 +65,12 @@ static struct line_driver driver = { write_irq_name : "ssl-write", symlink_from : "serial", symlink_to : "tts", + mc : { + name : "ssl", + config : ssl_config, + get_config : ssl_get_config, + remove : ssl_remove, + }, }; /* The array is initialized by line_init, which is an initcall. The @@ -70,6 +81,25 @@ static struct line serial_lines[NR_PORTS] = static struct lines lines = LINES_INIT(NR_PORTS); +static int ssl_config(char *str) +{ + return(line_config(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), str)); +} + +static int ssl_get_config(char *dev, char *str, int size, char **error_out) +{ + return(line_get_config(dev, serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), + str, size, error_out)); +} + +static int ssl_remove(char *str) +{ + return(line_remove(serial_lines, + sizeof(serial_lines)/sizeof(serial_lines[0]), str)); +} + int ssl_open(struct tty_struct *tty, struct file *filp) { return(line_open(serial_lines, tty, &opts)); @@ -83,12 +113,12 @@ static void ssl_close(struct tty_struct *tty, struct file * filp) static int ssl_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - return(line_write(serial_lines, tty, buf, count)); + return(line_write(serial_lines, tty, from_user, buf, count)); } static void ssl_put_char(struct tty_struct *tty, unsigned char ch) { - line_write(serial_lines, tty, &ch, sizeof(ch)); + line_write(serial_lines, tty, 0, &ch, sizeof(ch)); } static void ssl_flush_chars(struct tty_struct *tty) @@ -207,7 +237,7 @@ __initcall(ssl_init); static int ssl_chan_setup(char *str) { line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]), - str); + str, 1); return(1); } diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 4803c3e071b0..3844a7188508 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -27,6 +27,7 @@ #include "user_util.h" #include "kern_util.h" #include "irq_user.h" +#include "mconsole_kern.h" #include "init.h" #include "2_5compat.h" @@ -41,6 +42,7 @@ static struct tty_driver console_driver; static int console_refcount = 0; static struct chan_ops init_console_ops = { + type: "you shouldn't see this", init : NULL, open : NULL, close : NULL, @@ -78,6 +80,10 @@ static struct chan_opts opts = { in_kernel : 1, }; +static int con_config(char *str); +static int con_get_config(char *dev, char *str, int size, char **error_out); +static int con_remove(char *str); + static struct line_driver driver = { name : "UML console", devfs_name : "vc/%d", @@ -91,6 +97,12 @@ static struct line_driver driver = { write_irq_name : "console-write", symlink_from : "ttys", symlink_to : "vc", + mc : { + name : "con", + config : con_config, + get_config : con_get_config, + remove : con_remove, + }, }; static struct lines console_lines = LINES_INIT(MAX_TTYS); @@ -102,6 +114,22 @@ struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), [ 1 ... MAX_TTYS - 1 ] = LINE_INIT(CONFIG_CON_CHAN, &driver) }; +static int con_config(char *str) +{ + return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str)); +} + +static int con_get_config(char *dev, char *str, int size, char **error_out) +{ + return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str, + size, error_out)); +} + +static int con_remove(char *str) +{ + return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str)); +} + static int open_console(struct tty_struct *tty) { return(line_open(vts, tty, &opts)); @@ -120,7 +148,7 @@ static void con_close(struct tty_struct *tty, struct file *filp) static int con_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - return(line_write(vts, tty, buf, count)); + return(line_write(vts, tty, from_user, buf, count)); } static void set_termios(struct tty_struct *tty, struct termios * old) @@ -195,7 +223,7 @@ void stdio_console_init(void) static int console_chan_setup(char *str) { - line_setup(vts, sizeof(vts)/sizeof(vts[0]), str); + line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1); return(1); } diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index 75b4b93102b0..438e72268ef6 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -30,14 +30,15 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts) } str++; - if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL); + if((data = um_kmalloc(sizeof(*data))) == NULL) + return(NULL); *data = ((struct tty_chan) { dev : str, raw : opts->raw }); return(data); } -int tty_open(int input, int output, int primary, void *d) +int tty_open(int input, int output, int primary, void *d, char **dev_out) { struct tty_chan *data = d; int fd; @@ -48,6 +49,8 @@ int tty_open(int input, int output, int primary, void *d) tcgetattr(fd, &data->tt); raw(fd, 0); } + + *dev_out = data->dev; return(fd); } @@ -59,6 +62,7 @@ int tty_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops tty_ops = { + type: "tty", init: tty_chan_init, open: tty_open, close: generic_close, diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 93228f048940..2d9dfba302e8 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -218,7 +218,7 @@ static int ubd_setup_common(char *str, int *index_out) return(0); } major = simple_strtoul(str, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == str)){ printk(KERN_ERR "ubd_setup : didn't parse major number\n"); return(1); @@ -520,7 +520,10 @@ static int ubd_add(int n) struct ubd *dev = &ubd_dev[n]; int err; - if (!dev->file || dev->is_dir) + if(dev->is_dir) + return(-EISDIR); + + if (!dev->file) return(-ENODEV); if (ubd_open_dev(dev)) @@ -574,6 +577,44 @@ static int ubd_config(char *str) return(err); } +static int ubd_get_config(char *dev, char *str, int size, char **error_out) +{ + struct ubd *ubd; + char *end; + int major, n = 0; + + major = simple_strtoul(dev, &end, 0); + if((*end != '\0') || (end == dev)){ + *error_out = "ubd_get_config : didn't parse major number"; + return(-1); + } + + if((major >= MAX_DEV) || (major < 0)){ + *error_out = "ubd_get_config : major number out of range"; + return(-1); + } + + ubd = &ubd_dev[major]; + spin_lock(&ubd_lock); + + if(ubd->file == NULL){ + CONFIG_CHUNK(str, size, n, "", 1); + goto out; + } + + CONFIG_CHUNK(str, size, n, ubd->file, 0); + + if(ubd->cow.file != NULL){ + CONFIG_CHUNK(str, size, n, ",", 0); + CONFIG_CHUNK(str, size, n, ubd->cow.file, 1); + } + else CONFIG_CHUNK(str, size, n, "", 1); + + out: + spin_unlock(&ubd_lock); + return(n); +} + static int ubd_remove(char *str) { struct ubd *dev; @@ -583,7 +624,7 @@ static int ubd_remove(char *str) return(err); /* it should be a number 0-7/a-h */ n = *str - '0'; - if(n > MAX_DEV) + if(n >= MAX_DEV) return(err); dev = &ubd_dev[n]; @@ -620,6 +661,7 @@ static int ubd_remove(char *str) static struct mc_device ubd_mc = { .name = "ubd", .config = ubd_config, + .get_config = ubd_get_config, .remove = ubd_remove, }; diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index 8a4b6f52888c..93b6f3e90c22 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -473,6 +473,8 @@ void do_io(struct io_thread_req *req) &req->sector_mask) == bit)) end++; + if(end != nsectors) + printk("end != nsectors\n"); off = req->offset + req->offsets[bit] + start * req->sectorsize; len = (end - start) * req->sectorsize; diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index e7b4ab83c8f7..7e351c8012ad 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -83,7 +83,7 @@ __uml_setup("xterm=", xterm_setup, " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); -int xterm_open(int input, int output, int primary, void *d) +int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; unsigned long stack; @@ -93,6 +93,9 @@ int xterm_open(int input, int output, int primary, void *d) "/usr/lib/uml/port-helper", "-uml-socket", file, NULL }; + if(access(argv[4], X_OK)) + argv[4] = "port-helper"; + fd = mkstemp(file); if(fd < 0){ printk("xterm_open : mkstemp failed, errno = %d\n", errno); @@ -141,6 +144,7 @@ int xterm_open(int input, int output, int primary, void *d) if(data->raw) raw(new, 0); data->pid = pid; + *dev_out = NULL; return(new); } @@ -168,6 +172,7 @@ int xterm_console_write(int fd, const char *buf, int n, void *d) } struct chan_ops xterm_ops = { + type: "xterm", init: xterm_init, open: xterm_open, close: xterm_close, diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c index 28b2835bcb7c..c2308894a81e 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -22,11 +22,13 @@ struct xterm_wait { static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) { struct xterm_wait *xterm = data; + int fd; - xterm->new_fd = os_rcv_fd(xterm->fd, &xterm->pid); - if(xterm->new_fd == -EAGAIN) + fd = os_rcv_fd(xterm->fd, &xterm->pid); + if(fd == -EAGAIN) return; + xterm->new_fd = fd; up(&xterm->sem); } diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 8c2bb85c9edf..d2cd02a03c61 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h @@ -12,6 +12,7 @@ struct chan { struct list_head list; + char *dev; unsigned int primary:1; unsigned int input:1; unsigned int output:1; @@ -38,6 +39,8 @@ extern int chan_window_size(struct list_head *chans, unsigned short *rows_out, unsigned short *cols_out); extern int chan_out_fd(struct list_head *chans); +extern int chan_config_string(struct list_head *chans, char *str, int size, + char **error_out); #endif diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index 639ca8d6121a..9414c1a44c6d 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -19,8 +19,9 @@ struct chan_opts { enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; struct chan_ops { + char *type; void *(*init)(char *, int, struct chan_opts *); - int (*open)(int, int, int, void *); + int (*open)(int, int, int, void *, char **); void (*close)(int, void *); int (*read)(int, char *, void *); int (*write)(int, const char *, int, void *); @@ -43,7 +44,6 @@ extern void generic_free(void *data); extern void register_winch(int fd, void *device_data); extern void register_winch_irq(int fd, int tty_fd, int pid, void *line); -extern void setup_tracer_winch(void); #define __channel_help(fn, prefix) \ __uml_help(fn, prefix "[0-9]*=<channel description>\n" \ diff --git a/arch/um/include/choose-mode.h b/arch/um/include/choose-mode.h new file mode 100644 index 000000000000..55548984bd85 --- /dev/null +++ b/arch/um/include/choose-mode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __CHOOSE_MODE_H__ +#define __CHOOSE_MODE_H__ + +#include "uml-config.h" + +#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) +#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas)) + +#elif defined(CONFIG_MODE_SKAS) +#define CHOOSE_MODE(tt, skas) (skas) + +#elif defined(CONFIG_MODE_TT) +#define CHOOSE_MODE(tt, skas) (tt) +#endif + +#define CHOOSE_MODE_PROC(tt, skas, args...) \ + CHOOSE_MODE(tt(args), skas(args)) + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/frame.h b/arch/um/include/frame.h index 9df95a5f00a1..b4e12946f54f 100644 --- a/arch/um/include/frame.h +++ b/arch/um/include/frame.h @@ -8,34 +8,34 @@ #include "sysdep/frame.h" -struct sc_frame { +struct frame_common { void *data; int len; int sig_index; - int sc_index; int sr_index; int sr_relative; int sp_index; +}; + +struct sc_frame { + struct frame_common common; + int sc_index; struct arch_frame_data arch; }; extern struct sc_frame signal_frame_sc; +extern struct sc_frame signal_frame_sc_sr; + struct si_frame { - void *data; - int len; - int sig_index; + struct frame_common common; int sip_index; int si_index; - int sr_index; - int sr_relative; - int sp_index; }; extern struct si_frame signal_frame_si; extern void capture_signal_stack(void); -extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp); #endif diff --git a/arch/um/include/kern.h b/arch/um/include/kern.h index 09eae635a15e..3e3aed19f54c 100644 --- a/arch/um/include/kern.h +++ b/arch/um/include/kern.h @@ -25,7 +25,6 @@ extern void *sbrk(int increment); extern void *malloc(int size); extern void perror(char *err); extern int kill(int pid, int sig); -extern int getpid(void); extern int getuid(void); extern int pause(void); extern int write(int, const void *, int); @@ -34,6 +33,7 @@ extern int close(int); extern int read(unsigned int, char *, int); extern int pipe(int *); extern int sched_yield(void); +extern int ptrace(int op, int pid, long addr, long data); #endif /* diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 076b94d75765..8bef1a8a6153 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -15,23 +15,26 @@ extern char *gdb_init; extern int kmalloc_ok; extern int timer_irq_inited; extern int jail; +extern int nsyscalls; + extern struct task_struct *idle_threads[NR_CPUS]; -#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) -#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) +#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) +#define UML_ROUND_UP(addr) \ + UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); extern unsigned long stack_sp(unsigned long page); extern int kernel_thread_proc(void *data); extern void syscall_segv(int sig); extern int current_pid(void); -extern void set_init_pid(int pid); extern unsigned long alloc_stack(int order, int atomic); extern int do_signal(int error); extern int is_stack_fault(unsigned long sp); extern unsigned long segv(unsigned long address, unsigned long ip, - int is_write, int is_user, void *sc_ptr); -extern int set_user_mode(void *task); + int is_write, int is_user, void *sc); +extern int handle_page_fault(unsigned long address, unsigned long ip, + int is_write, int is_user, int *code_out); extern void syscall_ready(void); extern void set_tracing(void *t, int tracing); extern int is_tracing(void *task); @@ -40,7 +43,6 @@ extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); extern int page_size(void); extern int page_mask(void); extern int need_finish_fork(void); -extern int do_proc_op(void *t, int proc_id); extern void free_stack(unsigned long stack, int order); extern void add_input_request(int op, void (*proc)(int), void *arg); extern int sys_execve(char *file, char **argv, char **env); @@ -57,7 +59,6 @@ extern int next_trap_index(int max); extern void default_idle(void); extern void finish_fork(void); extern void paging_init(void); -extern unsigned long um_virt_to_phys(void *t, unsigned long addr); extern void init_flush_vm(void); extern void *syscall_sp(void *t); extern void syscall_trace(void); @@ -68,35 +69,28 @@ extern int external_pid(void *t); extern int pid_to_processor_id(int pid); extern void boot_timer_handler(int sig); extern void interrupt_end(void); -extern void tracing_reboot(void); -extern void tracing_halt(void); -extern void tracing_cb(void (*proc)(void *), void *arg); +extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int debugger_signal(int status, int pid); extern void debugger_parent_signal(int status, int pid); extern void child_signal(int pid, int status); extern int init_ptrace_proxy(int idle_pid, int startup, int stop); extern int init_parent_proxy(int pid); +extern int singlestepping(void *t); extern void check_stack_overflow(void *ptr); extern void relay_signal(int sig, struct uml_pt_regs *regs); -extern int singlestepping(void *t); -extern void clear_singlestep(void *t); extern void not_implemented(void); extern int user_context(unsigned long sp); extern void timer_irq(struct uml_pt_regs *regs); extern void unprotect_stack(unsigned long stack); extern void do_uml_exitcalls(void); extern int attach_debugger(int idle_pid, int pid, int stop); -extern void *round_up(unsigned long addr); -extern void *round_down(unsigned long addr); extern void bad_segv(unsigned long address, unsigned long ip, int is_write); extern int config_gdb(char *str); extern int remove_gdb(void); extern char *uml_strdup(char *string); extern void unprotect_kernel_mem(void); extern void protect_kernel_mem(void); -extern unsigned long get_kmem_end(void); extern void set_kmem_end(unsigned long); -extern void set_task_sizes(int arg); extern void uml_cleanup(void); extern int pid_to_processor_id(int pid); extern void set_current(void *t); @@ -107,7 +101,6 @@ extern void *get_init_task(void); extern int clear_user_proc(void *buf, int size); extern int copy_to_user_proc(void *to, void *from, int size); extern int copy_from_user_proc(void *to, void *from, int size); -extern void set_thread_sc(void *sc); extern void bus_handler(int sig, struct uml_pt_regs *regs); extern long execute_syscall(void *r); extern int smp_sigio_handler(void); @@ -116,7 +109,6 @@ extern struct task_struct *get_task(int pid, int require); extern void machine_halt(void); extern int is_syscall(unsigned long addr); extern void arch_switch(void); -extern int is_valid_pid(int pid); extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); extern int cpu(void); diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 4d45c270a80e..8bad9c56c66e 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -11,6 +11,7 @@ #include "linux/tty.h" #include "asm/semaphore.h" #include "chan_user.h" +#include "mconsole_kern.h" struct line_driver { char *name; @@ -25,6 +26,7 @@ struct line_driver { char *write_irq_name; char *symlink_from; char *symlink_to; + struct mc_device mc; }; struct line { @@ -70,8 +72,9 @@ extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_close(struct line *lines, struct tty_struct *tty); extern int line_open(struct line *lines, struct tty_struct *tty, struct chan_opts *opts); -extern void line_setup(struct line *lines, int num, char *init); -extern int line_write(struct line *line, struct tty_struct *tty, +extern int line_setup(struct line *lines, int num, char *init, + int all_allowed); +extern int line_write(struct line *line, struct tty_struct *tty, int from_user, const char *buf, int len); extern int line_write_room(struct tty_struct *tty); extern char *add_xterm_umid(char *base); @@ -84,6 +87,10 @@ extern void line_register_devfs(struct lines *set, int nlines); extern void lines_init(struct line *lines, int nlines); extern void close_lines(struct line *lines, int nlines); +extern int line_config(struct line *lines, int num, char *str); +extern int line_remove(struct line *lines, int num, char *str); +extern int line_get_config(char *dev, struct line *lines, int num, char *str, + int size, char **error_out); #endif diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h index 03c6d1734a28..61c274fcee5d 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/include/mconsole_kern.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -19,9 +19,23 @@ struct mc_device { struct list_head list; char *name; int (*config)(char *); + int (*get_config)(char *, char *, int, char **); int (*remove)(char *); }; +#define CONFIG_CHUNK(str, size, current, chunk, end) \ +do { \ + current += strlen(chunk); \ + if(current >= size) \ + str = NULL; \ + if(str != NULL){ \ + strcpy(str, chunk); \ + str += strlen(chunk); \ + } \ + if(end) \ + current++; \ +} while(0) + #ifdef CONFIG_MCONSOLE extern void mconsole_register_dev(struct mc_device *new); diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h index e7835b541196..bad6b30b8f7d 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/mem.h @@ -13,6 +13,7 @@ struct vm_reserved { }; extern void set_usable_vm(unsigned long start, unsigned long end); +extern void set_kmem_end(unsigned long new); #endif diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index 4a3e68d56a5a..d80ac354bf28 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -54,11 +54,6 @@ extern int create_mem_file(unsigned long len); extern void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn, unsigned long total, int need_vm, struct mem_region *region, void *reserved); -extern void map(unsigned long virt, unsigned long p, unsigned long len, - int r, int w, int x); -extern int unmap(void *addr, int len); -extern int protect(unsigned long addr, unsigned long len, int r, int w, - int x, int must_succeed); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); extern int init_maps(struct mem_region *region); @@ -68,10 +63,15 @@ extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, unsigned long len); extern int setup_region(struct mem_region *region, void *entry); -extern void add_iomem(char *name, int fd, int size); +extern void add_iomem(char *name, int fd, unsigned long size); extern struct mem_region *phys_region(unsigned long phys); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); +extern int map_memory(unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); +extern int protect_memory(unsigned long addr, unsigned long len, + int r, int w, int x, int must_succeed); +extern unsigned long get_kmem_end(void); #endif diff --git a/arch/um/include/mode.h b/arch/um/include/mode.h new file mode 100644 index 000000000000..ba7f6ff04121 --- /dev/null +++ b/arch/um/include/mode.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_H__ +#define __MODE_H__ + +#include "uml-config.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/mode.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/mode.h" +#endif + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h new file mode 100644 index 000000000000..562174bf48a0 --- /dev/null +++ b/arch/um/include/mode_kern.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_KERN_H__ +#define __MODE_KERN_H__ + +#include "linux/config.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/mode_kern.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/mode_kern.h" +#endif + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h index 22d43acb78f1..de793e9bf438 100644 --- a/arch/um/include/net_kern.h +++ b/arch/um/include/net_kern.h @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __UM_NET_KERN_H #define __UM_NET_KERN_H diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h index 01867cae92e2..36807b796e9f 100644 --- a/arch/um/include/net_user.h +++ b/arch/um/include/net_user.h @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __UM_NET_USER_H__ #define __UM_NET_USER_H__ diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 1c1e3a8b5eb6..524a60875d7b 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -103,10 +103,16 @@ extern int os_write_file(int fd, char *buf, int count); extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); extern void os_stop_process(int pid); -extern void os_kill_process(int pid); +extern void os_kill_process(int pid, int reap_child); extern void os_usr1_process(int pid); extern int os_getpid(void); +extern int os_map_memory(void *virt, int fd, unsigned long off, + unsigned long len, int r, int w, int x); +extern int os_protect_memory(void *addr, unsigned long len, + int r, int w, int x); +extern int os_unmap_memory(void *addr, int len); + #endif /* diff --git a/arch/um/include/sigcontext.h b/arch/um/include/sigcontext.h index 1d2b195bc5f8..59816ca7a8df 100644 --- a/arch/um/include/sigcontext.h +++ b/arch/um/include/sigcontext.h @@ -9,8 +9,6 @@ #include "sysdep/sigcontext.h" extern int sc_size(void *data); -extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data); -extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data); extern void sc_to_sc(void *to_ptr, void *from_ptr); #endif diff --git a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h index e430752cb7ec..bc7be6293702 100644 --- a/arch/um/include/syscall_user.h +++ b/arch/um/include/syscall_user.h @@ -1,16 +1,13 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#ifndef __SYSCALL_USER_H__ -#define __SYSCALL_USER_H__ +#ifndef __SYSCALL_USER_H +#define __SYSCALL_USER_H -#include <asm/sigcontext.h> - -extern void syscall_handler(int sig, struct uml_pt_regs *regs); -extern void exit_kernel(int pid, void *task); -extern int do_syscall(void *task, int pid); +extern int record_syscall_start(int syscall); +extern void record_syscall_end(int index, int result); #endif diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h new file mode 100644 index 000000000000..c77e434d61a9 --- /dev/null +++ b/arch/um/include/sysdep-i386/checksum.h @@ -0,0 +1,217 @@ +/* + * Licensed under the GPL + */ + +#ifndef __UM_SYSDEP_CHECKSUM_H +#define __UM_SYSDEP_CHECKSUM_H + +#include "linux/string.h" + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, + unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums, and handles user-space pointer exceptions correctly, when needed. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy_to(const char *src, char *dst, int len, + int sum, int *err_ptr); +unsigned int csum_partial_copy_from(const char *src, char *dst, int len, + int sum, int *err_ptr); + +/* + * Note: when you get a NULL pointer exception here this means someone + * passed in an incorrect kernel address to one of these functions. + * + * If you use these functions directly please don't forget the + * verify_area(). + */ + +static __inline__ +unsigned int csum_partial_copy_nocheck(const char *src, char *dst, + int len, int sum) +{ + memcpy(dst, src, len); + return(csum_partial(dst, len, sum)); +} + +static __inline__ +unsigned int csum_partial_copy_from_user(const char *src, char *dst, + int len, int sum, int *err_ptr) +{ + return csum_partial_copy_from(src, dst, len, sum, err_ptr); +} + +/* + * These are the old (and unsafe) way of doing checksums, a warning message + * will be printed if they are used and an exeption occurs. + * + * these functions should go away after some time. + */ + +#define csum_partial_copy_fromuser csum_partial_copy_from_user +unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum); + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + * + * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by + * Arnt Gulbrandsen. + */ +static inline unsigned short ip_fast_csum(unsigned char * iph, + unsigned int ihl) +{ + unsigned int sum; + + __asm__ __volatile__( + "movl (%1), %0 ;\n" + "subl $4, %2 ;\n" + "jbe 2f ;\n" + "addl 4(%1), %0 ;\n" + "adcl 8(%1), %0 ;\n" + "adcl 12(%1), %0 ;\n" +"1: adcl 16(%1), %0 ;\n" + "lea 4(%1), %1 ;\n" + "decl %2 ;\n" + "jne 1b ;\n" + "adcl $0, %0 ;\n" + "movl %0, %2 ;\n" + "shrl $16, %0 ;\n" + "addw %w2, %w0 ;\n" + "adcl $0, %0 ;\n" + "notl %0 ;\n" +"2: ;\n" + /* Since the input registers which are loaded with iph and ipl + are modified, we must also specify them as outputs, or gcc + will assume they contain their original values. */ + : "=r" (sum), "=r" (iph), "=r" (ihl) + : "1" (iph), "2" (ihl)); + return(sum); +} + +/* + * Fold a partial checksum + */ + +static inline unsigned int csum_fold(unsigned int sum) +{ + __asm__( + "addl %1, %0 ;\n" + "adcl $0xffff, %0 ;\n" + : "=r" (sum) + : "r" (sum << 16), "0" (sum & 0xffff0000) + ); + return (~sum) >> 16; +} + +static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + __asm__( + "addl %1, %0 ;\n" + "adcl %2, %0 ;\n" + "adcl %3, %0 ;\n" + "adcl $0, %0 ;\n" + : "=r" (sum) + : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum)); + return sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ + +static inline unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return csum_fold (csum_partial(buff, len, 0)); +} + +#define _HAVE_ARCH_IPV6_CSUM +static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, + struct in6_addr *daddr, + __u32 len, + unsigned short proto, + unsigned int sum) +{ + __asm__( + "addl 0(%1), %0 ;\n" + "adcl 4(%1), %0 ;\n" + "adcl 8(%1), %0 ;\n" + "adcl 12(%1), %0 ;\n" + "adcl 0(%2), %0 ;\n" + "adcl 4(%2), %0 ;\n" + "adcl 8(%2), %0 ;\n" + "adcl 12(%2), %0 ;\n" + "adcl %3, %0 ;\n" + "adcl %4, %0 ;\n" + "adcl $0, %0 ;\n" + : "=&r" (sum) + : "r" (saddr), "r" (daddr), + "r"(htonl(len)), "r"(htonl(proto)), "0"(sum)); + + return csum_fold(sum); +} + +/* + * Copy and checksum to user + */ +#define HAVE_CSUM_COPY_USER +static __inline__ unsigned int csum_and_copy_to_user(const char *src, + char *dst, int len, + int sum, int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) + return(csum_partial_copy_to(src, dst, len, sum, err_ptr)); + + if (len) + *err_ptr = -EFAULT; + + return -1; /* invalid checksum */ +} + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/sysdep-i386/frame_kern.h b/arch/um/include/sysdep-i386/frame_kern.h index ec234c6e15c1..f469b8c6ea23 100644 --- a/arch/um/include/sysdep-i386/frame_kern.h +++ b/arch/um/include/sysdep-i386/frame_kern.h @@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp) { unsigned long sc; - sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4; + sc = sp - signal_frame_si.common.sp_index + + signal_frame_si.common.len - 4; return((void *) sc); } @@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp) { unsigned long mask; - mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8; + mask = sp - signal_frame_sc.common.sp_index + + signal_frame_sc.common.len - 8; return((void *) mask); } @@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp) { unsigned long mask; - mask = sp - signal_frame_si.sp_index + signal_frame_si.len + + mask = sp - signal_frame_si.common.sp_index + + signal_frame_si.common.len + sc_size(&signal_frame_sc.arch) - 4; return((void *) mask); } diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index 46aa12342153..e658d491bc5b 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -1,44 +1,78 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ #ifndef __SYSDEP_I386_PTRACE_H #define __SYSDEP_I386_PTRACE_H -#include "sysdep/sc.h" +#include "uml-config.h" +#include "ptrace-tt.h" +#include "ptrace-skas.h" +#include "choose-mode.h" struct uml_pt_regs { unsigned long args[6]; long syscall; int is_user; - void *sc; + union { +#ifdef CONFIG_MODE_TT + void *tt; +#endif +#ifdef CONFIG_MODE_SKAS + struct { + unsigned long regs[HOST_FRAME_SIZE]; + unsigned long fp[HOST_FP_SIZE]; + unsigned long xfp[HOST_XFP_SIZE]; + unsigned long fault_addr; + unsigned long fault_type; + unsigned long trap_type; + } skas; +#endif + } mode; }; #define EMPTY_UML_PT_REGS { \ syscall : -1, \ args : { [0 ... 5] = 0 }, \ - is_user : 0, \ - sc : NULL } - -#define UPT_IP(regs) SC_IP((regs)->sc) -#define UPT_SP(regs) SC_SP((regs)->sc) -#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc) -#define UPT_EAX(regs) SC_EAX((regs)->sc) -#define UPT_EBX(regs) SC_EBX((regs)->sc) -#define UPT_ECX(regs) SC_ECX((regs)->sc) -#define UPT_EDX(regs) SC_EDX((regs)->sc) -#define UPT_ESI(regs) SC_ESI((regs)->sc) -#define UPT_EDI(regs) SC_EDI((regs)->sc) -#define UPT_EBP(regs) SC_EBP((regs)->sc) -#define UPT_ORIG_EAX(regs) ((regs)->syscall) -#define UPT_CS(regs) SC_CS((regs)->sc) -#define UPT_SS(regs) SC_SS((regs)->sc) -#define UPT_DS(regs) SC_DS((regs)->sc) -#define UPT_ES(regs) SC_ES((regs)->sc) -#define UPT_FS(regs) SC_FS((regs)->sc) -#define UPT_GS(regs) SC_GS((regs)->sc) -#define UPT_SC(regs) ((regs)->sc) + is_user : 0 } + +extern int mode_tt; + +#define UPT_IP(r) \ + CHOOSE_MODE(SC_IP((r)->mode.tt), REGS_IP((r)->mode.skas.regs)) +#define UPT_SP(r) \ + CHOOSE_MODE(SC_SP((r)->mode.tt), REGS_SP((r)->mode.skas.regs)) +#define UPT_EFLAGS(r) \ + CHOOSE_MODE(SC_EFLAGS((r)->mode.tt), REGS_EFLAGS((r)->mode.skas.regs)) +#define UPT_EAX(r) \ + CHOOSE_MODE(SC_EAX((r)->mode.tt), REGS_EAX((r)->mode.skas.regs)) +#define UPT_EBX(r) \ + CHOOSE_MODE(SC_EBX((r)->mode.tt), REGS_EBX((r)->mode.skas.regs)) +#define UPT_ECX(r) \ + CHOOSE_MODE(SC_ECX((r)->mode.tt), REGS_ECX((r)->mode.skas.regs)) +#define UPT_EDX(r) \ + CHOOSE_MODE(SC_EDX((r)->mode.tt), REGS_EDX((r)->mode.skas.regs)) +#define UPT_ESI(r) \ + CHOOSE_MODE(SC_ESI((r)->mode.tt), REGS_ESI((r)->mode.skas.regs)) +#define UPT_EDI(r) \ + CHOOSE_MODE(SC_EDI((r)->mode.tt), REGS_EDI((r)->mode.skas.regs)) +#define UPT_EBP(r) \ + CHOOSE_MODE(SC_EBP((r)->mode.tt), REGS_EBP((r)->mode.skas.regs)) +#define UPT_ORIG_EAX(r) ((r)->syscall) +#define UPT_CS(r) \ + CHOOSE_MODE(SC_CS((r)->mode.tt), REGS_CS((r)->mode.skas.regs)) +#define UPT_SS(r) \ + CHOOSE_MODE(SC_SS((r)->mode.tt), REGS_SS((r)->mode.skas.regs)) +#define UPT_DS(r) \ + CHOOSE_MODE(SC_DS((r)->mode.tt), REGS_DS((r)->mode.skas.regs)) +#define UPT_ES(r) \ + CHOOSE_MODE(SC_ES((r)->mode.tt), REGS_ES((r)->mode.skas.regs)) +#define UPT_FS(r) \ + CHOOSE_MODE(SC_FS((r)->mode.tt), REGS_FS((r)->mode.skas.regs)) +#define UPT_GS(r) \ + CHOOSE_MODE(SC_GS((r)->mode.tt), REGS_GS((r)->mode.skas.regs)) +#define UPT_SC(r) ((r)->mode.tt) #define UPT_REG(regs, reg) \ ({ unsigned long val; \ @@ -94,12 +128,29 @@ struct uml_pt_regs { } \ } while (0) -#define UPT_SET_SYSCALL_RETURN(regs, res) \ - SC_SET_SYSCALL_RETURN((regs)->sc, (res)) -#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc) -#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs) -#define UPT_SYSCALL_NR(regs) ((regs)->syscall) -#define UPT_SYSCALL_RET(regs) UPT_EAX(regs) +#define UPT_SET_SYSCALL_RETURN(r, res) \ + CHOOSE_MODE(SC_SET_SYSCALL_RETURN((r)->mode.tt, (res)), \ + REGS_SET_SYSCALL_RETURN((r)->mode.skas.regs, (res))) + +#define UPT_RESTART_SYSCALL(r) \ + CHOOSE_MODE(SC_RESTART_SYSCALL((r)->mode.tt), \ + REGS_RESTART_SYSCALL((r)->mode.skas.regs)) + +#define UPT_ORIG_SYSCALL(r) UPT_EAX(r) +#define UPT_SYSCALL_NR(r) ((r)->syscall) +#define UPT_SYSCALL_RET(r) UPT_EAX(r) + +#define UPT_SEGV_IS_FIXABLE(r) \ + CHOOSE_MODE(SC_SEGV_IS_FIXABLE(r->mode.tt), \ + REGS_SEGV_IS_FIXABLE(&r->mode.skas)) + +#define UPT_FAULT_ADDR(r) \ + CHOOSE_MODE(SC_FAULT_ADDR(r->mode.tt), \ + REGS_FAULT_ADDR(&r->mode.skas)) + +#define UPT_FAULT_WRITE(r) \ + CHOOSE_MODE(SC_FAULT_WRITE(r->mode.tt), \ + REGS_FAULT_WRITE(&r->mode.skas)) #endif diff --git a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h index f445f375c9a4..d52262e31499 100644 --- a/arch/um/include/sysdep-i386/sigcontext.h +++ b/arch/um/include/sysdep-i386/sigcontext.h @@ -6,13 +6,22 @@ #ifndef __SYS_SIGCONTEXT_I386_H #define __SYS_SIGCONTEXT_I386_H +#include "sc.h" + #define IP_RESTART_SYSCALL(ip) ((ip) -= 2) #define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) -#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0) +#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result) #define SC_FAULT_ADDR(sc) SC_CR2(sc) -#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2) +#define SC_FAULT_TYPE(sc) SC_ERR(sc) + +#define FAULT_WRITE(err) (err & 2) +#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0) + +#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc))) + +#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc) /* ptrace expects that, at the start of a system call, %eax contains * -ENOSYS, so this makes it so. @@ -20,10 +29,12 @@ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) /* These are General Protection and Page Fault */ -#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14)) +#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14)) -/* XXX struct sigcontext needs declaring by now */ +#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) +#ifdef CONFIG_MODE_TT +/* XXX struct sigcontext needs declaring by now */ static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc, unsigned long syscall) { @@ -35,6 +46,20 @@ static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc, regs->args[4] = SC_EDI(sc); regs->args[5] = SC_EBP(sc); } +#endif + +#ifdef CONFIG_MODE_SKAS +static inline void host_to_regs(struct uml_pt_regs *regs) +{ + regs->syscall = UPT_ORIG_EAX(regs); + regs->args[0] = UPT_EBX(regs); + regs->args[1] = UPT_ECX(regs); + regs->args[2] = UPT_EDX(regs); + regs->args[3] = UPT_ESI(regs); + regs->args[4] = UPT_EDI(regs); + regs->args[5] = UPT_EBP(regs); +} +#endif extern unsigned long *sc_sigmask(void *sc_ptr); extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h index d49a34f0bee8..ec7dc1a65465 100644 --- a/arch/um/include/time_user.h +++ b/arch/um/include/time_user.h @@ -8,7 +8,7 @@ extern void timer(void); extern void switch_timers(int to_real); -extern void user_time_init(void); +extern void set_interval(int timer_type); extern void idle_sleep(int secs); extern void enable_timer(void); extern void time_lock(void); diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h new file mode 100644 index 000000000000..3c5660ff97d7 --- /dev/null +++ b/arch/um/include/um_mmu.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_UM_MMU_H +#define __ARCH_UM_MMU_H + +#include "linux/config.h" +#include "choose-mode.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/mmu.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/mmu.h" +#endif + +typedef union { +#ifdef CONFIG_MODE_TT + struct mmu_context_tt tt; +#endif +#ifdef CONFIG_MODE_SKAS + struct mmu_context_skas skas; +#endif +} mm_context_t; + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h new file mode 100644 index 000000000000..41afa3a8f086 --- /dev/null +++ b/arch/um/include/um_uaccess.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __ARCH_UM_UACCESS_H +#define __ARCH_UM_UACCESS_H + +#include "linux/config.h" +#include "choose-mode.h" + +#ifdef CONFIG_MODE_TT +#include "../kernel/tt/include/uaccess.h" +#endif + +#ifdef CONFIG_MODE_SKAS +#include "../kernel/skas/include/uaccess.h" +#endif + +#define access_ok(type, addr, size) \ + CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) + +static inline int verify_area(int type, const void * addr, unsigned long size) +{ + return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr, + size)); +} + +static inline int copy_from_user(void *to, const void *from, int n) +{ + return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, + from, n)); +} + +static inline int copy_to_user(void *to, const void *from, int n) +{ + return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to, + from, n)); +} + +static inline int strncpy_from_user(char *dst, const char *src, int count) +{ + return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, + dst, src, count)); +} + +static inline int __clear_user(void *mem, int len) +{ + return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); +} + +static inline int clear_user(void *mem, int len) +{ + return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); +} + +static inline int strnlen_user(const void *str, int len) +{ + return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); +} + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 5f50aed753b2..a419cc9ccfff 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -8,6 +8,8 @@ #include "sysdep/ptrace.h" +extern int mode_tt; + extern int grantpt(int __fd); extern int unlockpt(int __fd); extern char *ptsname(int __fd); @@ -21,6 +23,13 @@ struct cpu_task { extern struct cpu_task cpu_tasks[]; +struct signal_info { + void (*handler)(int, struct uml_pt_regs *); + int is_irq; +}; + +extern struct signal_info sig_info[]; + extern unsigned long low_physmem; extern unsigned long high_physmem; extern unsigned long uml_physmem; @@ -29,16 +38,11 @@ extern unsigned long end_vm; extern unsigned long start_vm; extern unsigned long highmem; -extern int tracing_pid; -extern int honeypot; - extern char host_info[]; extern char saved_command_line[]; extern char command_line[]; -extern int gdb_pid; - extern char *tempdir; extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; @@ -51,12 +55,10 @@ extern int pty_close_sigio; extern void stop(void); extern void stack_protections(unsigned long address); extern void task_protections(unsigned long address); -extern int signals(int (*init_proc)(void *), void *sp); extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); extern void *add_signal_handler(int sig, void (*handler)(int)); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); -extern void trace_myself(void); extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); extern int linux_main(int argc, char **argv); extern void remap_data(void *segment_start, void *segment_end, int w); @@ -69,13 +71,12 @@ extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(void); extern void add_arg(char *cmd_line, char *arg); -extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int)); -extern void attach_process(int pid); -extern int fork_tramp(void *sig_stack); +extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); +extern void init_new_thread_signals(int altstack); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); -extern void do_longjmp(void *p); +extern void do_longjmp(void *p, int val); extern void suspend_new_thread(int fd); extern int detach(int pid, int sig); extern int attach(int pid); @@ -89,7 +90,8 @@ extern void arch_check_bugs(void); extern int arch_handle_signal(int sig, struct uml_pt_regs *regs); extern int arch_fixup(unsigned long address, void *sc_ptr); extern void forward_pending_sigio(int target); - +extern int can_do_skas(void); + #endif /* diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 82736d449d8b..de98110a7494 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -1,40 +1,47 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + EXTRA_TARGETS := unmap_fin.o -obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \ +obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ + time_kern.o tlb.o trap_kern.o trap_user.o um_arch.o \ umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o +obj-$(CONFIG_GPROF) += gprof_syms.o +obj-$(CONFIG_GCOV) += gmon_syms.o +obj-$(CONFIG_TTY_LOG) += tty_log.o -# user_syms.o not included here because kbuild has its own ideas about -# building anything in export-objs +obj-$(CONFIG_MODE_TT) += tt/ +obj-$(CONFIG_MODE_SKAS) += skas/ -USER_OBJS := $(filter %_user.o,$(obj-y)) config.o helper.o process.o \ - tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file)) +user-objs-$(CONFIG_TTY_LOG) += tty_log.o -export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o +# user_syms.o not included here because Rules.make has its own ideas about +# building anything in export-objs + +USER_OBJS := $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ + process.o tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) -ifeq ($(CONFIG_MODULES), y) - DMODULES = -D__CONFIG_MODULES__ -endif +DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ +DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ -ifeq ($(CONFIG_MODVERSIONS), y) - DMODVERSIONS = -D__CONFIG_MODVERSIONS__ -endif +export-objs-$(CONFIG_GPROF) += gprof_syms.o +export-objs-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_GPROF) += gprof_syms.o -obj-$(CONFIG_GCOV) += gmon_syms.o -obj-$(CONFIG_TTY_LOG) += tty_log.o +export-objs := ksyms.o process_kern.o signal_kern.o $(export-objs-y) -CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS) \ +CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \ -I/usr/include -I../include CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) @@ -42,27 +49,28 @@ CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< -arch/um/kernel/unmap.o: arch/um/kernel/unmap.c +$(obj)/unmap.o: $(src)/unmap.c $(CC) $(UNMAP_CFLAGS) -c -o $@ $< -arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o +$(obj)/unmap_fin.o : $(src)/unmap.o ld -r -o $@ $< -lc -L/usr/lib # This has to be separate because it needs be compiled with frame pointers # regardless of how the rest of the kernel is built. -arch/um/kernel/frame.o: arch/um/kernel/frame.c +$(obj)/frame.o: $(src)/frame.c $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }' -arch/um/kernel/config.c : arch/um/kernel/config.c.in $(TOPDIR)/.config - $(PERL) -e $(QUOTE) < arch/um/kernel/config.c.in > $@ +$(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config + $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@ -arch/um/kernel/config.o : arch/um/kernel/config.c +$(obj)/config.o : $(obj)/config.c clean: rm -f config.c + for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done modules: diff --git a/arch/um/kernel/checksum.c b/arch/um/kernel/checksum.c new file mode 100644 index 000000000000..6e27cb032258 --- /dev/null +++ b/arch/um/kernel/checksum.c @@ -0,0 +1,42 @@ +#include "asm/uaccess.h" +#include "linux/errno.h" + +extern unsigned int arch_csum_partial(const char *buff, int len, int sum); + +extern unsigned int csum_partial(char *buff, int len, int sum) +{ + return(arch_csum_partial(buff, len, sum)); +} + +unsigned int csum_partial_copy_to(const char *src, char *dst, int len, + int sum, int *err_ptr) +{ + if(copy_to_user(dst, src, len)){ + *err_ptr = -EFAULT; + return(-1); + } + + return(arch_csum_partial(src, len, sum)); +} + +unsigned int csum_partial_copy_from(const char *src, char *dst, int len, + int sum, int *err_ptr) +{ + if(copy_from_user(dst, src, len)){ + *err_ptr = -EFAULT; + return(-1); + } + + return(arch_csum_partial(dst, len, sum)); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 353bfa4da610..eaae628fa902 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -18,65 +18,17 @@ #include "2_5compat.h" #include "os.h" #include "time_user.h" - -/* See comment above fork_tramp for why sigstop is defined and used like - * this - */ - -static int sigstop = SIGSTOP; - -static int exec_tramp(void *sig_stack) -{ - int sig = sigstop; - - init_new_thread(sig_stack, NULL); - kill(os_getpid(), sig); - return(0); -} +#include "choose-mode.h" +#include "mode_kern.h" void flush_thread(void) { - unsigned long stack; - int new_pid; - - stack = alloc_stack(0, 0); - if(stack == 0){ - printk(KERN_ERR - "flush_thread : failed to allocate temporary stack\n"); - do_exit(SIGKILL); - } - - new_pid = start_fork_tramp((void *) current->thread.kernel_stack, - stack, 0, exec_tramp); - if(new_pid < 0){ - printk(KERN_ERR - "flush_thread : new thread failed, errno = %d\n", - -new_pid); - do_exit(SIGKILL); - } - - if(current->thread_info->cpu == 0) - forward_interrupts(new_pid); - current->thread.request.op = OP_EXEC; - current->thread.request.u.exec.pid = new_pid; - unprotect_stack((unsigned long) current->thread_info); - os_usr1_process(os_getpid()); - - enable_timer(); - free_page(stack); - protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - force_flush_all(); - unblock_signals(); + CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); } void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) { - set_fs(USER_DS); - flush_tlb_mm(current->mm); - PT_REGS_IP(regs) = eip; - PT_REGS_SP(regs) = esp; - PT_FIX_EXEC_STACK(esp); + CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); } static int execve1(char *file, char **argv, char **env) @@ -93,8 +45,12 @@ static int execve1(char *file, char **argv, char **env) int um_execve(char *file, char **argv, char **env) { - if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp); - return(-1); + int err; + + err = execve1(file, argv, env); + if(!err) + do_longjmp(current->thread.exec_buf, 1); + return(err); } int sys_execve(char *file, char **argv, char **env) diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 788f914d8510..14a748e2e25a 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -42,7 +42,7 @@ static int write_proc_exitcode(struct file *file, const char *buffer, return(count); } -int make_proc_exitcode(void) +static int make_proc_exitcode(void) { struct proc_dir_entry *ent; diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c index 28793041426a..ae5b0e3e5158 100644 --- a/arch/um/kernel/frame.c +++ b/arch/um/kernel/frame.c @@ -12,6 +12,7 @@ #include <sched.h> #include <errno.h> #include <sys/ptrace.h> +#include <sys/syscall.h> #include <sys/mman.h> #include <asm/page.h> #include <asm/ptrace.h> @@ -84,8 +85,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); } - if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ - printf("capture_stack : Expected exit status 0, " + if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){ + printf("capture_stack : Expected exit signal 9, " "got status = 0x%x\n", status); exit(1); } @@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, return(len); } -static void child_common(void *sp, int size, sighandler_t handler, int flags) +struct common_raw { + void *stack; + int size; + unsigned long sig; + unsigned long sr; + unsigned long sp; +}; + +#define SA_RESTORER (0x04000000) + +typedef unsigned long old_sigset_t; + +struct old_sigaction { + __sighandler_t handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +static void child_common(struct common_raw *common, sighandler_t handler, + int restorer, int flags) { - stack_t ss; - struct sigaction sa; + stack_t ss = ((stack_t) { .ss_sp = common->stack, + .ss_flags = 0, + .ss_size = common->size }); + int err; if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ printf("PTRACE_TRACEME failed, errno = %d\n", errno); } - ss.ss_sp = sp; - ss.ss_flags = 0; - ss.ss_size = size; if(sigaltstack(&ss, NULL) < 0){ printf("sigaltstack failed - errno = %d\n", errno); - _exit(1); + kill(getpid(), SIGKILL); } - sa.sa_handler = handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_ONSTACK | flags; - if(sigaction(SIGUSR1, &sa, NULL) < 0){ + if(restorer){ + struct sigaction sa; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_ONSTACK | flags; + err = sigaction(SIGUSR1, &sa, NULL); + } + else { + struct old_sigaction sa; + + sa.handler = handler; + sa.sa_mask = 0; + sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER; + err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL); + } + + if(err < 0){ printf("sigaction failed - errno = %d\n", errno); - _exit(1); + kill(getpid(), SIGKILL); } os_stop_process(os_getpid()); @@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags) /* Changed only during early boot */ struct sc_frame signal_frame_sc; +struct sc_frame signal_frame_sc_sr; + struct sc_frame_raw { - void *stack; - int size; - unsigned long sig; + struct common_raw common; unsigned long sc; - unsigned long sr; - unsigned long sp; + int restorer; struct arch_frame_data_raw arch; }; @@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL; static void sc_handler(int sig, struct sigcontext sc) { - raw_sc->sig = (unsigned long) &sig; + raw_sc->common.sig = (unsigned long) &sig; + raw_sc->common.sr = frame_restorer(); + raw_sc->common.sp = frame_sp(); raw_sc->sc = (unsigned long) ≻ - raw_sc->sr = frame_restorer(); - raw_sc->sp = frame_sp(); setup_arch_frame_raw(&raw_sc->arch, &sc); os_stop_process(os_getpid()); - _exit(0); + kill(getpid(), SIGKILL); } static int sc_child(void *arg) { raw_sc = arg; - child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler, - 0); + child_common(&raw_sc->common, (sighandler_t) sc_handler, + raw_sc->restorer, 0); return(-1); } @@ -169,13 +202,9 @@ static int sc_child(void *arg) struct si_frame signal_frame_si; struct si_frame_raw { - void *stack; - int size; - unsigned long sig; + struct common_raw common; unsigned long sip; unsigned long si; - unsigned long sr; - unsigned long sp; }; /* Changed only during early boot */ @@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL; static void si_handler(int sig, siginfo_t *si) { - raw_si->sig = (unsigned long) &sig; + raw_si->common.sig = (unsigned long) &sig; + raw_si->common.sr = frame_restorer(); + raw_si->common.sp = frame_sp(); raw_si->sip = (unsigned long) &si; raw_si->si = (unsigned long) si; - raw_si->sr = frame_restorer(); - raw_si->sp = frame_sp(); os_stop_process(os_getpid()); - _exit(0); + kill(getpid(), SIGKILL); } static int si_child(void *arg) { raw_si = arg; - child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler, - SA_SIGINFO); + child_common(&raw_si->common, (sighandler_t) si_handler, 1, + SA_SIGINFO); return(-1); } +static int relative_sr(unsigned long sr, int sr_index, void *stack, + void *framep) +{ + unsigned long *srp = (unsigned long *) sr; + unsigned long frame = (unsigned long) framep; + + if((*srp & PAGE_MASK) == (unsigned long) stack){ + *srp -= sr; + *((unsigned long *) (frame + sr_index)) = *srp; + return(1); + } + else return(0); +} + +static unsigned long capture_stack_common(int (*proc)(void *), void *arg, + struct common_raw *common_in, + void *top, void *sigstack, + int stack_len, + struct frame_common *common_out) +{ + unsigned long sig_top = (unsigned long) sigstack + stack_len, base; + + common_in->stack = (void *) sigstack; + common_in->size = stack_len; + common_out->len = capture_stack(proc, arg, top, sig_top, + &common_out->data); + base = sig_top - common_out->len; + common_out->sig_index = common_in->sig - base; + common_out->sp_index = common_in->sp - base; + common_out->sr_index = common_in->sr - base; + common_out->sr_relative = relative_sr(common_in->sr, + common_out->sr_index, sigstack, + common_out->data); + return(base); +} + void capture_signal_stack(void) { struct sc_frame_raw raw_sc; @@ -220,54 +285,29 @@ void capture_signal_stack(void) top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); sig_top = (unsigned long) sigstack + PAGE_SIZE; - raw_sc.stack = sigstack; - raw_sc.size = PAGE_SIZE; - signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top, - sig_top, &signal_frame_sc.data); - - /* These are the offsets within signal_frame_sc.data (counting from - * the bottom) of sig, sc, SA_RESTORER, and the initial sp. - */ + /* Get the sigcontext, no sigrestorer layout */ + raw_sc.restorer = 0; + base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, + (void *) top, sigstack, PAGE_SIZE, + &signal_frame_sc.common); - base = sig_top - signal_frame_sc.len; - signal_frame_sc.sig_index = raw_sc.sig - base; signal_frame_sc.sc_index = raw_sc.sc - base; - signal_frame_sc.sr_index = raw_sc.sr - base; - if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) == - (unsigned long) sigstack){ - unsigned long *sr = (unsigned long *) raw_sc.sr; - unsigned long frame = (unsigned long) signal_frame_sc.data; - - signal_frame_sc.sr_relative = 1; - *sr -= raw_sc.sr; - *((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr; - } - else signal_frame_sc.sr_relative = 0; - signal_frame_sc.sp_index = raw_sc.sp - base; setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch); - /* Repeat for the siginfo variant */ + /* Ditto for the sigcontext, sigrestorer layout */ + raw_sc.restorer = 1; + base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, + (void *) top, sigstack, PAGE_SIZE, + &signal_frame_sc_sr.common); + signal_frame_sc_sr.sc_index = raw_sc.sc - base; + + /* And the siginfo layout */ - raw_si.stack = sigstack; - raw_si.size = PAGE_SIZE; - signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top, - sig_top, &signal_frame_si.data); - base = sig_top - signal_frame_si.len; - signal_frame_si.sig_index = raw_si.sig - base; + base = capture_stack_common(si_child, &raw_si, &raw_si.common, + (void *) top, sigstack, PAGE_SIZE, + &signal_frame_si.common); signal_frame_si.sip_index = raw_si.sip - base; signal_frame_si.si_index = raw_si.si - base; - signal_frame_si.sr_index = raw_si.sr - base; - if((*((unsigned long *) raw_si.sr) & PAGE_MASK) == - (unsigned long) sigstack){ - unsigned long *sr = (unsigned long *) raw_si.sr; - unsigned long frame = (unsigned long) signal_frame_si.data; - - signal_frame_sc.sr_relative = 1; - *sr -= raw_si.sr; - *((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr; - } - else signal_frame_si.sr_relative = 0; - signal_frame_si.sp_index = raw_si.sp - base; if((munmap(stack, PAGE_SIZE) < 0) || (munmap(sigstack, PAGE_SIZE) < 0)){ @@ -277,14 +317,6 @@ void capture_signal_stack(void) } } -void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp) -{ - struct sigcontext *sc = sc_ptr; - - SC_IP(sc) = ip; - SC_SP(sc) = sp; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c index f71451c4c780..cd2177629bec 100644 --- a/arch/um/kernel/frame_kern.c +++ b/arch/um/kernel/frame_kern.c @@ -9,20 +9,31 @@ #include "frame_kern.h" #include "sigcontext.h" #include "sysdep/ptrace.h" +#include "choose-mode.h" +#include "mode.h" static int copy_restorer(void (*restorer)(void), unsigned long start, unsigned long sr_index, int sr_relative) { - if(restorer != 0){ - if(copy_to_user((void *) (start + sr_index), &restorer, - sizeof(restorer))) - return(1); - } - else if(sr_relative){ - unsigned long *sr = (unsigned long *) (start + sr_index); - *sr += (unsigned long) sr; + unsigned long sr; + + if(sr_relative){ + sr = (unsigned long) restorer; + sr += start + sr_index; + restorer = (void (*)(void)) sr; } - return(0); + + return(copy_to_user((void *) (start + sr_index), &restorer, + sizeof(restorer))); +} + +static int copy_sc_to_user(void *to, struct pt_regs *from) +{ + return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt, + &signal_frame_sc_sr.arch), + copy_sc_to_user_skas(to, &from->regs, + current->thread.cr2, + current->thread.err))); } int setup_signal_stack_si(unsigned long stack_top, int sig, @@ -34,27 +45,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, void *sip; int sig_size = _NSIG_WORDS * sizeof(unsigned long); - start = stack_top - signal_frame_si.len - + start = stack_top - signal_frame_si.common.len - sc_size(&signal_frame_sc.arch) - sig_size; sip = (void *) (start + signal_frame_si.si_index); - sc = start + signal_frame_si.len; + sc = start + signal_frame_si.common.len; sigs = sc + sc_size(&signal_frame_sc.arch); - if(copy_sc_to_user((void *) sc, regs->regs.sc, - &signal_frame_sc.arch) || - copy_to_user((void *) start, signal_frame_si.data, - signal_frame_si.len) || - copy_to_user((void *) (start + signal_frame_si.sig_index), &sig, - sizeof(sig)) || + + if(restorer == NULL) + panic("setup_signal_stack_si - no restorer"); + + if(copy_sc_to_user((void *) sc, regs) || + copy_to_user((void *) start, signal_frame_si.common.data, + signal_frame_si.common.len) || + copy_to_user((void *) (start + signal_frame_si.common.sig_index), + &sig, sizeof(sig)) || copy_siginfo_to_user(sip, info) || copy_to_user((void *) (start + signal_frame_si.sip_index), &sip, sizeof(sip)) || copy_to_user((void *) sigs, mask, sig_size) || - copy_restorer(restorer, start, signal_frame_si.sr_index, - signal_frame_si.sr_relative)) + copy_restorer(restorer, start, signal_frame_si.common.sr_index, + signal_frame_si.common.sr_relative)) return(1); PT_REGS_IP(regs) = handler; - PT_REGS_SP(regs) = start + signal_frame_sc.sp_index; + PT_REGS_SP(regs) = start + signal_frame_sc.common.sp_index; return(0); } @@ -62,26 +76,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, unsigned long handler, void (*restorer)(void), struct pt_regs *regs, sigset_t *mask) { + struct frame_common *frame = &signal_frame_sc_sr.common; + void *user_sc; int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size; - void *user_sc = (void *) (start + signal_frame_sc.sc_index); + unsigned long sigs, sr; + unsigned long start = stack_top - frame->len - sig_size; + + user_sc = (void *) (start + signal_frame_sc_sr.sc_index); + if(restorer == NULL){ + frame = &signal_frame_sc.common; + user_sc = (void *) (start + signal_frame_sc.sc_index); + sr = (unsigned long) frame->data; + sr += frame->sr_index; + sr = *((unsigned long *) sr); + restorer = ((void (*)(void)) sr); + } - sigs = start + signal_frame_sc.len; - if(copy_to_user((void *) start, signal_frame_sc.data, - signal_frame_sc.len) || - copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig, + sigs = start + frame->len; + if(copy_to_user((void *) start, frame->data, frame->len) || + copy_to_user((void *) (start + frame->sig_index), &sig, sizeof(sig)) || - copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) || + copy_sc_to_user(user_sc, regs) || copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || copy_to_user((void *) sigs, &mask->sig[1], sig_size) || - copy_restorer(restorer, start, signal_frame_sc.sr_index, - signal_frame_sc.sr_relative)) + copy_restorer(restorer, start, frame->sr_index, frame->sr_relative)) return(1); PT_REGS_IP(regs) = handler; - PT_REGS_SP(regs) = start + signal_frame_sc.sp_index; + PT_REGS_SP(regs) = start + frame->sp_index; - set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index); return(0); } diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c index 5d8fb7bba2b1..5c4b27942da3 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -43,9 +43,12 @@ static int helper_child(void *arg) execvp(argv[0], argv); printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); write(data->fd, &errno, sizeof(errno)); - _exit(1); + os_kill_process(os_getpid(), 0); + return(0); } +/* XXX The alloc_stack here breaks if this is called in the tracing thread */ + int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, unsigned long *stack_out) { @@ -86,7 +89,10 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, errno); return(-errno); } - else if(n != 0) pid = -err; + else if(n != 0){ + waitpid(pid, NULL, 0); + pid = -err; + } if(stack_out == NULL) free_stack(stack, 0); else *stack_out = stack; diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index f06162f5a113..c9bc00a19403 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -47,7 +47,7 @@ struct task_struct *alloc_task_struct(void){ void unprotect_stack(unsigned long stack) { - protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1); + protect_memory(stack, 4 * PAGE_SIZE, 1, 1, 0, 1); } void free_task_struct(struct task_struct *task) diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index a5abb61536cf..239a6a6126c9 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -188,7 +188,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id) pollfds_size++; } - if(type == IRQ_WRITE) events = 0; + if(type == IRQ_WRITE) + fd = -1; pollfds[pollfds_num] = ((struct pollfd) { fd : fd, events : events, @@ -337,6 +338,7 @@ void reactivate_fd(int fd, int irqnum) irq_unlock(flags); return; } + pollfds[i].fd = irq->fd; irq_unlock(flags); diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 28e728347041..7de3e05edbab 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -1,3 +1,8 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #include "linux/config.h" #include "linux/module.h" #include "linux/string.h" @@ -19,17 +24,13 @@ EXPORT_SYMBOL(stop); EXPORT_SYMBOL(uml_physmem); EXPORT_SYMBOL(set_signals); +EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(sys_waitpid); EXPORT_SYMBOL(task_size); -EXPORT_SYMBOL(__do_copy_from_user); -EXPORT_SYMBOL(__do_copy_to_user); -EXPORT_SYMBOL(__do_strncpy_from_user); -EXPORT_SYMBOL(__do_strnlen_user); EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(__do_clear_user); -EXPORT_SYMBOL(honeypot); EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); @@ -37,10 +38,10 @@ EXPORT_SYMBOL(region_pa); EXPORT_SYMBOL(region_va); EXPORT_SYMBOL(phys_mem_map); EXPORT_SYMBOL(page_mem_map); -EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(page_to_phys); EXPORT_SYMBOL(phys_to_page); EXPORT_SYMBOL(high_physmem); +EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(os_open_file); EXPORT_SYMBOL(os_read_file); @@ -53,7 +54,6 @@ EXPORT_SYMBOL(helper_wait); EXPORT_SYMBOL(os_shutdown_socket); EXPORT_SYMBOL(os_connect_socket); EXPORT_SYMBOL(run_helper); -EXPORT_SYMBOL(tracing_pid); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(dump_thread); @@ -75,6 +75,7 @@ EXPORT_SYMBOL_NOVERS(__write_lock_failed); extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); EXPORT_SYMBOL_NOVERS(__read_lock_failed); +EXPORT_SYMBOL(smp_num_cpus); #endif #ifdef CONFIG_HIGHMEM diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 5a582a8de7d1..178223bf2bfa 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -25,6 +25,8 @@ #include "mem.h" #include "kern.h" #include "init.h" +#include "os.h" +#include "mode_kern.h" /* Changed during early boot */ pgd_t swapper_pg_dir[1024]; @@ -56,12 +58,12 @@ static unsigned long brk_end; static void map_cb(void *unused) { - map(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); + map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); } void unmap_physmem(void) { - unmap((void *) brk_end, uml_reserved - brk_end); + os_unmap_memory((void *) brk_end, uml_reserved - brk_end); } extern char __binary_start; @@ -81,17 +83,17 @@ void mem_init(void) /* Map in the area just after the brk now that kmalloc is about * to be turned on. */ - brk_end = (unsigned long) ROUND_UP(sbrk(0)); + brk_end = (unsigned long) UML_ROUND_UP(sbrk(0)); map_cb(NULL); - tracing_cb(map_cb, NULL); + initial_thread_cb(map_cb, NULL); free_bootmem(__pa(brk_end), uml_reserved - brk_end); uml_reserved = brk_end; /* Fill in any hole at the start of the binary */ start = (unsigned long) &__binary_start; if(uml_physmem != start){ - map(uml_physmem, __pa(uml_physmem), start - uml_physmem, - 1, 1, 0); + map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem, + 1, 1, 0); } /* this will put all low memory onto the freelists */ @@ -106,6 +108,21 @@ void mem_init(void) kmalloc_ok = 1; } +/* Changed during early boot */ +static unsigned long kmem_top = 0; + +unsigned long get_kmem_end(void) +{ + if(kmem_top == 0) + kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); + return(kmem_top); +} + +void set_kmem_end(unsigned long new) +{ + kmem_top = new; +} + #if CONFIG_HIGHMEM /* Changed during early boot */ pte_t *kmap_pte; @@ -379,20 +396,6 @@ void show_mem(void) printk("%d pages swap cached\n", cached); } -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM; - return(kmem_top); -} - -void set_kmem_end(unsigned long new) -{ - kmem_top = new; -} - static int __init uml_mem_setup(char *line, int *add) { char *retptr; @@ -411,28 +414,8 @@ __uml_setup("mem=", uml_mem_setup, struct page *arch_validate(struct page *page, int mask, int order) { - unsigned long addr, zero = 0; - int i; - - again: - if(page == NULL) return(page); - if(PageHighMem(page)) return(page); - - addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ - current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void *) addr, &zero, - sizeof(zero), - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) return(NULL); - else break; - } - addr += PAGE_SIZE; - } - if(i == (1 << order)) return(page); - page = alloc_pages(mask, order); - goto again; + return(CHOOSE_MODE_PROC(arch_validate_tt, arch_validate_skas, page, + mask, order)); } DECLARE_MUTEX(vm_reserved_sem); @@ -513,7 +496,7 @@ unsigned long get_vm(unsigned long len) return(0); found: up(&vm_reserved_sem); - start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE; + start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE; err = reserve_vm(start, start + len, NULL); if(err) return(0); return(start); @@ -562,7 +545,7 @@ struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = int num_iomem_regions = 0; -void add_iomem(char *name, int fd, int size) +void add_iomem(char *name, int fd, unsigned long size) { if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0])) return; diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c index af857510d17a..d90345b5fd44 100644 --- a/arch/um/kernel/mem_user.c +++ b/arch/um/kernel/mem_user.c @@ -181,44 +181,22 @@ void log(char *fmt, ...) } #endif -void map(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x) +int map_memory(unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) { - struct mem_region *region; - void *loc; - int prot; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - region = phys_region(phys); - - loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, - region->fd, phys_offset(phys)); - if(loc != (void *) virt){ - panic("Error mapping a page - errno = %d", errno); - } -} - -int unmap(void *addr, int len) -{ - int err; + struct mem_region *region = phys_region(phys); - err = munmap(addr, len); - if(err < 0) return(-errno); - else return(err); + return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len, + r, w, x)); } -int protect(unsigned long addr, unsigned long len, int r, int w, int x, - int must_succeed) +int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, + int must_succeed) { - int prot; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - if(mprotect((void *) addr, len, prot) == -1){ - if(must_succeed) - panic("protect failed, errno = %d", errno); - else return(-errno); + if(os_protect_memory((void *) addr, len, r, w, x) < 0){ + if(must_succeed) + panic("protect failed, errno = %d", errno); + else return(-errno); } return(0); } diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index d410aaa7332b..44e9a980949f 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -21,9 +21,6 @@ #include <asm/sigcontext.h> #include <asm/unistd.h> #include <asm/page.h> -#ifdef PROFILING -#include <sys/gmon.h> -#endif #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -33,13 +30,19 @@ #include "sysdep/ptrace.h" #include "sysdep/sigcontext.h" #include "irq_user.h" -#include "syscall_user.h" #include "ptrace_user.h" #include "time_user.h" #include "init.h" #include "os.h" +#include "uml-config.h" +#include "choose-mode.h" +#include "mode.h" +#ifdef CONFIG_MODE_SKAS +#include "skas_ptrace.h" +#include "skas.h" +#endif -void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) +void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) { int flags = 0; @@ -47,6 +50,13 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) set_sigstack(sig_stack, 2 * page_size()); flags = SA_ONSTACK; } + if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); +} + +void init_new_thread_signals(int altstack) +{ + int flags = altstack ? SA_ONSTACK : 0; + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, @@ -61,11 +71,10 @@ void init_new_thread(void *sig_stack, void (*usr1_handler)(int)) SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, SA_NOMASK | flags, -1); - if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); - signal(SIGCHLD, SIG_IGN); + (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0); signal(SIGHUP, SIG_IGN); - init_irq_signals(sig_stack != NULL); + init_irq_signals(altstack); } struct tramp { @@ -122,32 +131,6 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, return(arg.pid); } -void trace_myself(void) -{ - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) - panic("ptrace failed in trace_myself"); -} - -void attach_process(int pid) -{ - if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) - tracer_panic("OP_FORK failed to attach pid"); - wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); - if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - tracer_panic("OP_FORK failed to continue process"); -} - -void tracer_panic(char *format, ...) -{ - va_list ap; - - va_start(ap, format); - vprintf(format, ap); - printf("\n"); - while(1) sleep(10); -} - void suspend_new_thread(int fd) { char c; @@ -164,19 +147,18 @@ static int ptrace_child(void *arg) if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ perror("ptrace"); - _exit(1); + os_kill_process(pid, 0); } os_stop_process(pid); _exit(os_getpid() == pid); } -void __init check_ptrace(void) +static int start_ptraced_child(void **stack_out) { void *stack; unsigned long sp; - int status, pid, n, syscall; - - printk("Checking that ptrace can change system call numbers..."); + int pid, n, status; + stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(stack == MAP_FAILED) @@ -191,6 +173,33 @@ void __init check_ptrace(void) if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) panic("check_ptrace : expected SIGSTOP, got status = %d", status); + + *stack_out = stack; + return(pid); +} + +static void stop_ptraced_child(int pid, void *stack, int exitcode) +{ + int status, n; + + if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) + panic("check_ptrace : ptrace failed, errno = %d", errno); + n = waitpid(pid, &status, 0); + if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) + panic("check_ptrace : child exited with status 0x%x", status); + + if(munmap(stack, PAGE_SIZE) < 0) + panic("check_ptrace : munmap failed, errno = %d", errno); +} + +void __init check_ptrace(void) +{ + void *stack; + int pid, syscall, n, status; + + printk("Checking that ptrace can change system call numbers..."); + pid = start_ptraced_child(&stack); + while(1){ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", @@ -213,23 +222,19 @@ void __init check_ptrace(void) break; } } - if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) - panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, 0); - if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - panic("check_ptrace : child exited with status 0x%x", status); - - if(munmap(stack, PAGE_SIZE) < 0) - panic("check_ptrace : munmap failed, errno = %d", errno); + stop_ptraced_child(pid, stack, 0); printk("OK\n"); } int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) { jmp_buf buf; + int n; *jmp_ptr = &buf; - if(setjmp(buf)) return(1); + n = setjmp(buf); + if(n != 0) + return(n); (*fn)(arg); return(0); } @@ -244,6 +249,41 @@ void forward_pending_sigio(int target) kill(target, SIGIO); } +int can_do_skas(void) +{ +#ifdef CONFIG_MODE_SKAS + struct ptrace_faultinfo fi; + void *stack; + int pid, n, ret = 1; + + printk("Checking for the skas3 patch in the host..."); + pid = start_ptraced_child(&stack); + + n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); + if(n < 0){ + if(errno == EIO) + printk("not found\n"); + else printk("No (unexpected errno - %d)\n", errno); + ret = 0; + } + else printk("found\n"); + + init_registers(pid); + stop_ptraced_child(pid, stack, 1); + + printk("Checking for /proc/mm..."); + if(access("/proc/mm", W_OK)){ + printk("not found\n"); + ret = 0; + } + else printk("found\n"); + + return(ret); +#else + return(0); +#endif +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 1588e175b4db..faf8609ceaf8 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -40,6 +40,9 @@ #include "sigcontext.h" #include "2_5compat.h" #include "os.h" +#include "mode.h" +#include "mode_kern.h" +#include "choose-mode.h" /* This is a per-cpu array. A processor only modifies its entry and it only * cares about its entry, so it's OK if another processor is modifying its @@ -64,26 +67,11 @@ struct task_struct *get_task(int pid, int require) return(ret); } -int is_valid_pid(int pid) -{ - struct task_struct *task; - - read_lock(&tasklist_lock); - for_each_process(task){ - if(task->thread.extern_pid == pid){ - read_unlock(&tasklist_lock); - return(1); - } - } - read_unlock(&tasklist_lock); - return(0); -} - int external_pid(void *t) { struct task_struct *task = t ? t : current; - return(task->thread.extern_pid); + return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task)); } int pid_to_processor_id(int pid) @@ -101,37 +89,6 @@ void free_stack(unsigned long stack, int order) free_pages(stack, order); } -void set_init_pid(int pid) -{ - int err; - - init_task.thread.extern_pid = pid; - err = os_pipe(init_task.thread.switch_pipe, 1, 1); - if(err) panic("Can't create switch pipe for init_task, errno = %d", - err); -} - -int set_user_mode(void *t) -{ - struct task_struct *task; - - task = t ? t : current; - if(task->thread.tracing) return(1); - task->thread.request.op = OP_TRACE_ON; - os_usr1_process(os_getpid()); - return(0); -} - -void set_tracing(void *task, int tracing) -{ - ((struct task_struct *) task)->thread.tracing = tracing; -} - -int is_tracing(void *t) -{ - return (((struct task_struct *) t)->thread.tracing); -} - unsigned long alloc_stack(int order, int atomic) { unsigned long page; @@ -144,53 +101,13 @@ unsigned long alloc_stack(int order, int atomic) return(page); } -extern void schedule_tail(struct task_struct *prev); - -static void new_thread_handler(int sig) -{ - int (*fn)(void *); - void *arg; - - fn = current->thread.request.u.thread.proc; - arg = current->thread.request.u.thread.arg; - current->thread.regs.regs.sc = (void *) (&sig + 1); - suspend_new_thread(current->thread.switch_pipe[0]); - - block_signals(); -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif - enable_timer(); - free_page(current->thread.temp_stack); - set_cmdline("(kernel thread)"); - force_flush_all(); - - current->thread.prev_sched = NULL; - change_sig(SIGUSR1, 1); - change_sig(SIGVTALRM, 1); - change_sig(SIGPROF, 1); - unblock_signals(); - if(!run_kernel_thread(fn, arg, ¤t->thread.jmp)) - do_exit(0); -} - -static int new_thread_proc(void *stack) -{ - change_sig(SIGIO, 0); - change_sig(SIGVTALRM, 0); - change_sig(SIGPROF, 0); - init_new_thread(stack, new_thread_handler); - os_usr1_process(os_getpid()); - return(0); -} - int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct task_struct *p; current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL); + p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL); if(IS_ERR(p)) panic("do_fork failed in kernel_thread"); return(p->pid); } @@ -208,83 +125,13 @@ void set_current(void *t) struct task_struct *task = t; cpu_tasks[task->thread_info->cpu] = ((struct cpu_task) - { task->thread.extern_pid, task }); + { external_pid(task), task }); } void *switch_to(void *prev, void *next, void *last) { - struct task_struct *from, *to; - unsigned long flags; - int vtalrm, alrm, prof, err, cpu; - char c; - /* jailing and SMP are incompatible, so this doesn't need to be - * made per-cpu - */ - static int reading; - - from = prev; - to = next; - - to->thread.prev_sched = from; - - cpu = from->thread_info->cpu; - if(cpu == 0) - forward_interrupts(to->thread.extern_pid); -#ifdef CONFIG_SMP - forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.extern_pid); -#endif - local_irq_save(flags); - - vtalrm = change_sig(SIGVTALRM, 0); - alrm = change_sig(SIGALRM, 0); - prof = change_sig(SIGPROF, 0); - - forward_pending_sigio(to->thread.extern_pid); - - c = 0; - set_current(to); - - reading = 0; - err = os_write_file(to->thread.switch_pipe[1], &c, sizeof(c)); - if(err != sizeof(c)) - panic("write of switch_pipe failed, errno = %d", -err); - - reading = 1; - if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) - os_kill_process(os_getpid()); - - err = os_read_file(from->thread.switch_pipe[0], &c, sizeof(c)); - if(err != sizeof(c)) - panic("read of switch_pipe failed, errno = %d", -err); - - /* This works around a nasty race with 'jail'. If we are switching - * between two threads of a threaded app and the incoming process - * runs before the outgoing process reaches the read, and it makes - * it all the way out to userspace, then it will have write-protected - * the outgoing process stack. Then, when the outgoing process - * returns from the write, it will segfault because it can no longer - * write its own stack. So, in order to avoid that, the incoming - * thread sits in a loop yielding until 'reading' is set. This - * isn't entirely safe, since there may be a reschedule from a timer - * happening between setting 'reading' and sleeping in read. But, - * it should get a whole quantum in which to reach the read and sleep, - * which should be enough. - */ - - if(jail){ - while(!reading) sched_yield(); - } - - change_sig(SIGVTALRM, vtalrm); - change_sig(SIGALRM, alrm); - change_sig(SIGPROF, prof); - - arch_switch(); - - flush_tlb_all(); - local_irq_restore(flags); - - return(current->thread.prev_sched); + return(CHOOSE_MODE(switch_to_tt(prev, next), + switch_to_skas(prev, next))); } void interrupt_end(void) @@ -295,193 +142,37 @@ void interrupt_end(void) void release_thread(struct task_struct *task) { - os_kill_process(task->thread.extern_pid); + CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); } - + void exit_thread(void) { - close(current->thread.switch_pipe[0]); - close(current->thread.switch_pipe[1]); + CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); unprotect_stack((unsigned long) current->thread_info); } - -/* Signal masking - signals are blocked at the start of fork_tramp. They - * are re-enabled when finish_fork_handler is entered by fork_tramp hitting - * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, - * so it is blocked before it's called. They are re-enabled on sigreturn - * despite the fact that they were blocked when the SIGUSR1 was issued because - * copy_thread copies the parent's signcontext, including the signal mask - * onto the signal frame. - */ - -void finish_fork_handler(int sig) -{ - current->thread.regs.regs.sc = (void *) (&sig + 1); - suspend_new_thread(current->thread.switch_pipe[0]); - -#ifdef CONFIG_SMP - schedule_tail(NULL); -#endif - enable_timer(); - change_sig(SIGVTALRM, 1); - force_flush_all(); - if(current->mm != current->parent->mm) - protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); - task_protections((unsigned long) current->thread_info); - - current->thread.prev_sched = NULL; - - free_page(current->thread.temp_stack); - change_sig(SIGUSR1, 0); - set_user_mode(current); -} - + void *get_current(void) { return(current); } -/* This sigusr1 business works around a bug in gcc's -pg support. - * Normally a procedure's mcount call comes after esp has been copied to - * ebp and the new frame is constructed. With procedures with no locals, - * the mcount comes before, as the first thing that the procedure does. - * When that procedure is main for a thread, ebp comes in as NULL. So, - * when mcount dereferences it, it segfaults. So, UML works around this - * by adding a non-optimizable local to the various trampolines, fork_tramp - * and outer_tramp below, and exec_tramp. - */ - -static int sigusr1 = SIGUSR1; - -int fork_tramp(void *stack) -{ - int sig = sigusr1; - - change_sig(SIGIO, 0); - change_sig(SIGVTALRM, 0); - change_sig(SIGPROF, 0); - init_new_thread(stack, finish_fork_handler); - - kill(os_getpid(), sig); - return(0); -} - int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { - int new_pid, err; - unsigned long stack; - int (*tramp)(void *); - p->thread = (struct thread_struct) INIT_THREAD; p->thread.kernel_stack = (unsigned long) p->thread_info + 2 * PAGE_SIZE; - - if(current->thread.forking) - tramp = fork_tramp; - else { - tramp = new_thread_proc; - p->thread.request.u.thread = current->thread.request.u.thread; - } - - err = os_pipe(p->thread.switch_pipe, 1, 1); - if(err){ - printk("copy_thread : pipe failed, errno = %d\n", -err); - return(err); - } - - stack = alloc_stack(0, 0); - if(stack == 0){ - printk(KERN_ERR "copy_thread : failed to allocate " - "temporary stack\n"); - return(-ENOMEM); - } - - clone_flags &= CLONE_VM; - p->thread.temp_stack = stack; - new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, - clone_flags, tramp); - if(new_pid < 0){ - printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", - -new_pid); - return(new_pid); - } - - if(current->thread.forking){ - sc_to_sc(p->thread.regs.regs.sc, current->thread.regs.regs.sc); - PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0); - if(sp != 0) PT_REGS_SP(&p->thread.regs) = sp; - } - p->thread.extern_pid = new_pid; - - current->thread.request.op = OP_FORK; - current->thread.request.u.fork.pid = new_pid; - os_usr1_process(os_getpid()); - return(0); -} - -void tracing_reboot(void) -{ - current->thread.request.op = OP_REBOOT; - os_usr1_process(os_getpid()); + return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, + clone_flags, sp, stack_top, p, regs)); } -void tracing_halt(void) +void initial_thread_cb(void (*proc)(void *), void *arg) { - current->thread.request.op = OP_HALT; - os_usr1_process(os_getpid()); + CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, + arg); } - -void tracing_cb(void (*proc)(void *), void *arg) -{ - if(os_getpid() == tracing_pid){ - (*proc)(arg); - } - else { - current->thread.request.op = OP_CB; - current->thread.request.u.cb.proc = proc; - current->thread.request.u.cb.arg = arg; - os_usr1_process(os_getpid()); - } -} - -int do_proc_op(void *t, int proc_id) -{ - struct task_struct *task; - struct thread_struct *thread; - int op, pid; - - task = t; - thread = &task->thread; - op = thread->request.op; - switch(op){ - case OP_NONE: - case OP_TRACE_ON: - break; - case OP_EXEC: - pid = thread->request.u.exec.pid; - do_exec(thread->extern_pid, pid); - thread->extern_pid = pid; - cpu_tasks[task->thread_info->cpu].pid = pid; - break; - case OP_FORK: - attach_process(thread->request.u.fork.pid); - break; - case OP_CB: - (*thread->request.u.cb.proc)(thread->request.u.cb.arg); - break; - case OP_REBOOT: - case OP_HALT: - break; - default: - tracer_panic("Bad op in do_proc_op"); - break; - } - thread->request.op = OP_NONE; - return(op); -} - + unsigned long stack_sp(unsigned long page) { return(page + PAGE_SIZE - sizeof(void *)); @@ -518,7 +209,7 @@ void default_idle(void) void cpu_idle(void) { - default_idle(); + CHOOSE_MODE(init_idle_tt(), init_idle_skas()); } int page_size(void) @@ -531,21 +222,25 @@ int page_mask(void) return(PAGE_MASK); } -unsigned long um_virt_to_phys(void *t, unsigned long addr) +void *um_virt_to_phys(struct task_struct *task, unsigned long addr, + pte_t *pte_out) { - struct task_struct *task; pgd_t *pgd; pmd_t *pmd; pte_t *pte; - task = t; - if(task->mm == NULL) return(0xffffffff); + if(task->mm == NULL) + return(ERR_PTR(-EINVAL)); pgd = pgd_offset(task->mm, addr); pmd = pmd_offset(pgd, addr); - if(!pmd_present(*pmd)) return(0xffffffff); + if(!pmd_present(*pmd)) + return(ERR_PTR(-EINVAL)); pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte)) return(0xffffffff); - return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); + if(!pte_present(*pte)) + return(ERR_PTR(-EINVAL)); + if(pte_out != NULL) + *pte_out = *pte; + return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); } char *current_cmd(void) @@ -553,8 +248,8 @@ char *current_cmd(void) #if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM) return("(Unknown)"); #else - unsigned long addr = um_virt_to_phys(current, current->mm->arg_start); - return addr == 0xffffffff? "(Unknown)": __va(addr); + void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL); + return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr); #endif } @@ -602,22 +297,6 @@ unsigned long get_fault_addr(void) EXPORT_SYMBOL(get_fault_addr); -void clear_singlestep(void *t) -{ - struct task_struct *task = (struct task_struct *) t; - - task->ptrace &= ~PT_DTRACE; -} - -int singlestepping(void *t) -{ - struct task_struct *task = (struct task_struct *) t; - - if(task->thread.singlestep_syscall) - return(0); - return(task->ptrace & PT_DTRACE); -} - void not_implemented(void) { printk(KERN_DEBUG "Something isn't implemented in here\n"); @@ -631,6 +310,7 @@ int user_context(unsigned long sp) } extern void remove_umid_dir(void); + __uml_exitcall(remove_umid_dir); extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; @@ -644,16 +324,6 @@ void do_uml_exitcalls(void) (*call)(); } -void *round_up(unsigned long addr) -{ - return(ROUND_UP(addr)); -} - -void *round_down(unsigned long addr) -{ - return(ROUND_DOWN(addr)); -} - char *uml_strdup(char *string) { char *new; @@ -664,82 +334,6 @@ char *uml_strdup(char *string) return(new); } -/* Changed by jail_setup, which is a setup */ -int jail = 0; - -int __init jail_setup(char *line, int *add) -{ - int ok = 1; - - if(jail) return(0); -#ifdef CONFIG_SMP - printf("'jail' may not used used in a kernel with CONFIG_SMP " - "enabled\n"); - ok = 0; -#endif -#ifdef CONFIG_HOSTFS - printf("'jail' may not used used in a kernel with CONFIG_HOSTFS " - "enabled\n"); - ok = 0; -#endif -#ifdef CONFIG_MODULES - printf("'jail' may not used used in a kernel with CONFIG_MODULES " - "enabled\n"); - ok = 0; -#endif - if(!ok) exit(1); - - /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem. - * Removing it from the bounding set eliminates the ability of anything - * to acquire it, and thus read or write kernel memory. - */ - cap_lower(cap_bset, CAP_SYS_RAWIO); - jail = 1; - return(0); -} - -__uml_setup("jail", jail_setup, -"jail\n" -" Enables the protection of kernel memory from processes.\n\n" -); - -static void mprotect_kernel_mem(int w) -{ - unsigned long start, end; - - if(!jail || (current == &init_task)) return; - - start = (unsigned long) current->thread_info + PAGE_SIZE; - end = (unsigned long) current->thread_info + PAGE_SIZE * 4; - protect(uml_reserved, start - uml_reserved, 1, w, 1, 1); - protect(end, high_physmem - end, 1, w, 1, 1); - - start = (unsigned long) ROUND_DOWN(&_stext); - end = (unsigned long) ROUND_UP(&_etext); - protect(start, end - start, 1, w, 1, 1); - - start = (unsigned long) ROUND_DOWN(&_unprotected_end); - end = (unsigned long) ROUND_UP(&_edata); - protect(start, end - start, 1, w, 1, 1); - - start = (unsigned long) ROUND_DOWN(&__bss_start); - end = (unsigned long) ROUND_UP(brk_start); - protect(start, end - start, 1, w, 1, 1); - - mprotect_kernel_vm(w); -} - -/* No SMP problems since jailing and SMP are incompatible */ -void unprotect_kernel_mem(void) -{ - mprotect_kernel_mem(1); -} - -void protect_kernel_mem(void) -{ - mprotect_kernel_mem(0); -} - void *get_init_task(void) { return(&init_thread_union.thread_info.task); @@ -760,11 +354,6 @@ int clear_user_proc(void *buf, int size) return(clear_user(buf, size)); } -void set_thread_sc(void *sc) -{ - current->thread.regs.regs.sc = sc; -} - int smp_sigio_handler(void) { #ifdef CONFIG_SMP diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index d6dacf475c33..5a32974de6d8 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -9,6 +9,7 @@ #include "linux/smp_lock.h" #include "linux/security.h" #include "linux/ptrace.h" +#include "linux/proc_mm.h" #include "asm/ptrace.h" #include "asm/uaccess.h" #include "kern_util.h" @@ -21,6 +22,11 @@ void ptrace_disable(struct task_struct *child) { } +extern long do_mmap2(struct task_struct *task, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long pgoff); + int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -182,13 +188,13 @@ int sys_ptrace(long request, long pid, long addr, long data) #ifdef PTRACE_GETREGS case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned *)data, + if (!access_ok(VERIFY_WRITE, (unsigned long *)data, FRAME_SIZE_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) { - __put_user(getreg(child, i),(unsigned long *) data); + __put_user(getreg(child, i), (unsigned long *) data); data += sizeof(long); } ret = 0; @@ -232,6 +238,57 @@ int sys_ptrace(long request, long pid, long addr, long data) ret = set_fpxregs(data, child); break; #endif + case PTRACE_FAULTINFO: { + struct ptrace_faultinfo fault; + + fault = ((struct ptrace_faultinfo) + { .is_write = child->thread.err, + .addr = child->thread.cr2 }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); + if(ret) + break; + break; + } + case PTRACE_SIGPENDING: + ret = copy_to_user((unsigned long *) data, + &child->pending.signal, + sizeof(child->pending.signal)); + break; + + case PTRACE_LDT: { + struct ptrace_ldt ldt; + + if(copy_from_user(&ldt, (unsigned long *) data, + sizeof(ldt))){ + ret = -EIO; + break; + } + + /* This one is confusing, so just punt and return -EIO for + * now + */ + ret = -EIO; + break; + } +#ifdef CONFIG_PROC_MM + case PTRACE_SWITCH_MM: { + struct mm_struct *old = child->mm; + struct mm_struct *new = proc_mm_get_mm(data); + + if(IS_ERR(new)){ + ret = PTR_ERR(new); + break; + } + + atomic_inc(&new->mm_users); + child->mm = new; + child->active_mm = new; + mmput(old); + ret = 0; + break; + } +#endif default: ret = -EIO; break; diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 41b1faec8140..61d7a4e6000f 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -8,6 +8,8 @@ #include "kern_util.h" #include "kern.h" #include "os.h" +#include "mode.h" +#include "choose-mode.h" #ifdef CONFIG_SMP static void kill_idlers(int me) @@ -17,26 +19,17 @@ static void kill_idlers(int me) for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ p = idle_threads[i]; - if((p != NULL) && (p->thread.extern_pid != me)) - os_kill_process(p->thread.extern_pid); + if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) + os_kill_process(p->thread.mode.tt.extern_pid, 0); } } #endif static void kill_off_processes(void) { - struct task_struct *p; - int me; - - me = os_getpid(); - for_each_process(p){ - if(p->thread.extern_pid != me) - os_kill_process(p->thread.extern_pid); - } - if(init_task.thread.extern_pid != me) - os_kill_process(init_task.thread.extern_pid); + CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas()); #ifdef CONFIG_SMP - kill_idlers(me); + kill_idlers(os_getpid()); #endif } @@ -50,16 +43,14 @@ void machine_restart(char * __unused) { do_uml_exitcalls(); kill_off_processes(); - tracing_reboot(); - os_kill_process(os_getpid()); + CHOOSE_MODE(reboot_tt(), reboot_skas()); } void machine_power_off(void) { do_uml_exitcalls(); kill_off_processes(); - tracing_halt(); - os_kill_process(os_getpid()); + CHOOSE_MODE(halt_tt(), halt_skas()); } void machine_halt(void) diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 740608075b7c..da00ed4feede 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -39,14 +39,13 @@ struct openpty_arg { int err; }; -static int openpty_cb(void *arg) +static void openpty_cb(void *arg) { struct openpty_arg *info = arg; info->err = 0; if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) info->err = errno; - return(0); } void __init check_one_sigio(void (*proc)(int, int)) @@ -54,13 +53,9 @@ void __init check_one_sigio(void (*proc)(int, int)) struct sigaction old, new; struct termios tt; struct openpty_arg pty = { master : -1, slave : -1 }; - int master, slave, flags, err; + int master, slave, flags; - err = run_helper_thread(openpty_cb, &pty, CLONE_FILES, NULL, 2); - if(err < 0){ - printk("run_helper_thread failed, errno = %d\n", -err); - return; - } + initial_thread_cb(openpty_cb, &pty); if(pty.err){ printk("openpty failed, errno = %d\n", pty.err); return; @@ -387,7 +382,7 @@ void write_sigio_workaround(void) goto out_close2; write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, - CLONE_FILES, &stack, 0); + CLONE_FILES | CLONE_VM, &stack, 0); if(write_sigio_pid < 0) goto out_close2; diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index be60440cf012..f18ea0e1ac01 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -16,6 +16,7 @@ #include "linux/binfmts.h" #include "asm/signal.h" #include "asm/uaccess.h" +#include "asm/unistd.h" #include "user_util.h" #include "kern_util.h" #include "signal_kern.h" @@ -23,6 +24,7 @@ #include "kern.h" #include "frame_kern.h" #include "sigcontext.h" +#include "mode.h" EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); @@ -69,6 +71,9 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, ret = 0; switch(error){ + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = + do_no_restart_syscall; case -ERESTARTNOHAND: ret = -EINTR; break; @@ -160,6 +165,10 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); PT_REGS_RESTART_SYSCALL(regs); } + else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){ + PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; + PT_REGS_RESTART_SYSCALL(regs); + } } /* This closes a way to execute a system call on the host. If @@ -171,7 +180,7 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) */ if((current->ptrace & PT_DTRACE) && is_syscall(PT_REGS_IP(¤t->thread.regs))) - current->thread.singlestep_syscall = 1; + (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0); return(0); } @@ -228,6 +237,16 @@ int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) } } +static int copy_sc_from_user(struct pt_regs *to, void *from) +{ + int ret; + + ret = CHOOSE_MODE(copy_sc_from_user_tt(to->regs.mode.tt, from, + &signal_frame_sc.arch), + copy_sc_from_user_skas(&to->regs, from)); + return(ret); +} + int sys_sigreturn(struct pt_regs regs) { void *sc = sp_to_sc(PT_REGS_SP(®s)); @@ -241,8 +260,7 @@ int sys_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.sc, sc, - &signal_frame_sc.arch); + copy_sc_from_user(¤t->thread.regs, sc); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } @@ -257,8 +275,7 @@ int sys_rt_sigreturn(struct pt_regs regs) sigdelsetmask(¤t->blocked, ~_BLOCKABLE); recalc_sigpending(); spin_unlock_irq(¤t->sig->siglock); - copy_sc_from_user(current->thread.regs.regs.sc, sc, - &signal_frame_sc.arch); + copy_sc_from_user(¤t->thread.regs, sc); return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); } diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c index 2ef64a89e014..52cfd60a1433 100644 --- a/arch/um/kernel/signal_user.c +++ b/arch/um/kernel/signal_user.c @@ -21,13 +21,12 @@ void set_sigstack(void *sig_stack, int size) { - stack_t stack; + stack_t stack = ((stack_t) { .ss_flags = 0, + .ss_sp = (__ptr_t) sig_stack, + .ss_size = size - sizeof(void *) }); - stack.ss_sp = (__ptr_t) sig_stack; - stack.ss_flags = 0; - stack.ss_size = size - sizeof(void *); if(sigaltstack(&stack, NULL) != 0) - panic("sigaltstack failed"); + panic("enabling signal stack failed, errno = %d\n", errno); } void set_handler(int sig, void (*handler)(int), int flags, ...) diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile new file mode 100644 index 000000000000..72c79956f6a6 --- /dev/null +++ b/arch/um/kernel/skas/Makefile @@ -0,0 +1,24 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ + process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \ + sys-$(SUBARCH)/ + +USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +include/skas_ptregs.h : util/mk_ptregs + util/mk_ptregs > $@ + +util/mk_ptregs : + $(MAKE) -C util + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean : + $(MAKE) -C util clean + $(RM) -f include/skas_ptregs.h diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c new file mode 100644 index 000000000000..49356d26ac28 --- /dev/null +++ b/arch/um/kernel/skas/exec_kern.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "asm/current.h" +#include "asm/page.h" +#include "asm/signal.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "asm/mmu_context.h" +#include "tlb.h" +#include "skas.h" +#include "mmu.h" +#include "os.h" + +void flush_thread_skas(void) +{ + force_flush_all(); + switch_mm_skas(current->mm->context.skas.mm_fd); +} + +void start_thread_skas(struct pt_regs *regs, unsigned long eip, + unsigned long esp) +{ + set_fs(USER_DS); + PT_REGS_IP(regs) = eip; + PT_REGS_SP(regs) = esp; +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/exec_user.c b/arch/um/kernel/skas/exec_user.c new file mode 100644 index 000000000000..c9942b6fc79b --- /dev/null +++ b/arch/um/kernel/skas/exec_user.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <errno.h> +#include <signal.h> +#include <sched.h> +#include <sys/wait.h> +#include <sys/ptrace.h> +#include "user.h" +#include "kern_util.h" +#include "os.h" +#include "time_user.h" + +static int user_thread_tramp(void *arg) +{ + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) + panic("user_thread_tramp - PTRACE_TRACEME failed, " + "errno = %d\n", errno); + enable_timer(); + os_stop_process(os_getpid()); + return(0); +} + +int user_thread(unsigned long stack, int flags) +{ + int pid, status; + + pid = clone(user_thread_tramp, (void *) stack_sp(stack), + flags | CLONE_FILES | SIGCHLD, NULL); + if(pid < 0){ + printk("user_thread - clone failed, errno = %d\n", errno); + return(pid); + } + + if(waitpid(pid, &status, WUNTRACED) < 0){ + printk("user_thread - waitpid failed, errno = %d\n", errno); + return(-errno); + } + + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){ + printk("user_thread - trampoline didn't stop, status = %d\n", + status); + return(-EINVAL); + } + + return(pid); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/mmu.h b/arch/um/kernel/skas/include/mmu.h new file mode 100644 index 000000000000..cfbc062bd9dc --- /dev/null +++ b/arch/um/kernel/skas/include/mmu.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_MMU_H +#define __SKAS_MMU_H + +#include "linux/list.h" +#include "linux/spinlock.h" + +struct mmu_context_skas { + int mm_fd; +}; + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h new file mode 100644 index 000000000000..09cadc99edc5 --- /dev/null +++ b/arch/um/kernel/skas/include/mode.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_SKAS_H__ +#define __MODE_SKAS_H__ + +extern unsigned long exec_regs[]; +extern unsigned long exec_fp_regs[]; +extern unsigned long exec_fpx_regs[]; +extern int have_fpx_regs; + +extern void user_time_init_skas(void); +extern int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr); +extern int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs, + unsigned long fault_addr, int fault_type); +extern void sig_handler_common_skas(int sig, struct sigcontext *sc); +extern void halt_skas(void); +extern void reboot_skas(void); +extern void kill_off_processes_skas(void); + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/mode_kern.h b/arch/um/kernel/skas/include/mode_kern.h new file mode 100644 index 000000000000..e4b472ac7d2d --- /dev/null +++ b/arch/um/kernel/skas/include/mode_kern.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_MODE_KERN_H__ +#define __SKAS_MODE_KERN_H__ + +#include "linux/sched.h" +#include "asm/page.h" +#include "asm/ptrace.h" + +extern void flush_thread_skas(void); +extern void *switch_to_skas(void *prev, void *next); +extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, + unsigned long esp); +extern int copy_thread_skas(int nr, unsigned long clone_flags, + unsigned long sp, unsigned long stack_top, + struct task_struct *p, struct pt_regs *regs); +extern void release_thread_skas(struct task_struct *task); +extern void exit_thread_skas(void); +extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); +extern void init_idle_skas(void); +extern void flush_tlb_kernel_vm_skas(void); +extern void __flush_tlb_one_skas(unsigned long addr); +extern void flush_tlb_range_skas(struct vm_area_struct *vma, + unsigned long start, unsigned long end); +extern void flush_tlb_mm_skas(struct mm_struct *mm); +extern void force_flush_all_skas(void); +extern long execute_syscall_skas(void *r); +extern void before_mem_skas(unsigned long unused); +extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, + unsigned long *task_size_out); +extern int start_uml_skas(void); +extern struct page *arch_validate_skas(struct page *page, int mask, int order); +extern int external_pid_skas(struct task_struct *task); +extern int thread_pid_skas(struct task_struct *task); + +#define kmem_end_skas (host_task_size) + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/proc_mm.h b/arch/um/kernel/skas/include/proc_mm.h new file mode 100644 index 000000000000..cce61a679052 --- /dev/null +++ b/arch/um/kernel/skas/include/proc_mm.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_PROC_MM_H +#define __SKAS_PROC_MM_H + +#define MM_MMAP 54 +#define MM_MUNMAP 55 +#define MM_MPROTECT 56 +#define MM_COPY_SEGMENTS 57 + +struct mm_mmap { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +struct mm_munmap { + unsigned long addr; + unsigned long len; +}; + +struct mm_mprotect { + unsigned long addr; + unsigned long len; + unsigned int prot; +}; + +struct proc_mm_op { + int op; + union { + struct mm_mmap mmap; + struct mm_munmap munmap; + struct mm_mprotect mprotect; + int copy_segments; + } u; +}; + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/ptrace-skas.h b/arch/um/kernel/skas/include/ptrace-skas.h new file mode 100644 index 000000000000..f4ab3fb43339 --- /dev/null +++ b/arch/um/kernel/skas/include/ptrace-skas.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PTRACE_SKAS_H +#define __PTRACE_SKAS_H + +#include "uml-config.h" + +#ifdef CONFIG_MODE_SKAS + +#include "skas_ptregs.h" + +#define HOST_FRAME_SIZE 17 + +#define REGS_IP(r) ((r)[HOST_IP]) +#define REGS_SP(r) ((r)[HOST_SP]) +#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) +#define REGS_EAX(r) ((r)[HOST_EAX]) +#define REGS_EBX(r) ((r)[HOST_EBX]) +#define REGS_ECX(r) ((r)[HOST_ECX]) +#define REGS_EDX(r) ((r)[HOST_EDX]) +#define REGS_ESI(r) ((r)[HOST_ESI]) +#define REGS_EDI(r) ((r)[HOST_EDI]) +#define REGS_EBP(r) ((r)[HOST_EBP]) +#define REGS_CS(r) ((r)[HOST_CS]) +#define REGS_SS(r) ((r)[HOST_SS]) +#define REGS_DS(r) ((r)[HOST_DS]) +#define REGS_ES(r) ((r)[HOST_ES]) +#define REGS_FS(r) ((r)[HOST_FS]) +#define REGS_GS(r) ((r)[HOST_GS]) + +#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) + +#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) + +#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) + +#define REGS_FAULT_ADDR(r) ((r)->fault_addr) + +#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) + +#endif + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h new file mode 100644 index 000000000000..e733b0c87448 --- /dev/null +++ b/arch/um/kernel/skas/include/skas.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_H +#define __SKAS_H + +#include "sysdep/ptrace.h" + +extern int userspace_pid; + +extern void switch_threads(void *me, void *next); +extern void thread_wait(void *sw, void *fb); +extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, + void (*handler)(int)); +extern int start_idle_thread(void *stack, void *switch_buf_ptr, + void **fork_buf_ptr); +extern int user_thread(unsigned long stack, int flags); +extern void userspace(struct uml_pt_regs *regs); +extern void new_thread_proc(void *stack, void (*handler)(int sig)); +extern void remove_sigstack(void); +extern void new_thread_handler(int sig); +extern void handle_syscall(struct uml_pt_regs *regs); +extern void map(int fd, unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); +extern int unmap(int fd, void *addr, int len); +extern int protect(int fd, unsigned long addr, unsigned long len, + int r, int w, int x, int must_succeed); +extern void user_signal(int sig, struct uml_pt_regs *regs); +extern int singlestepping_skas(void); +extern int new_mm(int from); +extern void save_registers(struct uml_pt_regs *regs); +extern void restore_registers(struct uml_pt_regs *regs); +extern void start_userspace(void); +extern void init_registers(int pid); + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/skas_ptrace.h b/arch/um/kernel/skas/include/skas_ptrace.h new file mode 100644 index 000000000000..7cd983d88d51 --- /dev/null +++ b/arch/um/kernel/skas/include/skas_ptrace.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_PTRACE_H +#define __SKAS_PTRACE_H + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#define PTRACE_FAULTINFO 52 +#define PTRACE_SIGPENDING 53 +#define PTRACE_LDT 54 +#define PTRACE_SWITCH_MM 55 + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h new file mode 100644 index 000000000000..df408e12d933 --- /dev/null +++ b/arch/um/kernel/skas/include/uaccess.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_UACCESS_H +#define __SKAS_UACCESS_H + +#include "linux/string.h" +#include "linux/sched.h" +#include "linux/err.h" +#include "asm/processor.h" +#include "asm/pgtable.h" +#include "asm/errno.h" +#include "asm/current.h" +#include "asm/a.out.h" +#include "kern_util.h" + +#define access_ok_skas(type, addr, size) \ + ((segment_eq(get_fs(), KERNEL_DS)) || \ + (((unsigned long) (addr) < TASK_SIZE) && \ + ((unsigned long) (addr) + (size) < TASK_SIZE))) + +static inline int verify_area_skas(int type, const void * addr, + unsigned long size) +{ + return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); +} + +extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, + pte_t *pte_out); + +static inline unsigned long maybe_map(unsigned long virt, int is_write) +{ + pte_t pte; + + void *phys = um_virt_to_phys(current, virt, &pte); + int dummy_code; + + if(IS_ERR(phys) || (is_write && !pte_write(pte))){ + if(handle_page_fault(virt, 0, is_write, 0, &dummy_code)) + return(0); + phys = um_virt_to_phys(current, virt, NULL); + } + return((unsigned long) __va((unsigned long) phys)); +} + +static inline int buffer_op(unsigned long addr, int len, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); + int remain = len, n; + + n = (*op)(addr, size, arg); + if(n != 0) + return(n < 0 ? remain : 0); + + addr += size; + remain -= size; + if(remain == 0) + return(0); + + while(addr < ((addr + remain) & PAGE_MASK)){ + n = (*op)(addr, PAGE_SIZE, arg); + if(n != 0) + return(n < 0 ? remain : 0); + + addr += PAGE_SIZE; + remain -= PAGE_SIZE; + } + if(remain == 0) + return(0); + + n = (*op)(addr, remain, arg); + if(n != 0) + return(n < 0 ? remain : 0); + return(0); +} + +static inline int copy_chunk_from_user(unsigned long from, int len, void *arg) +{ + unsigned long *to_ptr = arg, to = *to_ptr; + + from = maybe_map(from, 0); + if(from == 0) + return(-1); + + memcpy((void *) to, (void *) from, len); + *to_ptr += len; + return(0); +} + +static inline int copy_from_user_skas(void *to, const void *from, int n) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memcpy(to, from, n); + return(0); + } + + return(access_ok_skas(VERIFY_READ, from, n) ? + buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) : + n); +} + +static inline int copy_chunk_to_user(unsigned long to, int len, void *arg) +{ + unsigned long *from_ptr = arg, from = *from_ptr; + + to = maybe_map(to, 1); + if(to == 0) + return(-1); + + memcpy((void *) to, (void *) from, len); + *from_ptr += len; + return(0); +} + +static inline int copy_to_user_skas(void *to, const void *from, int n) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memcpy(to, from, n); + return(0); + } + + return(access_ok_skas(VERIFY_WRITE, to, n) ? + buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) : + n); +} + +static inline int strncpy_chunk_from_user(unsigned long from, int len, + void *arg) +{ + char **to_ptr = arg, *to = *to_ptr; + int n; + + from = maybe_map(from, 0); + if(from == 0) + return(-1); + + strncpy(to, (void *) from, len); + n = strnlen(to, len); + *to_ptr += n; + + if(n < len) + return(1); + return(0); +} + +static inline int strncpy_from_user_skas(char *dst, const char *src, int count) +{ + int n; + char *ptr = dst; + + if(segment_eq(get_fs(), KERNEL_DS)){ + strncpy(dst, src, count); + return(strnlen(dst, count)); + } + + if(!access_ok_skas(VERIFY_READ, src, 1)) + return(-EFAULT); + + n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user, + &ptr); + if(n != 0) + return(-EFAULT); + return(strnlen(dst, count)); +} + +static inline int clear_chunk(unsigned long addr, int len, void *unused) +{ + addr = maybe_map(addr, 1); + if(addr == 0) + return(-1); + + memset((void *) addr, 0, len); + return(0); +} + +static inline int __clear_user_skas(void *mem, int len) +{ + return(buffer_op((unsigned long) mem, len, clear_chunk, NULL)); +} + +static inline int clear_user_skas(void *mem, int len) +{ + if(segment_eq(get_fs(), KERNEL_DS)){ + memset(mem, 0, len); + return(0); + } + + return(access_ok_skas(VERIFY_WRITE, mem, len) ? + buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len); +} + +static inline int strnlen_chunk(unsigned long str, int len, void *arg) +{ + int *len_ptr = arg, n; + + str = maybe_map(str, 0); + if(str == 0) + return(-1); + + n = strnlen((void *) str, len); + *len_ptr += n; + + if(n < len) + return(1); + return(0); +} + +static inline int strnlen_user_skas(const void *str, int len) +{ + int count = 0, n; + + if(segment_eq(get_fs(), KERNEL_DS)) + return(strnlen(str, len) + 1); + + n = buffer_op((unsigned long) str, len, strnlen_chunk, &count); + if(n == 0) + return(count + 1); + return(-EFAULT); +} + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c new file mode 100644 index 000000000000..0968b583473a --- /dev/null +++ b/arch/um/kernel/skas/mem.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/mm.h" +#include "mem_user.h" + +unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, + unsigned long *task_size_out) +{ + /* Round up to the nearest 4M */ + unsigned long top = ROUND_4M((unsigned long) &arg); + + *host_size_out = top; + *task_size_out = top; + return(((unsigned long) set_task_sizes_skas) & ~0xffffff); +} + +struct page *arch_validate_skas(struct page *page, int mask, int order) +{ + return(page); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c new file mode 100644 index 000000000000..7d12cdd621ae --- /dev/null +++ b/arch/um/kernel/skas/mem_user.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <errno.h> +#include <sys/mman.h> +#include <sys/ptrace.h> +#include "mem_user.h" +#include "user.h" +#include "os.h" +#include "proc_mm.h" + +void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) +{ + struct proc_mm_op map; + struct mem_region *region; + int prot, n; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + region = phys_region(phys); + + map = ((struct proc_mm_op) { .op = MM_MMAP, + .u = + { .mmap = + { .addr = virt, + .len = len, + .prot = prot, + .flags = MAP_SHARED | + MAP_FIXED, + .fd = region->fd, + .offset = phys_offset(phys) + } } } ); + n = os_write_file(fd, (char *) &map, sizeof(map)); + if(n != sizeof(map)) + printk("map : /proc/mm map failed, errno = %d\n", errno); +} + +int unmap(int fd, void *addr, int len) +{ + struct proc_mm_op unmap; + int n; + + unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, + .u = + { .munmap = + { .addr = (unsigned long) addr, + .len = len } } } ); + n = os_write_file(fd, (char *) &unmap, sizeof(unmap)); + if((n != 0) && (n != sizeof(unmap))) + return(-errno); + return(0); +} + +int protect(int fd, unsigned long addr, unsigned long len, int r, int w, + int x, int must_succeed) +{ + struct proc_mm_op protect; + int prot, n; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + + protect = ((struct proc_mm_op) { .op = MM_MPROTECT, + .u = + { .mprotect = + { .addr = (unsigned long) addr, + .len = len, + .prot = prot } } } ); + + n = os_write_file(fd, (char *) &protect, sizeof(protect)); + if((n != 0) && (n != sizeof(protect))){ + if(must_succeed) + panic("protect failed, errno = %d", errno); + return(-errno); + } + return(0); +} + +void before_mem_skas(unsigned long unused) +{ +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c new file mode 100644 index 000000000000..5911cdd0c0b7 --- /dev/null +++ b/arch/um/kernel/skas/mmu.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/list.h" +#include "linux/spinlock.h" +#include "linux/slab.h" +#include "asm/current.h" +#include "asm/segment.h" +#include "asm/mmu.h" +#include "os.h" +#include "skas.h" + +int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) +{ + int from; + + if((current->mm != NULL) && (current->mm != &init_mm)) + from = current->mm->context.skas.mm_fd; + else from = -1; + + mm->context.skas.mm_fd = new_mm(from); + if(mm->context.skas.mm_fd < 0) + panic("init_new_context_skas - new_mm failed, errno = %d\n", + mm->context.skas.mm_fd); + + return(0); +} + +void destroy_context_skas(struct mm_struct *mm) +{ + os_close_file(mm->context.skas.mm_fd); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c new file mode 100644 index 000000000000..15a1fd345178 --- /dev/null +++ b/arch/um/kernel/skas/process.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <errno.h> +#include <signal.h> +#include <setjmp.h> +#include <sched.h> +#include <sys/wait.h> +#include <sys/ptrace.h> +#include <sys/mman.h> +#include <sys/user.h> +#include <asm/unistd.h> +#include "user.h" +#include "ptrace_user.h" +#include "time_user.h" +#include "sysdep/ptrace.h" +#include "user_util.h" +#include "kern_util.h" +#include "skas.h" +#include "skas_ptrace.h" +#include "sysdep/sigcontext.h" +#include "os.h" +#include "proc_mm.h" + +unsigned long exec_regs[FRAME_SIZE]; +unsigned long exec_fp_regs[HOST_FP_SIZE]; +unsigned long exec_fpx_regs[HOST_XFP_SIZE]; +int have_fpx_regs = 1; + +static void handle_segv(int pid) +{ + struct ptrace_faultinfo fault; + int err; + + err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); + if(err) + panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", + errno); + segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); +} + +static void handle_trap(int pid, struct uml_pt_regs *regs) +{ + int err, syscall_nr, status; + + syscall_nr = PT_SYSCALL_NR(regs->mode.skas.regs); + if(syscall_nr < 1){ + relay_signal(SIGTRAP, regs); + return; + } + UPT_SYSCALL_NR(regs) = syscall_nr; + + err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); + if(err < 0) + panic("handle_trap - nullifying syscall failed errno = %d\n", + errno); + + err = ptrace(PTRACE_SYSCALL, pid, 0, 0); + if(err < 0) + panic("handle_trap - continuing to end of syscall failed, " + "errno = %d\n", errno); + + err = waitpid(pid, &status, WUNTRACED); + if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + panic("handle_trap - failed to wait at end of syscall, " + "errno = %d, status = %d\n", errno, status); + + handle_syscall(regs); +} + +int userspace_pid; + +static int userspace_tramp(void *arg) +{ + init_new_thread_signals(0); + enable_timer(); + ptrace(PTRACE_TRACEME, 0, 0, 0); + os_stop_process(os_getpid()); +} + +void start_userspace(void) +{ + void *stack; + unsigned long sp; + int pid, status, n; + + stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if(stack == MAP_FAILED) + panic("start_userspace : mmap failed, errno = %d", errno); + sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); + + pid = clone(userspace_tramp, (void *) sp, + CLONE_FILES | CLONE_VM | SIGCHLD, NULL); + if(pid < 0) + panic("start_userspace : clone failed, errno = %d", errno); + + do { + n = waitpid(pid, &status, WUNTRACED); + if(n < 0) + panic("start_userspace : wait failed, errno = %d", + errno); + } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); + + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) + panic("start_userspace : expected SIGSTOP, got status = %d", + status); + + if(munmap(stack, PAGE_SIZE) < 0) + panic("start_userspace : munmap failed, errno = %d\n", errno); + + userspace_pid = pid; +} + +void userspace(struct uml_pt_regs *regs) +{ + int err, status, op; + + restore_registers(regs); + + err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0); + if(err) + panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", + errno); + while(1){ + err = waitpid(userspace_pid, &status, WUNTRACED); + if(err < 0) + panic("userspace - waitpid failed, errno = %d\n", + errno); + + regs->is_user = 1; + save_registers(regs); + + if(WIFSTOPPED(status)){ + switch(WSTOPSIG(status)){ + case SIGSEGV: + handle_segv(userspace_pid); + break; + case SIGTRAP: + handle_trap(userspace_pid, regs); + break; + case SIGIO: + case SIGVTALRM: + case SIGILL: + case SIGBUS: + case SIGFPE: + user_signal(WSTOPSIG(status), regs); + break; + default: + printk("userspace - child stopped with signal " + "%d\n", WSTOPSIG(status)); + } + interrupt_end(); + } + + restore_registers(regs); + + op = singlestepping_skas() ? PTRACE_SINGLESTEP : + PTRACE_SYSCALL; + err = ptrace(op, userspace_pid, 0, 0); + if(err) + panic("userspace - PTRACE_SYSCALL failed, " + "errno = %d\n", errno); + } +} + +void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, + void (*handler)(int)) +{ + jmp_buf switch_buf, fork_buf; + + *switch_buf_ptr = &switch_buf; + *fork_buf_ptr = &fork_buf; + + if(setjmp(fork_buf) == 0) + new_thread_proc(stack, handler); + + remove_sigstack(); +} + +void thread_wait(void *sw, void *fb) +{ + jmp_buf buf, **switch_buf = sw, *fork_buf; + + *switch_buf = &buf; + fork_buf = fb; + if(setjmp(buf) == 0) + longjmp(*fork_buf, 1); +} + +static int move_registers(int int_op, int fp_op, struct uml_pt_regs *regs, + unsigned long *fp_regs) +{ + if(ptrace(int_op, userspace_pid, 0, regs->mode.skas.regs) < 0) + return(-errno); + if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0) + return(-errno); + return(0); +} + +void save_registers(struct uml_pt_regs *regs) +{ + unsigned long *fp_regs; + int err, fp_op; + + if(have_fpx_regs){ + fp_op = PTRACE_GETFPXREGS; + fp_regs = regs->mode.skas.xfp; + } + else { + fp_op = PTRACE_GETFPREGS; + fp_regs = regs->mode.skas.fp; + } + + err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs); + if(err) + panic("save_registers - saving registers failed, errno = %d\n", + err); +} + +void restore_registers(struct uml_pt_regs *regs) +{ + unsigned long *fp_regs; + int err, fp_op; + + if(have_fpx_regs){ + fp_op = PTRACE_SETFPXREGS; + fp_regs = regs->mode.skas.xfp; + } + else { + fp_op = PTRACE_SETFPREGS; + fp_regs = regs->mode.skas.fp; + } + + err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs); + if(err) + panic("restore_registers - saving registers failed, " + "errno = %d\n", err); +} + +void switch_threads(void *me, void *next) +{ + jmp_buf my_buf, **me_ptr = me, *next_buf = next; + + *me_ptr = &my_buf; + if(setjmp(my_buf) == 0) + longjmp(*next_buf, 1); +} + +static jmp_buf initial_jmpbuf; + +/* XXX Make these percpu */ +static void (*cb_proc)(void *arg); +static void *cb_arg; +static jmp_buf *cb_back; + +int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) +{ + jmp_buf **switch_buf = switch_buf_ptr; + int n; + + *fork_buf_ptr = &initial_jmpbuf; + n = setjmp(initial_jmpbuf); + if(n == 0) + new_thread_proc((void *) stack, new_thread_handler); + else if(n == 1) + remove_sigstack(); + else if(n == 2){ + (*cb_proc)(cb_arg); + longjmp(*cb_back, 1); + } + else if(n == 3) + return(0); + else if(n == 4) + return(1); + longjmp(**switch_buf, 1); +} + +void remove_sigstack(void) +{ + stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, + .ss_sp = NULL, + .ss_size = 0 }); + + if(sigaltstack(&stack, NULL) != 0) + panic("disabling signal stack failed, errno = %d\n", errno); +} + +void initial_thread_cb_skas(void (*proc)(void *), void *arg) +{ + jmp_buf here; + + cb_proc = proc; + cb_arg = arg; + cb_back = &here; + if(setjmp(here) == 0) + longjmp(initial_jmpbuf, 2); + + cb_proc = NULL; + cb_arg = NULL; + cb_back = NULL; +} + +void halt_skas(void) +{ + block_signals(); + longjmp(initial_jmpbuf, 3); +} + +void reboot_skas(void) +{ + block_signals(); + longjmp(initial_jmpbuf, 4); +} + +int new_mm(int from) +{ + struct proc_mm_op copy; + int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0); + + if(fd < 0) + return(-errno); + + if(from != -1){ + copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, + .u = + { .copy_segments = from } } ); + n = os_write_file(fd, (char *) ©, sizeof(copy)); + if(n != sizeof(copy)) + printk("new_mm : /proc/mm copy_segments failed, " + "errno = %d\n", errno); + } + return(fd); +} + +void switch_mm_skas(int mm_fd) +{ + int err; + + err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd); + if(err) + panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", + errno); +} + +void kill_off_processes_skas(void) +{ + os_kill_process(userspace_pid, 1); +} + +void init_registers(int pid) +{ + int err; + + if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0) + panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", + errno); + + err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); + if(!err) + return; + + have_fpx_regs = 0; + if(errno != EIO) + panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", + errno); + + err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); + if(err) + panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", + errno); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c new file mode 100644 index 000000000000..ed17599d2c56 --- /dev/null +++ b/arch/um/kernel/skas/process_kern.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/slab.h" +#include "kern_util.h" +#include "time_user.h" +#include "signal_user.h" +#include "skas.h" +#include "os.h" +#include "user_util.h" +#include "tlb.h" +#include "frame.h" +#include "kern.h" +#include "mode.h" + +int singlestepping_skas(void) +{ + int ret = current->ptrace & PT_DTRACE; + + current->ptrace &= ~PT_DTRACE; + return(ret); +} + +void *switch_to_skas(void *prev, void *next) +{ + struct task_struct *from, *to; + + from = prev; + to = next; + + /* XXX need to check runqueues[cpu].idle */ + if(current->pid == 0) + switch_timers(0); + + to->thread.prev_sched = from; + set_current(to); + + switch_threads(&from->thread.mode.skas.switch_buf, + to->thread.mode.skas.switch_buf); + + if(current->pid == 0) + switch_timers(1); + + return(current->thread.prev_sched); +} + +extern void schedule_tail(struct task_struct *prev); + +void new_thread_handler(int sig) +{ + int (*fn)(void *), n; + void *arg; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + change_sig(SIGUSR1, 1); + thread_wait(¤t->thread.mode.skas.switch_buf, + current->thread.mode.skas.fork_buf); + +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + current->thread.prev_sched = NULL; + + n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); + if(n == 1) + userspace(¤t->thread.regs.regs); + else if(n == 2) + do_exit(0); +} + +void new_thread_proc(void *stack, void (*handler)(int sig)) +{ + init_new_thread_stack(stack, handler); + os_usr1_process(os_getpid()); +} + +void release_thread_skas(struct task_struct *task) +{ +} + +void exit_thread_skas(void) +{ +} + +void fork_handler(int sig) +{ + change_sig(SIGUSR1, 1); + thread_wait(¤t->thread.mode.skas.switch_buf, + current->thread.mode.skas.fork_buf); + + force_flush_all(); +#ifdef CONFIG_SMP + schedule_tail(current->thread.prev_sched); +#endif + current->thread.prev_sched = NULL; + unblock_signals(); + + userspace(¤t->thread.regs.regs); +} + +int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct * p, + struct pt_regs *regs) +{ + void (*handler)(int); + + if(current->thread.forking){ + memcpy(&p->thread.regs.regs.mode.skas, + ¤t->thread.regs.regs.mode.skas, + sizeof(p->thread.regs.regs.mode.skas)); + REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.mode.skas.regs, 0); + if(sp != 0) REGS_SP(p->thread.regs.regs.mode.skas.regs) = sp; + + handler = fork_handler; + } + else { + memcpy(p->thread.regs.regs.mode.skas.regs, exec_regs, + sizeof(p->thread.regs.regs.mode.skas.regs)); + memcpy(p->thread.regs.regs.mode.skas.fp, exec_fp_regs, + sizeof(p->thread.regs.regs.mode.skas.fp)); + memcpy(p->thread.regs.regs.mode.skas.xfp, exec_fpx_regs, + sizeof(p->thread.regs.regs.mode.skas.xfp)); + p->thread.request.u.thread = current->thread.request.u.thread; + handler = new_thread_handler; + } + + new_thread((void *) p->thread.kernel_stack, + &p->thread.mode.skas.switch_buf, + &p->thread.mode.skas.fork_buf, handler); + return(0); +} + +void init_idle_skas(void) +{ + cpu_tasks[current->thread_info->cpu].pid = os_getpid(); + default_idle(); +} + +extern void start_kernel(void); + +static int start_kernel_proc(void *unused) +{ + int pid; + + block_signals(); + pid = os_getpid(); + + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + cpu_online_map = 1; +#endif + start_kernel(); + return(0); +} + +int start_uml_skas(void) +{ + start_userspace(); + capture_signal_stack(); + + init_new_thread_signals(1); + idle_timer(); + + init_task.thread.request.u.thread.proc = start_kernel_proc; + init_task.thread.request.u.thread.arg = NULL; + return(start_idle_thread((void *) init_task.thread.kernel_stack, + &init_task.thread.mode.skas.switch_buf, + &init_task.thread.mode.skas.fork_buf)); +} + +int external_pid_skas(struct task_struct *task) +{ + return(userspace_pid); +} + +int thread_pid_skas(struct task_struct *task) +{ + return(userspace_pid); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/sys-i386/Makefile b/arch/um/kernel/skas/sys-i386/Makefile new file mode 100644 index 000000000000..2ad8271c604d --- /dev/null +++ b/arch/um/kernel/skas/sys-i386/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = sigcontext.o + +USER_OBJS = sigcontext.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean : diff --git a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c new file mode 100644 index 000000000000..07bb0ea0ed8a --- /dev/null +++ b/arch/um/kernel/skas/sys-i386/sigcontext.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <errno.h> +#include <asm/sigcontext.h> +#include <sys/ptrace.h> +#include <linux/ptrace.h> +#include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" +#include "kern_util.h" +#include "user.h" +#include "sigcontext.h" + +extern int userspace_pid; + +int copy_sc_from_user_skas(struct uml_pt_regs *regs, void *from_ptr) +{ + struct sigcontext sc, *from = from_ptr; + unsigned long fpregs[FP_FRAME_SIZE]; + int err; + + err = copy_from_user_proc(&sc, from, sizeof(sc)); + err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs)); + if(err) + return(err); + + regs->mode.skas.regs[GS] = sc.gs; + regs->mode.skas.regs[FS] = sc.fs; + regs->mode.skas.regs[ES] = sc.es; + regs->mode.skas.regs[DS] = sc.ds; + regs->mode.skas.regs[EDI] = sc.edi; + regs->mode.skas.regs[ESI] = sc.esi; + regs->mode.skas.regs[EBP] = sc.ebp; + regs->mode.skas.regs[UESP] = sc.esp; + regs->mode.skas.regs[EBX] = sc.ebx; + regs->mode.skas.regs[EDX] = sc.edx; + regs->mode.skas.regs[ECX] = sc.ecx; + regs->mode.skas.regs[EAX] = sc.eax; + regs->mode.skas.regs[EIP] = sc.eip; + regs->mode.skas.regs[CS] = sc.cs; + regs->mode.skas.regs[EFL] = sc.eflags; + regs->mode.skas.regs[UESP] = sc.esp_at_signal; + regs->mode.skas.regs[SS] = sc.ss; + regs->mode.skas.fault_addr = sc.cr2; + regs->mode.skas.fault_type = FAULT_WRITE(sc.err); + regs->mode.skas.trap_type = sc.trapno; + + err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs); + if(err < 0){ + printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " + "errno = %d\n", errno); + return(1); + } + + return(0); +} + +int copy_sc_to_user_skas(void *to_ptr, struct uml_pt_regs *regs, + unsigned long fault_addr, int fault_type) +{ + struct sigcontext sc, *to = to_ptr; + struct _fpstate *to_fp; + unsigned long fpregs[FP_FRAME_SIZE]; + int err; + + sc.gs = regs->mode.skas.regs[GS]; + sc.fs = regs->mode.skas.regs[FS]; + sc.es = regs->mode.skas.regs[ES]; + sc.ds = regs->mode.skas.regs[DS]; + sc.edi = regs->mode.skas.regs[EDI]; + sc.esi = regs->mode.skas.regs[ESI]; + sc.ebp = regs->mode.skas.regs[EBP]; + sc.esp = regs->mode.skas.regs[UESP]; + sc.ebx = regs->mode.skas.regs[EBX]; + sc.edx = regs->mode.skas.regs[EDX]; + sc.ecx = regs->mode.skas.regs[ECX]; + sc.eax = regs->mode.skas.regs[EAX]; + sc.eip = regs->mode.skas.regs[EIP]; + sc.cs = regs->mode.skas.regs[CS]; + sc.eflags = regs->mode.skas.regs[EFL]; + sc.esp_at_signal = regs->mode.skas.regs[UESP]; + sc.ss = regs->mode.skas.regs[SS]; + sc.cr2 = fault_addr; + sc.err = TO_SC_ERR(fault_type); + sc.trapno = regs->mode.skas.trap_type; + + err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs); + if(err < 0){ + printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " + "errno = %d\n", errno); + return(1); + } + to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to)); + sc.fpstate = to_fp; + + if(err) + return(err); + + return(copy_to_user_proc(to, &sc, sizeof(sc)) || + copy_to_user_proc(to_fp, fpregs, sizeof(fpregs))); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c new file mode 100644 index 000000000000..d870870db1ac --- /dev/null +++ b/arch/um/kernel/skas/syscall_kern.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sys.h" +#include "asm/errno.h" +#include "asm/unistd.h" +#include "asm/ptrace.h" +#include "asm/current.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +extern syscall_handler_t *sys_call_table[]; + +long execute_syscall_skas(void *r) +{ + struct pt_regs *regs = r; + long res; + int syscall; + + current->thread.nsyscalls++; + nsyscalls++; + syscall = regs->regs.syscall; + + if((syscall >= NR_syscalls) || (syscall < 0)) + res = -ENOSYS; + else res = EXECUTE_SYSCALL(syscall, regs); + + return(res); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c new file mode 100644 index 000000000000..4f43f5492163 --- /dev/null +++ b/arch/um/kernel/skas/syscall_user.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <signal.h> +#include "kern_util.h" +#include "syscall_user.h" +#include "sysdep/ptrace.h" +#include "sysdep/sigcontext.h" + +/* XXX Bogus */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 + +void handle_syscall(struct uml_pt_regs *regs) +{ + long result; + int index; + + host_to_regs(regs); + index = record_syscall_start(UPT_SYSCALL_NR(regs)); + + syscall_trace(); + result = execute_syscall(regs); + + REGS_SET_SYSCALL_RETURN(regs->mode.skas.regs, result); + if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || + (result == -ERESTARTNOINTR)) + do_signal(result); + + syscall_trace(); + record_syscall_end(index, result); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c new file mode 100644 index 000000000000..98091494b897 --- /dev/null +++ b/arch/um/kernel/skas/time.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <sys/signal.h> +#include <sys/time.h> +#include "time_user.h" +#include "process.h" +#include "user.h" + +void user_time_init_skas(void) +{ + if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR) + panic("Couldn't set SIGALRM handler"); + if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) + panic("Couldn't set SIGVTALRM handler"); + set_interval(ITIMER_VIRTUAL); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c new file mode 100644 index 000000000000..655d3cdee856 --- /dev/null +++ b/arch/um/kernel/skas/tlb.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/sched.h" +#include "linux/mm.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/mmu.h" +#include "user_util.h" +#include "mem_user.h" +#include "skas.h" +#include "os.h" + +static void fix_range(struct mm_struct *mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + pgd_t *npgd; + pmd_t *npmd; + pte_t *npte; + unsigned long addr; + int r, w, x, err, fd; + + if(mm == NULL) return; + fd = mm->context.skas.mm_fd; + for(addr = start_addr; addr < end_addr;){ + npgd = pgd_offset(mm, addr); + npmd = pmd_offset(npgd, addr); + if(pmd_present(*npmd)){ + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(force || pte_newpage(*npte)){ + err = unmap(fd, (void *) addr, PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*npte)) + map(fd, addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)){ + protect(fd, addr, PAGE_SIZE, r, w, x, 1); + } + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } + else { + if(force || pmd_newpage(*npmd)){ + err = unmap(fd, (void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pmd_mkuptodate(*npmd); + } + addr += PMD_SIZE; + } + } +} + +static void flush_kernel_vm_range(unsigned long start, unsigned long end) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long addr; + int updated = 0, err; + + mm = &init_mm; + for(addr = start_vm; addr < end_vm;){ + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + if(pmd_present(*pmd)){ + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*pte)) + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); + } + else if(pte_newprot(*pte)){ + updated = 1; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + } + addr += PAGE_SIZE; + + } + else { + if(pmd_newpage(*pmd)){ + updated = 1; + err = os_unmap_memory((void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr += PMD_SIZE; + } + } +} + +void flush_tlb_kernel_vm_skas(void) +{ + flush_kernel_vm_range(start_vm, end_vm); +} + +void __flush_tlb_one_skas(unsigned long addr) +{ + flush_kernel_vm_range(addr, addr + PAGE_SIZE); +} + +void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + if(vma->vm_mm == NULL) + flush_kernel_vm_range(start, end); + else fix_range(vma->vm_mm, start, end, 0); +} + +void flush_tlb_mm_skas(struct mm_struct *mm) +{ + if(mm == NULL) + flush_tlb_kernel_vm_skas(); + else fix_range(mm, 0, host_task_size, 0); +} + +void force_flush_all_skas(void) +{ + fix_range(current->mm, 0, host_task_size, 1); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c new file mode 100644 index 000000000000..e906e5a630cb --- /dev/null +++ b/arch/um/kernel/skas/trap_user.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <signal.h> +#include <errno.h> +#include <asm/sigcontext.h> +#include "sysdep/ptrace.h" +#include "signal_user.h" +#include "user_util.h" +#include "kern_util.h" +#include "task.h" +#include "sigcontext.h" + +void sig_handler_common_skas(int sig, struct sigcontext *sc) +{ + struct uml_pt_regs save_regs, *r; + struct signal_info *info; + int save_errno = errno; + + r = (struct uml_pt_regs *) TASK_REGS(get_current()); + save_regs = *r; + r->is_user = 0; + r->mode.skas.fault_addr = SC_FAULT_ADDR(sc); + r->mode.skas.fault_type = SC_FAULT_TYPE(sc); + r->mode.skas.trap_type = SC_TRAP_TYPE(sc); + + change_sig(SIGUSR1, 1); + info = &sig_info[sig]; + if(!info->is_irq) unblock_signals(); + + (*info->handler)(sig, r); + + *r = save_regs; + errno = save_errno; +} + +extern int missed_ticks[]; + +void user_signal(int sig, struct uml_pt_regs *regs) +{ + struct signal_info *info; + + if(sig == SIGVTALRM) + missed_ticks[cpu()]++; + regs->is_user = 1; + regs->mode.skas.fault_addr = 0; + regs->mode.skas.fault_type = 0; + regs->mode.skas.trap_type = 0; + info = &sig_info[sig]; + (*info->handler)(sig, regs); + + unblock_signals(); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile new file mode 100644 index 000000000000..e62dc253e895 --- /dev/null +++ b/arch/um/kernel/skas/util/Makefile @@ -0,0 +1,10 @@ +all: mk_ptregs + +mk_ptregs : mk_ptregs.o + $(CC) -o mk_ptregs mk_ptregs.o + +mk_ptregs.o : mk_ptregs.c + $(CC) -c $< + +clean : + $(RM) -f mk_ptregs *.o *~ diff --git a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c new file mode 100644 index 000000000000..658791017373 --- /dev/null +++ b/arch/um/kernel/skas/util/mk_ptregs.c @@ -0,0 +1,50 @@ +#include <asm/ptrace.h> +#include <asm/user.h> + +#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val)) + +int main(int argc, char **argv) +{ + printf("/* Automatically generated by " + "arch/um/kernel/skas/util/mk_ptregs */\n"); + printf("\n"); + printf("#ifndef __SKAS_PT_REGS_\n"); + printf("#define __SKAS_PT_REGS_\n"); + printf("\n"); + printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE); + printf("#define HOST_FP_SIZE %d\n", + sizeof(struct user_i387_struct) / sizeof(unsigned long)); + printf("#define HOST_XFP_SIZE %d\n", + sizeof(struct user_fxsr_struct) / sizeof(unsigned long)); + + PRINT_REG("IP", EIP); + PRINT_REG("SP", UESP); + PRINT_REG("EFLAGS", EFL); + PRINT_REG("EAX", EAX); + PRINT_REG("EBX", EBX); + PRINT_REG("ECX", ECX); + PRINT_REG("EDX", EDX); + PRINT_REG("ESI", ESI); + PRINT_REG("EDI", EDI); + PRINT_REG("EBP", EBP); + PRINT_REG("CS", CS); + PRINT_REG("SS", SS); + PRINT_REG("DS", DS); + PRINT_REG("FS", FS); + PRINT_REG("ES", ES); + PRINT_REG("GS", GS); + printf("\n"); + printf("#endif\n"); + return(0); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index c9d9b15789d1..3503ed13f59a 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -116,7 +116,8 @@ static int idle_proc(void *cpup) panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, -err); - activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid); + activate_ipi(cpu_data[cpu].ipi_pipe[0], + current->thread.mode.tt.extern_pid); wmb(); if (test_and_set_bit(cpu, &smp_callin_map)) { @@ -143,10 +144,12 @@ static struct task_struct *idle_thread(int cpu) if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); cpu_tasks[cpu] = ((struct cpu_task) - { .pid = new_task->thread.extern_pid, + { .pid = new_task->thread.mode.tt.extern_pid, .task = new_task } ); idle_threads[cpu] = new_task; - write(new_task->thread.switch_pipe[1], &c, sizeof(c)); + CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, + sizeof(c)), + ({ panic("skas mode doesn't support SMP"); })); return(new_task); } @@ -162,7 +165,8 @@ void smp_prepare_cpus(unsigned int maxcpus) err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid); + activate_ipi(cpu_data[0].ipi_pipe[0], + current->thread.mode.tt.extern_pid); for(cpu = 1; cpu < ncpus; cpu++){ printk("Booting processor %d...\n", cpu); diff --git a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c index f76c35dc568b..f54c2ae723b5 100644 --- a/arch/um/kernel/sys_call_table.c +++ b/arch/um/kernel/sys_call_table.c @@ -8,10 +8,12 @@ #include "linux/version.h" #include "linux/sys.h" #include "linux/swap.h" +#include "linux/sysctl.h" #include "asm/signal.h" #include "sysdep/syscalls.h" #include "kern_util.h" +extern syscall_handler_t sys_restart_syscall; extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_exit; extern syscall_handler_t sys_fork; @@ -125,10 +127,8 @@ extern syscall_handler_t sys_ni_syscall; extern syscall_handler_t sys_adjtimex; extern syscall_handler_t sys_mprotect; extern syscall_handler_t sys_sigprocmask; -extern syscall_handler_t sys_create_module; extern syscall_handler_t sys_init_module; extern syscall_handler_t sys_delete_module; -extern syscall_handler_t sys_get_kernel_syms; extern syscall_handler_t sys_quotactl; extern syscall_handler_t sys_getpgid; extern syscall_handler_t sys_fchdir; @@ -162,7 +162,6 @@ extern syscall_handler_t sys_mremap; extern syscall_handler_t sys_setresuid16; extern syscall_handler_t sys_getresuid16; extern syscall_handler_t sys_ni_syscall; -extern syscall_handler_t sys_query_module; extern syscall_handler_t sys_poll; extern syscall_handler_t sys_nfsservctl; extern syscall_handler_t sys_setresgid16; @@ -235,9 +234,10 @@ extern syscall_handler_t sys_epoll_create; extern syscall_handler_t sys_epoll_ctl; extern syscall_handler_t sys_epoll_wait; extern syscall_handler_t sys_remap_file_pages; +extern syscall_handler_t sys_set_tid_address; #if CONFIG_NFSD -#define NFSSERVCTL sys_nfsserctl +#define NFSSERVCTL sys_nfsservctl #else #define NFSSERVCTL sys_ni_syscall #endif @@ -246,7 +246,7 @@ extern syscall_handler_t um_mount; extern syscall_handler_t um_time; extern syscall_handler_t um_stime; -#define LAST_GENERIC_SYSCALL __NR_remap_file_pages +#define LAST_GENERIC_SYSCALL __NR_set_tid_address #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL #define LAST_SYSCALL LAST_GENERIC_SYSCALL @@ -255,7 +255,7 @@ extern syscall_handler_t um_stime; #endif syscall_handler_t *sys_call_table[] = { - [ 0 ] = sys_ni_syscall, + [ __NR_restart_syscall ] = sys_restart_syscall, [ __NR_exit ] = sys_exit, [ __NR_fork ] = sys_fork, [ __NR_read ] = (syscall_handler_t *) sys_read, @@ -384,10 +384,10 @@ syscall_handler_t *sys_call_table[] = { [ __NR_adjtimex ] = sys_adjtimex, [ __NR_mprotect ] = sys_mprotect, [ __NR_sigprocmask ] = sys_sigprocmask, - [ __NR_create_module ] = sys_create_module, + [ __NR_create_module ] = sys_ni_syscall, [ __NR_init_module ] = sys_init_module, [ __NR_delete_module ] = sys_delete_module, - [ __NR_get_kernel_syms ] = sys_get_kernel_syms, + [ __NR_get_kernel_syms ] = sys_ni_syscall, [ __NR_quotactl ] = sys_quotactl, [ __NR_getpgid ] = sys_getpgid, [ __NR_fchdir ] = sys_fchdir, @@ -424,7 +424,7 @@ syscall_handler_t *sys_call_table[] = { [ __NR_setresuid ] = sys_setresuid16, [ __NR_getresuid ] = sys_getresuid16, [ __NR_vm86 ] = sys_ni_syscall, - [ __NR_query_module ] = sys_query_module, + [ __NR_query_module ] = sys_ni_syscall, [ __NR_poll ] = sys_poll, [ __NR_nfsservctl ] = NFSSERVCTL, [ __NR_setresgid ] = sys_setresgid16, @@ -489,6 +489,7 @@ syscall_handler_t *sys_call_table[] = { [ __NR_epoll_ctl ] = sys_epoll_ctl, [ __NR_epoll_wait ] = sys_epoll_wait, [ __NR_remap_file_pages ] = sys_remap_file_pages, + [ __NR_set_tid_address ] = sys_set_tid_address, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index b15340a6b837..bcebea22c940 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -20,6 +20,11 @@ #include "kern_util.h" #include "user_util.h" #include "sysdep/syscalls.h" +#include "mode_kern.h" +#include "choose-mode.h" + +/* Unlocked, I don't care if this is a bit off */ +int nsyscalls = 0; long um_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void * data) @@ -33,7 +38,7 @@ long sys_fork(void) struct task_struct *p; current->thread.forking = 1; - p = do_fork(SIGCHLD, 0, NULL, 0, NULL); + p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; return(IS_ERR(p) ? PTR_ERR(p) : p->pid); } @@ -43,7 +48,7 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp) struct task_struct *p; current->thread.forking = 1; - p = do_fork(clone_flags, newsp, NULL, 0, NULL); + p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL); current->thread.forking = 0; return(IS_ERR(p) ? PTR_ERR(p) : p->pid); } @@ -53,7 +58,7 @@ long sys_vfork(void) struct task_struct *p; current->thread.forking = 1; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL); current->thread.forking = 0; return(IS_ERR(p) ? PTR_ERR(p) : p->pid); } @@ -182,7 +187,11 @@ int sys_ipc (uint call, int first, int second, switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + return sys_semtimedop(first, (struct sembuf *) ptr, second, + NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf *) ptr, second, + (const struct timespec *) fifth); case SEMGET: return sys_semget (first, second, third); case SEMCTL: { @@ -298,122 +307,9 @@ int sys_sigaltstack(const stack_t *uss, stack_t *uoss) return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); } -static inline int check_area(void *ptr, int size) -{ - return(verify_area(VERIFY_WRITE, ptr, size)); -} - -static int check_readlink(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], regs->regs.args[2])); -} - -static int check_utime(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], - sizeof(struct utimbuf))); -} - -static int check_oldstat(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], - sizeof(struct __old_kernel_stat))); -} - -static int check_stat(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], sizeof(struct stat))); -} - -static int check_stat64(struct pt_regs *regs) -{ - return(check_area((void *) regs->regs.args[1], sizeof(struct stat64))); -} - -struct bogus { - int kernel_ds; - int (*check_params)(struct pt_regs *); -}; - -struct bogus this_is_bogus[256] = { - [ __NR_mknod ] = { 1, NULL }, - [ __NR_mkdir ] = { 1, NULL }, - [ __NR_rmdir ] = { 1, NULL }, - [ __NR_unlink ] = { 1, NULL }, - [ __NR_symlink ] = { 1, NULL }, - [ __NR_link ] = { 1, NULL }, - [ __NR_rename ] = { 1, NULL }, - [ __NR_umount ] = { 1, NULL }, - [ __NR_mount ] = { 1, NULL }, - [ __NR_pivot_root ] = { 1, NULL }, - [ __NR_chdir ] = { 1, NULL }, - [ __NR_chroot ] = { 1, NULL }, - [ __NR_open ] = { 1, NULL }, - [ __NR_quotactl ] = { 1, NULL }, - [ __NR_sysfs ] = { 1, NULL }, - [ __NR_readlink ] = { 1, check_readlink }, - [ __NR_acct ] = { 1, NULL }, - [ __NR_execve ] = { 1, NULL }, - [ __NR_uselib ] = { 1, NULL }, - [ __NR_statfs ] = { 1, NULL }, - [ __NR_truncate ] = { 1, NULL }, - [ __NR_access ] = { 1, NULL }, - [ __NR_chmod ] = { 1, NULL }, - [ __NR_chown ] = { 1, NULL }, - [ __NR_lchown ] = { 1, NULL }, - [ __NR_utime ] = { 1, check_utime }, - [ __NR_oldlstat ] = { 1, check_oldstat }, - [ __NR_oldstat ] = { 1, check_oldstat }, - [ __NR_stat ] = { 1, check_stat }, - [ __NR_lstat ] = { 1, check_stat }, - [ __NR_stat64 ] = { 1, check_stat64 }, - [ __NR_lstat64 ] = { 1, check_stat64 }, - [ __NR_chown32 ] = { 1, NULL }, -}; - -/* sys_utimes */ - -static int check_bogosity(struct pt_regs *regs) -{ - struct bogus *bogon = &this_is_bogus[regs->regs.syscall]; - - if(!bogon->kernel_ds) return(0); - if(bogon->check_params && (*bogon->check_params)(regs)) - return(-EFAULT); - set_fs(KERNEL_DS); - return(0); -} - -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - -extern syscall_handler_t *sys_call_table[]; - long execute_syscall(void *r) { - struct pt_regs *regs = r; - long res; - int syscall; - - current->thread.nsyscalls++; - nsyscalls++; - syscall = regs->regs.syscall; - - if((syscall >= NR_syscalls) || (syscall < 0)) - res = -ENOSYS; - else if(honeypot && check_bogosity(regs)) - res = -EFAULT; - else res = EXECUTE_SYSCALL(syscall, regs); - - set_fs(USER_DS); - - if(current->thread.singlestep_syscall){ - current->thread.singlestep_syscall = 0; - current->ptrace &= ~PT_DTRACE; - force_sig(SIGTRAP, current); - } - - return(res); + return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r)); } spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED; diff --git a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c index 5da5aefce6d8..3712286fe5cb 100644 --- a/arch/um/kernel/syscall_user.c +++ b/arch/um/kernel/syscall_user.c @@ -1,30 +1,12 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately - * after setting up syscall stack - * block SIGVTALRM in any code that's under wait_for_stop - */ - -#include <unistd.h> +#include <stdlib.h> #include <sys/time.h> -#include <signal.h> -#include <errno.h> -#include <sys/ptrace.h> -#include <asm/unistd.h> -#include "sysdep/ptrace.h" -#include "sigcontext.h" -#include "ptrace_user.h" -#include "task.h" -#include "user_util.h" #include "kern_util.h" - -/* XXX Bogus */ -#define ERESTARTSYS 512 -#define ERESTARTNOINTR 513 -#define ERESTARTNOHAND 514 +#include "syscall_user.h" struct { int syscall; @@ -34,67 +16,24 @@ struct { struct timeval end; } syscall_record[1024]; -void syscall_handler(int sig, struct uml_pt_regs *regs) +int record_syscall_start(int syscall) { - void *sc; - long result; - int index, max, syscall; + int max, index; max = sizeof(syscall_record)/sizeof(syscall_record[0]); index = next_syscall_index(max); - syscall = regs->syscall; - sc = regs->sc; - sc_to_regs(regs, sc, syscall); - SC_START_SYSCALL(sc); - syscall_record[index].syscall = syscall; syscall_record[index].pid = current_pid(); syscall_record[index].result = 0xdeadbeef; gettimeofday(&syscall_record[index].start, NULL); - syscall_trace(); - result = execute_syscall(regs); - - /* regs->sc may have changed while the system call ran (there may - * have been an interrupt or segfault), so it needs to be refreshed. - */ - regs->sc = sc; - - SC_SET_SYSCALL_RETURN(sc, result); - if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || - (result == -ERESTARTNOINTR)) - do_signal(result); - - syscall_trace(); - syscall_record[index].result = result; - gettimeofday(&syscall_record[index].end, NULL); + return(index); } -int do_syscall(void *task, int pid) +void record_syscall_end(int index, int result) { - unsigned long proc_regs[FRAME_SIZE]; - struct uml_pt_regs *regs; - int syscall; - - if(ptrace_getregs(pid, proc_regs) < 0) - tracer_panic("Couldn't read registers"); - syscall = PT_SYSCALL_NR(proc_regs); - - regs = TASK_REGS(task); - UPT_SYSCALL_NR(regs) = syscall; - - if(syscall < 1) return(0); - - if((syscall != __NR_sigreturn) && - ((unsigned long *) PT_IP(proc_regs) >= &_stext) && - ((unsigned long *) PT_IP(proc_regs) <= &_etext)) - tracer_panic("I'm tracing myself and I can't get out"); - - if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, - __NR_getpid) < 0) - tracer_panic("do_syscall : Nullifying syscall failed, " - "errno = %d", errno); - return(1); + syscall_record[index].result = result; + gettimeofday(&syscall_record[index].end, NULL); } /* diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 5a05d66a125f..2bf29ad7ad27 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -19,8 +19,8 @@ #ifdef CONFIG_MODULES -extern struct module *module_list; -extern struct module kernel_module; +/* FIXME: Accessed without a lock --RR */ +extern struct list_head modules; static inline int kernel_text_address(unsigned long addr) { @@ -31,11 +31,11 @@ static inline int kernel_text_address(unsigned long addr) addr <= (unsigned long) &_etext) return 1; - for (mod = module_list; mod != &kernel_module; mod = mod->next) { + list_for_each_entry(mod, &modules, list) { /* mod_bound tests for addr being inside the vmalloc'ed * module area. Of course it'd be better to test only * for the .text subset... */ - if (mod_bound(addr, 0, mod)) { + if (mod_bound((void *) addr, 0, mod)) { retval = 1; break; } diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c index 0869e1a85ec9..64cd546a3a2d 100644 --- a/arch/um/kernel/tempfile.c +++ b/arch/um/kernel/tempfile.c @@ -11,7 +11,8 @@ #include <sys/param.h> #include "init.h" -char *tempdir = NULL; +/* Modified from create_mem_file and start_debugger */ +static char *tempdir = NULL; static void __init find_tempdir(void) { diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 2ab57626b43f..282756af3779 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -23,22 +23,21 @@ void timer(void) gettimeofday(&xtime, NULL); } -static void set_interval(int timer_type) +void set_interval(int timer_type) { - struct itimerval interval; + int usec = 1000000/hz(); + struct itimerval interval = ((struct itimerval) { { 0, usec }, + { 0, usec } }); - interval.it_interval.tv_sec = 0; - interval.it_interval.tv_usec = 1000000/hz(); - interval.it_value.tv_sec = 0; - interval.it_value.tv_usec = 1000000/hz(); if(setitimer(timer_type, &interval, NULL) == -1) panic("setitimer failed - errno = %d\n", errno); } void enable_timer(void) { - struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, - { 0, 1000000/hz() }}); + int usec = 1000000/hz(); + struct itimerval enable = ((struct itimerval) { { 0, usec }, + { 0, usec }}); if(setitimer(ITIMER_VIRTUAL, &enable, NULL)) printk("enable_timer - setitimer failed, errno = %d\n", errno); @@ -76,13 +75,6 @@ void idle_timer(void) set_interval(ITIMER_REAL); } -void user_time_init(void) -{ - if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) - panic("Couldn't set SIGVTALRM handler"); - set_interval(ITIMER_VIRTUAL); -} - void time_init(void) { if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 93199e99c6f8..713d7af4a696 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -17,6 +17,7 @@ #include "kern_util.h" #include "user_util.h" #include "time_user.h" +#include "mode.h" u64 jiffies_64; @@ -142,7 +143,7 @@ int __init timer_init(void) { int err; - user_time_init(); + CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL)) != 0) printk(KERN_ERR "timer_init : request_irq failed - " diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index f5e8458ff866..ea2ed5486881 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -1,232 +1,51 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/slab.h" -#include "linux/bootmem.h" +#include "linux/mm.h" +#include "asm/page.h" #include "asm/pgalloc.h" -#include "asm-generic/tlb.h" -#include "asm/pgtable.h" -#include "asm/a.out.h" -#include "asm/processor.h" -#include "asm/mmu_context.h" -#include "asm/uaccess.h" -#include "asm/atomic.h" -#include "mem_user.h" -#include "user_util.h" -#include "kern_util.h" -#include "kern.h" -#include "tlb.h" -#include "os.h" +#include "asm/tlbflush.h" +#include "choose-mode.h" +#include "mode_kern.h" -static void fix_range(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force) -{ - pgd_t *npgd; - pmd_t *npmd; - pte_t *npte; - unsigned long addr; - int r, w, x, err; - - if((current->thread.extern_pid != -1) && - (current->thread.extern_pid != os_getpid())) - panic("fix_range fixing wrong address space, current = 0x%p", - current); - if(mm == NULL) return; - for(addr=start_addr;addr<end_addr;){ - if(addr == TASK_SIZE){ - /* Skip over kernel text, kernel data, and physical - * memory, which don't have ptes, plus kernel virtual - * memory, which is flushed separately, and remap - * the process stack. The only way to get here is - * if (end_addr == STACK_TOP) > TASK_SIZE, which is - * only true in the honeypot case. - */ - addr = STACK_TOP - ABOVE_KMEM; - continue; - } - npgd = pgd_offset(mm, addr); - npmd = pmd_offset(npgd, addr); - if(pmd_present(*npmd)){ - npte = pte_offset_kernel(npmd, addr); - r = pte_read(*npte); - w = pte_write(*npte); - x = pte_exec(*npte); - if(!pte_dirty(*npte)) w = 0; - if(!pte_young(*npte)){ - r = 0; - w = 0; - } - if(force || pte_newpage(*npte)){ - err = unmap((void *) addr, PAGE_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - if(pte_present(*npte)) - map(addr, pte_val(*npte) & PAGE_MASK, - PAGE_SIZE, r, w, x); - } - else if(pte_newprot(*npte)){ - protect(addr, PAGE_SIZE, r, w, x, 1); - } - *npte = pte_mkuptodate(*npte); - addr += PAGE_SIZE; - } - else { - if(force || pmd_newpage(*npmd)){ - err = unmap((void *) addr, PMD_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - pmd_mkuptodate(*npmd); - } - addr += PMD_SIZE; - } - } -} - -atomic_t vmchange_seq = ATOMIC_INIT(1); - -void flush_kernel_range(unsigned long start, unsigned long end, int update_seq) -{ - struct mm_struct *mm; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long addr; - int updated = 0, err; - - mm = &init_mm; - for(addr = start; addr < end;){ - pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); - if(pmd_present(*pmd)){ - pte = pte_offset_kernel(pmd, addr); - if(!pte_present(*pte) || pte_newpage(*pte)){ - updated = 1; - err = unmap((void *) addr, PAGE_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - if(pte_present(*pte)) - map(addr, pte_val(*pte) & PAGE_MASK, - PAGE_SIZE, 1, 1, 1); - } - else if(pte_newprot(*pte)){ - updated = 1; - protect(addr, PAGE_SIZE, 1, 1, 1, 1); - } - addr += PAGE_SIZE; - } - else { - if(pmd_newpage(*pmd)){ - updated = 1; - err = unmap((void *) addr, PMD_SIZE); - if(err < 0) - panic("munmap failed, errno = %d\n", - -err); - } - addr += PMD_SIZE; - } - } - if(updated && update_seq) atomic_inc(&vmchange_seq); -} - -void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - flush_kernel_range(start, end, 1); -} - -static void protect_vm_page(unsigned long addr, int w, int must_succeed) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) { - int err; - - err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed); - if(err == 0) return; - else if((err == -EFAULT) || (err == -ENOMEM)){ - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); - protect_vm_page(addr, w, 1); - } - else panic("protect_vm_page : protect failed, errno = %d\n", err); + address &= PAGE_MASK; + flush_tlb_range(vma, address, address + PAGE_SIZE); } -void mprotect_kernel_vm(int w) +void flush_tlb_all(void) { - struct mm_struct *mm; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long addr; - - mm = &init_mm; - for(addr = start_vm; addr < end_vm;){ - pgd = pgd_offset(mm, addr); - pmd = pmd_offset(pgd, addr); - if(pmd_present(*pmd)){ - pte = pte_offset_kernel(pmd, addr); - if(pte_present(*pte)) protect_vm_page(addr, w, 0); - addr += PAGE_SIZE; - } - else addr += PMD_SIZE; - } + flush_tlb_mm(current->mm); } - + void flush_tlb_kernel_vm(void) { - flush_tlb_kernel_range(start_vm, end_vm); + CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas()); } void __flush_tlb_one(unsigned long addr) { - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); } - + void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - if(vma->vm_mm != current->mm) - return; - - /* Assumes that the range start ... end is entirely within - * either process memory or kernel vm - */ - if((start >= start_vm) && (start < end_vm)) - flush_kernel_range(start, end, 1); - else fix_range(vma->vm_mm, start, end, 0); + CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, + end); } void flush_tlb_mm(struct mm_struct *mm) { - unsigned long seq; - - if(mm != current->mm) - return; - - fix_range(mm, 0, STACK_TOP, 0); - - seq = atomic_read(&vmchange_seq); - if(current->thread.vm_seq == seq) return; - current->thread.vm_seq = seq; - flush_kernel_range(start_vm, end_vm, 0); -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); -} - -void flush_tlb_all(void) -{ - flush_tlb_mm(current->mm); + CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); } void force_flush_all(void) { - fix_range(current->mm, 0, STACK_TOP, 1); - flush_kernel_range(start_vm, end_vm, 0); + CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); } pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 33bfc04fc5d0..b93c2b4eb9c7 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -4,6 +4,7 @@ */ #include "linux/kernel.h" +#include "asm/errno.h" #include "linux/sched.h" #include "linux/mm.h" #include "linux/spinlock.h" @@ -19,41 +20,36 @@ #include "kern_util.h" #include "kern.h" #include "chan_kern.h" -#include "debug.h" #include "mconsole_kern.h" #include "2_5compat.h" -extern int nsyscalls; - -unsigned long segv(unsigned long address, unsigned long ip, int is_write, - int is_user, void *sc) +int handle_page_fault(unsigned long address, unsigned long ip, + int is_write, int is_user, int *code_out) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; - struct siginfo si; - void *catcher; pgd_t *pgd; pmd_t *pmd; pte_t *pte; unsigned long page; + int err = -EFAULT; - if((address >= start_vm) && (address < end_vm)){ - flush_tlb_kernel_vm(); - return(0); - } - if(mm == NULL) panic("Segfault with no mm"); - catcher = current->thread.fault_catcher; - si.si_code = SEGV_MAPERR; + *code_out = SEGV_MAPERR; down_read(&mm->mmap_sem); vma = find_vma(mm, address); - if(!vma) goto bad; - else if(vma->vm_start <= address) goto good_area; - else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad; - else if(expand_stack(vma, address)) goto bad; + if(!vma) + goto out; + else if(vma->vm_start <= address) + goto good_area; + else if(!(vma->vm_flags & VM_GROWSDOWN)) + goto out; + else if(expand_stack(vma, address)) + goto out; good_area: - si.si_code = SEGV_ACCERR; - if(is_write && !(vma->vm_flags & VM_WRITE)) goto bad; + *code_out = SEGV_ACCERR; + if(is_write && !(vma->vm_flags & VM_WRITE)) + goto out; page = address & PAGE_MASK; if(page == (unsigned long) current->thread_info + PAGE_SIZE) panic("Kernel stack overflow"); @@ -69,8 +65,10 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, current->maj_flt++; break; case VM_FAULT_SIGBUS: - goto do_sigbus; + err = -EACCES; + goto out; case VM_FAULT_OOM: + err = -ENOMEM; goto out_of_memory; default: BUG(); @@ -80,44 +78,46 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, *pte = pte_mkyoung(*pte); if(pte_write(*pte)) *pte = pte_mkdirty(*pte); flush_tlb_page(vma, page); + err = 0; + out: up_read(&mm->mmap_sem); - return(0); -do_sigbus: - up_read(&mm->mmap_sem); + return(err); - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - si.si_signo = SIGBUS; - si.si_errno = 0; - si.si_code = BUS_ADRERR; - si.si_addr = (void *)address; - force_sig_info(SIGBUS, &si, current); - if(!is_user) goto bad; - return(0); /* * We ran out of memory, or some other thing happened to us that made * us unable to handle the page fault gracefully. */ out_of_memory: - up_read(&mm->mmap_sem); if (current->pid == 1) { + up_read(&mm->mmap_sem); yield(); down_read(&mm->mmap_sem); goto survive; } - printk("VM: killing process %s\n", current->comm); - if(is_user) - do_exit(SIGKILL); + err = -ENOMEM; + goto out; +} + +unsigned long segv(unsigned long address, unsigned long ip, int is_write, + int is_user, void *sc) +{ + struct siginfo si; + void *catcher; + int err; - /* Fall through to bad */ + if(!is_user && (address >= start_vm) && (address < end_vm)){ + flush_tlb_kernel_vm(); + return(0); + } + if(current->mm == NULL) panic("Segfault with no mm"); + err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); - bad: - if(catcher != NULL){ + catcher = current->thread.fault_catcher; + if(!err) + return(0); + else if(catcher != NULL){ current->thread.fault_addr = (void *) address; - up_read(&mm->mmap_sem); - do_longjmp(catcher); + do_longjmp(catcher, 1); } else if(current->thread.fault_addr != NULL){ panic("fault_addr set but no fault catcher"); @@ -125,15 +125,28 @@ out_of_memory: else if(arch_fixup(ip, sc)) return(0); - if(!is_user) + if(!is_user) panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", address, ip); - si.si_signo = SIGSEGV; - si.si_addr = (void *) address; - current->thread.cr2 = address; - current->thread.err = is_write; - force_sig_info(SIGSEGV, &si, current); - up_read(&mm->mmap_sem); + + if(err == -EACCES){ + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRERR; + si.si_addr = (void *)address; + force_sig_info(SIGBUS, &si, current); + } + else if(err == -ENOMEM){ + printk("VM: killing process %s\n", current->comm); + do_exit(SIGKILL); + } + else { + si.si_signo = SIGSEGV; + si.si_addr = (void *) address; + current->thread.cr2 = address; + current->thread.err = is_write; + force_sig_info(SIGSEGV, &si, current); + } return(0); } @@ -161,7 +174,7 @@ void relay_signal(int sig, struct uml_pt_regs *regs) void bus_handler(int sig, struct uml_pt_regs *regs) { if(current->thread.fault_catcher != NULL) - do_longjmp(current->thread.fault_catcher); + do_longjmp(current->thread.fault_catcher, 1); else relay_signal(sig, regs); } @@ -185,250 +198,6 @@ int next_trap_index(int limit) return(ret); } -extern int debugger_pid; -extern int debugger_fd; -extern int debugger_parent; - -#ifdef CONFIG_PT_PROXY - -int debugger_signal(int status, pid_t pid) -{ - return(debugger_proxy(status, pid)); -} - -void child_signal(pid_t pid, int status) -{ - child_proxy(pid, status); -} - -static void gdb_announce(char *dev_name, int dev) -{ - printf("gdb assigned device '%s'\n", dev_name); -} - -static struct chan_opts opts = { - announce : gdb_announce, - xterm_title : "UML kernel debugger", - raw : 0, - tramp_stack : 0, - in_kernel : 0, -}; - -/* Accessed by the tracing thread, which automatically serializes access */ -static void *xterm_data; -static int xterm_fd; - -extern void *xterm_init(char *, int, struct chan_opts *); -extern int xterm_open(int, int, int, void *); -extern void xterm_close(int, void *); - -int open_gdb_chan(void) -{ - char stack[PAGE_SIZE]; - - opts.tramp_stack = (unsigned long) stack; - xterm_data = xterm_init("", 0, &opts); - xterm_fd = xterm_open(1, 1, 1, xterm_data); - return(xterm_fd); -} - -static void exit_debugger_cb(void *unused) -{ - if(debugger_pid != -1){ - if(gdb_pid != -1){ - fake_child_exit(); - gdb_pid = -1; - } - else kill_child_dead(debugger_pid); - debugger_pid = -1; - if(debugger_parent != -1) - detach(debugger_parent, SIGINT); - } - if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); -} - -static void exit_debugger(void) -{ - tracing_cb(exit_debugger_cb, NULL); -} - -__uml_exitcall(exit_debugger); - -struct gdb_data { - char *str; - int err; -}; - -static void config_gdb_cb(void *arg) -{ - struct gdb_data *data = arg; - struct task_struct *task; - int pid; - - data->err = -1; - if(debugger_pid != -1) exit_debugger_cb(NULL); - if(!strncmp(data->str, "pid,", strlen("pid,"))){ - data->str += strlen("pid,"); - pid = simple_strtoul(data->str, NULL, 0); - task = cpu_tasks[0].task; - debugger_pid = attach_debugger(task->thread.extern_pid, - pid, 0); - if(debugger_pid != -1){ - data->err = 0; - gdb_pid = pid; - } - return; - } - data->err = 0; - debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); - init_proxy(debugger_pid, 0, 0); -} - -int gdb_config(char *str) -{ - struct gdb_data data; - - if(*str++ != '=') return(-1); - data.str = str; - tracing_cb(config_gdb_cb, &data); - return(data.err); -} - -void remove_gdb_cb(void *unused) -{ - exit_debugger_cb(NULL); -} - -int gdb_remove(char *unused) -{ - tracing_cb(remove_gdb_cb, NULL); - return(0); -} - -#ifdef CONFIG_MCONSOLE - -static struct mc_device gdb_mc = { - name: "gdb", - config: gdb_config, - remove: gdb_remove, -}; - -int gdb_mc_init(void) -{ - mconsole_register_dev(&gdb_mc); - return(0); -} - -__initcall(gdb_mc_init); - -#endif - -void signal_usr1(int sig) -{ - if(debugger_pid != -1){ - printk(KERN_ERR "The debugger is already running\n"); - return; - } - debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); - init_proxy(debugger_pid, 0, 0); -} - -int init_ptrace_proxy(int idle_pid, int startup, int stop) -{ - int pid, status; - - pid = start_debugger(linux_prog, startup, stop, &debugger_fd); - status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); - if(pid < 0){ - cont(idle_pid); - return(-1); - } - init_proxy(pid, 1, status); - return(pid); -} - -int attach_debugger(int idle_pid, int pid, int stop) -{ - int status = 0, err; - - err = attach(pid); - if(err < 0){ - printf("Failed to attach pid %d, errno = %d\n", pid, -err); - return(-1); - } - if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); - init_proxy(pid, 1, status); - return(pid); -} - -#ifdef notdef /* Put this back in when it does something useful */ -static int __init uml_gdb_init_setup(char *line, int *add) -{ - gdb_init = uml_strdup(line); - return 0; -} - -__uml_setup("gdb=", uml_gdb_init_setup, -"gdb=<channel description>\n\n" -); -#endif - -static int __init uml_gdb_pid_setup(char *line, int *add) -{ - gdb_pid = simple_strtoul(line, NULL, 0); - *add = 0; - return 0; -} - -__uml_setup("gdb-pid=", uml_gdb_pid_setup, -"gdb-pid=<pid>\n" -" gdb-pid is used to attach an external debugger to UML. This may be\n" -" an already-running gdb or a debugger-like process like strace.\n\n" -); - -#else - -int debugger_signal(int status, pid_t pid){ return(0); } -void child_signal(pid_t pid, int status){ } -int init_ptrace_proxy(int idle_pid, int startup, int stop) -{ - printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); - kill_child_dead(idle_pid); - exit(1); -} - -void signal_usr1(int sig) -{ - printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); -} - -int attach_debugger(int idle_pid, int pid, int stop) -{ - printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " - "is off\n"); - return(-1); -} - -int config_gdb(char *str) -{ - return(-1); -} - -int remove_gdb(void) -{ - return(-1); -} - -int init_parent_proxy(int pid) -{ - return(-1); -} - -void debugger_parent_signal(int status, int pid) -{ -} - -#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 8971a61c8310..02e7b0eede15 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -3,66 +3,33 @@ * Licensed under the GPL */ -#include <stdio.h> #include <stdlib.h> -#include <unistd.h> -#include <signal.h> #include <errno.h> -#include <sched.h> #include <fcntl.h> #include <setjmp.h> -#include <string.h> -#include <sys/ptrace.h> +#include <signal.h> #include <sys/time.h> -#include <sys/wait.h> -#include <sys/mman.h> #include <sys/ioctl.h> +#include <sys/ptrace.h> +#include <sys/wait.h> #include <asm/page.h> #include <asm/unistd.h> #include <asm/ptrace.h> -#include "user_util.h" -#include "kern_util.h" -#include "signal_user.h" -#include "mem_user.h" -#include "user.h" -#include "process.h" +#include "init.h" +#include "sysdep/ptrace.h" #include "sigcontext.h" #include "sysdep/sigcontext.h" -#include "init.h" -#include "chan_user.h" #include "irq_user.h" #include "frame_user.h" -#include "syscall_user.h" -#include "ptrace_user.h" +#include "signal_user.h" #include "time_user.h" #include "task.h" +#include "mode.h" +#include "choose-mode.h" +#include "kern_util.h" +#include "user_util.h" #include "os.h" -static void signal_segv(int sig) -{ - write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n")); - for(;;) ; -} - -int detach(int pid, int sig) -{ - return(ptrace(PTRACE_DETACH, pid, 0, sig)); -} - -int attach(int pid) -{ - int err; - - err = ptrace(PTRACE_ATTACH, pid, 0, 0); - if(err < 0) return(-errno); - else return(err); -} - -int cont(int pid) -{ - return(ptrace(PTRACE_CONT, pid, 0, 0)); -} - void kill_child_dead(int pid) { kill(pid, SIGKILL); @@ -70,336 +37,6 @@ void kill_child_dead(int pid) while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); } -/* Changed early in boot, and then only read */ -int debug = 0; -int debug_stop = 1; -int debug_parent = 0; -int honeypot = 0; - -static int signal_tramp(void *arg) -{ - int (*proc)(void *); - - if(honeypot && munmap((void *) (host_task_size - 0x10000000), - 0x10000000)) - panic("Unmapping stack failed"); - if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) - panic("ptrace PTRACE_TRACEME failed"); - os_stop_process(os_getpid()); - change_sig(SIGWINCH, 0); - signal(SIGUSR1, SIG_IGN); - change_sig(SIGCHLD, 0); - signal(SIGSEGV, (__sighandler_t) sig_handler); - set_cmdline("(idle thread)"); - set_init_pid(os_getpid()); - proc = arg; - return((*proc)(NULL)); -} - -static void last_ditch_exit(int sig) -{ - kmalloc_ok = 0; - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - uml_cleanup(); - exit(1); -} - -static void sleeping_process_signal(int pid, int sig) -{ - switch(sig){ - /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is - * right because the process must be in the kernel already. - */ - case SIGCONT: - case SIGTSTP: - if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) - tracer_panic("sleeping_process_signal : Failed to " - "continue pid %d, errno = %d\n", pid, - sig); - break; - - /* This happens when the debugger (e.g. strace) is doing system call - * tracing on the kernel. During a context switch, the current task - * will be set to the incoming process and the outgoing process will - * hop into write and then read. Since it's not the current process - * any more, the trace of those will land here. So, we need to just - * PTRACE_SYSCALL it. - */ - case SIGTRAP: - if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) - tracer_panic("sleeping_process_signal : Failed to " - "PTRACE_SYSCALL pid %d, errno = %d\n", - pid, sig); - break; - case SIGSTOP: - break; - default: - tracer_panic("sleeping process %d got unexpected " - "signal : %d\n", pid, sig); - break; - } -} - -/* Accessed only by the tracing thread */ -int debugger_pid = -1; -int debugger_parent = -1; -int debugger_fd = -1; -int gdb_pid = -1; - -struct { - int pid; - int signal; - unsigned long addr; - struct timeval time; -} signal_record[1024][32]; - -int signal_index[32]; -int nsignals = 0; -int debug_trace = 0; -extern int io_nsignals, io_count, intr_count; - -extern void signal_usr1(int sig); - -int tracing_pid = -1; - -int signals(int (*init_proc)(void *), void *sp) -{ - void *task = NULL; - unsigned long eip = 0; - int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; - int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; - - capture_signal_stack(); - signal(SIGPIPE, SIG_IGN); - setup_tracer_winch(); - tracing_pid = os_getpid(); - printf("tracing thread pid = %d\n", tracing_pid); - - pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); - n = waitpid(pid, &status, WUNTRACED); - if(n < 0){ - printf("waitpid on idle thread failed, errno = %d\n", errno); - exit(1); - } - if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ - printf("Failed to continue idle thread, errno = %d\n", errno); - exit(1); - } - - signal(SIGSEGV, signal_segv); - signal(SIGUSR1, signal_usr1); - set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); - if(debug_trace){ - printf("Tracing thread pausing to be attached\n"); - stop(); - } - if(debug){ - if(gdb_pid != -1) - debugger_pid = attach_debugger(pid, gdb_pid, 1); - else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); - if(debug_parent){ - debugger_parent = os_process_parent(debugger_pid); - init_parent_proxy(debugger_parent); - err = attach(debugger_parent); - if(err){ - printf("Failed to attach debugger parent %d, " - "errno = %d\n", debugger_parent, err); - debugger_parent = -1; - } - else { - if(ptrace(PTRACE_SYSCALL, debugger_parent, - 0, 0) < 0){ - printf("Failed to continue debugger " - "parent, errno = %d\n", errno); - debugger_parent = -1; - } - } - } - } - set_cmdline("(tracing thread)"); - while(1){ - if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ - if(errno != ECHILD){ - printf("wait failed - errno = %d\n", errno); - } - continue; - } - if(pid == debugger_pid){ - int cont = 0; - - if(WIFEXITED(status) || WIFSIGNALED(status)) - debugger_pid = -1; - /* XXX Figure out how to deal with gdb and SMP */ - else cont = debugger_signal(status, cpu_tasks[0].pid); - if(cont == PTRACE_SYSCALL) strace = 1; - continue; - } - else if(pid == debugger_parent){ - debugger_parent_signal(status, pid); - continue; - } - nsignals++; - if(WIFEXITED(status)) ; -#ifdef notdef - { - printf("Child %d exited with status %d\n", pid, - WEXITSTATUS(status)); - } -#endif - else if(WIFSIGNALED(status)){ - sig = WTERMSIG(status); - if(sig != 9){ - printf("Child %d exited with signal %d\n", pid, - sig); - } - } - else if(WIFSTOPPED(status)){ - proc_id = pid_to_processor_id(pid); - sig = WSTOPSIG(status); - if(signal_index[proc_id] == 1024){ - signal_index[proc_id] = 0; - last_index = 1023; - } - else last_index = signal_index[proc_id] - 1; - if(((sig == SIGPROF) || (sig == SIGVTALRM) || - (sig == SIGALRM)) && - (signal_record[proc_id][last_index].signal == sig)&& - (signal_record[proc_id][last_index].pid == pid)) - signal_index[proc_id] = last_index; - signal_record[proc_id][signal_index[proc_id]].pid = pid; - gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); - eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); - signal_record[proc_id][signal_index[proc_id]].addr = eip; - signal_record[proc_id][signal_index[proc_id]++].signal = sig; - - if(proc_id == -1){ - sleeping_process_signal(pid, sig); - continue; - } - - task = cpu_tasks[proc_id].task; - tracing = is_tracing(task); - old_tracing = tracing; - - switch(sig){ - case SIGUSR1: - sig = 0; - op = do_proc_op(task, proc_id); - switch(op){ - case OP_TRACE_ON: - arch_leave_kernel(task, pid); - tracing = 1; - break; - case OP_REBOOT: - case OP_HALT: - unmap_physmem(); - kmalloc_ok = 0; - ptrace(PTRACE_KILL, pid, 0, 0); - return(op == OP_REBOOT); - case OP_NONE: - printf("Detaching pid %d\n", pid); - detach(pid, SIGSTOP); - continue; - default: - break; - } - /* OP_EXEC switches host processes on us, - * we want to continue the new one. - */ - pid = cpu_tasks[proc_id].pid; - break; - case SIGTRAP: - if(!tracing && (debugger_pid != -1)){ - child_signal(pid, status); - continue; - } - tracing = 0; - if(do_syscall(task, pid)) sig = SIGUSR2; - else clear_singlestep(task); - break; - case SIGPROF: - if(tracing) sig = 0; - break; - case SIGCHLD: - case SIGHUP: - sig = 0; - break; - case SIGSEGV: - case SIGIO: - case SIGALRM: - case SIGVTALRM: - case SIGFPE: - case SIGBUS: - case SIGILL: - case SIGWINCH: - default: - tracing = 0; - break; - } - set_tracing(task, tracing); - - if(!tracing && old_tracing) - arch_enter_kernel(task, pid); - - if(!tracing && (debugger_pid != -1) && (sig != 0) && - (sig != SIGALRM) && (sig != SIGVTALRM) && - (sig != SIGSEGV) && (sig != SIGTRAP) && - (sig != SIGUSR2) && (sig != SIGIO)){ - child_signal(pid, status); - continue; - } - - if(tracing){ - if(singlestepping(task)) - cont_type = PTRACE_SINGLESTEP; - else cont_type = PTRACE_SYSCALL; - } - else cont_type = PTRACE_CONT; - - if((cont_type == PTRACE_CONT) && - (debugger_pid != -1) && strace) - cont_type = PTRACE_SYSCALL; - - if(ptrace(cont_type, pid, 0, sig) != 0){ - tracer_panic("ptrace failed to continue " - "process - errno = %d\n", - errno); - } - } - } - return(0); -} - -static int __init uml_debugtrace_setup(char *line, int *add) -{ - debug_trace = 1; - return 0; -} -__uml_setup("debugtrace", uml_debugtrace_setup, -"debugtrace\n" -" Causes the tracing thread to pause until it is attached by a\n" -" debugger and continued. This is mostly for debugging crashes\n" -" early during boot, and should be pretty much obsoleted by\n" -" the debug switch.\n\n" -); - -static int __init uml_honeypot_setup(char *line, int *add) -{ - jail_setup("", add); - honeypot = 1; - return 0; -} -__uml_setup("honeypot", uml_honeypot_setup, -"honeypot\n" -" This makes UML put process stacks in the same location as they are\n" -" on the host, allowing expoits such as stack smashes to work against\n" -" UML. This implies 'jail'.\n\n" -); - /* Unlocked - don't care if this is a bit off */ int nsegfaults = 0; @@ -413,33 +50,32 @@ struct { void segv_handler(int sig, struct uml_pt_regs *regs) { - struct sigcontext *context = regs->sc; int index, max; - if(regs->is_user && !SEGV_IS_FIXABLE(context)){ - bad_segv(SC_FAULT_ADDR(context), SC_IP(context), - SC_FAULT_WRITE(context)); + if(regs->is_user && !UPT_SEGV_IS_FIXABLE(regs)){ + bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), + UPT_FAULT_WRITE(regs)); return; } max = sizeof(segfault_record)/sizeof(segfault_record[0]); index = next_trap_index(max); nsegfaults++; - segfault_record[index].address = SC_FAULT_ADDR(context); + segfault_record[index].address = UPT_FAULT_ADDR(regs); segfault_record[index].pid = os_getpid(); - segfault_record[index].is_write = SC_FAULT_WRITE(context); - segfault_record[index].sp = SC_SP(context); + segfault_record[index].is_write = UPT_FAULT_WRITE(regs); + segfault_record[index].sp = UPT_SP(regs); segfault_record[index].is_user = regs->is_user; - segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context), - regs->is_user, context); + segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), + regs->is_user, regs); } -struct signal_info { - void (*handler)(int, struct uml_pt_regs *); - int is_irq; -}; +void usr2_handler(int sig, struct uml_pt_regs *regs) +{ + CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); +} -static struct signal_info sig_info[] = { +struct signal_info sig_info[] = { [ SIGTRAP ] { handler : relay_signal, is_irq : 0 }, [ SIGFPE ] { handler : relay_signal, @@ -454,104 +90,42 @@ static struct signal_info sig_info[] = { is_irq : 1 }, [ SIGVTALRM ] { handler : timer_handler, is_irq : 1 }, - [ SIGALRM ] { handler : timer_handler, - is_irq : 1 }, - [ SIGUSR2 ] { handler : syscall_handler, + [ SIGALRM ] { handler : timer_handler, + is_irq : 1 }, + [ SIGUSR2 ] { handler : usr2_handler, is_irq : 0 }, }; -void sig_handler_common(int sig, struct sigcontext *sc) -{ - struct uml_pt_regs save_regs, *r; - struct signal_info *info; - int save_errno = errno, is_user; - - unprotect_kernel_mem(); - - r = (struct uml_pt_regs *) TASK_REGS(get_current()); - save_regs = *r; - is_user = user_context(SC_SP(sc)); - r->is_user = is_user; - r->sc = sc; - if(sig != SIGUSR2) r->syscall = -1; - - change_sig(SIGUSR1, 1); - info = &sig_info[sig]; - if(!info->is_irq) unblock_signals(); - - (*info->handler)(sig, r); - - if(is_user){ - interrupt_end(); - block_signals(); - change_sig(SIGUSR1, 0); - set_user_mode(NULL); - } - *r = save_regs; - errno = save_errno; - if(is_user) protect_kernel_mem(); -} - void sig_handler(int sig, struct sigcontext sc) { - sig_handler_common(sig, &sc); + CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, + sig, &sc); } extern int timer_irq_inited, missed_ticks[]; void alarm_handler(int sig, struct sigcontext sc) { - int user; - if(!timer_irq_inited) return; missed_ticks[cpu()]++; - user = user_context(SC_SP(&sc)); if(sig == SIGALRM) switch_timers(0); - sig_handler_common(sig, &sc); + CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, + sig, &sc); if(sig == SIGALRM) switch_timers(1); } -void do_longjmp(void *p) +void do_longjmp(void *b, int val) { - jmp_buf *jbuf = (jmp_buf *) p; + jmp_buf *buf = b; - longjmp(*jbuf, 1); + longjmp(*buf, val); } -static int __init uml_debug_setup(char *line, int *add) -{ - char *next; - - debug = 1; - *add = 0; - if(*line != '=') return(0); - line++; - - while(line != NULL){ - next = strchr(line, ','); - if(next) *next++ = '\0'; - - if(!strcmp(line, "go")) debug_stop = 0; - else if(!strcmp(line, "parent")) debug_parent = 1; - else printk("Unknown debug option : '%s'\n", line); - - line = next; - } - return(0); -} - -__uml_setup("debug", uml_debug_setup, -"debug\n" -" Starts up the kernel under the control of gdb. See the \n" -" kernel debugging tutorial and the debugging session pages\n" -" at http://user-mode-linux.sourceforge.net/ for more information.\n\n" -); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile new file mode 100644 index 000000000000..9b436c8ef1bb --- /dev/null +++ b/arch/um/kernel/tt/Makefile @@ -0,0 +1,20 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = exec_kern.o exec_user.o gdb.o gdb_kern.o ksyms.o mem.o process_kern.o \ + syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ + uaccess_user.o sys-$(SUBARCH)/ + +obj-$(CONFIG_PT_PROXY) += ptproxy/ + +export-objs = ksyms.o + +USER_OBJS := $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean : diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c new file mode 100644 index 000000000000..afd94713d742 --- /dev/null +++ b/arch/um/kernel/tt/exec_kern.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "linux/mm.h" +#include "asm/signal.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "asm/pgalloc.h" +#include "asm/tlbflush.h" +#include "user_util.h" +#include "kern_util.h" +#include "irq_user.h" +#include "time_user.h" +#include "mem_user.h" +#include "os.h" +#include "tlb.h" + +static int exec_tramp(void *sig_stack) +{ + init_new_thread_stack(sig_stack, NULL); + init_new_thread_signals(1); + os_stop_process(os_getpid()); + return(0); +} + +void flush_thread_tt(void) +{ + unsigned long stack; + int new_pid; + + stack = alloc_stack(0, 0); + if(stack == 0){ + printk(KERN_ERR + "flush_thread : failed to allocate temporary stack\n"); + do_exit(SIGKILL); + } + + new_pid = start_fork_tramp((void *) current->thread.kernel_stack, + stack, 0, exec_tramp); + if(new_pid < 0){ + printk(KERN_ERR + "flush_thread : new thread failed, errno = %d\n", + -new_pid); + do_exit(SIGKILL); + } + + if(current->thread_info->cpu == 0) + forward_interrupts(new_pid); + current->thread.request.op = OP_EXEC; + current->thread.request.u.exec.pid = new_pid; + unprotect_stack((unsigned long) current->thread_info); + os_usr1_process(os_getpid()); + + enable_timer(); + free_page(stack); + protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); + task_protections((unsigned long) current->thread_info); + force_flush_all(); + unblock_signals(); +} + +void start_thread_tt(struct pt_regs *regs, unsigned long eip, + unsigned long esp) +{ + set_fs(USER_DS); + flush_tlb_mm(current->mm); + PT_REGS_IP(regs) = eip; + PT_REGS_SP(regs) = esp; + PT_FIX_EXEC_STACK(esp); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/exec_user.c b/arch/um/kernel/tt/exec_user.c index 35d108266d41..35d108266d41 100644 --- a/arch/um/kernel/exec_user.c +++ b/arch/um/kernel/tt/exec_user.c diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c new file mode 100644 index 000000000000..22753784178a --- /dev/null +++ b/arch/um/kernel/tt/gdb.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include "uml-config.h" +#include "kern_constants.h" +#include "chan_user.h" +#include "init.h" +#include "user.h" +#include "debug.h" +#include "kern_util.h" +#include "user_util.h" +#include "tt.h" +#include "sysdep/thread.h" + +extern int debugger_pid; +extern int debugger_fd; +extern int debugger_parent; + +int detach(int pid, int sig) +{ + return(ptrace(PTRACE_DETACH, pid, 0, sig)); +} + +int attach(int pid) +{ + int err; + + err = ptrace(PTRACE_ATTACH, pid, 0, 0); + if(err < 0) return(-errno); + else return(err); +} + +int cont(int pid) +{ + return(ptrace(PTRACE_CONT, pid, 0, 0)); +} + +#ifdef CONFIG_PT_PROXY + +int debugger_signal(int status, pid_t pid) +{ + return(debugger_proxy(status, pid)); +} + +void child_signal(pid_t pid, int status) +{ + child_proxy(pid, status); +} + +static void gdb_announce(char *dev_name, int dev) +{ + printf("gdb assigned device '%s'\n", dev_name); +} + +static struct chan_opts opts = { + announce : gdb_announce, + xterm_title : "UML kernel debugger", + raw : 0, + tramp_stack : 0, + in_kernel : 0, +}; + +/* Accessed by the tracing thread, which automatically serializes access */ +static void *xterm_data; +static int xterm_fd; + +extern void *xterm_init(char *, int, struct chan_opts *); +extern int xterm_open(int, int, int, void *); +extern void xterm_close(int, void *); + +int open_gdb_chan(void) +{ + char stack[UM_KERN_PAGE_SIZE]; + + opts.tramp_stack = (unsigned long) stack; + xterm_data = xterm_init("", 0, &opts); + xterm_fd = xterm_open(1, 1, 1, xterm_data); + return(xterm_fd); +} + +static void exit_debugger_cb(void *unused) +{ + if(debugger_pid != -1){ + if(gdb_pid != -1){ + fake_child_exit(); + gdb_pid = -1; + } + else kill_child_dead(debugger_pid); + debugger_pid = -1; + if(debugger_parent != -1) + detach(debugger_parent, SIGINT); + } + if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); +} + +static void exit_debugger(void) +{ + initial_thread_cb(exit_debugger_cb, NULL); +} + +__uml_exitcall(exit_debugger); + +struct gdb_data { + char *str; + int err; +}; + +static void config_gdb_cb(void *arg) +{ + struct gdb_data *data = arg; + void *task; + int pid; + + data->err = -1; + if(debugger_pid != -1) exit_debugger_cb(NULL); + if(!strncmp(data->str, "pid,", strlen("pid,"))){ + data->str += strlen("pid,"); + pid = strtoul(data->str, NULL, 0); + task = cpu_tasks[0].task; + debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0); + if(debugger_pid != -1){ + data->err = 0; + gdb_pid = pid; + } + return; + } + data->err = 0; + debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); + init_proxy(debugger_pid, 0, 0); +} + +int gdb_config(char *str) +{ + struct gdb_data data; + + if(*str++ != '=') return(-1); + data.str = str; + initial_thread_cb(config_gdb_cb, &data); + return(data.err); +} + +void remove_gdb_cb(void *unused) +{ + exit_debugger_cb(NULL); +} + +int gdb_remove(char *unused) +{ + initial_thread_cb(remove_gdb_cb, NULL); + return(0); +} + +void signal_usr1(int sig) +{ + if(debugger_pid != -1){ + printk(UM_KERN_ERR "The debugger is already running\n"); + return; + } + debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); + init_proxy(debugger_pid, 0, 0); +} + +int init_ptrace_proxy(int idle_pid, int startup, int stop) +{ + int pid, status; + + pid = start_debugger(linux_prog, startup, stop, &debugger_fd); + status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); + if(pid < 0){ + cont(idle_pid); + return(-1); + } + init_proxy(pid, 1, status); + return(pid); +} + +int attach_debugger(int idle_pid, int pid, int stop) +{ + int status = 0, err; + + err = attach(pid); + if(err < 0){ + printf("Failed to attach pid %d, errno = %d\n", pid, -err); + return(-1); + } + if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); + init_proxy(pid, 1, status); + return(pid); +} + +#ifdef notdef /* Put this back in when it does something useful */ +static int __init uml_gdb_init_setup(char *line, int *add) +{ + gdb_init = uml_strdup(line); + return 0; +} + +__uml_setup("gdb=", uml_gdb_init_setup, +"gdb=<channel description>\n\n" +); +#endif + +static int __init uml_gdb_pid_setup(char *line, int *add) +{ + gdb_pid = strtoul(line, NULL, 0); + *add = 0; + return 0; +} + +__uml_setup("gdb-pid=", uml_gdb_pid_setup, +"gdb-pid=<pid>\n" +" gdb-pid is used to attach an external debugger to UML. This may be\n" +" an already-running gdb or a debugger-like process like strace.\n\n" +); + +#else + +int debugger_signal(int status, pid_t pid){ return(0); } +void child_signal(pid_t pid, int status){ } +int init_ptrace_proxy(int idle_pid, int startup, int stop) +{ + printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); + kill_child_dead(idle_pid); + exit(1); +} + +void signal_usr1(int sig) +{ + printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); +} + +int attach_debugger(int idle_pid, int pid, int stop) +{ + printk(UM_KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " + "is off\n"); + return(-1); +} + +int config_gdb(char *str) +{ + return(-1); +} + +int remove_gdb(void) +{ + return(-1); +} + +int init_parent_proxy(int pid) +{ + return(-1); +} + +void debugger_parent_signal(int status, int pid) +{ +} + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c new file mode 100644 index 000000000000..2b4320c1480c --- /dev/null +++ b/arch/um/kernel/tt/gdb_kern.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/init.h" +#include "linux/config.h" +#include "mconsole_kern.h" + +#ifdef CONFIG_MCONSOLE + +extern int gdb_config(char *str); +extern int gdb_remove(char *unused); + +static struct mc_device gdb_mc = { + name: "gdb", + config: gdb_config, + remove: gdb_remove, +}; + +int gdb_mc_init(void) +{ + mconsole_register_dev(&gdb_mc); + return(0); +} + +__initcall(gdb_mc_init); + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/include/debug.h b/arch/um/kernel/tt/include/debug.h index 1d8b0a2638a8..8eff674107ca 100644 --- a/arch/um/include/debug.h +++ b/arch/um/kernel/tt/include/debug.h @@ -3,6 +3,7 @@ * Lars Brinkhoff. * Licensed under the GPL */ + #ifndef __DEBUG_H #define __DEBUG_H @@ -11,6 +12,8 @@ extern void child_proxy(pid_t pid, int status); extern void init_proxy (pid_t pid, int waiting, int status); extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); extern void fake_child_exit(void); +extern int gdb_config(char *str); +extern int gdb_remove(char *unused); #endif diff --git a/arch/um/kernel/setup.c b/arch/um/kernel/tt/include/mmu.h index 3e4290a285f6..6b146bd84ca7 100644 --- a/arch/um/kernel/setup.c +++ b/arch/um/kernel/tt/include/mmu.h @@ -1,12 +1,15 @@ /* - * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ -#include "asm/processor.h" +#ifndef __TT_MMU_H +#define __TT_MMU_H -struct cpuinfo_um boot_cpu_data = { loops_per_jiffy : 0, - ipi_pipe : { -1, -1 } }; +struct mmu_context_tt { +}; + +#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h new file mode 100644 index 000000000000..183a61d40453 --- /dev/null +++ b/arch/um/kernel/tt/include/mode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_TT_H__ +#define __MODE_TT_H__ + +#include "sysdep/ptrace.h" + +extern int tracing_pid; + +extern int tracer(int (*init_proc)(void *), void *sp); +extern void user_time_init_tt(void); +extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data); +extern int copy_sc_to_user_tt(void *to_ptr, void *from_ptr, void *data); +extern void sig_handler_common_tt(int sig, struct sigcontext *sc); +extern void syscall_handler_tt(int sig, struct uml_pt_regs *regs); +extern void reboot_tt(void); +extern void halt_tt(void); +extern int is_tracer_winch(int pid, int fd, void *data); +extern void kill_off_processes_tt(void); + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/mode_kern.h b/arch/um/kernel/tt/include/mode_kern.h new file mode 100644 index 000000000000..3dbd434f1abe --- /dev/null +++ b/arch/um/kernel/tt/include/mode_kern.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_MODE_KERN_H__ +#define __TT_MODE_KERN_H__ + +#include "linux/sched.h" +#include "asm/page.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" + +extern void *switch_to_tt(void *prev, void *next); +extern void flush_thread_tt(void); +extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, + unsigned long esp); +extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct *p, + struct pt_regs *regs); +extern void release_thread_tt(struct task_struct *task); +extern void exit_thread_tt(void); +extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); +extern void init_idle_tt(void); +extern void flush_tlb_kernel_vm_tt(void); +extern void __flush_tlb_one_tt(unsigned long addr); +extern void flush_tlb_range_tt(struct vm_area_struct *vma, + unsigned long start, unsigned long end); +extern void flush_tlb_mm_tt(struct mm_struct *mm); +extern void force_flush_all_tt(void); +extern long execute_syscall_tt(void *r); +extern void before_mem_tt(unsigned long brk_start); +extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, + unsigned long *task_size_out); +extern int start_uml_tt(void); +extern struct page *arch_validate_tt(struct page *page, int mask, int order); +extern int external_pid_tt(struct task_struct *task); +extern int thread_pid_tt(struct task_struct *task); + +#define kmem_end_tt (host_task_size - ABOVE_KMEM) + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/ptrace-tt.h b/arch/um/kernel/tt/include/ptrace-tt.h new file mode 100644 index 000000000000..4e22b772c8f5 --- /dev/null +++ b/arch/um/kernel/tt/include/ptrace-tt.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PTRACE_TT_H +#define __PTRACE_TT_H + +#include "uml-config.h" + +#ifdef CONFIG_MODE_TT +#include "sysdep/sc.h" +#endif + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h new file mode 100644 index 000000000000..3769d2aabc66 --- /dev/null +++ b/arch/um/kernel/tt/include/tt.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_H__ +#define __TT_H__ + +#include "sysdep/ptrace.h" + +extern int gdb_pid; +extern int debug; +extern int debug_stop; +extern int debug_trace; + +extern int honeypot; + +extern int fork_tramp(void *sig_stack); +extern int do_proc_op(void *t, int proc_id); +extern int tracer(int (*init_proc)(void *), void *sp); +extern void attach_process(int pid); +extern void tracer_panic(char *format, ...); +extern void set_init_pid(int pid); +extern int set_user_mode(void *task); +extern void set_tracing(void *t, int tracing); +extern int is_tracing(void *task); +extern int singlestepping_tt(void *t); +extern void clear_singlestep(void *t); +extern void syscall_handler(int sig, struct uml_pt_regs *regs); +extern void exit_kernel(int pid, void *task); +extern int do_syscall(void *task, int pid); +extern int is_valid_pid(int pid); + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h new file mode 100644 index 000000000000..902de9f3783c --- /dev/null +++ b/arch/um/kernel/tt/include/uaccess.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TT_UACCESS_H +#define __TT_UACCESS_H + +#include "linux/string.h" +#include "linux/sched.h" +#include "asm/processor.h" +#include "asm/errno.h" +#include "asm/current.h" +#include "asm/a.out.h" + +#define ABOVE_KMEM (16 * 1024 * 1024) + +extern unsigned long end_vm; +extern unsigned long uml_physmem; + +#define under_task_size(addr, size) \ + (((unsigned long) (addr) < TASK_SIZE) && \ + (((unsigned long) (addr) + (size)) < TASK_SIZE)) + +#define is_stack(addr, size) \ + (((unsigned long) (addr) < STACK_TOP) && \ + ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ + (((unsigned long) (addr) + (size)) <= STACK_TOP)) + +#define access_ok_tt(type, addr, size) \ + ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \ + (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ + (under_task_size(addr, size) || is_stack(addr, size)))) + +static inline int verify_area_tt(int type, const void * addr, + unsigned long size) +{ + return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); +} + +extern unsigned long get_fault_addr(void); + +extern int __do_copy_from_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher); + +static inline int copy_from_user_tt(void *to, const void *from, int n) +{ + return(access_ok_tt(VERIFY_READ, from, n) ? + __do_copy_from_user(to, from, n, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : n); +} + +extern int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher); + +static inline int copy_to_user_tt(void *to, const void *from, int n) +{ + return(access_ok_tt(VERIFY_WRITE, to, n) ? + __do_copy_to_user(to, from, n, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : n); +} + +extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, + void **fault_addr, void **fault_catcher); + +static inline int strncpy_from_user_tt(char *dst, const char *src, int count) +{ + int n; + + if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT); + n = __do_strncpy_from_user(dst, src, count, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher); + if(n < 0) return(-EFAULT); + return(n); +} + +extern int __do_clear_user(void *mem, size_t len, void **fault_addr, + void **fault_catcher); + +static inline int __clear_user_tt(void *mem, int len) +{ + return(__do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +static inline int clear_user_tt(void *mem, int len) +{ + return(access_ok_tt(VERIFY_WRITE, mem, len) ? + __do_clear_user(mem, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher) : len); +} + +extern int __do_strnlen_user(const char *str, unsigned long n, + void **fault_addr, void **fault_catcher); + +static inline int strnlen_user_tt(const void *str, int len) +{ + return(__do_strnlen_user(str, len, + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)); +} + +#endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c new file mode 100644 index 000000000000..92ec85d67c7c --- /dev/null +++ b/arch/um/kernel/tt/ksyms.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/module.h" +#include "asm/uaccess.h" +#include "mode.h" + +EXPORT_SYMBOL(__do_copy_from_user); +EXPORT_SYMBOL(__do_copy_to_user); +EXPORT_SYMBOL(__do_strncpy_from_user); +EXPORT_SYMBOL(__do_strnlen_user); +EXPORT_SYMBOL(__do_clear_user); + +EXPORT_SYMBOL(tracing_pid); +EXPORT_SYMBOL(honeypot); + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c new file mode 100644 index 000000000000..ff92e59bd86b --- /dev/null +++ b/arch/um/kernel/tt/mem.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/config.h" +#include "linux/mm.h" +#include "asm/uaccess.h" +#include "mem_user.h" +#include "kern_util.h" +#include "user_util.h" +#include "kern.h" +#include "tt.h" + +void before_mem_tt(unsigned long brk_start) +{ + if(!jail || debug) + remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1); + remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1); + remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(brk_start), 1); +} + +#ifdef CONFIG_HOST_2G_2G +#define TOP 0x80000000 +#else +#define TOP 0xc0000000 +#endif + +#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) +#define START (TOP - SIZE) + +unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, + unsigned long *task_size_out) +{ + /* Round up to the nearest 4M */ + *host_size_out = ROUND_4M((unsigned long) &arg); + *task_size_out = START; + return(START); +} + +struct page *arch_validate_tt(struct page *page, int mask, int order) +{ + unsigned long addr, zero = 0; + int i; + + again: + if(page == NULL) return(page); + if(PageHighMem(page)) return(page); + + addr = (unsigned long) page_address(page); + for(i = 0; i < (1 << order); i++){ + current->thread.fault_addr = (void *) addr; + if(__do_copy_to_user((void *) addr, &zero, + sizeof(zero), + ¤t->thread.fault_addr, + ¤t->thread.fault_catcher)){ + if(!(mask & __GFP_WAIT)) return(NULL); + else break; + } + addr += PAGE_SIZE; + } + if(i == (1 << order)) return(page); + page = alloc_pages(mask, order); + goto again; +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c new file mode 100644 index 000000000000..a9f6264d1fc9 --- /dev/null +++ b/arch/um/kernel/tt/process_kern.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/signal.h" +#include "linux/kernel.h" +#include "asm/system.h" +#include "asm/pgalloc.h" +#include "asm/ptrace.h" +#include "asm/tlbflush.h" +#include "irq_user.h" +#include "signal_user.h" +#include "kern_util.h" +#include "user_util.h" +#include "os.h" +#include "kern.h" +#include "sigcontext.h" +#include "time_user.h" +#include "mem_user.h" +#include "tlb.h" +#include "mode.h" +#include "init.h" +#include "tt.h" + +void *switch_to_tt(void *prev, void *next, void *last) +{ + struct task_struct *from, *to; + unsigned long flags; + int err, vtalrm, alrm, prof, cpu; + char c; + /* jailing and SMP are incompatible, so this doesn't need to be + * made per-cpu + */ + static int reading; + + from = prev; + to = next; + + to->thread.prev_sched = from; + + cpu = from->thread_info->cpu; + if(cpu == 0) + forward_interrupts(to->thread.mode.tt.extern_pid); +#ifdef CONFIG_SMP + forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); +#endif + local_irq_save(flags); + + vtalrm = change_sig(SIGVTALRM, 0); + alrm = change_sig(SIGALRM, 0); + prof = change_sig(SIGPROF, 0); + + forward_pending_sigio(to->thread.mode.tt.extern_pid); + + c = 0; + set_current(to); + + reading = 0; + err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); + if(err != sizeof(c)) + panic("write of switch_pipe failed, errno = %d", -err); + + reading = 1; + if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) + os_kill_process(os_getpid(), 0); + + err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); + if(err != sizeof(c)) + panic("read of switch_pipe failed, errno = %d", -err); + + /* This works around a nasty race with 'jail'. If we are switching + * between two threads of a threaded app and the incoming process + * runs before the outgoing process reaches the read, and it makes + * it all the way out to userspace, then it will have write-protected + * the outgoing process stack. Then, when the outgoing process + * returns from the write, it will segfault because it can no longer + * write its own stack. So, in order to avoid that, the incoming + * thread sits in a loop yielding until 'reading' is set. This + * isn't entirely safe, since there may be a reschedule from a timer + * happening between setting 'reading' and sleeping in read. But, + * it should get a whole quantum in which to reach the read and sleep, + * which should be enough. + */ + + if(jail){ + while(!reading) sched_yield(); + } + + change_sig(SIGVTALRM, vtalrm); + change_sig(SIGALRM, alrm); + change_sig(SIGPROF, prof); + + arch_switch(); + + flush_tlb_all(); + local_irq_restore(flags); + + return(current->thread.prev_sched); +} + +void release_thread_tt(struct task_struct *task) +{ + os_kill_process(task->thread.mode.tt.extern_pid, 0); +} + +void exit_thread_tt(void) +{ + close(current->thread.mode.tt.switch_pipe[0]); + close(current->thread.mode.tt.switch_pipe[1]); +} + +extern void schedule_tail(struct task_struct *prev); + +static void new_thread_handler(int sig) +{ + int (*fn)(void *); + void *arg; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + current->thread.regs.regs.mode.tt = (void *) (&sig + 1); + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); + + block_signals(); + init_new_thread_signals(1); +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + enable_timer(); + free_page(current->thread.temp_stack); + set_cmdline("(kernel thread)"); + force_flush_all(); + + current->thread.prev_sched = NULL; + change_sig(SIGUSR1, 1); + change_sig(SIGVTALRM, 1); + change_sig(SIGPROF, 1); + unblock_signals(); + if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) + do_exit(0); +} + +static int new_thread_proc(void *stack) +{ + init_new_thread_stack(stack, new_thread_handler); + os_usr1_process(os_getpid()); + return(0); +} + +/* Signal masking - signals are blocked at the start of fork_tramp. They + * are re-enabled when finish_fork_handler is entered by fork_tramp hitting + * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, + * so it is blocked before it's called. They are re-enabled on sigreturn + * despite the fact that they were blocked when the SIGUSR1 was issued because + * copy_thread copies the parent's signcontext, including the signal mask + * onto the signal frame. + */ + +void finish_fork_handler(int sig) +{ + current->thread.regs.regs.mode.tt = (void *) (&sig + 1); + suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); + +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + enable_timer(); + change_sig(SIGVTALRM, 1); + force_flush_all(); + if(current->mm != current->parent->mm) + protect_memory(uml_reserved, high_physmem - uml_reserved, 1, + 1, 0, 1); + task_protections((unsigned long) current->thread_info); + + current->thread.prev_sched = NULL; + + free_page(current->thread.temp_stack); + change_sig(SIGUSR1, 0); + set_user_mode(current); +} + +static int sigusr1 = SIGUSR1; + +int fork_tramp(void *stack) +{ + int sig = sigusr1; + + init_new_thread_stack(stack, finish_fork_handler); + + kill(os_getpid(), sig); + return(0); +} + +int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, + unsigned long stack_top, struct task_struct * p, + struct pt_regs *regs) +{ + int (*tramp)(void *); + int new_pid, err; + unsigned long stack; + + if(current->thread.forking) + tramp = fork_tramp; + else { + tramp = new_thread_proc; + p->thread.request.u.thread = current->thread.request.u.thread; + } + + err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); + if(err){ + printk("copy_thread : pipe failed, errno = %d\n", -err); + return(err); + } + + stack = alloc_stack(0, 0); + if(stack == 0){ + printk(KERN_ERR "copy_thread : failed to allocate " + "temporary stack\n"); + return(-ENOMEM); + } + + clone_flags &= CLONE_VM; + p->thread.temp_stack = stack; + new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, + clone_flags, tramp); + if(new_pid < 0){ + printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", + -new_pid); + return(new_pid); + } + + if(current->thread.forking){ + sc_to_sc(p->thread.regs.regs.mode.tt, + current->thread.regs.regs.mode.tt); + SC_SET_SYSCALL_RETURN(p->thread.regs.regs.mode.tt, 0); + if(sp != 0) SC_SP(p->thread.regs.regs.mode.tt) = sp; + } + p->thread.mode.tt.extern_pid = new_pid; + + current->thread.request.op = OP_FORK; + current->thread.request.u.fork.pid = new_pid; + os_usr1_process(os_getpid()); + return(0); +} + +void reboot_tt(void) +{ + current->thread.request.op = OP_REBOOT; + os_usr1_process(os_getpid()); +} + +void halt_tt(void) +{ + current->thread.request.op = OP_HALT; + os_usr1_process(os_getpid()); +} + +void kill_off_processes_tt(void) +{ + struct task_struct *p; + int me; + + me = os_getpid(); + for_each_process(p){ + if(p->thread.mode.tt.extern_pid != me) + os_kill_process(p->thread.mode.tt.extern_pid, 0); + } + if(init_task.thread.mode.tt.extern_pid != me) + os_kill_process(init_task.thread.mode.tt.extern_pid, 0); +} + +void initial_thread_cb_tt(void (*proc)(void *), void *arg) +{ + if(os_getpid() == tracing_pid){ + (*proc)(arg); + } + else { + current->thread.request.op = OP_CB; + current->thread.request.u.cb.proc = proc; + current->thread.request.u.cb.arg = arg; + os_usr1_process(os_getpid()); + } +} + +int do_proc_op(void *t, int proc_id) +{ + struct task_struct *task; + struct thread_struct *thread; + int op, pid; + + task = t; + thread = &task->thread; + op = thread->request.op; + switch(op){ + case OP_NONE: + case OP_TRACE_ON: + break; + case OP_EXEC: + pid = thread->request.u.exec.pid; + do_exec(thread->mode.tt.extern_pid, pid); + thread->mode.tt.extern_pid = pid; + cpu_tasks[task->thread_info->cpu].pid = pid; + break; + case OP_FORK: + attach_process(thread->request.u.fork.pid); + break; + case OP_CB: + (*thread->request.u.cb.proc)(thread->request.u.cb.arg); + break; + case OP_REBOOT: + case OP_HALT: + break; + default: + tracer_panic("Bad op in do_proc_op"); + break; + } + thread->request.op = OP_NONE; + return(op); +} + +void init_idle_tt(void) +{ + default_idle(); +} + +/* Changed by jail_setup, which is a setup */ +int jail = 0; + +int __init jail_setup(char *line, int *add) +{ + int ok = 1; + + if(jail) return(0); +#ifdef CONFIG_SMP + printf("'jail' may not used used in a kernel with CONFIG_SMP " + "enabled\n"); + ok = 0; +#endif +#ifdef CONFIG_HOSTFS + printf("'jail' may not used used in a kernel with CONFIG_HOSTFS " + "enabled\n"); + ok = 0; +#endif +#ifdef CONFIG_MODULES + printf("'jail' may not used used in a kernel with CONFIG_MODULES " + "enabled\n"); + ok = 0; +#endif + if(!ok) exit(1); + + /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem. + * Removing it from the bounding set eliminates the ability of anything + * to acquire it, and thus read or write kernel memory. + */ + cap_lower(cap_bset, CAP_SYS_RAWIO); + jail = 1; + return(0); +} + +__uml_setup("jail", jail_setup, +"jail\n" +" Enables the protection of kernel memory from processes.\n\n" +); + +static void mprotect_kernel_mem(int w) +{ + unsigned long start, end; + + if(!jail || (current == &init_task)) return; + + start = (unsigned long) current->thread_info + PAGE_SIZE; + end = (unsigned long) current->thread_info + PAGE_SIZE * 4; + protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1); + protect_memory(end, high_physmem - end, 1, w, 1, 1); + + start = (unsigned long) UML_ROUND_DOWN(&_stext); + end = (unsigned long) UML_ROUND_UP(&_etext); + protect_memory(start, end - start, 1, w, 1, 1); + + start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end); + end = (unsigned long) UML_ROUND_UP(&_edata); + protect_memory(start, end - start, 1, w, 1, 1); + + start = (unsigned long) UML_ROUND_DOWN(&__bss_start); + end = (unsigned long) UML_ROUND_UP(brk_start); + protect_memory(start, end - start, 1, w, 1, 1); + + mprotect_kernel_vm(w); +} + +void unprotect_kernel_mem(void) +{ + mprotect_kernel_mem(1); +} + +void protect_kernel_mem(void) +{ + mprotect_kernel_mem(0); +} + +extern void start_kernel(void); + +static int start_kernel_proc(void *unused) +{ + int pid; + + block_signals(); + pid = os_getpid(); + + cpu_tasks[0].pid = pid; + cpu_tasks[0].task = current; +#ifdef CONFIG_SMP + cpu_online_map = 1; +#endif + if(debug) os_stop_process(pid); + start_kernel(); + return(0); +} + +void set_tracing(void *task, int tracing) +{ + ((struct task_struct *) task)->thread.mode.tt.tracing = tracing; +} + +int is_tracing(void *t) +{ + return (((struct task_struct *) t)->thread.mode.tt.tracing); +} + +int set_user_mode(void *t) +{ + struct task_struct *task; + + task = t ? t : current; + if(task->thread.mode.tt.tracing) + return(1); + task->thread.request.op = OP_TRACE_ON; + os_usr1_process(os_getpid()); + return(0); +} + +void set_init_pid(int pid) +{ + int err; + + init_task.thread.mode.tt.extern_pid = pid; + err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); + if(err) panic("Can't create switch pipe for init_task, errno = %d", + err); +} + +int singlestepping_tt(void *t) +{ + struct task_struct *task = t; + + if(task->thread.mode.tt.singlestep_syscall) + return(0); + return(task->ptrace & PT_DTRACE); +} + +void clear_singlestep(void *t) +{ + struct task_struct *task = t; + + task->ptrace &= ~PT_DTRACE; +} + +int start_uml_tt(void) +{ + void *sp; + + sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - + sizeof(unsigned long); + return(tracer(start_kernel_proc, sp)); +} + +int external_pid_tt(struct task_struct *task) +{ + return(task->thread.mode.tt.extern_pid); +} + +int thread_pid_tt(struct task_struct *task) +{ + return(task->thread.mode.tt.extern_pid); +} + +int is_valid_pid(int pid) +{ + struct task_struct *task; + + read_lock(&tasklist_lock); + for_each_process(task){ + if(task->thread.mode.tt.extern_pid == pid){ + read_unlock(&tasklist_lock); + return(1); + } + } + read_unlock(&tasklist_lock); + return(0); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile new file mode 100644 index 000000000000..97d4f0bc18d7 --- /dev/null +++ b/arch/um/kernel/tt/ptproxy/Makefile @@ -0,0 +1,13 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = proxy.o ptrace.o sysdep.o wait.o + +USER_OBJS := $(foreach file,$(obj-y),$(src)/$(file)) + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean: diff --git a/arch/um/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c index d5cd8c8919ba..d5cd8c8919ba 100644 --- a/arch/um/ptproxy/proxy.c +++ b/arch/um/kernel/tt/ptproxy/proxy.c diff --git a/arch/um/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h index 5eb0285b1968..5eb0285b1968 100644 --- a/arch/um/ptproxy/ptproxy.h +++ b/arch/um/kernel/tt/ptproxy/ptproxy.h diff --git a/arch/um/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c index 910d026677ca..721d0a306fde 100644 --- a/arch/um/ptproxy/ptrace.c +++ b/arch/um/kernel/tt/ptproxy/ptrace.c @@ -21,6 +21,7 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml #include "user_util.h" #include "kern_util.h" #include "ptrace_user.h" +#include "tt.h" long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, long arg3, long arg4, pid_t child, int *ret) diff --git a/arch/um/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c index 50a120d5e65c..50a120d5e65c 100644 --- a/arch/um/ptproxy/sysdep.c +++ b/arch/um/kernel/tt/ptproxy/sysdep.c diff --git a/arch/um/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h index 735f488049aa..735f488049aa 100644 --- a/arch/um/ptproxy/sysdep.h +++ b/arch/um/kernel/tt/ptproxy/sysdep.h diff --git a/arch/um/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c index aad7e4b62ee5..aad7e4b62ee5 100644 --- a/arch/um/ptproxy/wait.c +++ b/arch/um/kernel/tt/ptproxy/wait.c diff --git a/arch/um/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h index 542e73ee2cee..542e73ee2cee 100644 --- a/arch/um/ptproxy/wait.h +++ b/arch/um/kernel/tt/ptproxy/wait.h diff --git a/arch/um/kernel/tt/sys-i386/Makefile b/arch/um/kernel/tt/sys-i386/Makefile new file mode 100644 index 000000000000..2ad8271c604d --- /dev/null +++ b/arch/um/kernel/tt/sys-i386/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +# Licensed under the GPL +# + +obj-y = sigcontext.o + +USER_OBJS = sigcontext.o +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) + +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +clean : diff --git a/arch/um/kernel/tt/sys-i386/sigcontext.c b/arch/um/kernel/tt/sys-i386/sigcontext.c new file mode 100644 index 000000000000..1701c0dfb030 --- /dev/null +++ b/arch/um/kernel/tt/sys-i386/sigcontext.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <asm/sigcontext.h> +#include "kern_util.h" +#include "sysdep/frame.h" + +int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data) +{ + struct arch_frame_data *arch = data; + struct sigcontext *to = to_ptr, *from = from_ptr; + struct _fpstate *to_fp, *from_fp; + unsigned long sigs; + int err; + + to_fp = to->fpstate; + from_fp = from->fpstate; + sigs = to->oldmask; + err = copy_from_user_proc(to, from, sizeof(*to)); + to->oldmask = sigs; + if(to_fp != NULL){ + err |= copy_from_user_proc(&to->fpstate, &to_fp, + sizeof(to->fpstate)); + err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size); + } + return(err); +} + +int copy_sc_to_user_tt(void *to_ptr, void *from_ptr, void *data) +{ + struct arch_frame_data *arch = data; + struct sigcontext *to = to_ptr, *from = from_ptr; + struct _fpstate *to_fp, *from_fp; + int err; + + to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to)); + from_fp = from->fpstate; + err = copy_to_user_proc(to, from, sizeof(*to)); + if(from_fp != NULL){ + err |= copy_to_user_proc(&to->fpstate, &to_fp, + sizeof(to->fpstate)); + err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size); + } + return(err); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c new file mode 100644 index 000000000000..3fb449db2885 --- /dev/null +++ b/arch/um/kernel/tt/syscall_kern.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/types.h" +#include "linux/utime.h" +#include "linux/sys.h" +#include "asm/unistd.h" +#include "asm/ptrace.h" +#include "asm/uaccess.h" +#include "asm/stat.h" +#include "sysdep/syscalls.h" +#include "kern_util.h" + +static inline int check_area(void *ptr, int size) +{ + return(verify_area(VERIFY_WRITE, ptr, size)); +} + +static int check_readlink(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], regs->regs.args[2])); +} + +static int check_utime(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], + sizeof(struct utimbuf))); +} + +static int check_oldstat(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], + sizeof(struct __old_kernel_stat))); +} + +static int check_stat(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], sizeof(struct stat))); +} + +static int check_stat64(struct pt_regs *regs) +{ + return(check_area((void *) regs->regs.args[1], sizeof(struct stat64))); +} + +struct bogus { + int kernel_ds; + int (*check_params)(struct pt_regs *); +}; + +struct bogus this_is_bogus[256] = { + [ __NR_mknod ] = { 1, NULL }, + [ __NR_mkdir ] = { 1, NULL }, + [ __NR_rmdir ] = { 1, NULL }, + [ __NR_unlink ] = { 1, NULL }, + [ __NR_symlink ] = { 1, NULL }, + [ __NR_link ] = { 1, NULL }, + [ __NR_rename ] = { 1, NULL }, + [ __NR_umount ] = { 1, NULL }, + [ __NR_mount ] = { 1, NULL }, + [ __NR_pivot_root ] = { 1, NULL }, + [ __NR_chdir ] = { 1, NULL }, + [ __NR_chroot ] = { 1, NULL }, + [ __NR_open ] = { 1, NULL }, + [ __NR_quotactl ] = { 1, NULL }, + [ __NR_sysfs ] = { 1, NULL }, + [ __NR_readlink ] = { 1, check_readlink }, + [ __NR_acct ] = { 1, NULL }, + [ __NR_execve ] = { 1, NULL }, + [ __NR_uselib ] = { 1, NULL }, + [ __NR_statfs ] = { 1, NULL }, + [ __NR_truncate ] = { 1, NULL }, + [ __NR_access ] = { 1, NULL }, + [ __NR_chmod ] = { 1, NULL }, + [ __NR_chown ] = { 1, NULL }, + [ __NR_lchown ] = { 1, NULL }, + [ __NR_utime ] = { 1, check_utime }, + [ __NR_oldlstat ] = { 1, check_oldstat }, + [ __NR_oldstat ] = { 1, check_oldstat }, + [ __NR_stat ] = { 1, check_stat }, + [ __NR_lstat ] = { 1, check_stat }, + [ __NR_stat64 ] = { 1, check_stat64 }, + [ __NR_lstat64 ] = { 1, check_stat64 }, + [ __NR_chown32 ] = { 1, NULL }, +}; + +/* sys_utimes */ + +static int check_bogosity(struct pt_regs *regs) +{ + struct bogus *bogon = &this_is_bogus[regs->regs.syscall]; + + if(!bogon->kernel_ds) return(0); + if(bogon->check_params && (*bogon->check_params)(regs)) + return(-EFAULT); + set_fs(KERNEL_DS); + return(0); +} + +extern syscall_handler_t *sys_call_table[]; + +long execute_syscall_tt(void *r) +{ + struct pt_regs *regs = r; + long res; + int syscall; + + current->thread.nsyscalls++; + nsyscalls++; + syscall = regs->regs.syscall; + + if((syscall >= NR_syscalls) || (syscall < 0)) + res = -ENOSYS; + else if(honeypot && check_bogosity(regs)) + res = -EFAULT; + else res = EXECUTE_SYSCALL(syscall, regs); + + set_fs(USER_DS); + + if(current->thread.mode.tt.singlestep_syscall){ + current->thread.mode.tt.singlestep_syscall = 0; + current->ptrace &= ~PT_DTRACE; + force_sig(SIGTRAP, current); + } + + return(res); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c new file mode 100644 index 000000000000..699e91f09c92 --- /dev/null +++ b/arch/um/kernel/tt/syscall_user.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sys/ptrace.h> +#include <asm/unistd.h> +#include "sysdep/ptrace.h" +#include "sigcontext.h" +#include "ptrace_user.h" +#include "task.h" +#include "user_util.h" +#include "kern_util.h" +#include "syscall_user.h" +#include "tt.h" + +/* XXX Bogus */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 + +void syscall_handler_tt(int sig, struct uml_pt_regs *regs) +{ + void *sc; + long result; + int index, syscall; + + syscall = regs->syscall; + sc = regs->mode.tt; + sc_to_regs(regs, sc, syscall); + SC_START_SYSCALL(sc); + + index = record_syscall_start(syscall); + syscall_trace(); + result = execute_syscall(regs); + + /* regs->sc may have changed while the system call ran (there may + * have been an interrupt or segfault), so it needs to be refreshed. + */ + regs->mode.tt = sc; + + SC_SET_SYSCALL_RETURN(sc, result); + if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || + (result == -ERESTARTNOINTR)) + do_signal(result); + + syscall_trace(); + record_syscall_end(index, result); +} + +int do_syscall(void *task, int pid) +{ + unsigned long proc_regs[FRAME_SIZE]; + struct uml_pt_regs *regs; + int syscall; + + if(ptrace_getregs(pid, proc_regs) < 0) + tracer_panic("Couldn't read registers"); + syscall = PT_SYSCALL_NR(proc_regs); + + regs = TASK_REGS(task); + UPT_SYSCALL_NR(regs) = syscall; + + if(syscall < 1) return(0); + + if((syscall != __NR_sigreturn) && + ((unsigned long *) PT_IP(proc_regs) >= &_stext) && + ((unsigned long *) PT_IP(proc_regs) <= &_etext)) + tracer_panic("I'm tracing myself and I can't get out"); + + if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, + __NR_getpid) < 0) + tracer_panic("do_syscall : Nullifying syscall failed, " + "errno = %d", errno); + return(1); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c new file mode 100644 index 000000000000..8565b71b07cd --- /dev/null +++ b/arch/um/kernel/tt/time.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <signal.h> +#include <sys/time.h> +#include <time_user.h> +#include "process.h" +#include "user.h" + +void user_time_init_tt(void) +{ + if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) + panic("Couldn't set SIGVTALRM handler"); + set_interval(ITIMER_VIRTUAL); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c new file mode 100644 index 000000000000..e7e95a5c6ad2 --- /dev/null +++ b/arch/um/kernel/tt/tlb.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/kernel.h" +#include "linux/sched.h" +#include "linux/mm.h" +#include "asm/page.h" +#include "asm/pgtable.h" +#include "asm/uaccess.h" +#include "user_util.h" +#include "mem_user.h" +#include "os.h" + +static void fix_range(struct mm_struct *mm, unsigned long start_addr, + unsigned long end_addr, int force) +{ + pgd_t *npgd; + pmd_t *npmd; + pte_t *npte; + unsigned long addr; + int r, w, x, err; + + if((current->thread.mode.tt.extern_pid != -1) && + (current->thread.mode.tt.extern_pid != os_getpid())) + panic("fix_range fixing wrong address space, current = 0x%p", + current); + if(mm == NULL) return; + for(addr=start_addr;addr<end_addr;){ + if(addr == TASK_SIZE){ + /* Skip over kernel text, kernel data, and physical + * memory, which don't have ptes, plus kernel virtual + * memory, which is flushed separately, and remap + * the process stack. The only way to get here is + * if (end_addr == STACK_TOP) > TASK_SIZE, which is + * only true in the honeypot case. + */ + addr = STACK_TOP - ABOVE_KMEM; + continue; + } + npgd = pgd_offset(mm, addr); + npmd = pmd_offset(npgd, addr); + if(pmd_present(*npmd)){ + npte = pte_offset_kernel(npmd, addr); + r = pte_read(*npte); + w = pte_write(*npte); + x = pte_exec(*npte); + if(!pte_dirty(*npte)) w = 0; + if(!pte_young(*npte)){ + r = 0; + w = 0; + } + if(force || pte_newpage(*npte)){ + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*npte)) + map_memory(addr, + pte_val(*npte) & PAGE_MASK, + PAGE_SIZE, r, w, x); + } + else if(pte_newprot(*npte)){ + protect_memory(addr, PAGE_SIZE, r, w, x, 1); + } + *npte = pte_mkuptodate(*npte); + addr += PAGE_SIZE; + } + else { + if(force || pmd_newpage(*npmd)){ + err = os_unmap_memory((void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + pmd_mkuptodate(*npmd); + } + addr += PMD_SIZE; + } + } +} + +atomic_t vmchange_seq = ATOMIC_INIT(1); + +static void flush_kernel_vm_range(unsigned long start, unsigned long end, + int update_seq) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long addr; + int updated = 0, err; + + mm = &init_mm; + for(addr = start; addr < end;){ + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + if(pmd_present(*pmd)){ + pte = pte_offset_kernel(pmd, addr); + if(!pte_present(*pte) || pte_newpage(*pte)){ + updated = 1; + err = os_unmap_memory((void *) addr, + PAGE_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + if(pte_present(*pte)) + map_memory(addr, + pte_val(*pte) & PAGE_MASK, + PAGE_SIZE, 1, 1, 1); + } + else if(pte_newprot(*pte)){ + updated = 1; + protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + } + addr += PAGE_SIZE; + } + else { + if(pmd_newpage(*pmd)){ + updated = 1; + err = os_unmap_memory((void *) addr, PMD_SIZE); + if(err < 0) + panic("munmap failed, errno = %d\n", + -err); + } + addr += PMD_SIZE; + } + } + if(updated && update_seq) atomic_inc(&vmchange_seq); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + flush_kernel_vm_range(start, end, 1); +} + +static void protect_vm_page(unsigned long addr, int w, int must_succeed) +{ + int err; + + err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed); + if(err == 0) return; + else if((err == -EFAULT) || (err == -ENOMEM)){ + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + protect_vm_page(addr, w, 1); + } + else panic("protect_vm_page : protect failed, errno = %d\n", err); +} + +void mprotect_kernel_vm(int w) +{ + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long addr; + + mm = &init_mm; + for(addr = start_vm; addr < end_vm;){ + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + if(pmd_present(*pmd)){ + pte = pte_offset_kernel(pmd, addr); + if(pte_present(*pte)) protect_vm_page(addr, w, 0); + addr += PAGE_SIZE; + } + else addr += PMD_SIZE; + } +} + +void flush_tlb_kernel_vm_tt(void) +{ + flush_tlb_kernel_range(start_vm, end_vm); +} + +void __flush_tlb_one_tt(unsigned long addr) +{ + flush_tlb_kernel_range(addr, addr + PAGE_SIZE); +} + +void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + if(vma->vm_mm != current->mm) return; + + /* Assumes that the range start ... end is entirely within + * either process memory or kernel vm + */ + if((start >= start_vm) && (start < end_vm)) + flush_kernel_vm_range(start, end, 1); + else fix_range(vma->vm_mm, start, end, 0); +} + +void flush_tlb_mm_tt(struct mm_struct *mm) +{ + unsigned long seq; + + if(mm != current->mm) return; + + fix_range(mm, 0, STACK_TOP, 0); + + seq = atomic_read(&vmchange_seq); + if(current->thread.mode.tt.vm_seq == seq) return; + current->thread.mode.tt.vm_seq = seq; + flush_kernel_vm_range(start_vm, end_vm, 0); +} + +void force_flush_all_tt(void) +{ + fix_range(current->mm, 0, STACK_TOP, 1); + flush_kernel_vm_range(start_vm, end_vm, 0); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c new file mode 100644 index 000000000000..90e948c836bb --- /dev/null +++ b/arch/um/kernel/tt/tracer.c @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sched.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/ptrace.h> +#include <sys/time.h> +#include <sys/wait.h> +#include "user.h" +#include "sysdep/ptrace.h" +#include "sigcontext.h" +#include "sysdep/sigcontext.h" +#include "os.h" +#include "signal_user.h" +#include "user_util.h" +#include "mem_user.h" +#include "process.h" +#include "kern_util.h" +#include "frame.h" +#include "chan_user.h" +#include "ptrace_user.h" +#include "mode.h" +#include "tt.h" + +static int tracer_winch[2]; + +int is_tracer_winch(int pid, int fd, void *data) +{ + if(pid != tracing_pid) + return(0); + + register_winch_irq(tracer_winch[0], fd, -1, data); + return(0); +} + +static void tracer_winch_handler(int sig) +{ + char c = 1; + + if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c)) + printk("tracer_winch_handler - write failed, errno = %d\n", + errno); +} + +/* Called only by the tracing thread during initialization */ + +static void setup_tracer_winch(void) +{ + int err; + + err = os_pipe(tracer_winch, 1, 1); + if(err){ + printk("setup_tracer_winch : os_pipe failed, errno = %d\n", + -err); + return; + } + signal(SIGWINCH, tracer_winch_handler); +} + +void attach_process(int pid) +{ + if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || + (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) + tracer_panic("OP_FORK failed to attach pid"); + wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); + if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) + tracer_panic("OP_FORK failed to continue process"); +} + +void tracer_panic(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + printf("\n"); + while(1) pause(); +} + +static void tracer_segv(int sig, struct sigcontext sc) +{ + printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", + SC_FAULT_ADDR(&sc), SC_IP(&sc)); + while(1) + pause(); +} + +/* Changed early in boot, and then only read */ +int debug = 0; +int debug_stop = 1; +int debug_parent = 0; +int honeypot = 0; + +static int signal_tramp(void *arg) +{ + int (*proc)(void *); + + if(honeypot && munmap((void *) (host_task_size - 0x10000000), + 0x10000000)) + panic("Unmapping stack failed"); + if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) + panic("ptrace PTRACE_TRACEME failed"); + os_stop_process(os_getpid()); + change_sig(SIGWINCH, 0); + signal(SIGUSR1, SIG_IGN); + change_sig(SIGCHLD, 0); + signal(SIGSEGV, (__sighandler_t) sig_handler); + set_cmdline("(idle thread)"); + set_init_pid(os_getpid()); + proc = arg; + return((*proc)(NULL)); +} + +static void last_ditch_exit(int sig) +{ + kmalloc_ok = 0; + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + uml_cleanup(); + exit(1); +} + +static void sleeping_process_signal(int pid, int sig) +{ + switch(sig){ + /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is + * right because the process must be in the kernel already. + */ + case SIGCONT: + case SIGTSTP: + if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) + tracer_panic("sleeping_process_signal : Failed to " + "continue pid %d, errno = %d\n", pid, + sig); + break; + + /* This happens when the debugger (e.g. strace) is doing system call + * tracing on the kernel. During a context switch, the current task + * will be set to the incoming process and the outgoing process will + * hop into write and then read. Since it's not the current process + * any more, the trace of those will land here. So, we need to just + * PTRACE_SYSCALL it. + */ + case SIGTRAP: + if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) + tracer_panic("sleeping_process_signal : Failed to " + "PTRACE_SYSCALL pid %d, errno = %d\n", + pid, sig); + break; + case SIGSTOP: + break; + default: + tracer_panic("sleeping process %d got unexpected " + "signal : %d\n", pid, sig); + break; + } +} + +/* Accessed only by the tracing thread */ +int debugger_pid = -1; +int debugger_parent = -1; +int debugger_fd = -1; +int gdb_pid = -1; + +struct { + int pid; + int signal; + unsigned long addr; + struct timeval time; +} signal_record[1024][32]; + +int signal_index[32]; +int nsignals = 0; +int debug_trace = 0; +extern int io_nsignals, io_count, intr_count; + +extern void signal_usr1(int sig); + +int tracing_pid = -1; + +int tracer(int (*init_proc)(void *), void *sp) +{ + void *task = NULL; + unsigned long eip = 0; + int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; + int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; + + capture_signal_stack(); + signal(SIGPIPE, SIG_IGN); + setup_tracer_winch(); + tracing_pid = os_getpid(); + printf("tracing thread pid = %d\n", tracing_pid); + + pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); + n = waitpid(pid, &status, WUNTRACED); + if(n < 0){ + printf("waitpid on idle thread failed, errno = %d\n", errno); + exit(1); + } + if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ + printf("Failed to continue idle thread, errno = %d\n", errno); + exit(1); + } + + signal(SIGSEGV, (sighandler_t) tracer_segv); + signal(SIGUSR1, signal_usr1); + set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + if(debug_trace){ + printf("Tracing thread pausing to be attached\n"); + stop(); + } + if(debug){ + if(gdb_pid != -1) + debugger_pid = attach_debugger(pid, gdb_pid, 1); + else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); + if(debug_parent){ + debugger_parent = os_process_parent(debugger_pid); + init_parent_proxy(debugger_parent); + err = attach(debugger_parent); + if(err){ + printf("Failed to attach debugger parent %d, " + "errno = %d\n", debugger_parent, err); + debugger_parent = -1; + } + else { + if(ptrace(PTRACE_SYSCALL, debugger_parent, + 0, 0) < 0){ + printf("Failed to continue debugger " + "parent, errno = %d\n", errno); + debugger_parent = -1; + } + } + } + } + set_cmdline("(tracing thread)"); + while(1){ + if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ + if(errno != ECHILD){ + printf("wait failed - errno = %d\n", errno); + } + continue; + } + if(pid == debugger_pid){ + int cont = 0; + + if(WIFEXITED(status) || WIFSIGNALED(status)) + debugger_pid = -1; + /* XXX Figure out how to deal with gdb and SMP */ + else cont = debugger_signal(status, cpu_tasks[0].pid); + if(cont == PTRACE_SYSCALL) strace = 1; + continue; + } + else if(pid == debugger_parent){ + debugger_parent_signal(status, pid); + continue; + } + nsignals++; + if(WIFEXITED(status)) ; +#ifdef notdef + { + printf("Child %d exited with status %d\n", pid, + WEXITSTATUS(status)); + } +#endif + else if(WIFSIGNALED(status)){ + sig = WTERMSIG(status); + if(sig != 9){ + printf("Child %d exited with signal %d\n", pid, + sig); + } + } + else if(WIFSTOPPED(status)){ + proc_id = pid_to_processor_id(pid); + sig = WSTOPSIG(status); + if(signal_index[proc_id] == 1024){ + signal_index[proc_id] = 0; + last_index = 1023; + } + else last_index = signal_index[proc_id] - 1; + if(((sig == SIGPROF) || (sig == SIGVTALRM) || + (sig == SIGALRM)) && + (signal_record[proc_id][last_index].signal == sig)&& + (signal_record[proc_id][last_index].pid == pid)) + signal_index[proc_id] = last_index; + signal_record[proc_id][signal_index[proc_id]].pid = pid; + gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); + eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); + signal_record[proc_id][signal_index[proc_id]].addr = eip; + signal_record[proc_id][signal_index[proc_id]++].signal = sig; + + if(proc_id == -1){ + sleeping_process_signal(pid, sig); + continue; + } + + task = cpu_tasks[proc_id].task; + tracing = is_tracing(task); + old_tracing = tracing; + + switch(sig){ + case SIGUSR1: + sig = 0; + op = do_proc_op(task, proc_id); + switch(op){ + case OP_TRACE_ON: + arch_leave_kernel(task, pid); + tracing = 1; + break; + case OP_REBOOT: + case OP_HALT: + unmap_physmem(); + kmalloc_ok = 0; + ptrace(PTRACE_KILL, pid, 0, 0); + return(op == OP_REBOOT); + case OP_NONE: + printf("Detaching pid %d\n", pid); + detach(pid, SIGSTOP); + continue; + default: + break; + } + /* OP_EXEC switches host processes on us, + * we want to continue the new one. + */ + pid = cpu_tasks[proc_id].pid; + break; + case SIGTRAP: + if(!tracing && (debugger_pid != -1)){ + child_signal(pid, status); + continue; + } + tracing = 0; + if(do_syscall(task, pid)) sig = SIGUSR2; + else clear_singlestep(task); + break; + case SIGPROF: + if(tracing) sig = 0; + break; + case SIGCHLD: + case SIGHUP: + sig = 0; + break; + case SIGSEGV: + case SIGIO: + case SIGALRM: + case SIGVTALRM: + case SIGFPE: + case SIGBUS: + case SIGILL: + case SIGWINCH: + default: + tracing = 0; + break; + } + set_tracing(task, tracing); + + if(!tracing && old_tracing) + arch_enter_kernel(task, pid); + + if(!tracing && (debugger_pid != -1) && (sig != 0) && + (sig != SIGALRM) && (sig != SIGVTALRM) && + (sig != SIGSEGV) && (sig != SIGTRAP) && + (sig != SIGUSR2) && (sig != SIGIO) && + (sig != SIGFPE)){ + child_signal(pid, status); + continue; + } + + if(tracing){ + if(singlestepping_tt(task)) + cont_type = PTRACE_SINGLESTEP; + else cont_type = PTRACE_SYSCALL; + } + else cont_type = PTRACE_CONT; + + if((cont_type == PTRACE_CONT) && + (debugger_pid != -1) && strace) + cont_type = PTRACE_SYSCALL; + + if(ptrace(cont_type, pid, 0, sig) != 0){ + tracer_panic("ptrace failed to continue " + "process - errno = %d\n", + errno); + } + } + } + return(0); +} + +static int __init uml_debug_setup(char *line, int *add) +{ + char *next; + + debug = 1; + *add = 0; + if(*line != '=') return(0); + line++; + + while(line != NULL){ + next = strchr(line, ','); + if(next) *next++ = '\0'; + + if(!strcmp(line, "go")) debug_stop = 0; + else if(!strcmp(line, "parent")) debug_parent = 1; + else printk("Unknown debug option : '%s'\n", line); + + line = next; + } + return(0); +} + +__uml_setup("debug", uml_debug_setup, +"debug\n" +" Starts up the kernel under the control of gdb. See the \n" +" kernel debugging tutorial and the debugging session pages\n" +" at http://user-mode-linux.sourceforge.net/ for more information.\n\n" +); + +static int __init uml_debugtrace_setup(char *line, int *add) +{ + debug_trace = 1; + return 0; +} +__uml_setup("debugtrace", uml_debugtrace_setup, +"debugtrace\n" +" Causes the tracing thread to pause until it is attached by a\n" +" debugger and continued. This is mostly for debugging crashes\n" +" early during boot, and should be pretty much obsoleted by\n" +" the debug switch.\n\n" +); + +static int __init uml_honeypot_setup(char *line, int *add) +{ + jail_setup("", add); + honeypot = 1; + return 0; +} +__uml_setup("honeypot", uml_honeypot_setup, +"honeypot\n" +" This makes UML put process stacks in the same location as they are\n" +" on the host, allowing expoits such as stack smashes to work against\n" +" UML. This implies 'jail'.\n\n" +); + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c new file mode 100644 index 000000000000..37c8af88e39e --- /dev/null +++ b/arch/um/kernel/tt/trap_user.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <errno.h> +#include <signal.h> +#include <asm/sigcontext.h> +#include "sysdep/ptrace.h" +#include "signal_user.h" +#include "user_util.h" +#include "kern_util.h" +#include "task.h" +#include "tt.h" + +void sig_handler_common_tt(int sig, struct sigcontext *sc) +{ + struct uml_pt_regs save_regs, *r; + struct signal_info *info; + int save_errno = errno, is_user; + + unprotect_kernel_mem(); + + r = (struct uml_pt_regs *) TASK_REGS(get_current()); + save_regs = *r; + is_user = user_context(SC_SP(sc)); + r->is_user = is_user; + r->mode.tt = sc; + if(sig != SIGUSR2) r->syscall = -1; + + change_sig(SIGUSR1, 1); + info = &sig_info[sig]; + if(!info->is_irq) unblock_signals(); + + (*info->handler)(sig, r); + + if(is_user){ + interrupt_end(); + block_signals(); + change_sig(SIGUSR1, 0); + set_user_mode(NULL); + } + *r = save_regs; + errno = save_errno; + if(is_user) protect_kernel_mem(); +} + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index 639ea1c4be37..639ea1c4be37 100644 --- a/arch/um/kernel/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c index 7d53a6ea2ab0..61c4cc3af749 100644 --- a/arch/um/kernel/tty_log.c +++ b/arch/um/kernel/tty_log.c @@ -103,7 +103,7 @@ static int __init set_tty_log_fd(char *name, int *add) char *end; tty_log_fd = strtoul(name, &end, 0); - if(*end != '\0'){ + if((*end != '\0') || (end == name)){ printk("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index b7d436981572..aacf0ca51a63 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -34,17 +34,21 @@ #include "initrd.h" #include "init.h" #include "os.h" +#include "choose-mode.h" +#include "mode_kern.h" +#include "mode.h" #define DEFAULT_COMMAND_LINE "root=6200" struct cpuinfo_um boot_cpu_data = { - .loops_per_jiffy = 0, - .ipi_pipe = { -1, -1 } + .loops_per_jiffy = 0, + .ipi_pipe = { -1, -1 } }; unsigned long thread_saved_pc(struct task_struct *task) { - return(os_process_pc(task->thread.extern_pid)); + return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, + task))); } static int show_cpuinfo(struct seq_file *m, void *v) @@ -93,47 +97,11 @@ pte_t * __bad_pagetable(void) return(NULL); } -extern void start_kernel(void); - -extern int debug; -extern int debug_stop; - -static int start_kernel_proc(void *unused) -{ - int pid; - - block_signals(); - pid = os_getpid(); - - cpu_tasks[0].pid = pid; - cpu_tasks[0].task = current; -#ifdef CONFIG_SMP - cpu_online_map = 1; -#endif - if(debug) os_stop_process(pid); - start_kernel(); - return(0); -} - -#ifdef CONFIG_HOST_2G_2G -#define TOP 0x80000000 -#else -#define TOP 0xc0000000 -#endif - -#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) -#define START (TOP - SIZE) - -/* Set in main */ +/* Set in linux_main */ unsigned long host_task_size; unsigned long task_size; -void set_task_sizes(int arg) -{ - /* Round up to the nearest 4M */ - host_task_size = ROUND_4M((unsigned long) &arg); - task_size = START; -} +unsigned long uml_start; /* Set in early boot */ unsigned long uml_physmem; @@ -156,7 +124,8 @@ long physmem_size = 32 * 1024 * 1024; void set_cmdline(char *cmd) { char *umid, *ptr; - if(honeypot) return; + + if(CHOOSE_MODE(honeypot, 0)) return; umid = get_umid(1); if(umid != NULL){ @@ -215,11 +184,48 @@ static int __init uml_ncpus_setup(char *line, int *add) __uml_setup("ncpus=", uml_ncpus_setup, "ncpus=<# of desired CPUs>\n" -" This tells an SMP kernel how many virtual processors to start.\n" -" Currently, this has no effect because SMP isn't enabled.\n\n" +" This tells an SMP kernel how many virtual processors to start.\n\n" ); #endif +int force_tt = 0; + +#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) +#define DEFAULT_TT 0 + +static int __init mode_tt_setup(char *line, int *add) +{ + force_tt = 1; + return(0); +} + +__uml_setup("mode=tt", mode_tt_setup, +"mode=tt\n" +" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" +" forces UML to run in tt (tracing thread) mode. It is not the default\n" +" because it's slower and less secure than skas mode.\n\n" +); + +#else +#ifdef CONFIG_MODE_SKAS + +#define DEFAULT_TT 0 + +#else +#ifdef CONFIG_MODE_TT + +#define DEFAULT_TT 1 + +#else + +#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled + +#endif +#endif +#endif + +int mode_tt = DEFAULT_TT; + static int __init Usage(char *line, int *add) { const char **p; @@ -267,8 +273,6 @@ static void __init uml_postsetup(void) return; } -extern int debug_trace; - /* Set during early boot */ unsigned long brk_start; static struct vm_reserved kernel_vm_reserved; @@ -280,7 +284,6 @@ int linux_main(int argc, char **argv) unsigned long avail; unsigned long virtmem_size, max_physmem; unsigned int i, add, err; - void *sp; for (i = 1; i < argc; i++){ if((i == 1) && (argv[i][0] == ' ')) continue; @@ -290,13 +293,14 @@ int linux_main(int argc, char **argv) } if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE); - if(!jail || debug) - remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1); - remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1); + mode_tt = force_tt ? 1 : !can_do_skas(); + uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, + &host_task_size, &task_size); + brk_start = (unsigned long) sbrk(0); - remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1); + CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); - uml_physmem = START; + uml_physmem = uml_start; /* Reserve up to 4M after the current brk */ uml_reserved = ROUND_4M(brk_start) + (1 << 22); @@ -331,8 +335,10 @@ int linux_main(int argc, char **argv) virtmem_size); err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved); - if(err) - tracer_panic("Failed to reserve VM area for kernel VM\n"); + if(err){ + printf("Failed to reserve VM area for kernel VM\n"); + exit(1); + } uml_postsetup(); @@ -340,9 +346,8 @@ int linux_main(int argc, char **argv) 2 * PAGE_SIZE; task_protections((unsigned long) &init_thread_info); - sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - - sizeof(unsigned long); - return(signals(start_kernel_proc, sp)); + + return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); } static int panic_exit(struct notifier_block *self, unsigned long unused1, diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 2ba2049510b3..e08acf5d5354 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -17,6 +17,8 @@ #include "umid.h" #include "init.h" #include "os.h" +#include "user_util.h" +#include "choose-mode.h" #define UMID_LEN 64 #define UML_DIR "~/.uml/" @@ -91,7 +93,7 @@ static int __init create_pid_file(void) return 0; } - sprintf(pid, "%d\n", (tracing_pid == -1) ? os_getpid() : tracing_pid); + sprintf(pid, "%d\n", os_getpid()); if(write(fd, pid, strlen(pid)) != strlen(pid)) printk("Write of pid file failed - errno = %d\n", errno); close(fd); @@ -179,7 +181,7 @@ int not_dead_yet(char *dir) dead = 1; } if(((kill(p, 0) < 0) && (errno == ESRCH)) || - (p == tracing_pid)) + (p == CHOOSE_MODE(tracing_pid, os_getpid()))) dead = 1; } if(!dead) return(1); diff --git a/arch/um/main.c b/arch/um/main.c index 204c7a189fdd..3addff95120c 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -17,6 +17,8 @@ #include "mem_user.h" #include "user.h" #include "init.h" +#include "mode.h" +#include "choose-mode.h" /* Set in set_stklim, which is called from main and __wrap_malloc. * __wrap_malloc only calls it if main hasn't started. @@ -97,9 +99,6 @@ int main(int argc, char **argv, char **envp) new_argv[i] = argv[i - 1]; new_argv[argc + 1] = NULL; -#ifdef PROFILING - disable_profile_timer(); -#endif execvp(new_argv[0], new_argv); perror("execing with extended args"); exit(1); @@ -108,7 +107,6 @@ int main(int argc, char **argv, char **envp) linux_prog = argv[0]; set_stklim(); - set_task_sizes(0); if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){ perror("Mallocing argv"); @@ -136,60 +134,14 @@ int main(int argc, char **argv, char **envp) return(uml_exitcode); } -/* Changed in __wrap___monstartup and __wrap_malloc very early */ -static int allocating_monbuf = 0; - -#ifdef PROFILING -extern void __real___monstartup (unsigned long, unsigned long); - -void __wrap___monstartup (unsigned long lowpc, unsigned long highpc) -{ - allocating_monbuf = 1; - __real___monstartup(lowpc, highpc); - allocating_monbuf = 0; - get_profile_timer(); -} -#endif +#define CAN_KMALLOC() \ + (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) extern void *__real_malloc(int); -extern unsigned long host_task_size; - -/* Set in __wrap_malloc early */ -static void *gmon_buf = NULL; void *__wrap_malloc(int size) { - if(allocating_monbuf){ - unsigned long start, end; - int fd; - - /* Turn this off now in case create_mem_file tries allocating - * memory - */ - allocating_monbuf = 0; - fd = create_mem_file(size); - - /* Calculate this here because linux_main hasn't run yet - * and host_task_size figures in STACK_TOP, which figures - * in kmem_end. - */ - set_task_sizes(0); - - /* Same with stacksizelim */ - set_stklim(); - - end = get_kmem_end(); - start = (end - size) & PAGE_MASK; - gmon_buf = mmap((void *) start, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_FIXED, fd, 0); - if(gmon_buf != (void *) start){ - perror("Creating gprof buffer"); - exit(1); - } - set_kmem_end(start); - return(gmon_buf); - } - if(kmalloc_ok) return(um_kmalloc(size)); + if(CAN_KMALLOC()) return(um_kmalloc(size)); else return(__real_malloc(size)); } @@ -206,11 +158,7 @@ extern void __real_free(void *); void __wrap_free(void *ptr) { - /* Could maybe unmap the gmon buffer, but we're just about to - * exit anyway - */ - if(ptr == gmon_buf) return; - if(kmalloc_ok) kfree(ptr); + if(CAN_KMALLOC()) kfree(ptr); else __real_free(ptr); } diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index d36e16af7732..37eea4a327a2 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,12 +3,12 @@ # Licensed under the GPL # -obj-y = file.o process.o tty.o +obj-y = file.o process.o tty.o drivers/ -USER_OBJS := $(foreach file,$(obj-y),arch/um/os-Linux/$(file)) +USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file)) $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< clean : diff --git a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile index f3c044922133..52cae521eb65 100644 --- a/arch/um/os-Linux/drivers/Makefile +++ b/arch/um/os-Linux/drivers/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs)) USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 53e83d6607e1..318233b06e21 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -171,7 +171,8 @@ int os_pipe(int *fds, int stream, int close_on_exec) int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err) return(-errno); + if(err) + return(-errno); if(!close_on_exec) return(0); @@ -185,6 +186,7 @@ int os_pipe(int *fds, int stream, int close_on_exec) int os_set_fd_async(int fd, int owner) { + /* XXX This should do F_GETFL first */ if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){ printk("os_set_fd_async : failed to set O_ASYNC and " "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index ca5df7d03495..b7a565a2d721 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -7,6 +7,8 @@ #include <stdio.h> #include <errno.h> #include <signal.h> +#include <sys/mman.h> +#include <sys/wait.h> #include "os.h" #include "user.h" @@ -75,9 +77,12 @@ void os_stop_process(int pid) kill(pid, SIGSTOP); } -void os_kill_process(int pid) +void os_kill_process(int pid, int reap_child) { kill(pid, SIGKILL); + if(reap_child) + waitpid(pid, NULL, 0); + } void os_usr1_process(int pid) @@ -90,6 +95,41 @@ int os_getpid(void) return(getpid()); } +int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, + int r, int w, int x) +{ + void *loc; + int prot; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + + loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, + fd, off); + if(loc < 0) + return(-errno); + return(0); +} + +int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) +{ + int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0)); + + if(mprotect(addr, len, prot) < 0) + return(-errno); + return(0); +} + +int os_unmap_memory(void *addr, int len) +{ + int err; + + err = munmap(addr, len); + if(err < 0) return(-errno); + return(0); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index 64a5c21bda29..2866ddbc9203 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -35,7 +35,7 @@ int get_pty(void) } info.fd = fd; - tracing_cb(grantpt_cb, &info); + initial_thread_cb(grantpt_cb, &info); if(info.res < 0){ printk("get_pty : Couldn't grant pty - errno = %d\n", diff --git a/arch/um/ptproxy/Makefile b/arch/um/ptproxy/Makefile deleted file mode 100644 index fdb1ba781043..000000000000 --- a/arch/um/ptproxy/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -obj-y = proxy.o ptrace.o sysdep.o wait.o - -USER_OBJS := $(foreach file,$(obj-y),arch/um/ptproxy/$(file)) - -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< - -clean: - rm -f *.o core child ptproxy - diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 19258ea6e695..bc0cbe6ba325 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,4 +1,4 @@ -obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o \ +obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \ ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o obj-$(CONFIG_HIGHMEM) += highmem.o @@ -6,28 +6,26 @@ obj-$(CONFIG_HIGHMEM) += highmem.o export-objs = ksyms.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o -USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/sys-i386/$(file)) +USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) -SYMLINKS = semaphore.c checksum.S extable.c highmem.c +SYMLINKS = semaphore.c extable.c highmem.c module.c -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< +semaphore.c-dir = kernel +extable.c-dir = mm +highmem.c-dir = mm +module.c-dir = kernel -arch/um/sys-i386/checksum.S: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/lib/$(notdir $@) $@ +define make_link + -rm -f $1 + ln -sf $(TOPDIR)/arch/i386/$($(notdir $1)-dir)/$(notdir $1) $1 +endef -arch/um/sys-i386/semaphore.c: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/kernel/$(notdir $@) $@ +$(USER_OBJS) : %.o: %.c + $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< -arch/um/sys-i386/extable.c: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@ +$(foreach f,$(SYMLINKS),$(src)/$f): + $(call make_link,$@) -arch/um/sys-i386/highmem.c: - -rm -f $@ - -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@ clean: $(MAKE) -C util clean diff --git a/arch/um/sys-i386/checksum.S b/arch/um/sys-i386/checksum.S new file mode 100644 index 000000000000..a11171fb6223 --- /dev/null +++ b/arch/um/sys-i386/checksum.S @@ -0,0 +1,460 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, <jorge@laser.satlink.net> + * Arnt Gulbrandsen, <agulbra@nvg.unit.no> + * Tom May, <ftom@netcom.com> + * Pentium Pro/II routines: + * Alexander Kjeldaas <astor@guardian.no> + * Finn Arne Gangstad <finnag@guardian.no> + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception + * handling. + * Andi Kleen, add zeroing on error + * converted to pure assembler + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/config.h> +#include <asm/errno.h> + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +/* +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) + */ + +.text +.align 4 +.globl arch_csum_partial + +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM + + /* + * Experiments with Ethernet and SLIP connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. We get at + * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. + * Fortunately, it is easy to convert 2-byte alignment to 4-byte + * alignment for the unrolled loop. + */ +arch_csum_partial: + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: unsigned char *buff + testl $2, %esi # Check alignment. + jz 2f # Jump if alignment is ok. + subl $2, %ecx # Alignment uses up two bytes. + jae 1f # Jump if we had at least two bytes. + addl $2, %ecx # ecx was < 2. Deal with it. + jmp 4f +1: movw (%esi), %bx + addl $2, %esi + addw %bx, %ax + adcl $0, %eax +2: + movl %ecx, %edx + shrl $5, %ecx + jz 2f + testl %esi, %esi +1: movl (%esi), %ebx + adcl %ebx, %eax + movl 4(%esi), %ebx + adcl %ebx, %eax + movl 8(%esi), %ebx + adcl %ebx, %eax + movl 12(%esi), %ebx + adcl %ebx, %eax + movl 16(%esi), %ebx + adcl %ebx, %eax + movl 20(%esi), %ebx + adcl %ebx, %eax + movl 24(%esi), %ebx + adcl %ebx, %eax + movl 28(%esi), %ebx + adcl %ebx, %eax + lea 32(%esi), %esi + dec %ecx + jne 1b + adcl $0, %eax +2: movl %edx, %ecx + andl $0x1c, %edx + je 4f + shrl $2, %edx # This clears CF +3: adcl (%esi), %eax + lea 4(%esi), %esi + dec %edx + jne 3b + adcl $0, %eax +4: andl $3, %ecx + jz 7f + cmpl $2, %ecx + jb 5f + movw (%esi),%cx + leal 2(%esi),%esi + je 6f + shll $16,%ecx +5: movb (%esi),%cl +6: addl %ecx,%eax + adcl $0, %eax +7: + popl %ebx + popl %esi + ret + +#else + +/* Version for PentiumII/PPro */ + +arch_csum_partial: + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: const unsigned char *buf + + testl $2, %esi + jnz 30f +10: + movl %ecx, %edx + movl %ecx, %ebx + andl $0x7c, %ebx + shrl $7, %ecx + addl %ebx,%esi + shrl $2, %ebx + negl %ebx + lea 45f(%ebx,%ebx,2), %ebx + testl %esi, %esi + jmp *%ebx + + # Handle 2-byte-aligned regions +20: addw (%esi), %ax + lea 2(%esi), %esi + adcl $0, %eax + jmp 10b + +30: subl $2, %ecx + ja 20b + je 32f + movzbl (%esi),%ebx # csumming 1 byte, 2-aligned + addl %ebx, %eax + adcl $0, %eax + jmp 80f +32: + addw (%esi), %ax # csumming 2 bytes, 2-aligned + adcl $0, %eax + jmp 80f + +40: + addl -128(%esi), %eax + adcl -124(%esi), %eax + adcl -120(%esi), %eax + adcl -116(%esi), %eax + adcl -112(%esi), %eax + adcl -108(%esi), %eax + adcl -104(%esi), %eax + adcl -100(%esi), %eax + adcl -96(%esi), %eax + adcl -92(%esi), %eax + adcl -88(%esi), %eax + adcl -84(%esi), %eax + adcl -80(%esi), %eax + adcl -76(%esi), %eax + adcl -72(%esi), %eax + adcl -68(%esi), %eax + adcl -64(%esi), %eax + adcl -60(%esi), %eax + adcl -56(%esi), %eax + adcl -52(%esi), %eax + adcl -48(%esi), %eax + adcl -44(%esi), %eax + adcl -40(%esi), %eax + adcl -36(%esi), %eax + adcl -32(%esi), %eax + adcl -28(%esi), %eax + adcl -24(%esi), %eax + adcl -20(%esi), %eax + adcl -16(%esi), %eax + adcl -12(%esi), %eax + adcl -8(%esi), %eax + adcl -4(%esi), %eax +45: + lea 128(%esi), %esi + adcl $0, %eax + dec %ecx + jge 40b + movl %edx, %ecx +50: andl $3, %ecx + jz 80f + + # Handle the last 1-3 bytes without jumping + notl %ecx # 1->2, 2->1, 3->0, higher bits are masked + movl $0xffffff,%ebx # by the shll and shrl instructions + shll $3,%ecx + shrl %cl,%ebx + andl -128(%esi),%ebx # esi is 4-aligned so should be ok + addl %ebx,%eax + adcl $0,%eax +80: + popl %ebx + popl %esi + ret + +#endif + +/* +unsigned int csum_partial_copy_generic (const char *src, char *dst, + int len, int sum, int *src_err_ptr, int *dst_err_ptr) + */ + +/* + * Copy from ds while checksumming, otherwise like csum_partial + * + * The macros SRC and DST specify the type of access for the instruction. + * thus we can call a custom exception handler for all access types. + * + * FIXME: could someone double-check whether I haven't mixed up some SRC and + * DST definitions? It's damn hard to trigger all cases. I hope I got + * them all but there's no guarantee. + */ + +#define SRC(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6001f ; \ + .previous + +#define DST(y...) \ + 9999: y; \ + .section __ex_table, "a"; \ + .long 9999b, 6002f ; \ + .previous + +.align 4 +.globl csum_partial_copy_generic_i386 + +#ifndef CONFIG_X86_USE_PPRO_CHECKSUM + +#define ARGBASE 16 +#define FP 12 + +csum_partial_copy_generic_i386: + subl $4,%esp + pushl %edi + pushl %esi + pushl %ebx + movl ARGBASE+16(%esp),%eax # sum + movl ARGBASE+12(%esp),%ecx # len + movl ARGBASE+4(%esp),%esi # src + movl ARGBASE+8(%esp),%edi # dst + + testl $2, %edi # Check alignment. + jz 2f # Jump if alignment is ok. + subl $2, %ecx # Alignment uses up two bytes. + jae 1f # Jump if we had at least two bytes. + addl $2, %ecx # ecx was < 2. Deal with it. + jmp 4f +SRC(1: movw (%esi), %bx ) + addl $2, %esi +DST( movw %bx, (%edi) ) + addl $2, %edi + addw %bx, %ax + adcl $0, %eax +2: + movl %ecx, FP(%esp) + shrl $5, %ecx + jz 2f + testl %esi, %esi +SRC(1: movl (%esi), %ebx ) +SRC( movl 4(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, (%edi) ) + adcl %edx, %eax +DST( movl %edx, 4(%edi) ) + +SRC( movl 8(%esi), %ebx ) +SRC( movl 12(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, 8(%edi) ) + adcl %edx, %eax +DST( movl %edx, 12(%edi) ) + +SRC( movl 16(%esi), %ebx ) +SRC( movl 20(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, 16(%edi) ) + adcl %edx, %eax +DST( movl %edx, 20(%edi) ) + +SRC( movl 24(%esi), %ebx ) +SRC( movl 28(%esi), %edx ) + adcl %ebx, %eax +DST( movl %ebx, 24(%edi) ) + adcl %edx, %eax +DST( movl %edx, 28(%edi) ) + + lea 32(%esi), %esi + lea 32(%edi), %edi + dec %ecx + jne 1b + adcl $0, %eax +2: movl FP(%esp), %edx + movl %edx, %ecx + andl $0x1c, %edx + je 4f + shrl $2, %edx # This clears CF +SRC(3: movl (%esi), %ebx ) + adcl %ebx, %eax +DST( movl %ebx, (%edi) ) + lea 4(%esi), %esi + lea 4(%edi), %edi + dec %edx + jne 3b + adcl $0, %eax +4: andl $3, %ecx + jz 7f + cmpl $2, %ecx + jb 5f +SRC( movw (%esi), %cx ) + leal 2(%esi), %esi +DST( movw %cx, (%edi) ) + leal 2(%edi), %edi + je 6f + shll $16,%ecx +SRC(5: movb (%esi), %cl ) +DST( movb %cl, (%edi) ) +6: addl %ecx, %eax + adcl $0, %eax +7: +5000: + +# Exception handler: +.section .fixup, "ax" + +6001: + movl ARGBASE+20(%esp), %ebx # src_err_ptr + movl $-EFAULT, (%ebx) + + # zero the complete destination - computing the rest + # is too much work + movl ARGBASE+8(%esp), %edi # dst + movl ARGBASE+12(%esp), %ecx # len + xorl %eax,%eax + rep ; stosb + + jmp 5000b + +6002: + movl ARGBASE+24(%esp), %ebx # dst_err_ptr + movl $-EFAULT,(%ebx) + jmp 5000b + +.previous + + popl %ebx + popl %esi + popl %edi + popl %ecx # equivalent to addl $4,%esp + ret + +#else + +/* Version for PentiumII/PPro */ + +#define ROUND1(x) \ + SRC(movl x(%esi), %ebx ) ; \ + addl %ebx, %eax ; \ + DST(movl %ebx, x(%edi) ) ; + +#define ROUND(x) \ + SRC(movl x(%esi), %ebx ) ; \ + adcl %ebx, %eax ; \ + DST(movl %ebx, x(%edi) ) ; + +#define ARGBASE 12 + +csum_partial_copy_generic_i386: + pushl %ebx + pushl %edi + pushl %esi + movl ARGBASE+4(%esp),%esi #src + movl ARGBASE+8(%esp),%edi #dst + movl ARGBASE+12(%esp),%ecx #len + movl ARGBASE+16(%esp),%eax #sum +# movl %ecx, %edx + movl %ecx, %ebx + movl %esi, %edx + shrl $6, %ecx + andl $0x3c, %ebx + negl %ebx + subl %ebx, %esi + subl %ebx, %edi + lea -1(%esi),%edx + andl $-32,%edx + lea 3f(%ebx,%ebx), %ebx + testl %esi, %esi + jmp *%ebx +1: addl $64,%esi + addl $64,%edi + SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) + ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52) + ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36) + ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20) + ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4) +3: adcl $0,%eax + addl $64, %edx + dec %ecx + jge 1b +4: movl ARGBASE+12(%esp),%edx #len + andl $3, %edx + jz 7f + cmpl $2, %edx + jb 5f +SRC( movw (%esi), %dx ) + leal 2(%esi), %esi +DST( movw %dx, (%edi) ) + leal 2(%edi), %edi + je 6f + shll $16,%edx +5: +SRC( movb (%esi), %dl ) +DST( movb %dl, (%edi) ) +6: addl %edx, %eax + adcl $0, %eax +7: +.section .fixup, "ax" +6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr + movl $-EFAULT, (%ebx) + # zero the complete destination (computing the rest is too much work) + movl ARGBASE+8(%esp),%edi # dst + movl ARGBASE+12(%esp),%ecx # len + xorl %eax,%eax + rep; stosb + jmp 7b +6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr + movl $-EFAULT, (%ebx) + jmp 7b +.previous + + popl %esi + popl %edi + popl %ebx + ret + +#undef ROUND +#undef ROUND1 + +#endif diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c index bf57ac7e04e1..74f70a120458 100644 --- a/arch/um/sys-i386/ksyms.c +++ b/arch/um/sys-i386/ksyms.c @@ -13,4 +13,5 @@ EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(csum_partial_copy_from); +EXPORT_SYMBOL(csum_partial_copy_to); diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 7af4ef3d5dfd..33e302160d7c 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -3,15 +3,82 @@ * Licensed under the GPL */ +#include "linux/config.h" +#include "linux/slab.h" #include "asm/uaccess.h" +#include "asm/ptrace.h" +#include "choose-mode.h" +#include "kern.h" +#ifdef CONFIG_MODE_TT extern int modify_ldt(int func, void *ptr, unsigned long bytecount); -int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) { if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); return(modify_ldt(func, ptr, bytecount)); } +#endif + +#ifdef CONFIG_MODE_SKAS +extern int userspace_pid; + +int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) +{ + struct ptrace_ldt ldt; + void *buf; + int res, n; + + buf = kmalloc(bytecount, GFP_KERNEL); + if(buf == NULL) + return(-ENOMEM); + + res = 0; + + switch(func){ + case 1: + case 0x11: + res = copy_from_user(buf, ptr, bytecount); + break; + } + + if(res != 0){ + res = -EFAULT; + goto out; + } + + ldt = ((struct ptrace_ldt) { .func = func, + .ptr = buf, + .bytecount = bytecount }); + res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt); + if(res < 0) + goto out; + + switch(func){ + case 0: + case 2: + n = res; + res = copy_to_user(ptr, buf, n); + if(res != 0) + res = -EFAULT; + else + res = n; + break; + } + + out: + kfree(buf); + return(res); +} +#endif + +int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, + ptr, bytecount)); +} + + /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index cb47c4e86b1e..817ef7479d3f 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -169,11 +169,12 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave } /* -b * FXSR floating point environment conversions. + * FXSR floating point environment conversions. */ -static inline int convert_fxsr_to_user(struct _fpstate *buf, - struct pt_regs *regs) +#ifdef CONFIG_MODE_TT +static inline int convert_fxsr_to_user_tt(struct _fpstate *buf, + struct pt_regs *regs) { struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned long env[7]; @@ -200,9 +201,17 @@ static inline int convert_fxsr_to_user(struct _fpstate *buf, } return 0; } +#endif -static inline int convert_fxsr_from_user(struct pt_regs *regs, - struct _fpstate *buf) +static inline int convert_fxsr_to_user(struct _fpstate *buf, + struct pt_regs *regs) +{ + return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); +} + +#ifdef CONFIG_MODE_TT +static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, + struct _fpstate *buf) { struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned long env[7]; @@ -230,6 +239,13 @@ static inline int convert_fxsr_from_user(struct pt_regs *regs, } return 0; } +#endif + +static inline int convert_fxsr_from_user(struct pt_regs *regs, + struct _fpstate *buf) +{ + return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0)); +} int get_fpregs(unsigned long buf, struct task_struct *child) { @@ -251,7 +267,8 @@ int set_fpregs(unsigned long buf, struct task_struct *child) else return(0); } -int get_fpxregs(unsigned long buf, struct task_struct *tsk) +#ifdef CONFIG_MODE_TT +int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk) { struct pt_regs *regs = &tsk->thread.regs; struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); @@ -262,8 +279,15 @@ int get_fpxregs(unsigned long buf, struct task_struct *tsk) if(err) return -EFAULT; else return 0; } +#endif -int set_fpxregs(unsigned long buf, struct task_struct *tsk) +int get_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0)); +} + +#ifdef CONFIG_MODE_TT +int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk) { struct pt_regs *regs = &tsk->thread.regs; struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); @@ -274,6 +298,12 @@ int set_fpxregs(unsigned long buf, struct task_struct *tsk) if(err) return -EFAULT; else return 0; } +#endif + +int set_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0)); +} #ifdef notdef int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) @@ -291,8 +321,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) return(1); } #endif -static inline void copy_fpu_fxsave(struct pt_regs *regs, - struct user_i387_struct *buf) + +#ifdef CONFIG_MODE_TT +static inline void copy_fpu_fxsave_tt(struct pt_regs *regs, + struct user_i387_struct *buf) { struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs)); unsigned short *to; @@ -307,6 +339,13 @@ static inline void copy_fpu_fxsave(struct pt_regs *regs, memcpy( to, from, 5 * sizeof(unsigned short) ); } } +#endif + +static inline void copy_fpu_fxsave(struct pt_regs *regs, + struct user_i387_struct *buf) +{ + (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0); +} int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) { diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 659db8a6e2d8..70da62313616 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -102,7 +102,7 @@ void update_debugregs(int seq) if(seq == debugregs_seq) return; me = os_getpid(); - tracing_cb(update_debugregs_cb, &me); + initial_thread_cb(update_debugregs_cb, &me); } /* diff --git a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c index e61a94651371..6d33bedc07d7 100644 --- a/arch/um/sys-i386/sigcontext.c +++ b/arch/um/sys-i386/sigcontext.c @@ -18,45 +18,6 @@ int sc_size(void *data) return(sizeof(struct sigcontext) + arch->fpstate_size); } -int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data) -{ - struct arch_frame_data *arch = data; - struct sigcontext *to = to_ptr, *from = from_ptr; - struct _fpstate *to_fp, *from_fp; - int err; - - to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to)); - from_fp = from->fpstate; - err = copy_to_user_proc(to, from, sizeof(*to)); - if(from_fp != NULL){ - err |= copy_to_user_proc(&to->fpstate, &to_fp, - sizeof(to->fpstate)); - err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size); - } - return(err); -} - -int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data) -{ - struct arch_frame_data *arch = data; - struct sigcontext *to = to_ptr, *from = from_ptr; - struct _fpstate *to_fp, *from_fp; - unsigned long sigs; - int err; - - to_fp = to->fpstate; - from_fp = from->fpstate; - sigs = to->oldmask; - err = copy_from_user_proc(to, from, sizeof(*to)); - to->oldmask = sigs; - if(to_fp != NULL){ - err |= copy_from_user_proc(&to->fpstate, &to_fp, - sizeof(to->fpstate)); - err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size); - } - return(err); -} - void sc_to_sc(void *to_ptr, void *from_ptr) { struct sigcontext *to = to_ptr, *from = from_ptr; diff --git a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c index 6d7b853a6157..ad3671423d41 100644 --- a/arch/um/sys-i386/util/mk_thread_kern.c +++ b/arch/um/sys-i386/util/mk_thread_kern.c @@ -1,7 +1,19 @@ #include "linux/stddef.h" #include "linux/sched.h" -int debugreg(void) +extern void print_head(void); +extern void print_constant_ptr(char *name, int value); +extern void print_constant(char *name, char *type, int value); +extern void print_tail(void); + +#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) + +int main(int argc, char **argv) { - return(offsetof(struct task_struct, thread.arch.debugregs)); + print_head(); + print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs)); + print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid)); + print_tail(); + return(0); } + diff --git a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c index 997a02e9b35a..2620cd6aa1f1 100644 --- a/arch/um/sys-i386/util/mk_thread_user.c +++ b/arch/um/sys-i386/util/mk_thread_user.c @@ -1,12 +1,30 @@ #include <stdio.h> -#include <linux/stddef.h> -#include <asm/user.h> -extern int debugreg(void); +void print_head(void) +{ + printf("/*\n"); + printf(" * Generated by mk_thread\n"); + printf(" */\n"); + printf("\n"); + printf("#ifndef __UM_THREAD_H\n"); + printf("#define __UM_THREAD_H\n"); + printf("\n"); +} + +void print_constant_ptr(char *name, int value) +{ + printf("#define %s(task) ((unsigned long *) " + "&(((char *) (task))[%d]))\n", name, value); +} + +void print_constant(char *name, char *type, int value) +{ + printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, + value); +} -int main(int argc, char **argv) +void print_tail(void) { - printf("#define TASK_DEBUGREGS(task) ((unsigned long *) " - "&(((char *) (task))[%d]))\n", debugreg()); - return(0); + printf("\n"); + printf("#endif\n"); } diff --git a/arch/um/uml.lds.S b/arch/um/uml.lds.S index c15bc24842c3..736df4695129 100644 --- a/arch/um/uml.lds.S +++ b/arch/um/uml.lds.S @@ -38,6 +38,7 @@ SECTIONS __ex_table : { *(__ex_table) } __stop___ex_table = .; + . = ALIGN(64); __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; @@ -58,18 +59,27 @@ SECTIONS __uml_setup_start = .; .uml.setup.init : { *(.uml.setup.init) } __uml_setup_end = .; + __uml_help_start = .; .uml.help.init : { *(.uml.help.init) } __uml_help_end = .; + __uml_postsetup_start = .; .uml.postsetup.init : { *(.uml.postsetup.init) } __uml_postsetup_end = .; + __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; + + __start___param = .; + __param : { *(__param) } + __stop___param = .; + __per_cpu_start = . ; .data.percpu : { *(.data.percpu) } - __per_cpu_end = . ; + __per_cpu_end = . ; + __initcall_start = .; .initcall.init : { *(.initcall1.init) diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile index 1a59751c61e0..a595641bed1b 100644 --- a/arch/um/util/Makefile +++ b/arch/um/util/Makefile @@ -1,4 +1,4 @@ -EXTRA_TARGETS := mk_task mk_task_kern.o +EXTRA_TARGETS := mk_task mk_constants $(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o $(CC) -o $@ $^ @@ -6,6 +6,15 @@ $(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o $(obj)/mk_task_user.o: $(src)/mk_task_user.c $(CC) -o $@ -c $< +$(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o + $(CC) -o $@ $^ + +$(obj)/mk_constants_user.o : $(src)/mk_constants_user.c + $(CC) -c $< -o $@ + +$(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c + $(CC) $(CFLAGS) -c $< -o $@ + clean: $(RM) $(EXTRA_TARGETS) diff --git a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c new file mode 100644 index 000000000000..7e74934318c4 --- /dev/null +++ b/arch/um/util/mk_constants_kern.c @@ -0,0 +1,24 @@ +#include "linux/kernel.h" +#include "linux/stringify.h" +#include "asm/page.h" + +extern void print_head(void); +extern void print_constant_str(char *name, char *value); +extern void print_constant_int(char *name, int value); +extern void print_tail(void); + +int main(int argc, char **argv) +{ + print_head(); + print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE); + print_constant_str("UM_KERN_EMERG", KERN_EMERG); + print_constant_str("UM_KERN_ALERT", KERN_ALERT); + print_constant_str("UM_KERN_CRIT", KERN_CRIT); + print_constant_str("UM_KERN_ERR", KERN_ERR); + print_constant_str("UM_KERN_WARNING", KERN_WARNING); + print_constant_str("UM_KERN_NOTICE", KERN_NOTICE); + print_constant_str("UM_KERN_INFO", KERN_INFO); + print_constant_str("UM_KERN_DEBUG", KERN_DEBUG); + print_tail(); + return(0); +} diff --git a/arch/um/util/mk_constants_user.c b/arch/um/util/mk_constants_user.c new file mode 100644 index 000000000000..8f4d7e50be7c --- /dev/null +++ b/arch/um/util/mk_constants_user.c @@ -0,0 +1,28 @@ +#include <stdio.h> + +void print_head(void) +{ + printf("/*\n"); + printf(" * Generated by mk_constants\n"); + printf(" */\n"); + printf("\n"); + printf("#ifndef __UM_CONSTANTS_H\n"); + printf("#define __UM_CONSTANTS_H\n"); + printf("\n"); +} + +void print_constant_str(char *name, char *value) +{ + printf("#define %s \"%s\"\n", name, value); +} + +void print_constant_int(char *name, int value) +{ + printf("#define %s %d\n", name, value); +} + +void print_tail(void) +{ + printf("\n"); + printf("#endif\n"); +} diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 91472e7f99f7..13f7e51be1b3 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -672,6 +672,7 @@ source "drivers/usb/Kconfig" source "net/bluetooth/Kconfig" +source "arch/x86_64/oprofile/Kconfig" menu "Kernel hacking" @@ -728,7 +729,6 @@ config INIT_DEBUG config KALLSYMS bool "Load all symbols for debugging/kksymoops" - depends on DEBUG_KERNEL help Say Y here to let the kernel print out symbolic crash information and symbolic stack backtraces. This increases the size of the kernel diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index ac9649fd9b87..05f428f6a8cf 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -54,6 +54,8 @@ libs-y += arch/x86_64/lib/ core-y += arch/x86_64/kernel/ arch/x86_64/mm/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86_64/pci/ +# FIXME: is drivers- right ? +drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/ makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/x86_64/boot $(1) diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile index b81e05baff84..2d234181b61b 100644 --- a/arch/x86_64/boot/Makefile +++ b/arch/x86_64/boot/Makefile @@ -47,6 +47,7 @@ cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ $(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) + @echo 'Kernel: $@ is ready' $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index 864d6aa2ba60..e628de000df2 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -470,6 +470,7 @@ CONFIG_RTC=y # CONFIG_FTAPE is not set # CONFIG_AGP is not set # CONFIG_AGP_GART is not set +# CONFIG_AGP3 is not set # CONFIG_DRM is not set # CONFIG_MWAVE is not set CONFIG_RAW_DRIVER=y @@ -586,6 +587,11 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_BT is not set # +# Profiling support +# +# CONFIG_PROFILING is not set + +# # Kernel hacking # CONFIG_DEBUG_KERNEL=y diff --git a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile index 457a337a43c4..0fa49b5c536a 100644 --- a/arch/x86_64/ia32/Makefile +++ b/arch/x86_64/ia32/Makefile @@ -6,4 +6,4 @@ export-objs := ia32_ioctl.o sys_ia32.o obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \ ia32_signal.o \ - ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o + ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o syscall32.o diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c index ab476cbb12c9..0528b55b42d5 100644 --- a/arch/x86_64/ia32/fpu32.c +++ b/arch/x86_64/ia32/fpu32.c @@ -70,10 +70,6 @@ static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave) return ret; } -struct s10 { - u64 a; - u16 b; -} __attribute__((packed)); static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, struct _fpstate_ia32 *buf) @@ -98,9 +94,7 @@ static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, to = (struct _fpxreg *)&fxsave->st_space[0]; from = &buf->_st[0]; for (i = 0 ; i < 8 ; i++, to++, from++) { - struct s10 *top = (void *)to, *fromp = (void *)from; - if (__put_user(fromp->a, &top->a) || - __put_user(fromp->b, &top->b)) + if (__copy_from_user(to, from, sizeof(*from))) return -1; } return 0; @@ -136,9 +130,7 @@ static inline int convert_fxsr_to_user(struct _fpstate_ia32 *buf, to = &buf->_st[0]; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { - struct s10 *top = (void *)top, *fromp = (void *)from; - if (__get_user(fromp->a, &top->a) || - __get_user(fromp->b, &top->b)) + if (__copy_to_user(to, from, sizeof(*to))) return -1; } return 0; diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 3fd8ae63faaf..be9f9da4bb2d 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -23,6 +23,12 @@ #include <asm/uaccess.h> #include <asm/ia32.h> +#define ELF_NAME "elf/i386" + +#define AT_SYSINFO 32 + +#define ARCH_DLINFO NEW_AUX_ENT(AT_SYSINFO, 0xffffe000) + struct file; struct elf_phdr; diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 002940247a7f..b5f238bc5533 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -2,8 +2,6 @@ * Compatibility mode system call entry point for x86-64. * * Copyright 2000-2002 Andi Kleen, SuSE Labs. - * - * $Id: ia32entry.S,v 1.31 2002/03/24 13:01:45 ak Exp $ */ #include <asm/calling.h> @@ -15,19 +13,21 @@ #include <asm/segment.h> #include <linux/linkage.h> - .macro IA32_ARG_FIXUP + .macro IA32_ARG_FIXUP noebp=0 movl %edi,%r8d + .if \noebp + .else movl %ebp,%r9d + .endif xchg %ecx,%esi movl %ebx,%edi movl %edx,%edx /* zero extension */ .endm /* - * 32bit SYSCALL instruction entry. This is called from the 32bit vsyscall page. - * - * Register setup: + * 32bit SYSCALL instruction entry. * + * Arguments: * %eax System call number. * %ebx Arg1 * %ecx return EIP @@ -53,40 +53,51 @@ ENTRY(ia32_cstar_target) movl %eax,%eax /* zero extension */ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) + movq %rbp,RCX-ARGOFFSET(%rsp) /* this lies slightly to ptrace */ movl %ebp,%ecx movq $__USER32_CS,CS-ARGOFFSET(%rsp) movq $__USER32_DS,SS-ARGOFFSET(%rsp) movq %r11,EFLAGS-ARGOFFSET(%rsp) movq %r8,RSP-ARGOFFSET(%rsp) - /* no need to do an access_ok check here because the 32bit - user space cannot set r8 to a value > 4GB and the kernel has no - memory mapping in the first 4GB. */ + /* no need to do an access_ok check here because r8 has been + 32bit zero extended */ /* hardware stack frame is complete now */ -1: movl (%r8),%ebp +1: movl (%r8),%r9d .section __ex_table,"a" .quad 1b,cstar_badarg .previous + movq %r9,R9-ARGOFFSET(%rsp) GET_THREAD_INFO(%r10) bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10) jc ia32_tracesys +cstar_do_call: cmpl $IA32_NR_syscalls,%eax jae ia32_badsys - IA32_ARG_FIXUP + IA32_ARG_FIXUP 1 call *ia32_sys_call_table(,%rax,8) - .globl ia32_sysret + .globl cstar_sysret cstar_sysret: movq %rax,RAX-ARGOFFSET(%rsp) GET_THREAD_INFO(%r10) cli - testl $_TIF_WORK_MASK,threadinfo_flags(%r10) + testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10) jnz int_ret_from_sys_call - RESTORE_ARGS 1,0,1,1 /* could avoid the stack restore here */ - movl RIP-SWFRAME(%rsp),%ecx - movl RSP-SWFRAME(%rsp),%esp - movl EFLAGS-SWFRAME(%rsp),%r11d + RESTORE_ARGS 1,-ARG_SKIP,1,1 + movl RIP-ARGOFFSET(%rsp),%ecx + movl EFLAGS-ARGOFFSET(%rsp),%r11d + movl RSP-ARGOFFSET(%rsp),%esp swapgs sysretl +cstar_tracesys: + SAVE_REST + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace + LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST + jmp cstar_do_call + cstar_badarg: movq $-EFAULT,%rax jmp cstar_sysret @@ -115,8 +126,11 @@ cstar_badarg: ENTRY(ia32_syscall) swapgs sti + movl %eax,%eax pushq %rax cld + /* note the registers are not zero extended to the sf. + this could be a problem */ SAVE_ARGS GET_THREAD_INFO(%r10) bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10) diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 24b33f75bfb5..3d9ef0ff67ce 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -86,6 +86,11 @@ extern int overflowuid,overflowgid; +extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf); +extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf); +extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf); + + int cp_compat_stat(struct kstat *kbuf, struct compat_stat *ubuf) { if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) || diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c new file mode 100644 index 000000000000..f0d45a725064 --- /dev/null +++ b/arch/x86_64/ia32/syscall32.c @@ -0,0 +1,64 @@ +/* Copyright 2002 Andi Kleen, SuSE Labs */ + +/* vsyscall handling for 32bit processes. Map a stub page into it + on demand because 32bit cannot reach the kernel's fixmaps */ + +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/init.h> +#include <asm/proto.h> +#include <asm/tlbflush.h> + +/* 32bit SYSCALL stub mapped into user space. */ +asm(" .code32\n" + "\nsyscall32:\n" + " pushl %ebp\n" + " movl %ecx,%ebp\n" + " syscall\n" + " popl %ebp\n" + " ret\n" + "syscall32_end:\n" + " .code64\n"); + +extern unsigned char syscall32[], syscall32_end[]; + +static unsigned long syscall32_page; + +/* RED-PEN: This knows too much about high level VM */ +/* Alternative would be to generate a vma with appropiate backing options + and let it be handled by generic VM */ +int map_syscall32(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + int err = 0; + down_read(&mm->mmap_sem); + spin_lock(&mm->page_table_lock); + pmd_t *pmd = pmd_alloc(mm, pgd_offset(mm, address), address); + if (pmd && (pte = pte_alloc_map(mm, pmd, address)) != NULL) { + if (pte_none(*pte)) { + set_pte(pte, + mk_pte(virt_to_page(syscall32_page), + PAGE_KERNEL_VSYSCALL)); + } + /* Flush only the local CPU. Other CPUs taking a fault + will just end up here again */ + __flush_tlb_one(address); + } else + err = -ENOMEM; + spin_unlock(&mm->page_table_lock); + up_read(&mm->mmap_sem); + return err; +} + +static int __init init_syscall32(void) +{ + syscall32_page = get_zeroed_page(GFP_KERNEL); + if (!syscall32_page) + panic("Cannot allocate syscall32 page"); + SetPageReserved(virt_to_page(syscall32_page)); + memcpy((void *)syscall32_page, syscall32, syscall32_end - syscall32); +} + +__initcall(init_syscall32); diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index e5b573273dd8..61d5387df48c 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -9,7 +9,7 @@ export-objs := x8664_ksyms.o pci-gart.o pci-dma.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \ - setup64.o bluesmoke.o bootflag.o e820.o reboot.o profile.o + setup64.o bluesmoke.o bootflag.o e820.o reboot.o obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_X86_MSR) += msr.o @@ -24,6 +24,8 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_PROFILING) += profile.o + $(obj)/bootflag.c: @ln -sf ../../i386/kernel/bootflag.c $(obj)/bootflag.c diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index d1effba49185..f56ca7829a82 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -987,6 +987,7 @@ asmlinkage void smp_spurious_interrupt(void) printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n", smp_processor_id(), skipped); last_warning = jiffies; + skipped = 0; } else { skipped++; } diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index d7e21aa7eb0a..a2c0878a1c16 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -472,6 +472,11 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_ thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current)); #endif + /* Pending single-step? */ + if (thread_info_flags & _TIF_SINGLESTEP) { + regs->eflags |= TF_MASK; + clear_thread_flag(TIF_SINGLESTEP); + } /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index b1e4cefda410..67d2cf41c2ed 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -222,6 +222,19 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) do_timer(regs); /* + * In the SMP case we use the local APIC timer interrupt to do the profiling, + * except when we simulate SMP mode on a uniprocessor system, in that case we + * have to call the local interrupt handler. + */ + +#ifndef CONFIG_X86_LOCAL_APIC + x86_do_profile(regs); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif + +/* * If we have an externally synchronized Linux clock, then update CMOS clock * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy * closest to exactly 500 ms before the next second. If the update fails, we diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 21b3fbd5330e..46a397e924a3 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -635,7 +635,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) * interface. */ if ((regs->cs & 3) == 0) - goto clear_TF; + goto clear_TF_reenable; if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) goto clear_TF; } @@ -653,6 +653,9 @@ clear_dr7: asm("movq %0,%%db7"::"r"(0UL)); return; +clear_TF_reenable: + set_tsk_thread_flag(tsk, TIF_SINGLESTEP); + clear_TF: regs->eflags &= ~TF_MASK; return; diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index 7d2700fbbedd..2cb3459d0337 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -26,6 +26,7 @@ #include <asm/desc.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> +#include <asm/nmi.h> #include <asm/kdebug.h> #include <asm/unistd.h> @@ -116,7 +117,11 @@ EXPORT_SYMBOL_NOVERS(__read_lock_failed); EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(smp_call_function); +#endif +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM) +EXPORT_SYMBOL_GPL(set_nmi_pm_callback); +EXPORT_SYMBOL_GPL(unset_nmi_pm_callback); #endif #ifdef CONFIG_VT @@ -127,6 +132,11 @@ EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(rtc_lock); +EXPORT_SYMBOL_GPL(register_profile_notifier); +EXPORT_SYMBOL_GPL(unregister_profile_notifier); +EXPORT_SYMBOL_GPL(set_nmi_callback); +EXPORT_SYMBOL_GPL(unset_nmi_callback); + /* Export string functions. We normally rely on gcc builtin for most of these, but gcc sometimes decides not to inline them. */ #undef memcpy diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 5f93c2d6ba2f..00708d1d82e3 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -29,6 +29,7 @@ #include <asm/hardirq.h> #include <asm/smp.h> #include <asm/tlbflush.h> +#include <asm/proto.h> extern void die(const char *,struct pt_regs *,long); @@ -211,6 +212,15 @@ bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { +#ifdef CONFIG_IA32_EMULATION + /* 32bit vsyscall. map on demand. */ + if (test_thread_flag(TIF_IA32) && + address >= 0xffffe000 && address < 0xffffefff-7) { + if (map_syscall32(mm, address) < 0) + goto out_of_memory2; + return; + } +#endif printk("%s[%d] segfault at rip:%lx rsp:%lx adr:%lx err:%lx\n", tsk->comm, tsk->pid, regs->rip, regs->rsp, address, error_code); @@ -263,6 +273,7 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); +out_of_memory2: if (current->pid == 1) { yield(); goto again; @@ -300,9 +311,6 @@ vmalloc_fault: pmd_t *pmd; pte_t *pte; - printk("vmalloc_fault err %lx addr %lx rip %lx\n", - error_code, address, regs->rip); - /* * x86-64 has the same kernel 3rd level pages for all CPUs. * But for vmalloc/modules the TLB synchronization works lazily, diff --git a/arch/x86_64/oprofile/Kconfig b/arch/x86_64/oprofile/Kconfig new file mode 100644 index 000000000000..5ade19801b97 --- /dev/null +++ b/arch/x86_64/oprofile/Kconfig @@ -0,0 +1,23 @@ + +menu "Profiling support" + depends on EXPERIMENTAL + +config PROFILING + bool "Profiling support (EXPERIMENTAL)" + help + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + + +config OPROFILE + tristate "OProfile system profiling (EXPERIMENTAL)" + depends on PROFILING + help + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. + +endmenu + diff --git a/arch/x86_64/oprofile/Makefile b/arch/x86_64/oprofile/Makefile new file mode 100644 index 000000000000..ab145c3f81c5 --- /dev/null +++ b/arch/x86_64/oprofile/Makefile @@ -0,0 +1,33 @@ +# +# oprofile for x86-64. +# Just reuse the one from i386. The Hammer performance counters +# are similar to Athlon. +# + +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o ) + +oprofile-objs := $(DRIVER_OBJS) init.o timer_int.o + +oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o + +INCL := $(obj)/op_counter.h $(obj)/op_x86_model.h + +$(obj)/nmi_int.c: ${INCL} + @ln -sf ../../i386/oprofile/nmi_int.c $(obj)/nmi_int.c +$(obj)/op_model_athlon.c: ${INCL} + @ln -sf ../../i386/oprofile/op_model_athlon.c $(obj)/op_model_athlon.c +$(obj)/init.c: ${INCL} + @ln -sf ../../i386/oprofile/init.c $(obj)/init.c +$(obj)/timer_int.c: ${INCL} + @ln -sf ../../i386/oprofile/timer_int.c $(obj)/timer_int.c +$(obj)/op_counter.h: + @ln -sf ../../i386/oprofile/op_counter.h $(obj)/op_counter.h +$(obj)/op_x86_model.h: + @ln -sf ../../i386/oprofile/op_x86_model.h $(obj)/op_x86_model.h +clean-files += op_x86_model.h op_counter.h timer_int.c init.c \ + op_model_athlon.c nmi_int.c diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 2a3b46773d88..958ef4898971 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -493,8 +493,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, i acsi_delay_end(COMMAND_DELAY); DISABLE_IRQ(); - save_flags(flags); - cli(); + local_irq_save(flags); /* Low on A1 */ dma_wd.dma_mode_status = 0x88 | rwflag; MFPDELAY(); @@ -511,7 +510,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, i else dma_wd.dma_hi = (unsigned char)paddr; MFPDELAY(); - restore_flags(flags); + local_irq_restore(flags); /* send the command bytes except the last */ for( i = 0; i < 5; ++i ) { diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index 7ca90514abf0..918b0e8cb287 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -500,12 +500,11 @@ static void slm_test_ready( unsigned long dummy ) int did_wait = 0; #endif - save_flags(flags); - cli(); - + local_irq_save(flags); + addr = get_dma_addr(); if ((d = SLMEndAddr - addr) > 0) { - restore_flags(flags); + local_irq_restore(flags); /* slice not yet finished, decide whether to start another timer or to * busy-wait */ @@ -523,7 +522,7 @@ static void slm_test_ready( unsigned long dummy ) do_gettimeofday( &start_tm ); did_wait = 1; #endif - cli(); + local_irq_disable(); while( get_dma_addr() < SLMEndAddr ) barrier(); } @@ -547,7 +546,7 @@ static void slm_test_ready( unsigned long dummy ) DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 ); #endif - restore_flags(flags); + local_irq_restore(flags); #ifdef DEBUG if (did_wait) { @@ -584,10 +583,9 @@ static void slm_test_ready( unsigned long dummy ) static void set_dma_addr( unsigned long paddr ) -{ unsigned long flags; - - save_flags(flags); - cli(); +{ unsigned long flags; + + local_irq_save(flags); dma_wd.dma_lo = (unsigned char)paddr; paddr >>= 8; MFPDELAY(); @@ -599,7 +597,7 @@ static void set_dma_addr( unsigned long paddr ) else dma_wd.dma_hi = (unsigned char)paddr; MFPDELAY(); - restore_flags(flags); + local_irq_restore(flags); } diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index f28d18733af5..85728c00645f 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -72,6 +72,7 @@ #include <linux/amifd.h> #include <linux/ioport.h> #include <linux/buffer_head.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/uaccess.h> @@ -228,12 +229,11 @@ static void ms_delay(int ms) unsigned long flags; int ticks; if (ms > 0) { - save_flags(flags); - cli(); + local_irq_save(flags); while (ms_busy == 0) sleep_on(&ms_wait); ms_busy = 0; - restore_flags(flags); + local_irq_restore(flags); ticks = MS_TICKS*ms-1; ciaa.tblo=ticks%256; ciaa.tbhi=ticks/256; @@ -259,13 +259,12 @@ static void get_fdc(int drive) #ifdef DEBUG printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested); #endif - save_flags(flags); - cli(); + local_irq_save(flags); while (!try_fdc(drive)) sleep_on(&fdc_wait); fdc_busy = drive; fdc_nested++; - restore_flags(flags); + local_irq_restore(flags); } static inline void rel_fdc(void) @@ -321,8 +320,7 @@ static void fd_deselect (int drive) } get_fdc(drive); - save_flags (flags); - sti(); + local_irq_save(flags); selected = -1; @@ -330,7 +328,7 @@ static void fd_deselect (int drive) prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3)); ciab.prb = prb; - restore_flags (flags); + local_irq_restore (flags); rel_fdc(); } @@ -1305,10 +1303,9 @@ static int non_int_flush_track (unsigned long nr) rel_fdc(); return 0; } - save_flags(flags); - cli(); + local_irq_save(flags); if (writepending != 2) { - restore_flags(flags); + local_irq_restore(flags); (*unit[nr].dtype->write_fkt)(nr); if (!raw_write(nr)) { printk (KERN_NOTICE "floppy disk write protected " @@ -1320,7 +1317,7 @@ static int non_int_flush_track (unsigned long nr) sleep_on (&wait_fd_block); } else { - restore_flags(flags); + local_irq_restore(flags); ms_delay(2); /* 2 ms post_write delay */ post_write(nr); } @@ -1428,8 +1425,7 @@ static void redo_fd_request(void) * setup a callback to write the track buffer * after a short (1 tick) delay. */ - save_flags (flags); - cli(); + local_irq_save(flags); floppy->dirty = 1; /* reset the timer */ @@ -1437,7 +1433,7 @@ static void redo_fd_request(void) flush_track_timer[drive].expires = jiffies + 1; add_timer (flush_track_timer + drive); - restore_flags (flags); + local_irq_restore(flags); break; } } @@ -1606,15 +1602,14 @@ static int floppy_open(struct inode *inode, struct file *filp) } } - save_flags(flags); - cli(); + local_irq_save(flags); fd_ref[drive]++; fd_device[drive] = system; #ifdef MODULE if (unit[drive].motor == 0) MOD_INC_USE_COUNT; #endif - restore_flags(flags); + local_irq_restore(flags); if (old_dev != system) invalidate_buffers(mk_kdev(FLOPPY_MAJOR, drive + (system << 2))); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index d4d03d9a6a1d..c9dc16a8059e 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -248,24 +248,24 @@ static struct atari_floppy_struct { #define FDC_READ(reg) ({ \ /* unsigned long __flags; */ \ unsigned short __val; \ - /* save_flags(__flags); cli(); */ \ + /* local_irq_save(__flags); */ \ dma_wd.dma_mode_status = 0x80 | (reg); \ udelay(25); \ __val = dma_wd.fdc_acces_seccount; \ MFPDELAY(); \ - /* restore_flags(__flags); */ \ + /* local_irq_restore(__flags); */ \ __val & 0xff; \ }) #define FDC_WRITE(reg,val) \ do { \ /* unsigned long __flags; */ \ - /* save_flags(__flags); cli(); */ \ + /* local_irq_save(__flags); */ \ dma_wd.dma_mode_status = 0x80 | (reg); \ udelay(25); \ dma_wd.fdc_acces_seccount = (val); \ MFPDELAY(); \ - /* restore_flags(__flags); */ \ + /* local_irq_restore(__flags); */ \ } while(0) @@ -394,7 +394,7 @@ static int floppy_release( struct inode * inode, struct file * filp ); static struct timer_list motor_off_timer = TIMER_INITIALIZER(fd_motor_off_timer, 0, 0); -static struct timer_list readtrack_timer +static struct timer_list readtrack_timer = TIMER_INITIALIZER(fd_readtrack_check, 0, 0); static struct timer_list timeout_timer = @@ -434,14 +434,14 @@ static void fd_select_side( int side ) { unsigned long flags; - save_flags(flags); - cli(); /* protect against various other ints mucking around with the PSG */ + /* protect against various other ints mucking around with the PSG */ + local_irq_save(flags); sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ sound_ym.wd_data = (side == 0) ? sound_ym.rd_data_reg_sel | 0x01 : sound_ym.rd_data_reg_sel & 0xfe; - restore_flags(flags); + local_irq_restore(flags); } @@ -457,13 +457,13 @@ static void fd_select_drive( int drive ) if (drive == SelectedDrive) return; - save_flags(flags); - cli(); /* protect against various other ints mucking around with the PSG */ + /* protect against various other ints mucking around with the PSG */ + local_irq_save(flags); sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1); atari_dont_touch_floppy_select = 1; - restore_flags(flags); + local_irq_restore(flags); /* restore track register to saved value */ FDC_WRITE( FDCREG_TRACK, UD.track ); @@ -484,8 +484,8 @@ static void fd_deselect( void ) { unsigned long flags; - save_flags(flags); - cli(); /* protect against various other ints mucking around with the PSG */ + /* protect against various other ints mucking around with the PSG */ + local_irq_save(flags); atari_dont_touch_floppy_select = 0; sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */ sound_ym.wd_data = (sound_ym.rd_data_reg_sel | @@ -493,7 +493,7 @@ static void fd_deselect( void ) /* On Falcon, the drive B select line is used on the printer port, so * leave it alone... */ SelectedDrive = -1; - restore_flags(flags); + local_irq_restore(flags); } @@ -549,8 +549,8 @@ static void check_change( unsigned long dummy ) if (++drive > 1 || !UD.connected) drive = 0; - save_flags(flags); - cli(); /* protect against various other ints mucking around with the PSG */ + /* protect against various other ints mucking around with the PSG */ + local_irq_save(flags); if (!stdma_islocked()) { sound_ym.rd_data_reg_sel = 14; @@ -566,7 +566,7 @@ static void check_change( unsigned long dummy ) set_bit (drive, &changed_floppies); } } - restore_flags(flags); + local_irq_restore(flags); start_check_change_timer(); } @@ -666,13 +666,12 @@ static int do_format(kdev_t device, struct atari_format_descr *desc) DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", drive, desc->track, desc->head, desc->sect_offset )); - save_flags(flags); - cli(); + local_irq_save(flags); while( fdc_busy ) sleep_on( &fdc_wait ); fdc_busy = 1; stdma_lock(floppy_irq, NULL); atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ - restore_flags(flags); + local_irq_restore(flags); type = minor(device) >> 2; if (type) { @@ -930,8 +929,7 @@ static void fd_rwsec( void ) udelay(25); /* Setup DMA */ - save_flags(flags); - cli(); + local_irq_save(flags); dma_wd.dma_lo = (unsigned char)paddr; MFPDELAY(); paddr >>= 8; @@ -943,7 +941,7 @@ static void fd_rwsec( void ) else dma_wd.dma_hi = (unsigned char)paddr; MFPDELAY(); - restore_flags(flags); + local_irq_restore(flags); /* Clear FIFO and switch DMA to correct mode */ dma_wd.dma_mode_status = 0x90 | rwflag; @@ -990,8 +988,7 @@ static void fd_readtrack_check( unsigned long dummy ) { unsigned long flags, addr, addr2; - save_flags(flags); - cli(); + local_irq_save(flags); if (!MultReadInProgress) { /* This prevents a race condition that could arise if the @@ -1000,7 +997,7 @@ static void fd_readtrack_check( unsigned long dummy ) * already cleared 'MultReadInProgress' when flow of control * gets here. */ - restore_flags(flags); + local_irq_restore(flags); return; } @@ -1026,7 +1023,7 @@ static void fd_readtrack_check( unsigned long dummy ) */ SET_IRQ_HANDLER( NULL ); MultReadInProgress = 0; - restore_flags(flags); + local_irq_restore(flags); DPRINT(("fd_readtrack_check(): done\n")); FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); udelay(25); @@ -1038,7 +1035,7 @@ static void fd_readtrack_check( unsigned long dummy ) } else { /* not yet finished, wait another tenth rotation */ - restore_flags(flags); + local_irq_restore(flags); DPRINT(("fd_readtrack_check(): not yet finished\n")); mod_timer(&readtrack_timer, jiffies + HZ/5/10); } @@ -1199,8 +1196,7 @@ static void fd_writetrack( void ) udelay(40); /* Setup DMA */ - save_flags(flags); - cli(); + local_irq_save(flags); dma_wd.dma_lo = (unsigned char)paddr; MFPDELAY(); paddr >>= 8; @@ -1212,7 +1208,7 @@ static void fd_writetrack( void ) else dma_wd.dma_hi = (unsigned char)paddr; MFPDELAY(); - restore_flags(flags); + local_irq_restore(flags); /* Clear FIFO and switch DMA to correct mode */ dma_wd.dma_mode_status = 0x190; @@ -1325,12 +1321,11 @@ static void finish_fdc_done( int dummy ) start_check_change_timer(); start_motor_off_timer(); - save_flags(flags); - cli(); + local_irq_save(flags); stdma_release(); fdc_busy = 0; wake_up( &fdc_wait ); - restore_flags(flags); + local_irq_restore(flags); DPRINT(("finish_fdc() finished\n")); } @@ -1519,10 +1514,10 @@ void do_fd_request(request_queue_t * q) stdma_lock(floppy_irq, NULL); atari_disable_irq( IRQ_MFP_FDC ); - save_flags(flags); /* The request function is called with ints - sti(); * disabled... so must save the IPL for later */ + local_save_flags(flags); /* The request function is called with ints + local_irq_disable(); * disabled... so must save the IPL for later */ redo_fd_request(); - restore_flags(flags); + local_irq_restore(flags); atari_enable_irq( IRQ_MFP_FDC ); } diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c index 18e8548bfcdb..755fc9c3a81f 100644 --- a/drivers/block/swim_iop.c +++ b/drivers/block/swim_iop.c @@ -209,17 +209,16 @@ static void swimiop_init_request(struct swim_iop_req *req) static int swimiop_send_request(struct swim_iop_req *req) { - unsigned long cpu_flags; + unsigned long flags; int err; /* It's doubtful an interrupt routine would try to send */ /* a SWIM request, but I'd rather play it safe here. */ - save_flags(cpu_flags); - cli(); + local_irq_save(flags); if (current_req != NULL) { - restore_flags(cpu_flags); + local_irq_restore(flags); return -ENOMEM; } @@ -227,7 +226,7 @@ static int swimiop_send_request(struct swim_iop_req *req) /* Interrupts should be back on for iop_send_message() */ - restore_flags(cpu_flags); + local_irq_restore(flags); err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req, sizeof(req->command), (__u8 *) &req->command[0], @@ -423,14 +422,13 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state, { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); if (fs->state != idle) { ++fs->wanted; while (fs->state != available) { if (interruptible && signal_pending(current)) { --fs->wanted; - restore_flags(flags); + local_irq_restore(flags); return -EINTR; } interruptible_sleep_on(&fs->wait); @@ -438,7 +436,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state, --fs->wanted; } fs->state = state; - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -446,11 +444,10 @@ static void release_drive(struct floppy_state *fs) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); fs->state = idle; start_request(fs); - restore_flags(flags); + local_irq_restore(flags); } static void set_timeout(struct floppy_state *fs, int nticks, @@ -458,7 +455,7 @@ static void set_timeout(struct floppy_state *fs, int nticks, { unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); if (fs->timeout_pending) del_timer(&fs->timeout); init_timer(&fs->timeout); @@ -467,7 +464,7 @@ static void set_timeout(struct floppy_state *fs, int nticks, fs->timeout.data = (unsigned long) fs; add_timer(&fs->timeout); fs->timeout_pending = 1; - restore_flags(flags); + local_irq_restore(flags); } static void do_fd_request(request_queue_t * q) diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 80096fad0c32..263772c3ae1a 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -73,8 +73,6 @@ static struct gendisk *z2ram_gendisk; static void do_z2_request(request_queue_t *q) { - u_long start, len, addr, size; - while (!blk_queue_empty(q)) { struct request *req = elv_next_request(q); unsigned long start = req->sector << 9; diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 79ac0284783e..ed775912bac9 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -213,7 +213,7 @@ static void rs_stop(struct tty_struct *tty) if (serial_paranoia_check(info, tty->device, "rs_stop")) return; - save_flags(flags); cli(); + local_irq_save(flags); if (info->IER & UART_IER_THRI) { info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ @@ -222,7 +222,7 @@ static void rs_stop(struct tty_struct *tty) custom.intreq = IF_TBE; mb(); } - restore_flags(flags); + local_irq_restore(flags); } static void rs_start(struct tty_struct *tty) @@ -233,7 +233,7 @@ static void rs_start(struct tty_struct *tty) if (serial_paranoia_check(info, tty->device, "rs_start")) return; - save_flags(flags); cli(); + local_irq_save(flags); if (info->xmit.head != info->xmit.tail && info->xmit.buf && !(info->IER & UART_IER_THRI)) { @@ -244,7 +244,7 @@ static void rs_start(struct tty_struct *tty) custom.intreq = IF_SETCLR | IF_TBE; mb(); } - restore_flags(flags); + local_irq_restore(flags); } /* @@ -601,7 +601,7 @@ static int startup(struct async_struct * info) if (!page) return -ENOMEM; - save_flags(flags); cli(); + local_irq_save(flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -672,11 +672,11 @@ static int startup(struct async_struct * info) change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + local_irq_restore(flags); return 0; errout: - restore_flags(flags); + local_irq_restore(flags); return retval; } @@ -698,7 +698,7 @@ static void shutdown(struct async_struct * info) printk("Shutting down serial port %d ....\n", info->line); #endif - save_flags(flags); cli(); /* Disable interrupts */ + local_irq_save(flags); /* Disable interrupts */ /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -734,7 +734,7 @@ static void shutdown(struct async_struct * info) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + local_irq_restore(flags); } @@ -862,7 +862,7 @@ static void change_speed(struct async_struct *info, */ if ((cflag & CREAD) == 0) info->ignore_status_mask |= UART_LSR_DR; - save_flags(flags); cli(); + local_irq_save(flags); { short serper; @@ -880,7 +880,7 @@ static void change_speed(struct async_struct *info, } info->LCR = cval; /* Save LCR */ - restore_flags(flags); + local_irq_restore(flags); } static void rs_put_char(struct tty_struct *tty, unsigned char ch) @@ -894,17 +894,17 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch) if (!tty || !info->xmit.buf) return; - save_flags(flags); cli(); + local_irq_save(flags); if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { - restore_flags(flags); + local_irq_restore(flags); return; } info->xmit.buf[info->xmit.head++] = ch; info->xmit.head &= SERIAL_XMIT_SIZE-1; - restore_flags(flags); + local_irq_restore(flags); } static void rs_flush_chars(struct tty_struct *tty) @@ -921,14 +921,14 @@ static void rs_flush_chars(struct tty_struct *tty) || !info->xmit.buf) return; - save_flags(flags); cli(); + local_irq_save(flags); info->IER |= UART_IER_THRI; custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ custom.intreq = IF_SETCLR | IF_TBE; mb(); - restore_flags(flags); + local_irq_restore(flags); } static int rs_write(struct tty_struct * tty, int from_user, @@ -944,7 +944,7 @@ static int rs_write(struct tty_struct * tty, int from_user, if (!tty || !info->xmit.buf || !tmp_buf) return 0; - save_flags(flags); + local_save_flags(flags); if (from_user) { down(&tmp_buf_sem); while (1) { @@ -961,7 +961,7 @@ static int rs_write(struct tty_struct * tty, int from_user, ret = -EFAULT; break; } - cli(); + local_irq_disable(); c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); @@ -970,14 +970,14 @@ static int rs_write(struct tty_struct * tty, int from_user, memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1)); - restore_flags(flags); + local_irq_restore(flags); buf += c; count -= c; ret += c; } up(&tmp_buf_sem); } else { - cli(); + local_irq_disable(); while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, @@ -994,20 +994,20 @@ static int rs_write(struct tty_struct * tty, int from_user, count -= c; ret += c; } - restore_flags(flags); + local_irq_restore(flags); } if (info->xmit.head != info->xmit.tail && !tty->stopped && !tty->hw_stopped && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; - cli(); + local_irq_disable(); custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ custom.intreq = IF_SETCLR | IF_TBE; mb(); - restore_flags(flags); + local_irq_restore(flags); } return ret; } @@ -1037,9 +1037,9 @@ static void rs_flush_buffer(struct tty_struct *tty) if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) return; - save_flags(flags); cli(); + local_irq_save(flags); info->xmit.head = info->xmit.tail = 0; - restore_flags(flags); + local_irq_restore(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -1063,8 +1063,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) /* Make sure transmit interrupts are on */ /* Check this ! */ - save_flags(flags); - cli(); + local_irq_save(flags); if(!(custom.intenar & IF_TBE)) { custom.intena = IF_SETCLR | IF_TBE; mb(); @@ -1072,7 +1071,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) custom.intreq = IF_SETCLR | IF_TBE; mb(); } - restore_flags(flags); + local_irq_restore(flags); info->IER |= UART_IER_THRI; } @@ -1106,9 +1105,9 @@ static void rs_throttle(struct tty_struct * tty) if (tty->termios->c_cflag & CRTSCTS) info->MCR &= ~SER_RTS; - save_flags(flags); cli(); + local_irq_save(flags); rtsdtr_ctrl(info->MCR); - restore_flags(flags); + local_irq_restore(flags); } static void rs_unthrottle(struct tty_struct * tty) @@ -1133,9 +1132,9 @@ static void rs_unthrottle(struct tty_struct * tty) } if (tty->termios->c_cflag & CRTSCTS) info->MCR |= SER_RTS; - save_flags(flags); cli(); + local_irq_save(flags); rtsdtr_ctrl(info->MCR); - restore_flags(flags); + local_irq_restore(flags); } /* @@ -1256,10 +1255,10 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value) unsigned int result; unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); status = custom.serdatr; mb(); - restore_flags(flags); + local_irq_restore(flags); result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -1274,9 +1273,9 @@ static int get_modem_info(struct async_struct * info, unsigned int *value) unsigned long flags; control = info->MCR; - save_flags(flags); cli(); + local_irq_save(flags); status = ciab.pra; - restore_flags(flags); + local_irq_restore(flags); result = ((control & SER_RTS) ? TIOCM_RTS : 0) | ((control & SER_DTR) ? TIOCM_DTR : 0) | (!(status & SER_DCD) ? TIOCM_CAR : 0) @@ -1317,9 +1316,9 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd, default: return -EINVAL; } - save_flags(flags); cli(); + local_irq_save(flags); rtsdtr_ctrl(info->MCR); - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -1334,13 +1333,13 @@ static void rs_break(struct tty_struct *tty, int break_state) if (serial_paranoia_check(info, tty->device, "rs_break")) return; - save_flags(flags); cli(); + local_irq_save(flags); if (break_state == -1) custom.adkcon = AC_SETCLR | AC_UARTBRK; else custom.adkcon = AC_UARTBRK; mb(); - restore_flags(flags); + local_irq_restore(flags); } @@ -1394,18 +1393,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: - save_flags(flags); cli(); + local_irq_save(flags); /* note the counters on entry */ cprev = info->state->icount; - restore_flags(flags); + local_irq_restore(flags); while (1) { interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; - save_flags(flags); cli(); + local_irq_save(flags); cnow = info->state->icount; /* atomic copy */ - restore_flags(flags); + local_irq_restore(flags); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) return -EIO; /* no change => error */ @@ -1426,9 +1425,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, * RI where only 0->1 is counted. */ case TIOCGICOUNT: - save_flags(flags); cli(); + local_irq_save(flags); cnow = info->state->icount; - restore_flags(flags); + local_irq_restore(flags); icount.cts = cnow.cts; icount.dsr = cnow.dsr; icount.rng = cnow.rng; @@ -1473,9 +1472,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) { info->MCR &= ~(SER_DTR|SER_RTS); - save_flags(flags); cli(); + local_irq_save(flags); rtsdtr_ctrl(info->MCR); - restore_flags(flags); + local_irq_restore(flags); } /* Handle transition away from B0 status */ @@ -1486,9 +1485,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) !test_bit(TTY_THROTTLED, &tty->flags)) { info->MCR |= SER_RTS; } - save_flags(flags); cli(); + local_irq_save(flags); rtsdtr_ctrl(info->MCR); - restore_flags(flags); + local_irq_restore(flags); } /* Handle turning off CRTSCTS */ @@ -1532,12 +1531,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp) state = info->state; - save_flags(flags); cli(); + local_irq_save(flags); if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); MOD_DEC_USE_COUNT; - restore_flags(flags); + local_irq_restore(flags); return; } @@ -1564,7 +1563,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (state->count) { DBG_CNT("before DEC-2"); MOD_DEC_USE_COUNT; - restore_flags(flags); + local_irq_restore(flags); return; } info->flags |= ASYNC_CLOSING; @@ -1624,7 +1623,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; - restore_flags(flags); + local_irq_restore(flags); } /* @@ -1797,19 +1796,19 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready before block: ttys%d, count = %d\n", state->line, state->count); #endif - save_flags(flags); cli(); + local_irq_save(flags); if (!tty_hung_up_p(filp)) { extra_count = 1; state->count--; } - restore_flags(flags); + local_irq_restore(flags); info->blocked_open++; while (1) { - save_flags(flags); cli(); + local_irq_save(flags); if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) rtsdtr_ctrl(SER_DTR|SER_RTS); - restore_flags(flags); + local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { @@ -2009,10 +2008,10 @@ static inline int line_info(char *buf, struct serial_state *state) info->quot = 0; info->tty = 0; } - save_flags(flags); cli(); + local_irq_save(flags); status = ciab.pra; control = info ? info->MCR : status; - restore_flags(flags); + local_irq_restore(flags); stat_buf[0] = 0; stat_buf[1] = 0; @@ -2207,8 +2206,7 @@ static int __init rs_init(void) state->baud_base = amiga_colorclock; state->xmit_fifo_size = 1; - save_flags (flags); - cli(); + local_irq_save(flags); /* set ISRs, and then disable the rx interrupts */ request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); @@ -2222,7 +2220,7 @@ static int __init rs_init(void) custom.intreq = IF_RBF | IF_TBE; mb(); - restore_flags (flags); + local_irq_restore(flags); /* * set the appropriate directions for the modem control flags, diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 8e373bcbe71b..b8a01d45027d 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -201,10 +201,9 @@ static void a2232_disable_tx_interrupts(void *ptr) stat->OutDisable = -1; /* Does this here really have to be? */ - save_flags(flags); - cli(); + local_irq_save(flags); port->gs.flags &= ~GS_TX_INTEN; - restore_flags(flags); + local_irq_restore(flags); } static void a2232_enable_tx_interrupts(void *ptr) @@ -218,10 +217,9 @@ static void a2232_enable_tx_interrupts(void *ptr) stat->OutDisable = 0; /* Does this here really have to be? */ - save_flags(flags); - cli(); + local_irq_save(flags); port->gs.flags |= GS_TX_INTEN; - restore_flags(flags); + local_irq_restore(flags); } static void a2232_disable_rx_interrupts(void *ptr) @@ -252,8 +250,7 @@ static void a2232_shutdown_port(void *ptr) port = ptr; stat = a2232stat(port->which_a2232, port->which_port_on_a2232); - save_flags(flags); - cli(); + local_irq_save(flags); port->gs.flags &= ~GS_ACTIVE; @@ -266,7 +263,7 @@ static void a2232_shutdown_port(void *ptr) stat->Setup = -1; } - restore_flags(flags); + local_irq_restore(flags); /* After analyzing control flow, I think a2232_shutdown_port is actually the last call from the system when at application @@ -300,15 +297,14 @@ static int a2232_set_real_termios(void *ptr) baud = port->gs.baud; if (baud == 0) { /* speed == 0 -> drop DTR, do nothing else */ - save_flags(flags); - cli(); + local_irq_save(flags); // Clear DTR (and RTS... mhhh). status->Command = ( (status->Command & ~A2232CMD_CMask) | A2232CMD_Close ); status->OutFlush = -1; status->Setup = -1; - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -387,8 +383,7 @@ static int a2232_set_real_termios(void *ptr) /* Now we have all parameters and can go to set them: */ - save_flags(flags); - cli(); + local_irq_save(flags); status->Param = a2232_param | A2232PARAM_RcvBaud; status->Command = a2232_cmd | A2232CMD_Open | A2232CMD_Enable; @@ -396,7 +391,7 @@ static int a2232_set_real_termios(void *ptr) status->OutDisable = 0; status->Setup = -1; - restore_flags(flags); + local_irq_restore(flags); return 0; } diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index e6d33dc1e8ab..65a8e8438c0a 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -274,18 +274,18 @@ serial_paranoia_check(struct cyclades_port *info, kdev_t device, void SP(char *data){ unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); console_print(data); - restore_flags(flags); + local_irq_restore(flags); } char scrn[2]; void CP(char data){ unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); scrn[0] = data; console_print(scrn); - restore_flags(flags); + local_irq_restore(flags); }/* CP */ void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */ @@ -305,7 +305,7 @@ write_cy_cmd(volatile u_char *base_addr, u_char cmd) unsigned long flags; volatile int i; - save_flags(flags); cli(); + local_irq_save(flags); /* Check to see that the previous command has completed */ for(i = 0 ; i < 100 ; i++){ if (base_addr[CyCCR] == 0){ @@ -316,13 +316,13 @@ write_cy_cmd(volatile u_char *base_addr, u_char cmd) /* if the CCR never cleared, the previous command didn't finish within the "reasonable time" */ if ( i == 10 ) { - restore_flags(flags); + local_irq_restore(flags); return (-1); } /* Issue the new command */ base_addr[CyCCR] = cmd; - restore_flags(flags); + local_irq_restore(flags); return(0); } /* write_cy_cmd */ @@ -347,10 +347,10 @@ cy_stop(struct tty_struct *tty) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)(channel); /* index channel */ base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - restore_flags(flags); + local_irq_restore(flags); return; } /* cy_stop */ @@ -372,10 +372,10 @@ cy_start(struct tty_struct *tty) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)(channel); base_addr[CyIER] |= CyTxMpty; - restore_flags(flags); + local_irq_restore(flags); return; } /* cy_start */ @@ -816,7 +816,7 @@ startup(struct cyclades_port * info) printk("startup channel %d\n", channel); #endif - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); @@ -838,7 +838,7 @@ startup(struct cyclades_port * info) } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - restore_flags(flags); + local_irq_restore(flags); #ifdef SERIAL_DEBUG_OPEN printk(" done\n"); @@ -854,10 +854,10 @@ start_xmit( struct cyclades_port *info ) int channel; channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = channel; base_addr[CyIER] |= CyTxMpty; - restore_flags(flags); + local_irq_restore(flags); } /* start_xmit */ /* @@ -888,7 +888,7 @@ shutdown(struct cyclades_port * info) Other choices are to delay some fixed interval or schedule some later processing. */ - save_flags(flags); cli(); + local_irq_save(flags); if (info->xmit_buf){ free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; @@ -912,7 +912,7 @@ shutdown(struct cyclades_port * info) set_bit(TTY_IO_ERROR, &info->tty->flags); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + local_irq_restore(flags); #ifdef SERIAL_DEBUG_OPEN printk(" done\n"); @@ -1079,7 +1079,7 @@ config_setup(struct cyclades_port * info) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CyCMR set once only in mvme167_init_serial() */ @@ -1159,7 +1159,7 @@ config_setup(struct cyclades_port * info) clear_bit(TTY_IO_ERROR, &info->tty->flags); } - restore_flags(flags); + local_irq_restore(flags); } /* config_setup */ @@ -1180,16 +1180,16 @@ cy_put_char(struct tty_struct *tty, unsigned char ch) if (!tty || !info->xmit_buf) return; - save_flags(flags); cli(); + local_irq_save(flags); if (info->xmit_cnt >= PAGE_SIZE - 1) { - restore_flags(flags); + local_irq_restore(flags); return; } info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= PAGE_SIZE - 1; info->xmit_cnt++; - restore_flags(flags); + local_irq_restore(flags); } /* cy_put_char */ @@ -1214,10 +1214,10 @@ cy_flush_chars(struct tty_struct *tty) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = channel; base_addr[CyIER] |= CyTxMpty; - restore_flags(flags); + local_irq_restore(flags); } /* cy_flush_chars */ @@ -1262,13 +1262,13 @@ cy_write(struct tty_struct * tty, int from_user, break; } - save_flags(flags); cli(); + local_irq_save(flags); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt += c; - restore_flags(flags); + local_irq_restore(flags); buf += c; count -= c; @@ -1277,18 +1277,18 @@ cy_write(struct tty_struct * tty, int from_user, up(&tmp_buf_sem); } else { while (1) { - save_flags(flags); cli(); + local_irq_save(flags); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { - restore_flags(flags); + local_irq_restore(flags); break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt += c; - restore_flags(flags); + local_irq_restore(flags); buf += c; count -= c; @@ -1352,9 +1352,9 @@ cy_flush_buffer(struct tty_struct *tty) if (serial_paranoia_check(info, tty->device, "cy_flush_buffer")) return; - save_flags(flags); cli(); + local_irq_save(flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - restore_flags(flags); + local_irq_restore(flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) @@ -1393,10 +1393,10 @@ cy_throttle(struct tty_struct * tty) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = 0; - restore_flags(flags); + local_irq_restore(flags); return; } /* cy_throttle */ @@ -1429,10 +1429,10 @@ cy_unthrottle(struct tty_struct * tty) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; - restore_flags(flags); + local_irq_restore(flags); return; } /* cy_unthrottle */ @@ -1514,10 +1514,10 @@ get_modem_info(struct cyclades_port * info, unsigned int *value) channel = info->line; - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; status = base_addr[CyMSVR1] | base_addr[CyMSVR2]; - restore_flags(flags); + local_irq_restore(flags); result = ((status & CyRTS) ? TIOCM_RTS : 0) | ((status & CyDTR) ? TIOCM_DTR : 0) @@ -1543,13 +1543,13 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd, switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS){ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; - restore_flags(flags); + local_irq_restore(flags); } if (arg & TIOCM_DTR){ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CP('S');CP('2'); */ base_addr[CyMSVR2] = CyDTR; @@ -1557,18 +1557,18 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd, printk("cyc: %d: raising DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); #endif - restore_flags(flags); + local_irq_restore(flags); } break; case TIOCMBIC: if (arg & TIOCM_RTS){ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = 0; - restore_flags(flags); + local_irq_restore(flags); } if (arg & TIOCM_DTR){ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CP('C');CP('2'); */ base_addr[CyMSVR2] = 0; @@ -1576,23 +1576,23 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd, printk("cyc: %d: dropping DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); #endif - restore_flags(flags); + local_irq_restore(flags); } break; case TIOCMSET: if (arg & TIOCM_RTS){ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; - restore_flags(flags); + local_irq_restore(flags); }else{ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = 0; - restore_flags(flags); + local_irq_restore(flags); } if (arg & TIOCM_DTR){ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CP('S');CP('3'); */ base_addr[CyMSVR2] = CyDTR; @@ -1600,9 +1600,9 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd, printk("cyc: %d: raising DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); #endif - restore_flags(flags); + local_irq_restore(flags); }else{ - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CP('C');CP('3'); */ base_addr[CyMSVR2] = 0; @@ -1610,7 +1610,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd, printk("cyc: %d: dropping DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); #endif - restore_flags(flags); + local_irq_restore(flags); } break; default: @@ -2060,7 +2060,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, channel = info->line; while (1) { - save_flags(flags); cli(); + local_irq_save(flags); if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){ base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; @@ -2071,7 +2071,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); #endif } - restore_flags(flags); + local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ){ @@ -2082,17 +2082,17 @@ block_til_ready(struct tty_struct *tty, struct file * filp, } break; } - save_flags(flags); cli(); + local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && !(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (base_addr[CyMSVR1] & CyDCD))) { - restore_flags(flags); + local_irq_restore(flags); break; } - restore_flags(flags); + local_irq_restore(flags); if (signal_pending(current)) { retval = -ERESTARTSYS; break; @@ -2238,7 +2238,7 @@ mvme167_serial_console_setup(int cflag) u_char rcor, rbpr, badspeed = 0; unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); /* * First probe channel zero of the chip, to see what speed has @@ -2263,7 +2263,7 @@ mvme167_serial_console_setup(int cflag) my_udelay(20000L); /* Allow time for any active o/p to complete */ if(base_addr[CyCCR] != 0x00){ - restore_flags(flags); + local_irq_restore(flags); /* printk(" chip is never idle (CCR != 0)\n"); */ return; } @@ -2272,7 +2272,7 @@ mvme167_serial_console_setup(int cflag) my_udelay(1000L); if(base_addr[CyGFRCR] == 0x00){ - restore_flags(flags); + local_irq_restore(flags); /* printk(" chip is not responding (GFRCR stayed 0)\n"); */ return; } @@ -2331,7 +2331,7 @@ mvme167_serial_console_setup(int cflag) base_addr[CyIER] = CyRxData; write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); - restore_flags(flags); + local_irq_restore(flags); my_udelay(20000L); /* Let it all settle down */ @@ -2606,7 +2606,7 @@ show_status(int line_num) info->session, info->pgrp, (long)info->open_wait); - save_flags(flags); cli(); + local_irq_save(flags); /* Global Registers */ @@ -2664,7 +2664,7 @@ show_status(int line_num) printk(" CyTBPR %x\n", base_addr[CyTBPR]); printk(" CyTCOR %x\n", base_addr[CyTCOR]); - restore_flags(flags); + local_irq_restore(flags); } /* show_status */ #endif @@ -2764,7 +2764,7 @@ void serial167_console_write(struct console *co, const char *str, unsigned count u_char do_lf = 0; int i = 0; - save_flags(flags); cli(); + local_irq_save(flags); /* Ensure transmitter is enabled! */ @@ -2811,7 +2811,7 @@ void serial167_console_write(struct console *co, const char *str, unsigned count base_addr[CyIER] = ier; - restore_flags(flags); + local_irq_restore(flags); } static kdev_t serial167_console_device(struct console *c) @@ -2855,7 +2855,7 @@ void putDebugChar (int c) u_char ier; int port; - save_flags(flags); cli(); + local_irq_save(flags); /* Ensure transmitter is enabled! */ @@ -2885,7 +2885,7 @@ void putDebugChar (int c) base_addr[CyIER] = ier; - restore_flags(flags); + local_irq_restore(flags); } int getDebugChar() @@ -2907,7 +2907,7 @@ int getDebugChar() } /* OK, nothing in queue, wait in poll loop */ - save_flags(flags); cli(); + local_irq_save(flags); /* Ensure receiver is enabled! */ @@ -2953,7 +2953,7 @@ int getDebugChar() base_addr[CyIER] = ier; - restore_flags(flags); + local_irq_restore(flags); return (c); } @@ -2979,7 +2979,7 @@ debug_setup() cflag = B19200; - save_flags(flags); cli(); + local_irq_save(flags); for (i = 0; i < 4; i++) { @@ -3034,7 +3034,7 @@ debug_setup() base_addr[CyIER] = CyRxData; - restore_flags(flags); + local_irq_restore(flags); } /* debug_setup */ diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 5b0351cc11cf..4cadd82064be 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -624,11 +624,10 @@ static void scc_disable_tx_interrupts(void *ptr) unsigned long flags; SCC_ACCESS_INIT(port); - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); port->gs.flags &= ~GS_TX_INTEN; - restore_flags(flags); + local_irq_restore(flags); } @@ -638,12 +637,11 @@ static void scc_enable_tx_interrupts(void *ptr) unsigned long flags; SCC_ACCESS_INIT(port); - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); /* restart the transmitter */ scc_tx_int (0, port, 0); - restore_flags(flags); + local_irq_restore(flags); } @@ -653,11 +651,10 @@ static void scc_disable_rx_interrupts(void *ptr) unsigned long flags; SCC_ACCESS_INIT(port); - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(INT_AND_DMA_REG, ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0); - restore_flags(flags); + local_irq_restore(flags); } @@ -667,11 +664,10 @@ static void scc_enable_rx_interrupts(void *ptr) unsigned long flags; SCC_ACCESS_INIT(port); - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(INT_AND_DMA_REG, 0xff, IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL); - restore_flags(flags); + local_irq_restore(flags); } @@ -717,10 +713,9 @@ static int scc_set_real_termios (void *ptr) if (baud == 0) { /* speed == 0 -> drop DTR */ - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(TX_CTRL_REG, ~TCR_DTR, 0); - restore_flags(flags); + local_irq_restore(flags); return 0; } else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) || @@ -748,8 +743,7 @@ static int scc_set_real_termios (void *ptr) brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2; #endif /* Now we have all parameters and can go to set them: */ - save_flags(flags); - cli(); + local_irq_save(flags); /* receiver's character size and auto-enables */ SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE), @@ -773,7 +767,7 @@ static int scc_set_real_termios (void *ptr) /* BRG enable, and clock source never changes */ SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB); - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -823,13 +817,12 @@ static void scc_setsignals(struct scc_port *port, int dtr, int rts) unsigned char t; SCC_ACCESS_INIT(port); - save_flags(flags); - cli(); + local_irq_save(flags); t = SCCread(TX_CTRL_REG); if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); SCCwrite(TX_CTRL_REG, t); - restore_flags(flags); + local_irq_restore(flags); } @@ -914,8 +907,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp) }; #endif if (!(port->gs.flags & ASYNC_INITIALIZED)) { - save_flags(flags); - cli(); + local_irq_save(flags); #if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) if (MACH_IS_MVME147 || MACH_IS_MVME16x) { for (i=0; i<sizeof(mvme_init_tab)/sizeof(*mvme_init_tab); ++i) @@ -934,7 +926,7 @@ static int scc_open (struct tty_struct * tty, struct file * filp) port->c_dcd = 0; /* Prevent initial 1->0 interrupt */ scc_setsignals (port, 1,1); - restore_flags(flags); + local_irq_restore(flags); } tty->driver_data = port; @@ -982,10 +974,9 @@ static void scc_throttle (struct tty_struct * tty) SCC_ACCESS_INIT(port); if (tty->termios->c_cflag & CRTSCTS) { - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(TX_CTRL_REG, ~TCR_RTS, 0); - restore_flags(flags); + local_irq_restore(flags); } if (I_IXOFF(tty)) scc_send_xchar(tty, STOP_CHAR(tty)); @@ -999,10 +990,9 @@ static void scc_unthrottle (struct tty_struct * tty) SCC_ACCESS_INIT(port); if (tty->termios->c_cflag & CRTSCTS) { - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(TX_CTRL_REG, 0xff, TCR_RTS); - restore_flags(flags); + local_irq_restore(flags); } if (I_IXOFF(tty)) scc_send_xchar(tty, START_CHAR(tty)); @@ -1022,11 +1012,10 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state) unsigned long flags; SCC_ACCESS_INIT(port); - save_flags(flags); - cli(); + local_irq_save(flags); SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, break_state ? TCR_SEND_BREAK : 0); - restore_flags(flags); + local_irq_restore(flags); } @@ -1069,8 +1058,7 @@ static void scc_console_write (struct console *co, const char *str, unsigned cou { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); while (count--) { @@ -1078,7 +1066,7 @@ static void scc_console_write (struct console *co, const char *str, unsigned cou scc_ch_write ('\r'); scc_ch_write (*str++); } - restore_flags(flags); + local_irq_restore(flags); } static kdev_t scc_console_device(struct console *c) diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 89e956d8b011..64ee462aaa97 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -743,7 +743,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) ide_startstop_t startstop; /* for atari only: POSSIBLY BROKEN HERE(?) */ - ide_get_lock(&ide_intr_lock, ide_intr, hwgroup); + ide_get_lock(ide_intr, hwgroup); /* necessary paranoia: ensure IRQs are masked on local CPU */ local_irq_disable(); @@ -783,7 +783,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) */ /* for atari only */ - ide_release_lock(&ide_intr_lock); + ide_release_lock(); hwgroup->busy = 0; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9b4130b92ae6..3c07fbefa9bf 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -181,14 +181,6 @@ spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ -#ifdef IDE_ARCH_LOCK -/* - * ide_lock is used by the Atari code to obtain access to the IDE interrupt, - * which is shared between several drivers. - */ -static int ide_intr_lock; -#endif /* IDE_ARCH_LOCK */ - #ifdef CONFIG_IDEDMA_AUTO int noautodma = 0; #else @@ -2097,12 +2089,12 @@ void __init ide_init_builtin_drivers (void) #ifdef CONFIG_BLK_DEV_IDE if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) - ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */ + ide_get_lock(NULL, NULL); /* for atari only */ (void) ideprobe_init(); if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) - ide_release_lock(&ide_intr_lock); /* for atari only */ + ide_release_lock(); /* for atari only */ #endif /* CONFIG_BLK_DEV_IDE */ #ifdef CONFIG_PROC_FS diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index 0ff0a3c54cff..f51ff785d0ab 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/interrupt.h> #include <asm/system.h> #include <asm/amigahw.h> diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index d0a5b7617fd3..5e1cea29ffb2 100644 --- a/drivers/input/keyboard/amikbd.c +++ b/drivers/input/keyboard/amikbd.c @@ -35,6 +35,7 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <asm/amigaints.h> #include <asm/amigahw.h> diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index 91b9de9c5d47..f89593c4f4bf 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/interrupt.h> #include <asm/irq.h> #include <asm/setup.h> diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index c54b7317e59f..ad69eedf557e 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/serio.h> +#include <linux/interrupt.h> #include <asm/keyboard.h> #include <asm/bitops.h> @@ -54,7 +55,6 @@ static int q40kbd_open(struct serio *port) } static void q40kbd_close(struct serio *port) { - return 0; } static struct serio q40kbd_port = @@ -69,8 +69,6 @@ static struct serio q40kbd_port = static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - unsigned long flags; - if (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) if (q40kbd_port.dev) q40kbd_port.dev->interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0); diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c index cf0504e0e233..9a2392ac290e 100644 --- a/drivers/macintosh/adb-iop.c +++ b/drivers/macintosh/adb-iop.c @@ -83,15 +83,14 @@ static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs) struct adb_request *req; uint flags; - save_flags(flags); - cli(); + local_irq_save(flags); req = current_req; if ((adb_iop_state == sending) && req && req->reply_expected) { adb_iop_state = awaiting_reply; } - restore_flags(flags); + local_irq_restore(flags); } /* @@ -107,8 +106,7 @@ static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs) struct adb_request *req; uint flags; - save_flags(flags); - cli(); + local_irq_save(flags); req = current_req; @@ -150,7 +148,7 @@ static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs) memcpy(msg->reply, msg->message, IOP_MSG_LEN); } iop_complete_message(msg); - restore_flags(flags); + local_irq_restore(flags); } /* @@ -170,8 +168,7 @@ static void adb_iop_start(void) req = current_req; if (!req) return; - save_flags(flags); - cli(); + local_irq_save(flags); #ifdef DEBUG_ADB_IOP printk("adb_iop_start: sending packet, %d bytes:", req->nbytes); @@ -192,7 +189,7 @@ static void adb_iop_start(void) req->sent = 1; adb_iop_state = sending; - restore_flags(flags); + local_irq_restore(flags); /* Now send it. The IOP manager will call adb_iop_complete */ /* when the packet has been sent. */ @@ -236,8 +233,7 @@ static int adb_iop_write(struct adb_request *req) return -EINVAL; } - save_flags(flags); - cli(); + local_irq_save(flags); req->next = 0; req->sent = 0; @@ -252,7 +248,7 @@ static int adb_iop_write(struct adb_request *req) last_req = req; } - restore_flags(flags); + local_irq_restore(flags); if (adb_iop_state == idle) adb_iop_start(); return 0; } diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 38b2c1afdaba..32dcc992231e 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -18,6 +18,7 @@ #include <linux/adb.h> #include <linux/cuda.h> #include <linux/spinlock.h> +#include <linux/interrupt.h> #ifdef CONFIG_PPC #include <asm/prom.h> #include <asm/machdep.h> diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 82cc3df633f1..0aa34eebe478 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -21,6 +21,7 @@ #include <linux/delay.h> #include <linux/sched.h> #include <linux/adb.h> +#include <linux/interrupt.h> #include <asm/macintosh.h> #include <asm/macints.h> #include <asm/machw.h> @@ -144,8 +145,7 @@ int macii_init(void) unsigned long flags; int err; - save_flags(flags); - cli(); + local_irq_save(flags); err = macii_init_via(); if (err) return err; @@ -155,7 +155,7 @@ int macii_init(void) if (err) return err; macii_state = idle; - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -196,13 +196,12 @@ static void macii_queue_poll(void) adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, ADB_READREG(device, 0)); - save_flags(flags); - cli(); + local_irq_save(flags); req.next = current_req; current_req = &req; - restore_flags(flags); + local_irq_restore(flags); macii_start(); in_poll--; } @@ -221,8 +220,7 @@ static void macii_retransmit(int device) adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, ADB_READREG(device, 0)); - save_flags(flags); - cli(); + local_irq_save(flags); if (current_req != NULL) { last_req->next = &rt; @@ -234,7 +232,7 @@ static void macii_retransmit(int device) if (macii_state == idle) macii_start(); - restore_flags(flags); + local_irq_restore(flags); in_retransmit--; } @@ -267,7 +265,7 @@ static int macii_write(struct adb_request *req) req->complete = 0; req->reply_len = 0; - save_flags(flags); cli(); + local_irq_save(flags); if (current_req != NULL) { last_req->next = req; @@ -278,7 +276,7 @@ static int macii_write(struct adb_request *req) if (macii_state == idle) macii_start(); } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -296,9 +294,9 @@ static void macii_poll(void) { unsigned long flags; - save_flags(flags); cli(); + local_irq_save(flags); if (via[IFR] & SR_INT) macii_interrupt(0, 0, 0); - restore_flags(flags); + local_irq_restore(flags); } /* Reset the bus */ @@ -328,7 +326,7 @@ static void macii_start(void) return; } - save_flags(flags); cli(); + local_irq_save(flags); /* * IRQ signaled ?? (means ADB controller wants to send, or might @@ -356,7 +354,7 @@ static void macii_start(void) (uint) via[B] & (ST_MASK|TREQ)); retry_req = req; /* set ADB status here ? */ - restore_flags(flags); + local_irq_restore(flags); return; } else { need_poll = 0; @@ -385,7 +383,7 @@ static void macii_start(void) macii_state = sending; data_index = 2; - restore_flags(flags); + local_irq_restore(flags); } /* @@ -421,10 +419,10 @@ void macii_interrupt(int irq, void *arg, struct pt_regs *regs) last_status = status; /* prevent races due to SCSI enabling ints */ - save_flags(flags); cli(); + local_irq_save(flags); if (driver_running) { - restore_flags(flags); + local_irq_restore(flags); return; } @@ -650,5 +648,5 @@ void macii_interrupt(int irq, void *arg, struct pt_regs *regs) } /* reset mutex and interrupts */ driver_running = 0; - restore_flags(flags); + local_irq_restore(flags); } diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 7a32a295fd52..162ce3f2acd0 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c @@ -22,6 +22,7 @@ #include <linux/adb.h> #include <linux/cuda.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <asm/macintosh.h> #include <asm/macints.h> #include <asm/machw.h> @@ -312,8 +313,7 @@ maciisi_write(struct adb_request* req) req->complete = 0; req->reply_len = 0; - save_flags(flags); - cli(); + local_irq_save(flags); if (current_req) { last_req->next = req; @@ -327,7 +327,7 @@ maciisi_write(struct adb_request* req) i = maciisi_start(); if(i != 0) { - restore_flags(flags); + local_irq_restore(flags); return i; } } @@ -336,11 +336,11 @@ maciisi_write(struct adb_request* req) #ifdef DEBUG_MACIISI_ADB printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state); #endif - restore_flags(flags); + local_irq_restore(flags); return -EBUSY; } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -401,15 +401,14 @@ maciisi_poll(void) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); if (via[IFR] & SR_INT) { maciisi_interrupt(0, 0, 0); } else /* avoid calling this function too quickly in a loop */ udelay(ADB_DELAY); - restore_flags(flags); + local_irq_restore(flags); } /* Shift register interrupt - this is *supposed* to mean that the @@ -426,8 +425,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) int i; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); status = via[B] & (TIP|TREQ); #ifdef DEBUG_MACIISI_ADB @@ -437,7 +435,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) if (!(via[IFR] & SR_INT)) { /* Shouldn't happen, we hope */ printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n"); - restore_flags(flags); + local_irq_restore(flags); return; } @@ -636,7 +634,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) default: printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state); } - restore_flags(flags); + local_irq_restore(flags); } static void diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 50f62a8d2505..3bb653489391 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -28,6 +28,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/adb.h> #include <linux/pmu.h> @@ -495,7 +496,7 @@ pmu_queue_request(struct adb_request *req) req->next = 0; req->sent = 0; req->complete = 0; - save_flags(flags); cli(); + local_irq_save(flags); if (current_req != 0) { last_req->next = req; @@ -507,7 +508,7 @@ pmu_queue_request(struct adb_request *req) pmu_start(); } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -537,7 +538,7 @@ pmu_start() /* assert pmu_state == idle */ /* get the packet to send */ - save_flags(flags); cli(); + local_irq_save(flags); req = current_req; if (req == 0 || pmu_state != idle || (req->reply_expected && req_awaiting_reply)) @@ -551,16 +552,15 @@ pmu_start() send_byte(req->data[0]); out: - restore_flags(flags); + local_irq_restore(flags); } void pmu_poll() { - unsigned long cpu_flags; + unsigned long flags; - save_flags(cpu_flags); - cli(); + local_irq_save(flags); if (via1[IFR] & SR_INT) { via1[IFR] = SR_INT; pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL); @@ -569,7 +569,7 @@ pmu_poll() via1[IFR] = CB1_INT; pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL); } - restore_flags(cpu_flags); + local_irq_restore(flags); } static void @@ -963,9 +963,9 @@ int __openfirmware powerbook_sleep(void) asm volatile("mfspr %0,1008" : "=r" (hid0) :); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; asm volatile("mtspr 1008,%0" : : "r" (hid0)); - save_flags(msr); + local_save_flags(msr); msr |= MSR_POW | MSR_EE; - restore_flags(msr); + local_irq_restore(msr); udelay(10); /* OK, we're awake again, start restoring things */ diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 7661224c7286..9c986c98384b 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -571,11 +571,10 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) skblen = skb->len; - save_flags(flags); - cli(); + local_irq_save(flags); if (!TX_BUFFS_AVAIL){ - restore_flags(flags); + local_irq_restore(flags); return -1; } @@ -616,7 +615,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; dev_kfree_skb (skb); - restore_flags(flags); + local_irq_restore(flags); return status; } diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 9055f2a8317b..ea8272358c98 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -604,8 +604,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); #endif - save_flags(flags); - cli(); + local_irq_save(flags); entry = priv->cur_tx % TX_RING_SIZE; @@ -662,7 +661,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); priv->tx_full = 1; } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -765,13 +764,12 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev) short saved_addr; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); saved_addr = lance->RAP; lance->RAP = CSR112; /* Missed Frame Count */ priv->stats.rx_missed_errors = swapw(lance->RDP); lance->RAP = saved_addr; - restore_flags(flags); + local_irq_restore(flags); return &priv->stats; } diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c index 4dd5791c553c..1cd15dae2a5b 100644 --- a/drivers/net/atari_bionet.c +++ b/drivers/net/atari_bionet.c @@ -235,8 +235,7 @@ get_frame(unsigned long paddr, int odd) { unsigned long flags; DISABLE_IRQ(); - save_flags(flags); - cli(); + local_irq_save(flags); dma_wd.dma_mode_status = 0x9a; dma_wd.dma_mode_status = 0x19a; @@ -247,7 +246,7 @@ get_frame(unsigned long paddr, int odd) { dma_wd.dma_md = (unsigned char)paddr; paddr >>= 8; dma_wd.dma_hi = (unsigned char)paddr; - restore_flags(flags); + local_irq_restore(flags); c = sendcmd(0,0x00,NODE_ADR | C_READ); /* CMD: READ */ if( c < 128 ) goto rend; @@ -284,8 +283,7 @@ hardware_send_packet(unsigned long paddr, int cnt) { unsigned long flags; DISABLE_IRQ(); - save_flags(flags); - cli(); + local_irq_save(flags); dma_wd.dma_mode_status = 0x19a; dma_wd.dma_mode_status = 0x9a; @@ -297,7 +295,7 @@ hardware_send_packet(unsigned long paddr, int cnt) { dma_wd.dma_hi = (unsigned char)paddr; dma_wd.fdc_acces_seccount = 0x4; /* sector count */ - restore_flags(flags); + local_irq_restore(flags); c = sendcmd(0,0x100,NODE_ADR | C_WRITE); /* CMD: WRITE */ c = sendcmd(1,0x100,cnt&0xff); @@ -438,11 +436,10 @@ bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { /* Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - save_flags(flags); - cli(); + local_irq_save(flags); if (stdma_islocked()) { - restore_flags(flags); + local_irq_restore(flags); lp->stats.tx_errors++; } else { @@ -451,7 +448,7 @@ bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { int stat; stdma_lock(bionet_intr, NULL); - restore_flags(flags); + local_irq_restore(flags); if( !STRAM_ADDR(buf+length-1) ) { memcpy(nic_packet->buffer, skb->data, length); buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer; @@ -504,20 +501,19 @@ bionet_poll_rx(struct net_device *dev) { int pkt_len, status; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* ++roman: Take care at locking the ST-DMA... This must be done with ints * off, since otherwise an int could slip in between the question and the * locking itself, and then we'd go to sleep... And locking itself is * necessary to keep the floppy_change timer from working with ST-DMA * registers. */ if (stdma_islocked()) { - restore_flags(flags); + local_irq_restore(flags); return; } stdma_lock(bionet_intr, NULL); DISABLE_IRQ(); - restore_flags(flags); + local_irq_restore(flags); if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++; diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c index c42659667d35..95d6640fabd5 100644 --- a/drivers/net/atari_pamsnet.c +++ b/drivers/net/atari_pamsnet.c @@ -702,11 +702,10 @@ pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) { /* Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - save_flags(flags); - cli(); + local_irq_save(flags); if (stdma_islocked()) { - restore_flags(flags); + local_irq_restore(flags); lp->stats.tx_errors++; } else { @@ -717,7 +716,7 @@ pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) { stdma_lock(pamsnet_intr, NULL); DISABLE_IRQ(); - restore_flags(flags); + local_irq_restore(flags); if( !STRAM_ADDR(buf+length-1) ) { memcpy(nic_packet->buffer, skb->data, length); buf = (unsigned long)phys_nic_packet; @@ -749,20 +748,19 @@ pamsnet_poll_rx(struct net_device *dev) { struct sk_buff *skb; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* ++roman: Take care at locking the ST-DMA... This must be done with ints * off, since otherwise an int could slip in between the question and the * locking itself, and then we'd go to sleep... And locking itself is * necessary to keep the floppy_change timer from working with ST-DMA * registers. */ if (stdma_islocked()) { - restore_flags(flags); + local_irq_restore(flags); return; } stdma_lock(pamsnet_intr, NULL); DISABLE_IRQ(); - restore_flags(flags); + local_irq_restore(flags); boguscount = testpkt(lance_target); if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++; diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index e8e91d299896..a23c024c1da1 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -402,8 +402,7 @@ static int __init addr_accessible( volatile void *regp, int wordflag, int writef long flags; long *vbr, save_berr; - save_flags(flags); - cli(); + local_irq_save(flags); __asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : ); save_berr = vbr[2]; @@ -440,7 +439,7 @@ static int __init addr_accessible( volatile void *regp, int wordflag, int writef ); vbr[2] = save_berr; - restore_flags(flags); + local_irq_restore(flags); return( ret ); } diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index c6255c3b8f21..45c74135572f 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -194,7 +194,7 @@ int __init mac8390_memsize(unsigned long membase) unsigned long flags; int i, j; - save_flags(flags); cli(); + local_irq_save(flags); /* Check up to 32K in 4K increments */ for (i = 0; i < 8; i++) { volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000)); @@ -217,7 +217,7 @@ int __init mac8390_memsize(unsigned long membase) break; } } - restore_flags(flags); + local_irq_restore(flags); /* in any case, we stopped once we tried one block too many, or once we reached 32K */ return i * 0x1000; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index ba9adba053a0..95f72759aa0f 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -52,7 +52,8 @@ Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001 check kmalloc and release the allocated memory on failure in mac89x0_probe and in init_module - use save_flags/restore_flags in net_get_stat, not just cli/sti + use local_irq_{save,restore}(flags) in net_get_stat, not just + local_irq_{dis,en}able() */ static char *version = @@ -199,11 +200,10 @@ int __init mac89x0_probe(struct net_device *dev) unsigned long flags; int card_present; - save_flags(flags); - cli(); + local_irq_save(flags); card_present = hwreg_present((void*) ioaddr+4) && hwreg_present((void*) ioaddr + DATA_PORT); - restore_flags(flags); + local_irq_restore(flags); if (!card_present) return -ENODEV; @@ -397,8 +397,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) /* keep the upload from being interrupted, since we ask the chip to start transmitting before the whole packet has been completely uploaded. */ - save_flags(flags); - cli(); + local_irq_save(flags); /* initiate a transmit sequence */ writereg(dev, PP_TxCMD, lp->send_cmd); @@ -408,14 +407,14 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { /* Gasp! It hasn't. But that shouldn't happen since we're waiting for TxOk, so return 1 and requeue this packet. */ - restore_flags(flags); + local_irq_restore(flags); return 1; } /* Write the contents of the packet */ memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); - restore_flags(flags); + local_irq_restore(flags); dev->trans_start = jiffies; } dev_kfree_skb (skb); @@ -568,12 +567,11 @@ net_get_stats(struct net_device *dev) struct net_local *lp = (struct net_local *)dev->priv; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); - restore_flags(flags); + local_irq_restore(flags); return &lp->stats; } diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 7bab986b43b4..4e8a08b78804 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -256,8 +256,7 @@ static int mace_set_address(struct net_device *dev, void *addr) unsigned long flags; u8 maccc; - save_flags(flags); - cli(); + local_irq_save(flags); maccc = mb->maccc; @@ -270,7 +269,7 @@ static int mace_set_address(struct net_device *dev, void *addr) } mb->maccc = maccc; - restore_flags(flags); + local_irq_restore(flags); return 0; } diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index e87f5aad0542..16c7160e0eb0 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -332,10 +332,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) unsigned long flags; int card_present; - save_flags(flags); - cli(); + local_irq_save(flags); card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); - restore_flags(flags); + local_irq_restore(flags); if (!card_present) { printk("none.\n"); diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index cdd2252d83cf..61b6e3be8557 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1078,12 +1078,11 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); if(p->xmit_count != p->xmit_last) netif_wake_queue(dev); p->lock = 0; - restore_flags(flags); + local_irq_restore(flags); } dev_kfree_skb(skb); #endif diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index ed2070e280f0..70dbe64a2612 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -574,7 +574,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) #endif /* We're not prepared for the int until the last flags are set/reset. * And the int may happen already after setting the OWN_CHIP... */ - save_and_cli(flags); + local_irq_save(flags); /* Mask to ring buffer boundary. */ entry = lp->new_tx; @@ -610,7 +610,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) TMD1_OWN_HOST) netif_start_queue(dev); - restore_flags(flags); + local_irq_restore(flags); return 0; } diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index d6cfff7ff8fa..14cbe34eb897 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -915,10 +915,9 @@ void __init nubus_probe_slot(int slot) int card_present; rp--; - save_flags(flags); - cli(); + local_irq_save(flags); card_present = hwreg_present(rp); - restore_flags(flags); + local_irq_restore(flags); if (!card_present) continue; diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c index b09e1f2d5441..d1caad0d6744 100644 --- a/drivers/parport/parport_amiga.c +++ b/drivers/parport/parport_amiga.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/parport.h> #include <linux/ioport.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/amigahw.h> #include <asm/irq.h> diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c index ae831176b7b1..461b3ffa2a66 100644 --- a/drivers/parport/parport_atari.c +++ b/drivers/parport/parport_atari.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/parport.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/atarihw.h> #include <asm/irq.h> @@ -25,11 +26,10 @@ parport_atari_read_data(struct parport *p) unsigned long flags; unsigned char data; - save_flags(flags); - cli(); + local_irq_save(flags); sound_ym.rd_data_reg_sel = 15; data = sound_ym.rd_data_reg_sel; - restore_flags(flags); + local_irq_restore(flags); return data; } @@ -38,11 +38,10 @@ parport_atari_write_data(struct parport *p, unsigned char data) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); sound_ym.rd_data_reg_sel = 15; sound_ym.wd_data = data; - restore_flags(flags); + local_irq_restore(flags); } static unsigned char @@ -51,12 +50,11 @@ parport_atari_read_control(struct parport *p) unsigned long flags; unsigned char control = 0; - save_flags(flags); - cli(); + local_irq_save(flags); sound_ym.rd_data_reg_sel = 14; if (!(sound_ym.rd_data_reg_sel & (1 << 5))) control = PARPORT_CONTROL_STROBE; - restore_flags(flags); + local_irq_restore(flags); return control; } @@ -65,14 +63,13 @@ parport_atari_write_control(struct parport *p, unsigned char control) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); sound_ym.rd_data_reg_sel = 14; if (control & PARPORT_CONTROL_STROBE) sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5); else sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); - restore_flags(flags); + local_irq_restore(flags); } static unsigned char @@ -129,12 +126,11 @@ parport_atari_data_forward(struct parport *p) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* Soundchip port B as output. */ sound_ym.rd_data_reg_sel = 7; sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x40; - restore_flags(flags); + local_irq_restore(flags); } static void @@ -143,12 +139,11 @@ parport_atari_data_reverse(struct parport *p) #if 0 /* too dangerous, can kill sound chip */ unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* Soundchip port B as input. */ sound_ym.rd_data_reg_sel = 7; sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40; - restore_flags(flags); + local_irq_restore(flags); #endif } @@ -209,15 +204,14 @@ parport_atari_init(void) unsigned long flags; if (MACH_IS_ATARI) { - save_flags(flags); - cli(); + local_irq_save(flags); /* Soundchip port A/B as output. */ sound_ym.rd_data_reg_sel = 7; sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0; /* STROBE high. */ sound_ym.rd_data_reg_sel = 14; sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5); - restore_flags(flags); + local_irq_restore(flags); /* MFP port I0 as input. */ mfp.data_dir &= ~1; /* MFP port I0 interrupt on high->low edge. */ diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c index 2f78ad1450d8..e6582994fb99 100644 --- a/drivers/parport/parport_mfc3.c +++ b/drivers/parport/parport_mfc3.c @@ -59,6 +59,7 @@ #include <linux/delay.h> #include <linux/mc6821.h> #include <linux/zorro.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/amigahw.h> #include <asm/irq.h> diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c index e05fb57bda60..f30641c4a23c 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta.c @@ -593,6 +593,7 @@ static void yenta_open_bh(void * data) if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) { /* No IRQ or request_irq failed. Poll */ socket->cb_irq = 0; /* But zero is a valid IRQ number. */ + init_timer(&socket->poll_timer); socket->poll_timer.function = yenta_interrupt_wrapper; socket->poll_timer.data = (unsigned long)socket; socket->poll_timer.expires = jiffies + HZ; diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index 4715fc295c29..e9b395952b38 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -251,6 +251,7 @@ #include <linux/time.h> #include <linux/blk.h> #include <linux/spinlock.h> +#include <linux/interrupt.h> #include <asm/pgtable.h> #ifdef CONFIG_AMIGA @@ -713,15 +714,14 @@ request_synchronous (int host, int target) { } hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0]; - save_flags(flags); - cli(); + local_irq_save(flags); if (hostdata->initiate_sdtr & (1 << target)) { - restore_flags(flags); + local_irq_restore(flags); printk (KERN_ALERT "target %d already doing SDTR\n", target); return -1; } hostdata->initiate_sdtr |= (1 << target); - restore_flags(flags); + local_irq_restore(flags); return 0; } #endif @@ -1588,11 +1588,10 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { /* The NCR chip _must_ be idle to run the test scripts */ - save_flags(flags); - cli(); + local_irq_save(flags); if (!hostdata->idle) { printk ("scsi%d : chip not idle, aborting tests\n", host->host_no); - restore_flags(flags); + local_irq_restore(flags); return -1; } @@ -1616,7 +1615,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); printk (" started\n"); - restore_flags(flags); + local_irq_restore(flags); /* * This is currently a .5 second timeout, since (in theory) no slow @@ -1655,7 +1654,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { hostdata->script, start); printk ("scsi%d : DSPS = 0x%x\n", host->host_no, NCR53c7x0_read32(DSPS_REG)); - restore_flags(flags); + local_irq_restore(flags); return -1; } hostdata->test_running = 0; @@ -1690,10 +1689,10 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { if (!hostdata->valid_ids[i]) continue; #endif - cli(); + local_irq_disable(); if (!hostdata->idle) { printk ("scsi%d : chip not idle, aborting tests\n", host->host_no); - restore_flags(flags); + local_irq_restore(flags); return -1; } @@ -1709,7 +1708,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { if (hostdata->options & OPTION_DEBUG_TRACE) NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); - restore_flags(flags); + local_irq_restore(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) @@ -1731,19 +1730,19 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) { host->host_no, i); if (!hostdata->idle) { printk("scsi%d : not idle\n", host->host_no); - restore_flags(flags); + local_irq_restore(flags); return -1; } } else if (hostdata->test_completed == -1) { printk ("scsi%d : test 2 timed out\n", host->host_no); - restore_flags(flags); + local_irq_restore(flags); return -1; } hostdata->test_running = 0; } } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -1826,8 +1825,7 @@ static volatile int process_issue_queue_running = 0; static __inline__ void run_process_issue_queue(void) { unsigned long flags; - save_flags (flags); - cli(); + local_irq_save(flags); if (!process_issue_queue_running) { process_issue_queue_running = 1; process_issue_queue(flags); @@ -1837,7 +1835,7 @@ run_process_issue_queue(void) { * interrupts disabled. */ } - restore_flags (flags); + local_irq_restore(flags); } /* @@ -1871,8 +1869,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) { printk ("scsi%d: abnormal finished\n", host->host_no); #endif - save_flags(flags); - cli(); + local_irq_save(flags); found = 0; /* * Traverse the NCR issue array until we find a match or run out @@ -1955,7 +1952,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) { c->result = result; c->scsi_done(c); - restore_flags(flags); + local_irq_restore(flags); run_process_issue_queue(); } @@ -1990,8 +1987,7 @@ intr_break (struct Scsi_Host *host, struct * dump the appropriate debugging information to standard * output. */ - save_flags(flags); - cli(); + local_irq_save(flags); dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG)); for (bp = hostdata->breakpoints; bp && bp->address != dsp; bp = bp->next); @@ -2013,7 +2009,7 @@ intr_break (struct Scsi_Host *host, struct * instruction in bytes. */ - restore_flags(flags); + local_irq_restore(flags); } /* * Function : static void print_synchronous (const char *prefix, @@ -2919,8 +2915,7 @@ NCR53c7x0_soft_reset (struct Scsi_Host *host) { host->hostdata[0]; NCR53c7x0_local_setup(host); - save_flags(flags); - cli(); + local_irq_save(flags); /* Disable scsi chip and s/w level 7 ints */ @@ -3021,7 +3016,7 @@ NCR53c7x0_soft_reset (struct Scsi_Host *host) { } #endif /* Anything needed for your hardware? */ - restore_flags(flags); + local_irq_restore(flags); } @@ -3122,19 +3117,17 @@ allocate_cmd (Scsi_Cmnd *cmd) { tmp->real = (void *)real; tmp->size = size; tmp->free = ((void (*)(void *, int)) my_free_page); - save_flags (flags); - cli(); + local_irq_save(flags); tmp->next = hostdata->free; hostdata->free = tmp; - restore_flags (flags); + local_irq_restore(flags); } - save_flags(flags); - cli(); + local_irq_save(flags); tmp = (struct NCR53c7x0_cmd *) hostdata->free; if (tmp) { hostdata->free = tmp->next; } - restore_flags(flags); + local_irq_restore(flags); if (!tmp) printk ("scsi%d : can't allocate command for target %d lun %d\n", host->host_no, cmd->target, cmd->lun); @@ -3353,19 +3346,17 @@ create_cmd (Scsi_Cmnd *cmd) { memcpy ((void *) (tmp->select + 1), (void *) wdtr_message, sizeof(wdtr_message)); patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message)); - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->initiate_wdtr &= ~(1 << cmd->target); - restore_flags(flags); + local_irq_restore(flags); } else if (hostdata->initiate_sdtr & (1 << cmd->target)) { memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, sizeof(sdtr_message)); patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message)); tmp->flags |= CMD_FLAG_SDTR; - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->initiate_sdtr &= ~(1 << cmd->target); - restore_flags(flags); + local_irq_restore(flags); } #if 1 @@ -3622,8 +3613,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { } #endif - save_flags(flags); - cli(); + local_irq_save(flags); if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY)) || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) && !(hostdata->debug_lun_limit[cmd->target] & (1 << cmd->lun))) @@ -3638,7 +3628,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { cmd->target, cmd->lun); cmd->result = (DID_BAD_TARGET << 16); done(cmd); - restore_flags (flags); + local_irq_restore(flags); return 0; } @@ -3647,7 +3637,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { printk("scsi%d : maximum commands exceeded\n", host->host_no); cmd->result = (DID_BAD_TARGET << 16); done(cmd); - restore_flags (flags); + local_irq_restore(flags); return 0; } @@ -3659,7 +3649,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { host->host_no); cmd->result = (DID_BAD_TARGET << 16); done(cmd); - restore_flags (flags); + local_irq_restore(flags); return 0; } } @@ -3686,7 +3676,7 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { tmp = (Scsi_Cmnd *) tmp->SCp.ptr); tmp->SCp.ptr = (unsigned char *) cmd; } - restore_flags (flags); + local_irq_restore(flags); run_process_issue_queue(); return 0; } @@ -3726,8 +3716,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, virt_to_bus(hostdata->dsa), hostdata->dsa); #endif - save_flags(flags); - cli(); + local_irq_save(flags); /* * Work around race condition : if an interrupt fired and we @@ -3740,7 +3729,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, cmd->next = (struct NCR53c7x0_cmd *) hostdata->free; hostdata->free = cmd; tmp->scsi_done(tmp); - restore_flags (flags); + local_irq_restore(flags); return; } @@ -3770,7 +3759,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, cmd->next = (struct NCR53c7x0_cmd *) hostdata->free; hostdata->free = cmd; tmp->scsi_done(tmp); - restore_flags (flags); + local_irq_restore(flags); return; } @@ -3791,7 +3780,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP); } - restore_flags(flags); + local_irq_restore(flags); } /* @@ -3849,12 +3838,12 @@ process_issue_queue (unsigned long flags) { */ do { - cli(); /* Freeze request queues */ + local_irq_disable(); /* Freeze request queues */ done = 1; for (host = first_host; host && host->hostt == the_template; host = host->next) { hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; - cli(); + local_irq_disable(); if (hostdata->issue_queue) { if (hostdata->state == STATE_DISABLED) { tmp = (Scsi_Cmnd *) hostdata->issue_queue; @@ -3904,7 +3893,7 @@ process_issue_queue (unsigned long flags) { } /* if target/lun is not busy */ } /* if hostdata->issue_queue */ if (!done) - restore_flags (flags); + local_irq_restore(flags); } /* for host */ } while (!done); process_issue_queue_running = 0; @@ -4171,8 +4160,7 @@ NCR53c7x0_intfly (struct Scsi_Host *host) * completion. */ - save_flags(flags); - cli(); + local_irq_save(flags); restart: for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list), cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ; @@ -4226,7 +4214,7 @@ restart: tmp->scsi_done(tmp); goto restart; } - restore_flags(flags); + local_irq_restore(flags); if (!search_found) { printk ("scsi%d : WARNING : INTFLY with no completed commands.\n", @@ -4906,13 +4894,12 @@ intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) { /* Don't print instr. until we write DSP at end of intr function */ } else if (hostdata->options & OPTION_DEBUG_SINGLE) { print_insn (host, dsp, "s ", 0); - save_flags(flags); - cli(); + local_irq_save(flags); /* XXX - should we do this, or can we get away with writing dsp? */ NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) & ~DCNTL_SSM) | DCNTL_STD); - restore_flags(flags); + local_irq_restore(flags); } else { printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n" " ", host->host_no); @@ -5190,8 +5177,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) { return SCSI_ABORT_BUSY; } - save_flags(flags); - cli(); + local_irq_save(flags); #if 0 if (cache_pid == cmd->pid) panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid); @@ -5226,7 +5212,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) { cmd->scsi_done(cmd); printk ("scsi%d : found command %ld in Linux issue queue\n", host->host_no, me->pid); - restore_flags(flags); + local_irq_restore(flags); run_process_issue_queue(); return SCSI_ABORT_SUCCESS; } @@ -5252,12 +5238,12 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) { cmd->scsi_done(cmd); printk ("scsi%d : found finished command %ld in running list\n", host->host_no, cmd->pid); - restore_flags(flags); + local_irq_restore(flags); return SCSI_ABORT_NOT_RUNNING; } else { printk ("scsi%d : DANGER : command running, can not abort.\n", cmd->host->host_no); - restore_flags(flags); + local_irq_restore(flags); return SCSI_ABORT_BUSY; } } @@ -5289,7 +5275,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) { */ --hostdata->busy[cmd->target][cmd->lun]; } - restore_flags(flags); + local_irq_restore(flags); cmd->scsi_done(cmd); /* @@ -5337,8 +5323,7 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) { (struct NCR53c7x0_hostdata *) host->hostdata[0]; NCR53c7x0_local_setup(host); - save_flags(flags); - cli(); + local_irq_save(flags); ncr_halt (host); print_lots (host); dump_events (host, 30); @@ -5372,13 +5357,13 @@ NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) { disable(host); else if (hostdata->resets != -1) --hostdata->resets; - restore_flags(flags); + local_irq_restore(flags); for (; nuke_list; nuke_list = tmp) { tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer; nuke_list->result = DID_RESET << 16; nuke_list->scsi_done (nuke_list); } - restore_flags(flags); + local_irq_restore(flags); return SCSI_RESET_SUCCESS; } @@ -5607,8 +5592,7 @@ print_queues (struct Scsi_Host *host) { left >= 0 && cmd; cmd = next_cmd) { next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr; - save_flags(flags); - cli(); + local_irq_save(flags); if (cmd->host_scribble) { if (check_address ((unsigned long) (cmd->host_scribble), sizeof (cmd->host_scribble)) == -1) @@ -5621,7 +5605,7 @@ print_queues (struct Scsi_Host *host) { } else printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n", host->host_no, cmd->pid, cmd->target, cmd->lun); - restore_flags(flags); + local_irq_restore(flags); } if (left <= 0) { @@ -5653,8 +5637,7 @@ print_queues (struct Scsi_Host *host) { dsa = bus_to_virt (hostdata->reconnect_dsa_head); left >= 0 && dsa; dsa = next_dsa) { - save_flags (flags); - cli(); + local_irq_save(flags); if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) { printk ("scsi%d: bad DSA pointer 0x%p", host->host_no, dsa); @@ -5665,7 +5648,7 @@ print_queues (struct Scsi_Host *host) { next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]); print_dsa (host, dsa, ""); } - restore_flags(flags); + local_irq_restore(flags); } printk ("scsi%d : end reconnect_dsa_head\n", host->host_no); if (left < 0) @@ -5755,15 +5738,14 @@ shutdown (struct Scsi_Host *host) { struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; NCR53c7x0_local_setup(host); - save_flags (flags); - cli(); + local_irq_save(flags); /* Get in a state where we can reset the SCSI bus */ ncr_halt (host); ncr_scsi_reset (host); hostdata->soft_reset(host); disable (host); - restore_flags (flags); + local_irq_restore(flags); return 0; } @@ -5778,12 +5760,11 @@ ncr_scsi_reset (struct Scsi_Host *host) { NCR53c7x0_local_declare(); unsigned long flags; NCR53c7x0_local_setup(host); - save_flags (flags); - cli(); + local_irq_save(flags); NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST); udelay(25); /* Minimum amount of time to assert RST */ NCR53c7x0_write8(SCNTL1_REG, 0); - restore_flags (flags); + local_irq_restore(flags); } /* @@ -5796,13 +5777,12 @@ hard_reset (struct Scsi_Host *host) { struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0]; unsigned long flags; - save_flags (flags); - cli(); + local_irq_save(flags); ncr_scsi_reset(host); NCR53c7x0_driver_init (host); if (hostdata->soft_reset) hostdata->soft_reset (host); - restore_flags(flags); + local_irq_restore(flags); } @@ -5898,14 +5878,13 @@ disable (struct Scsi_Host *host) { host->hostdata[0]; unsigned long flags; Scsi_Cmnd *nuke_list, *tmp; - save_flags(flags); - cli(); + local_irq_save(flags); if (hostdata->state != STATE_HALTED) ncr_halt (host); nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */); hard_reset (host); hostdata->state = STATE_DISABLED; - restore_flags(flags); + local_irq_restore(flags); printk ("scsi%d : nuking commands\n", host->host_no); for (; nuke_list; nuke_list = tmp) { tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer; @@ -5938,8 +5917,7 @@ ncr_halt (struct Scsi_Host *host) { int stage; NCR53c7x0_local_setup(host); - save_flags(flags); - cli(); + local_irq_save(flags); /* Stage 0 : eat all interrupts Stage 1 : set ABORT Stage 2 : eat all but abort interrupts @@ -5974,7 +5952,7 @@ ncr_halt (struct Scsi_Host *host) { } } hostdata->state = STATE_HALTED; - restore_flags(flags); + local_irq_restore(flags); #if 0 print_lots (host); #endif @@ -6022,14 +6000,13 @@ dump_events (struct Scsi_Host *host, int count) { count = hostdata->event_size; for (i = hostdata->event_index; count > 0; i = (i ? i - 1 : hostdata->event_size -1), --count) { - save_flags(flags); /* * By copying the event we're currently examining with interrupts * disabled, we can do multiple printk(), etc. operations and * still be guaranteed that they're happening on the same * event structure. */ - cli(); + local_irq_save(flags); #if 0 event = hostdata->events[i]; #else @@ -6037,7 +6014,7 @@ dump_events (struct Scsi_Host *host, int count) { sizeof(event)); #endif - restore_flags(flags); + local_irq_restore(flags); printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n", host->host_no, event_name (event.event), count, (long) event.time.tv_sec, (long) event.time.tv_usec, diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index cb389fef9700..4499f1f6b3ae 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -2489,8 +2489,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); - } else { + } else #endif /* def AUTOSENSE */ + { collect_stats(hostdata, cmd); cmd->scsi_done(cmd); } diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index ead703c05e88..43681be4afd5 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -715,6 +715,9 @@ void esp_initialize(struct NCR_ESP *esp) esp->targets_present = 0; esp->resetting_bus = 0; esp->snip = 0; + + init_waitqueue_head(&esp->reset_queue); + esp->fas_premature_intr_workaround = 0; for(i = 0; i < 32; i++) esp->espcmdlog[i] = 0; @@ -1037,25 +1040,6 @@ static void esp_exec_cmd(struct NCR_ESP *esp) lun = SCptr->lun; target = SCptr->target; - /* - * If esp_dev == NULL then we need to allocate a struct for our data - */ - if (!esp_dev) { - esp_dev = kmalloc(sizeof(struct esp_device), GFP_ATOMIC); - if (!esp_dev) { - /* We're SOL. Print a message and bail */ - printk(KERN_WARNING "esp: no mem for esp_device %d/%d\n", - target, lun); - esp->current_SC = NULL; - SCptr->result = DID_ERROR << 16; - SCptr->done(SCptr); - return; - } - memset(esp_dev, 0, sizeof(struct esp_device)); - SDptr->hostdata = esp_dev; - } - - esp->snip = 0; esp->msgout_len = 0; @@ -1371,7 +1355,7 @@ static void esp_dump_state(struct NCR_ESP *esp, ESPLOG(("\n")); } -/* Abort a command. */ +/* Abort a command. The host_lock is acquired by caller. */ int esp_abort(Scsi_Cmnd *SCptr) { struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata; @@ -1392,7 +1376,7 @@ int esp_abort(Scsi_Cmnd *SCptr) esp->msgout_len = 1; esp->msgout_ctr = 0; esp_cmd(esp, eregs, ESP_CMD_SATN); - return SCSI_ABORT_PENDING; + return SUCCESS; } /* If it is still in the issue queue then we can safely @@ -1417,7 +1401,7 @@ int esp_abort(Scsi_Cmnd *SCptr) this->done(this); if(don) esp->dma_ints_on(esp); - return SCSI_ABORT_SUCCESS; + return SUCCESS; } } } @@ -1430,19 +1414,19 @@ int esp_abort(Scsi_Cmnd *SCptr) if(esp->current_SC) { if(don) esp->dma_ints_on(esp); - return SCSI_ABORT_BUSY; + return FAILED; } /* It's disconnected, we have to reconnect to re-establish * the nexus and tell the device to abort. However, we really - * cannot 'reconnect' per se, therefore we tell the upper layer - * the safest thing we can. This is, wait a bit, if nothing - * happens, we are really hung so reset the bus. + * cannot 'reconnect' per se. Don't try to be fancy, just + * indicate failure, which causes our caller to reset the whole + * bus. */ if(don) esp->dma_ints_on(esp); - return SCSI_ABORT_SNOOZE; + return FAILED; } /* We've sent ESP_CMD_RS to the ESP, the interrupt had just @@ -1476,6 +1460,7 @@ static int esp_finish_reset(struct NCR_ESP *esp, /* SCSI bus reset is complete. */ esp->resetting_bus = 0; + wake_up(&esp->reset_queue); /* Ok, now it is safe to get commands going once more. */ if(esp->issue_SC) @@ -1496,13 +1481,22 @@ static int esp_do_resetbus(struct NCR_ESP *esp, /* Reset ESP chip, reset hanging bus, then kill active and * disconnected commands for targets without soft reset. + * + * The host_lock is acquired by caller. */ -int esp_reset(Scsi_Cmnd *SCptr, unsigned int how) +int esp_reset(Scsi_Cmnd *SCptr) { struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->host->hostdata; (void) esp_do_resetbus(esp, esp->eregs); - return SCSI_RESET_PENDING; + + spin_unlock_irq(esp->ehost->host_lock); + + wait_event(esp->reset_queue, (esp->resetting_bus == 0)); + + spin_lock_irq(esp->ehost->host_lock); + + return SUCCESS; } /* Internal ESP done function. */ @@ -1859,8 +1853,7 @@ static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs) ESPDATA(( /*"\n"*/ "\r")); #endif #if 0 - save_flags(flags); - cli(); + local_irq_save(flags); #endif if(thisphase == in_datain) { /* 'go' ... */ @@ -1951,7 +1944,7 @@ static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs) ESPDATA(("done! \n")); #if 0 - restore_flags(flags); + local_irq_restore(flags); #endif /* check new bus phase */ diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h index d8e161840e1a..3f20b6aaffa9 100644 --- a/drivers/scsi/NCR53C9x.h +++ b/drivers/scsi/NCR53C9x.h @@ -407,6 +407,7 @@ struct NCR_ESP { * cannot be assosciated with any specific command. */ unchar resetting_bus; + wait_queue_head_t reset_queue; unchar do_pio_cmds; /* Do command transfer with pio */ @@ -657,4 +658,11 @@ extern void esp_deallocate(struct NCR_ESP *); extern void esp_release(void); extern void esp_initialize(struct NCR_ESP *); extern void esp_intr(int, void *, struct pt_regs *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_command(Scsi_Cmnd *); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *); +extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, + int hostno, int inout); #endif /* !(NCR53C9X_H) */ diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index d1f7b9fa0410..f8b04da74c83 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -4,6 +4,7 @@ #include <linux/sched.h> #include <linux/version.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/page.h> @@ -230,7 +231,21 @@ int __init a2091_detect(Scsi_Host_Template *tpnt) #define HOSTS_C -static Scsi_Host_Template driver_template = A2091_SCSI; +static Scsi_Host_Template driver_template = { + .proc_name = "A2901", + .name = "Commodore A2091/A590 SCSI", + .detect = a2091_detect, + .release = a2091_release, + .queuecommand = wd33c93_queuecommand, + .abort = wd33c93_abort, + .reset = wd33c93_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h index ad0e524f65f3..3b6e57c742a3 100644 --- a/drivers/scsi/a2091.h +++ b/drivers/scsi/a2091.h @@ -30,19 +30,6 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); #define CAN_QUEUE 16 #endif -#define A2091_SCSI { .proc_name = "A2901", \ - .name = "Commodore A2091/A590 SCSI", \ - .detect = a2091_detect, \ - .release = a2091_release, \ - .queuecommand = wd33c93_queuecommand, \ - .abort = wd33c93_abort, \ - .reset = wd33c93_reset, \ - .can_queue = CAN_QUEUE, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = CMD_PER_LUN, \ - .use_clustering = DISABLE_CLUSTERING } - /* * if the transfer address ANDed with this results in a non-zero * result, then we can't use DMA. diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 15dd86e4b194..28a393b68c5c 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -6,6 +6,7 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/page.h> @@ -206,7 +207,21 @@ fail_register: #define HOSTS_C -static Scsi_Host_Template driver_template = _A3000_SCSI; +static Scsi_Host_Template driver_template = { + .proc_name = "A3000", + .name = "Amiga 3000 built-in SCSI", + .detect = a3000_detect, + .release = a3000_release, + .queuecommand = wd33c93_queuecommand, + .abort = wd33c93_abort, + .reset = wd33c93_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = ENABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h index ee134f111792..ddd13e856fc4 100644 --- a/drivers/scsi/a3000.h +++ b/drivers/scsi/a3000.h @@ -30,20 +30,6 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); #define CAN_QUEUE 16 #endif -#define _A3000_SCSI { .proc_name = "A3000", \ - .proc_info = NULL, \ - .name = "Amiga 3000 built-in SCSI", \ - .detect = a3000_detect, \ - .release = a3000_release, \ - .queuecommand = wd33c93_queuecommand, \ - .abort = wd33c93_abort, \ - .reset = wd33c93_reset, \ - .can_queue = CAN_QUEUE, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = CMD_PER_LUN, \ - .use_clustering = ENABLE_CLUSTERING } - /* * if the transfer address ANDed with this results in a non-zero * result, then we can't use DMA. diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index c2404c8433f4..0b6c04b23581 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -87,7 +87,7 @@ config AIC79XX_DEBUG_MASK config AIC79XX_REG_PRETTY_PRINT bool "Decode registers during diagnostics" - depends on SCSI_AIC79XX + depends on SCSI_AIC79XX && SCSI_AIC7XXX_BUILD_FIRMWARE default y help Compile in register value tables for the output of expanded register diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 760f98082ad2..9d9a9e4b02c7 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -92,7 +92,7 @@ config AIC7XXX_DEBUG_MASK config AIC7XXX_REG_PRETTY_PRINT bool "Decode registers during diagnostics" - depends on SCSI_AIC7XXX + depends on SCSI_AIC7XXX && SCSI_AIC7XXX_BUILD_FIRMWARE default y help Compile in register value tables for the output of expanded register diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c index 3ab6a15e39ad..715365d8c02c 100644 --- a/drivers/scsi/amiga7xx.c +++ b/drivers/scsi/amiga7xx.c @@ -134,5 +134,18 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt) return num; } -static Scsi_Host_Template driver_template = AMIGA7XX_SCSI; +static Scsi_Host_Template driver_template = { + .name = "Amiga NCR53c710 SCSI", + .detect = amiga7xx_detect, + .queuecommand = NCR53c7xx_queue_command, + .abort = NCR53c7xx_abort, + .reset = NCR53c7xx_reset, + .can_queue = 24, + .this_id = 7, + .sg_tablesize = 63, + .cmd_per_lun = 3, + .use_clustering = DISABLE_CLUSTERING +}; + + #include "scsi_module.c" diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h index d563ac5a7b82..80da6a8261fe 100644 --- a/drivers/scsi/amiga7xx.h +++ b/drivers/scsi/amiga7xx.h @@ -24,15 +24,4 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); #include <scsi/scsicam.h> -#define AMIGA7XX_SCSI {.name = "Amiga NCR53c710 SCSI", \ - .detect = amiga7xx_detect, \ - .queuecommand = NCR53c7xx_queue_command, \ - .abort = NCR53c7xx_abort, \ - .reset = NCR53c7xx_reset, \ - .can_queue = 24, \ - .this_id = 7, \ - .sg_tablesize = 63, \ - .cmd_per_lun = 3, \ - .use_clustering = DISABLE_CLUSTERING } - #endif /* AMIGA7XX_H */ diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 537e3a6f448f..70da49bc0372 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -315,7 +315,7 @@ static Scsi_Host_Template *the_template = NULL; #endif typedef struct { - char allocated[MAX_TAGS/8]; + long allocated[MAX_TAGS/32]; int nr_allocated; int queue_size; } TAG_ALLOC; @@ -561,14 +561,13 @@ static void NCR5380_print(struct Scsi_Host *instance) { unsigned char status, data, basr, mr, icr, i; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); data = NCR5380_read(CURRENT_SCSI_DATA_REG); status = NCR5380_read(STATUS_REG); mr = NCR5380_read(MODE_REG); icr = NCR5380_read(INITIATOR_COMMAND_REG); basr = NCR5380_read(BUS_AND_STATUS_REG); - restore_flags(flags); + local_irq_restore(flags); printk("STATUS_REG: %02x ", status); for (i = 0; signals[i].mask ; ++i) if (status & signals[i].mask) @@ -769,9 +768,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset, } \ } while (0) - for (instance = first_instance; instance && HOSTNO != hostno; - instance = instance->next) - ; + instance = scsi_host_hn_get(hostno); if (!instance) return(-ESRCH); hostdata = (struct NCR5380_hostdata *)instance->hostdata; @@ -781,8 +778,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset, } SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); check_offset(); - save_flags(flags); - cli(); + local_irq_save(flags); SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); check_offset(); if (!hostdata->connected) @@ -805,7 +801,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset, check_offset(); } - restore_flags(flags); + local_irq_restore(flags); *start = buffer + (offset - begin); if (pos - buffer < offset - begin) return 0; @@ -979,8 +975,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * sense data is only guaranteed to be valid while the condition exists. */ - save_flags(flags); - cli(); + local_irq_save(flags); /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. * Otherwise a running NCR5380_main may steal the lock. * Lock before actually inserting due to fairness reasons explained in @@ -1009,7 +1004,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) LIST(cmd, tmp); NEXT(tmp) = cmd; } - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); @@ -1073,9 +1068,9 @@ static void NCR5380_main (void) return; main_running = 1; - save_flags(flags); + local_save_flags(flags); do { - cli(); /* Freeze request queues */ + local_irq_disable(); /* Freeze request queues */ done = 1; if (!hostdata->connected) { @@ -1109,7 +1104,8 @@ static void NCR5380_main (void) !(hostdata->busy[tmp->target] & (1 << tmp->lun)) #endif ) { - cli(); /* ++guenther: just to be sure, this must be atomic */ + /* ++guenther: just to be sure, this must be atomic */ + local_irq_disable(); if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); NEXT(prev) = NEXT(tmp); @@ -1121,7 +1117,7 @@ static void NCR5380_main (void) falcon_dont_release++; /* reenable interrupts after finding one */ - restore_flags(flags); + local_irq_restore(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1153,7 +1149,7 @@ static void NCR5380_main (void) falcon_release_lock_if_possible( hostdata ); break; } else { - cli(); + local_irq_disable(); LIST(tmp, hostdata->issue_queue); NEXT(tmp) = hostdata->issue_queue; hostdata->issue_queue = tmp; @@ -1161,7 +1157,7 @@ static void NCR5380_main (void) cmd_free_tag( tmp ); #endif falcon_dont_release--; - restore_flags(flags); + local_irq_restore(flags); MAIN_PRINTK("scsi%d: main(): select() failed, " "returned to issue_queue\n", HOSTNO); if (hostdata->connected) @@ -1176,7 +1172,7 @@ static void NCR5380_main (void) && !hostdata->dma_len #endif ) { - restore_flags(flags); + local_irq_restore(flags); MAIN_PRINTK("scsi%d: main: performing information transfer\n", HOSTNO); NCR5380_information_transfer(instance); @@ -1189,7 +1185,7 @@ static void NCR5380_main (void) an interrupt could believe we'll pick up the work it left for us, but we won't see it anymore here... */ main_running = 0; - restore_flags(flags); + local_irq_restore(flags); } @@ -1430,10 +1426,9 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) * data bus during SELECTION. */ - save_flags(flags); - cli(); + local_irq_save(flags); if (hostdata->connected) { - restore_flags(flags); + local_irq_restore(flags); return -1; } NCR5380_write(TARGET_COMMAND_REG, 0); @@ -1446,7 +1441,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); - restore_flags(flags); + local_irq_restore(flags); /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT @@ -1954,12 +1949,11 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, /* On the Medusa, it is a must to initialize the DMA before * starting the NCR. This is also the cleaner way for the TT. */ - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); - restore_flags(flags); + local_irq_restore(flags); } if (p & SR_IO) @@ -1973,12 +1967,11 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, /* On the Falcon, the DMA setup must be done after the last */ /* NCR access, else the DMA setup gets trashed! */ - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); - restore_flags(flags); + local_irq_restore(flags); } return 0; } @@ -2259,12 +2252,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) cmd->request_buffer = (char *) cmd->sense_buffer; cmd->request_bufflen = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); + local_irq_save(flags); LIST(cmd,hostdata->issue_queue); NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: REQUEST SENSE added to head of " "issue queue\n", H_NO(cmd)); } else @@ -2321,14 +2313,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) case DISCONNECT: /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - save_flags(flags); - cli(); + local_irq_save(flags); cmd->device->disconnect = 1; LIST(cmd,hostdata->disconnected_queue); NEXT(cmd) = hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: command for target %d lun %d was " "moved from connected to the " "disconnected_queue\n", HOSTNO, @@ -2671,8 +2662,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) NCR5380_print_status (instance); - save_flags(flags); - cli(); + local_irq_save(flags); if (!IS_A_TT() && !falcon_got_lock) printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", @@ -2718,12 +2708,12 @@ int NCR5380_abort (Scsi_Cmnd *cmd) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - restore_flags(flags); + local_irq_restore(flags); cmd->scsi_done(cmd); falcon_release_lock_if_possible( hostdata ); return SCSI_ABORT_SUCCESS; } else { -/* restore_flags(flags); */ +/* local_irq_restore(flags); */ printk("scsi%d: abort of connected command failed!\n", HOSTNO); return SCSI_ABORT_ERROR; } @@ -2742,7 +2732,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) (*prev) = NEXT(tmp); NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", HOSTNO); /* Tagged queuing note: no tag to free here, hasn't been assigned @@ -2764,7 +2754,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) */ if (hostdata->connected) { - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); return SCSI_ABORT_SNOOZE; } @@ -2797,7 +2787,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = NEXT(tmp)) if (cmd == tmp) { - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); if (NCR5380_select (instance, cmd, (int) cmd->tag)) @@ -2807,8 +2797,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) do_abort (instance); - save_flags(flags); - cli(); + local_irq_save(flags); for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) @@ -2826,7 +2815,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - restore_flags(flags); + local_irq_restore(flags); tmp->scsi_done(tmp); falcon_release_lock_if_possible( hostdata ); return SCSI_ABORT_SUCCESS; @@ -2843,7 +2832,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) * broke. */ - restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" KERN_INFO " before abortion\n", HOSTNO); @@ -2906,8 +2895,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) * into the issue_queue (via scsi_done()), the aborted commands are * remembered in local variables first. */ - save_flags(flags); - cli(); + local_irq_save(flags); connected = (Scsi_Cmnd *)hostdata->connected; hostdata->connected = NULL; disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; @@ -2920,7 +2908,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #ifdef REAL_DMA hostdata->dma_len = 0; #endif - restore_flags(flags); + local_irq_restore(flags); /* In order to tell the mid-level code which commands were aborted, * set the command status to DID_RESET and call scsi_done() !!! @@ -2986,8 +2974,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) if (hostdata->disconnected_queue) ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->issue_queue = NULL; hostdata->connected = NULL; hostdata->disconnected_queue = NULL; @@ -2999,7 +2986,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #ifdef REAL_DMA hostdata->dma_len = 0; #endif - restore_flags(flags); + local_irq_restore(flags); /* we did no complete reset of all commands, so a wakeup is required */ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 8572300a1282..07c40bd87e67 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -508,12 +508,11 @@ static int falcon_dont_release = 0; static void falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) { - unsigned long oldflags; + unsigned long flags; if (IS_A_TT()) return; - save_flags(oldflags); - cli(); + local_irq_save(flags); if (falcon_got_lock && !hostdata->disconnected_queue && @@ -524,7 +523,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) #if 0 printk("WARNING: Lock release not allowed. Ignored\n"); #endif - restore_flags(oldflags); + local_irq_restore(flags); return; } falcon_got_lock = 0; @@ -532,7 +531,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) wake_up( &falcon_fairness_wait ); } - restore_flags(oldflags); + local_irq_restore(flags); } /* This function manages the locking of the ST-DMA. @@ -552,12 +551,11 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) static void falcon_get_lock( void ) { - unsigned long oldflags; + unsigned long flags; if (IS_A_TT()) return; - save_flags(oldflags); - cli(); + local_irq_save(flags); while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() ) sleep_on( &falcon_fairness_wait ); @@ -577,7 +575,7 @@ static void falcon_get_lock( void ) } } - restore_flags(oldflags); + local_irq_restore(flags); if (!falcon_got_lock) panic("Falcon SCSI: someone stole the lock :-(\n"); } @@ -1141,7 +1139,23 @@ static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value #include "atari_NCR5380.c" -static Scsi_Host_Template driver_template = ATARI_SCSI; +static Scsi_Host_Template driver_template = { + .proc_info = atari_scsi_proc_info, + .name = "Atari native SCSI", + .detect = atari_scsi_detect, + .release = atari_scsi_release, + .info = atari_scsi_info, + .queuecommand = atari_scsi_queue_command, + .abort = atari_scsi_abort, + .reset = atari_scsi_reset, + .can_queue = 0, /* initialized at run-time */ + .this_id = 0, /* initialized at run-time */ + .sg_tablesize = 0, /* initialized at run-time */ + .cmd_per_lun = 0, /* initialized at run-time */ + .use_clustering = DISABLE_CLUSTERING +}; + + #include "scsi_module.c" MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h index bab788445261..a6fd05a74d33 100644 --- a/drivers/scsi/atari_scsi.h +++ b/drivers/scsi/atari_scsi.h @@ -51,20 +51,6 @@ int atari_scsi_release (struct Scsi_Host *); #define DEFAULT_USE_TAGGED_QUEUING 0 -#define ATARI_SCSI { .proc_info = atari_scsi_proc_info, \ - .name = "Atari native SCSI", \ - .detect = atari_scsi_detect, \ - .release = atari_scsi_release, \ - .info = atari_scsi_info, \ - .queuecommand = atari_scsi_queue_command, \ - .abort = atari_scsi_abort, \ - .reset = atari_scsi_reset, \ - .can_queue = 0, /* initialized at run-time */ \ - .this_id = 0, /* initialized at run-time */ \ - .sg_tablesize = 0, /* initialized at run-time */ \ - .cmd_per_lun = 0, /* initialized at run-time */ \ - .use_clustering = DISABLE_CLUSTERING } - #define NCR5380_implementation_fields /* none */ #define NCR5380_read(reg) atari_scsi_reg_read( reg ) diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c index 90221a640e15..57296ffd25af 100644 --- a/drivers/scsi/blz1230.c +++ b/drivers/scsi/blz1230.c @@ -25,11 +25,11 @@ #include <linux/blk.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "blz1230.h" #include <linux/zorro.h> #include <asm/irq.h> @@ -40,6 +40,42 @@ #define MKIV 1 +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define BLZ1230_ESP_ADDR 0x8000 +#define BLZ1230_DMA_ADDR 0x10000 +#define BLZ1230II_ESP_ADDR 0x10000 +#define BLZ1230II_DMA_ADDR 0x10021 + + +/* The Blizzard 1230 DMA interface + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Only two things can be programmed in the Blizzard DMA: + * 1) The data direction is controlled by the status of bit 31 (1 = write) + * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 + * + * Program DMA by first latching the highest byte of the address/direction + * (i.e. bits 31-24 of the long word constructed as described in steps 1+2 + * above). Then write each byte of the address/direction (starting with the + * top byte, working down) to the DMA address register. + * + * Figure out interrupt status by reading the ESP status byte. + */ +struct blz1230_dma_registers { + volatile unsigned char dma_addr; /* DMA address [0x0000] */ + unsigned char dmapad2[0x7fff]; + volatile unsigned char dma_latch; /* DMA latch [0x8000] */ +}; + +struct blz1230II_dma_registers { + volatile unsigned char dma_addr; /* DMA address [0x0000] */ + unsigned char dmapad2[0xf]; + volatile unsigned char dma_latch; /* DMA latch [0x0010] */ +}; + +#define BLZ1230_DMA_WRITE 0x80000000 + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); @@ -279,12 +315,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) #define HOSTS_C -#include "blz1230.h" - -static Scsi_Host_Template driver_template = SCSI_BLZ1230; - -#include "scsi_module.c" - int blz1230_esp_release(struct Scsi_Host *instance) { #ifdef MODULE @@ -297,4 +327,25 @@ int blz1230_esp_release(struct Scsi_Host *instance) return 1; } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp-blz1230", + .proc_info = esp_proc_info, + .name = "Blizzard1230 SCSI IV", + .detect = blz1230_esp_detect, + .release = blz1230_esp_release, + .command = esp_command, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/blz1230.h b/drivers/scsi/blz1230.h deleted file mode 100644 index 233d500c9d9e..000000000000 --- a/drivers/scsi/blz1230.h +++ /dev/null @@ -1,75 +0,0 @@ -/* blz1230.h: Defines and structures for the Blizzard 1230 SCSI IV driver. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * This file is based on cyber_esp.h (hence the occasional reference to - * CyberStorm). - */ - -#include "NCR53C9x.h" - -#ifndef BLZ1230_H -#define BLZ1230_H - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define BLZ1230_ESP_ADDR 0x8000 -#define BLZ1230_DMA_ADDR 0x10000 -#define BLZ1230II_ESP_ADDR 0x10000 -#define BLZ1230II_DMA_ADDR 0x10021 - - -/* The Blizzard 1230 DMA interface - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Only two things can be programmed in the Blizzard DMA: - * 1) The data direction is controlled by the status of bit 31 (1 = write) - * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 - * - * Program DMA by first latching the highest byte of the address/direction - * (i.e. bits 31-24 of the long word constructed as described in steps 1+2 - * above). Then write each byte of the address/direction (starting with the - * top byte, working down) to the DMA address register. - * - * Figure out interrupt status by reading the ESP status byte. - */ -struct blz1230_dma_registers { - volatile unsigned char dma_addr; /* DMA address [0x0000] */ - unsigned char dmapad2[0x7fff]; - volatile unsigned char dma_latch; /* DMA latch [0x8000] */ -}; - -struct blz1230II_dma_registers { - volatile unsigned char dma_addr; /* DMA address [0x0000] */ - unsigned char dmapad2[0xf]; - volatile unsigned char dma_latch; /* DMA latch [0x0010] */ -}; - -#define BLZ1230_DMA_WRITE 0x80000000 - -extern int blz1230_esp_detect(struct SHT *); -extern int blz1230_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_BLZ1230 { .proc_name = "esp-blz1230", \ - .proc_info = esp_proc_info, \ - .name = "Blizzard1230 SCSI IV", \ - .detect = blz1230_esp_detect, \ - .release = blz1230_esp_release, \ - .command = esp_command, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* BLZ1230_H */ diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c index f5007bc6b697..07a9220816a3 100644 --- a/drivers/scsi/blz2060.c +++ b/drivers/scsi/blz2060.c @@ -25,11 +25,11 @@ #include <linux/blk.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "blz2060.h" #include <linux/zorro.h> #include <asm/irq.h> @@ -38,6 +38,38 @@ #include <asm/pgtable.h> +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define BLZ2060_ESP_ADDR 0x1ff00 +#define BLZ2060_DMA_ADDR 0x1ffe0 + + +/* The Blizzard 2060 DMA interface + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Only two things can be programmed in the Blizzard DMA: + * 1) The data direction is controlled by the status of bit 31 (1 = write) + * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 + * + * Figure out interrupt status by reading the ESP status byte. + */ +struct blz2060_dma_registers { + volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */ + unsigned char dmapad1[0x0f]; + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */ + unsigned char dmapad2[0x03]; + volatile unsigned char dma_addr1; /* DMA address [0x014] */ + unsigned char dmapad3[0x03]; + volatile unsigned char dma_addr2; /* DMA address [0x018] */ + unsigned char dmapad4[0x03]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */ +}; + +#define BLZ2060_DMA_WRITE 0x80000000 + +/* DMA control bits */ +#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */ + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); @@ -236,12 +268,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) #define HOSTS_C -#include "blz2060.h" - -static Scsi_Host_Template driver_template = SCSI_BLZ2060; - -#include "scsi_module.c" - int blz2060_esp_release(struct Scsi_Host *instance) { #ifdef MODULE @@ -255,4 +281,24 @@ int blz2060_esp_release(struct Scsi_Host *instance) return 1; } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp-blz2060", + .proc_info = esp_proc_info, + .name = "Blizzard2060 SCSI", + .detect = blz2060_esp_detect, + .release = blz2060_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/blz2060.h b/drivers/scsi/blz2060.h deleted file mode 100644 index ca119b9e6d67..000000000000 --- a/drivers/scsi/blz2060.h +++ /dev/null @@ -1,70 +0,0 @@ -/* blz2060.h: Defines and structures for the Blizzard 2060 SCSI driver. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * This file is based on cyber_esp.h (hence the occasional reference to - * CyberStorm). - */ - -#include "NCR53C9x.h" - -#ifndef BLZ2060_H -#define BLZ2060_H - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define BLZ2060_ESP_ADDR 0x1ff00 -#define BLZ2060_DMA_ADDR 0x1ffe0 - - -/* The Blizzard 2060 DMA interface - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Only two things can be programmed in the Blizzard DMA: - * 1) The data direction is controlled by the status of bit 31 (1 = write) - * 2) The source/dest address (word aligned, shifted one right) in bits 30-0 - * - * Figure out interrupt status by reading the ESP status byte. - */ -struct blz2060_dma_registers { - volatile unsigned char dma_led_ctrl; /* DMA led control [0x000] */ - unsigned char dmapad1[0x0f]; - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x010] */ - unsigned char dmapad2[0x03]; - volatile unsigned char dma_addr1; /* DMA address [0x014] */ - unsigned char dmapad3[0x03]; - volatile unsigned char dma_addr2; /* DMA address [0x018] */ - unsigned char dmapad4[0x03]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x01c] */ -}; - -#define BLZ2060_DMA_WRITE 0x80000000 - -/* DMA control bits */ -#define BLZ2060_DMA_LED 0x02 /* HD led control 1 = off */ - -extern int blz2060_esp_detect(struct SHT *); -extern int blz2060_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_BLZ2060 { .proc_name = "esp-blz2060", \ - .proc_info = esp_proc_info, \ - .name = "Blizzard2060 SCSI", \ - .detect = blz2060_esp_detect, \ - .release = blz2060_esp_release, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* BLZ2060_H */ diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c index 75b99d4a257e..9f7ba7890ad1 100644 --- a/drivers/scsi/bvme6000.c +++ b/drivers/scsi/bvme6000.c @@ -51,5 +51,18 @@ int bvme6000_scsi_detect(Scsi_Host_Template *tpnt) return 1; } -static Scsi_Host_Template driver_template = BVME6000_SCSI; +static Scsi_Host_Template driver_template = { + .name = "BVME6000 NCR53c710 SCSI", + .detect = bvme6000_scsi_detect, + .queuecommand = NCR53c7xx_queue_command, + .abort = NCR53c7xx_abort, + .reset = NCR53c7xx_reset, + .can_queue = 24, + .this_id = 7, + .sg_tablesize = 63, + .cmd_per_lun = 3, + .use_clustering = DISABLE_CLUSTERING +}; + + #include "scsi_module.c" diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h index a1bfe3b0e06c..61dd486b9677 100644 --- a/drivers/scsi/bvme6000.h +++ b/drivers/scsi/bvme6000.h @@ -25,15 +25,4 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); #include <scsi/scsicam.h> -#define BVME6000_SCSI {.name = "BVME6000 NCR53c710 SCSI", \ - .detect = bvme6000_scsi_detect, \ - .queuecommand = NCR53c7xx_queue_command, \ - .abort = NCR53c7xx_abort, \ - .reset = NCR53c7xx_reset, \ - .can_queue = 24, \ - .this_id = 7, \ - .sg_tablesize = 63, \ - .cmd_per_lun = 3, \ - .use_clustering = DISABLE_CLUSTERING } - #endif /* BVME6000_SCSI_H */ diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c index bb1fa3cf7cc2..83a3a0a9e5da 100644 --- a/drivers/scsi/cyberstorm.c +++ b/drivers/scsi/cyberstorm.c @@ -28,11 +28,11 @@ #include <linux/blk.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "cyberstorm.h" #include <linux/zorro.h> #include <asm/irq.h> @@ -41,6 +41,43 @@ #include <asm/pgtable.h> +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define CYBER_ESP_ADDR 0xf400 +#define CYBER_DMA_ADDR 0xf800 + + +/* The CyberStorm DMA interface */ +struct cyber_dma_registers { + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */ + unsigned char dmapad1[1]; + volatile unsigned char dma_addr1; /* DMA address [0x002] */ + unsigned char dmapad2[1]; + volatile unsigned char dma_addr2; /* DMA address [0x004] */ + unsigned char dmapad3[1]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */ + unsigned char dmapad4[0x3fb]; + volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */ +}; + +/* DMA control bits */ +#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */ +#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */ +#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */ + +/* DMA status bits */ +#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */ + +/* The bits below appears to be Phase5 Debug bits only; they were not + * described by Phase5 so using them may seem a bit stupid... + */ +#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise + * it should be 6. + */ +#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */ + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); @@ -302,12 +339,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) #define HOSTS_C -#include "cyberstorm.h" - -static Scsi_Host_Template driver_template = SCSI_CYBERSTORM; - -#include "scsi_module.c" - int cyber_esp_release(struct Scsi_Host *instance) { #ifdef MODULE @@ -321,4 +352,24 @@ int cyber_esp_release(struct Scsi_Host *instance) return 1; } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp-cyberstorm", + .proc_info = esp_proc_info, + .name = "CyberStorm SCSI", + .detect = cyber_esp_detect, + .release = cyber_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/cyberstorm.h b/drivers/scsi/cyberstorm.h deleted file mode 100644 index bbae3199b0ac..000000000000 --- a/drivers/scsi/cyberstorm.h +++ /dev/null @@ -1,73 +0,0 @@ -/* cyberstorm.h: Defines and structures for the CyberStorm SCSI driver. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - */ - -#include "NCR53C9x.h" - -#ifndef CYBER_ESP_H -#define CYBER_ESP_H - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define CYBER_ESP_ADDR 0xf400 -#define CYBER_DMA_ADDR 0xf800 - - -/* The CyberStorm DMA interface */ -struct cyber_dma_registers { - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x000] */ - unsigned char dmapad1[1]; - volatile unsigned char dma_addr1; /* DMA address [0x002] */ - unsigned char dmapad2[1]; - volatile unsigned char dma_addr2; /* DMA address [0x004] */ - unsigned char dmapad3[1]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x006] */ - unsigned char dmapad4[0x3fb]; - volatile unsigned char cond_reg; /* DMA cond (ro) [0x402] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x402] */ -}; - -/* DMA control bits */ -#define CYBER_DMA_LED 0x80 /* HD led control 1 = on */ -#define CYBER_DMA_WRITE 0x40 /* DMA direction. 1 = write */ -#define CYBER_DMA_Z3 0x20 /* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */ - -/* DMA status bits */ -#define CYBER_DMA_HNDL_INTR 0x80 /* DMA IRQ pending? */ - -/* The bits below appears to be Phase5 Debug bits only; they were not - * described by Phase5 so using them may seem a bit stupid... - */ -#define CYBER_HOST_ID 0x02 /* If set, host ID should be 7, otherwise - * it should be 6. - */ -#define CYBER_SLOW_CABLE 0x08 /* If *not* set, assume SLOW_CABLE */ - -extern int cyber_esp_detect(struct SHT *); -extern int cyber_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - - -#define SCSI_CYBERSTORM { .proc_name = "esp-cyberstorm", \ - .proc_info = esp_proc_info, \ - .name = "CyberStorm SCSI", \ - .detect = cyber_esp_detect, \ - .release = cyber_esp_release, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* CYBER_ESP_H */ diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c index d35b853b7ab4..25eb423ce467 100644 --- a/drivers/scsi/cyberstormII.c +++ b/drivers/scsi/cyberstormII.c @@ -24,11 +24,11 @@ #include <linux/blk.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "cyberstormII.h" #include <linux/zorro.h> #include <asm/irq.h> @@ -37,6 +37,30 @@ #include <asm/pgtable.h> +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define CYBERII_ESP_ADDR 0x1ff03 +#define CYBERII_DMA_ADDR 0x1ff43 + + +/* The CyberStorm II DMA interface */ +struct cyberII_dma_registers { + volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */ + unsigned char dmapad4[0x3f]; + volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */ + unsigned char dmapad1[3]; + volatile unsigned char dma_addr1; /* DMA address [0x044] */ + unsigned char dmapad2[3]; + volatile unsigned char dma_addr2; /* DMA address [0x048] */ + unsigned char dmapad3[3]; + volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */ +}; + +/* DMA control bits */ +#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */ + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); @@ -252,13 +276,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) #define HOSTS_C -#include "cyberstormII.h" - -static Scsi_Host_Template driver_template = SCSI_CYBERSTORMII; - -#include "scsi_module.c" - - int cyberII_esp_release(struct Scsi_Host *instance) { #ifdef MODULE @@ -272,4 +289,24 @@ int cyberII_esp_release(struct Scsi_Host *instance) return 1; } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp-cyberstormII", + .proc_info = esp_proc_info, + .name = "CyberStorm Mk II SCSI", + .detect = cyberII_esp_detect, + .release = cyberII_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/cyberstormII.h b/drivers/scsi/cyberstormII.h deleted file mode 100644 index 4a6bc0d9bf01..000000000000 --- a/drivers/scsi/cyberstormII.h +++ /dev/null @@ -1,60 +0,0 @@ -/* cyberstormII.h: Defines and structures for the CyberStorm SCSI Mk II driver. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - */ - -#include "NCR53C9x.h" - -#ifndef CYBERII_ESP_H -#define CYBERII_ESP_H - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define CYBERII_ESP_ADDR 0x1ff03 -#define CYBERII_DMA_ADDR 0x1ff43 - - -/* The CyberStorm II DMA interface */ -struct cyberII_dma_registers { - volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */ - unsigned char dmapad4[0x3f]; - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */ - unsigned char dmapad1[3]; - volatile unsigned char dma_addr1; /* DMA address [0x044] */ - unsigned char dmapad2[3]; - volatile unsigned char dma_addr2; /* DMA address [0x048] */ - unsigned char dmapad3[3]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */ -}; - -/* DMA control bits */ -#define CYBERII_DMA_LED 0x02 /* HD led control 1 = on */ - - -extern int cyberII_esp_detect(struct SHT *); -extern int cyberII_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_CYBERSTORMII { .proc_name = "esp-cyberstormII", \ - .proc_info = esp_proc_info, \ - .name = "CyberStorm Mk II SCSI", \ - .detect = cyberII_esp_detect, \ - .release = cyberII_esp_release, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* CYBERII_ESP_H */ diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index 23eabb24f434..b932a401df4f 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -31,7 +31,6 @@ #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "dec_esp.h" #include <asm/irq.h> #include <asm/jazz.h> @@ -46,6 +45,11 @@ #include <asm/dec/ioasic_ints.h> #include <asm/dec/machtype.h> +#define DEC_SCSI_SREG 0 +#define DEC_SCSI_DMAREG 0x40000 +#define DEC_SCSI_SRAM 0x80000 +#define DEC_SCSI_DIAG 0xC0000 + /* * Once upon a time the pmaz code used to be working but * it hasn't been maintained for quite some time. @@ -103,7 +107,25 @@ volatile unsigned long *scsi_sdr1; static void scsi_dma_int(int, void *, struct pt_regs *); -static Scsi_Host_Template driver_template = SCSI_DEC_ESP; +int dec_esp_detect(Scsi_Host_Template * tpnt); + +static Scsi_Host_Template driver_template = { + .proc_name = "esp", + .proc_info = &esp_proc_info, + .name = "NCR53C94", + .detect = dec_esp_detect, + .info = esp_info, + .command = esp_command, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + #include "scsi_module.c" diff --git a/drivers/scsi/dec_esp.h b/drivers/scsi/dec_esp.h deleted file mode 100644 index 6c428b553777..000000000000 --- a/drivers/scsi/dec_esp.h +++ /dev/null @@ -1,45 +0,0 @@ -/* dec_esp.h: Defines and structures for the JAZZ SCSI driver. - * - * DECstation changes Copyright (C) 1998 Harald Koerfgen - * and David Airlie - * - * based on jazz_esp.h: - * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - */ - -#ifndef DEC_ESP_H -#define DEC_ESP_H - -#include "NCR53C9x.h" - -#define DEC_SCSI_SREG 0 -#define DEC_SCSI_DMAREG 0x40000 -#define DEC_SCSI_SRAM 0x80000 -#define DEC_SCSI_DIAG 0xC0000 - -extern int dec_esp_detect(struct SHT *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_DEC_ESP { \ - .proc_name = "esp", \ - .proc_info = &esp_proc_info, \ - .name = "NCR53C94", \ - .detect = dec_esp_detect, \ - .info = esp_info, \ - .command = esp_command, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = DISABLE_CLUSTERING, } - -#endif /* DEC_ESP_H */ diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c index b30cf21c8a91..b58c0289ea14 100644 --- a/drivers/scsi/fastlane.c +++ b/drivers/scsi/fastlane.c @@ -33,11 +33,11 @@ #include <linux/blk.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "fastlane.h" #include <linux/zorro.h> #include <asm/irq.h> @@ -53,6 +53,36 @@ #define NODMAIRQ #endif +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define FASTLANE_ESP_ADDR 0x1000001 +#define FASTLANE_DMA_ADDR 0x1000041 + + +/* The Fastlane DMA interface */ +struct fastlane_dma_registers { + volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */ +#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */ + unsigned char dmapad1[0x3f]; + volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */ +}; + + +/* DMA status bits */ +#define FASTLANE_DMA_MINT 0x80 +#define FASTLANE_DMA_IACT 0x40 +#define FASTLANE_DMA_CREQ 0x20 + +/* DMA control bits */ +#define FASTLANE_DMA_FCODE 0xa0 +#define FASTLANE_DMA_MASK 0xf3 +#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */ +#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */ +#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */ +#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */ +#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */ + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); static inline void dma_clear(struct NCR_ESP *esp); @@ -140,7 +170,7 @@ int __init fastlane_esp_detect(Scsi_Host_Template *tpnt) /* Map the physical address space into virtual kernel space */ address = (unsigned long) - ioremap_nocache(board, z->resource.end-board+1); + z_ioremap(board, z->resource.end-board+1); if(!address){ printk("Could not remap Fastlane controller memory!"); @@ -189,7 +219,7 @@ int __init fastlane_esp_detect(Scsi_Host_Template *tpnt) return 0; err_unmap: - iounmap((void *)address); + z_iounmap((void *)address); err_unregister: scsi_unregister (esp->ehost); err_release: @@ -356,11 +386,6 @@ static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) #define HOSTS_C -#include "fastlane.h" - -static Scsi_Host_Template driver_template = SCSI_FASTLANE; -#include "scsi_module.c" - int fastlane_esp_release(struct Scsi_Host *instance) { #ifdef MODULE @@ -373,4 +398,23 @@ int fastlane_esp_release(struct Scsi_Host *instance) return 1; } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp-fastlane", + .proc_info = esp_proc_info, + .name = "Fastlane SCSI", + .detect = fastlane_esp_detect, + .release = fastlane_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + +#include "scsi_module.c" + MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/fastlane.h b/drivers/scsi/fastlane.h deleted file mode 100644 index 57e956cf539a..000000000000 --- a/drivers/scsi/fastlane.h +++ /dev/null @@ -1,65 +0,0 @@ -/* fastlane.h: Defines and structures for the Fastlane SCSI driver. - * - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - */ - -#include "NCR53C9x.h" - -#ifndef FASTLANE_H -#define FASTLANE_H - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define FASTLANE_ESP_ADDR 0x1000001 -#define FASTLANE_DMA_ADDR 0x1000041 - - -/* The Fastlane DMA interface */ -struct fastlane_dma_registers { - volatile unsigned char cond_reg; /* DMA status (ro) [0x0000] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x0000] */ - unsigned char dmapad1[0x3f]; - volatile unsigned char clear_strobe; /* DMA clear (wo) [0x0040] */ -}; - - -/* DMA status bits */ -#define FASTLANE_DMA_MINT 0x80 -#define FASTLANE_DMA_IACT 0x40 -#define FASTLANE_DMA_CREQ 0x20 - -/* DMA control bits */ -#define FASTLANE_DMA_FCODE 0xa0 -#define FASTLANE_DMA_MASK 0xf3 -#define FASTLANE_DMA_LED 0x10 /* HD led control 1 = on */ -#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */ -#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */ -#define FASTLANE_DMA_EDI 0x02 /* Enable DMA IRQ ? */ -#define FASTLANE_DMA_ESI 0x01 /* Enable SCSI IRQ */ - -extern int fastlane_esp_detect(struct SHT *); -extern int fastlane_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_FASTLANE { .proc_name = "esp-fastlane", \ - .proc_info = esp_proc_info, \ - .name = "Fastlane SCSI", \ - .detect = fastlane_esp_detect, \ - .release = fastlane_esp_release, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* FASTLANE_H */ diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 5dece79737d7..ad2d6c301d30 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -4,6 +4,7 @@ #include <linux/sched.h> #include <linux/version.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/page.h> @@ -355,7 +356,21 @@ release: #include "gvp11.h" -static Scsi_Host_Template driver_template = GVP11_SCSI; +static Scsi_Host_Template driver_template = { + .proc_name = "GVP11", + .name = "GVP Series II SCSI", + .detect = gvp11_detect, + .release = gvp11_release, + .queuecommand = wd33c93_queuecommand, + .abort = wd33c93_abort, + .reset = wd33c93_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h index d95b1a63726d..c60eedbee117 100644 --- a/drivers/scsi/gvp11.h +++ b/drivers/scsi/gvp11.h @@ -30,21 +30,7 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); #define CAN_QUEUE 16 #endif -#ifdef HOSTS_C - -#define GVP11_SCSI { .proc_name = "GVP11", \ - .name = "GVP Series II SCSI", \ - .detect = gvp11_detect, \ - .release = gvp11_release, \ - .queuecommand = wd33c93_queuecommand, \ - .abort = wd33c93_abort, \ - .reset = wd33c93_reset, \ - .can_queue = CAN_QUEUE, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = CMD_PER_LUN, \ - .use_clustering = DISABLE_CLUSTERING } -#else +#ifndef HOSTS_C /* * if the transfer address ANDed with this results in a non-zero diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 108bb4292725..29e0115ad68d 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -18,7 +18,6 @@ #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "jazz_esp.h" #include <asm/irq.h> #include <asm/jazz.h> @@ -273,3 +272,21 @@ static void dma_led_on(struct NCR_ESP *esp) *(unsigned char *)JAZZ_HDC_LED = 1; #endif } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp", + .proc_info = &esp_proc_info, + .name = "ESP 100/100a/200", + .detect = jazz_esp_detect, + .info = esp_info, + .command = esp_command, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + diff --git a/drivers/scsi/jazz_esp.h b/drivers/scsi/jazz_esp.h deleted file mode 100644 index 0f95410ed9a7..000000000000 --- a/drivers/scsi/jazz_esp.h +++ /dev/null @@ -1,39 +0,0 @@ -/* jazz_esp.h: Defines and structures for the JAZZ SCSI driver. - * - * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - */ - -#ifndef JAZZ_ESP_H -#define JAZZ_ESP_H - -#define EREGS_PAD(n) - -#include "NCR53C9x.h" - - -extern int jazz_esp_detect(struct SHT *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_JAZZ_ESP { \ - .proc_name = "esp", \ - .proc_info = &esp_proc_info, \ - .name = "ESP 100/100a/200", \ - .detect = jazz_esp_detect, \ - .info = esp_info, \ - .command = esp_command, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = DISABLE_CLUSTERING, } - -#endif /* JAZZ_ESP_H */ diff --git a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c index 521338547345..2fe5a1c5b76e 100644 --- a/drivers/scsi/mac_NCR5380.c +++ b/drivers/scsi/mac_NCR5380.c @@ -578,14 +578,13 @@ static void NCR5380_print(struct Scsi_Host *instance) { unsigned char status, data, basr, mr, icr, i; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); data = NCR5380_read(CURRENT_SCSI_DATA_REG); status = NCR5380_read(STATUS_REG); mr = NCR5380_read(MODE_REG); icr = NCR5380_read(INITIATOR_COMMAND_REG); basr = NCR5380_read(BUS_AND_STATUS_REG); - restore_flags(flags); + local_irq_restore(flags); printk("STATUS_REG: %02x ", status); for (i = 0; signals[i].mask ; ++i) if (status & signals[i].mask) @@ -801,8 +800,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset, } SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); check_offset(); - save_flags(flags); - cli(); + local_irq_save(flags); SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); check_offset(); if (!hostdata->connected) @@ -825,7 +823,7 @@ int NCR5380_proc_info (char *buffer, char **start, off_t offset, check_offset(); } - restore_flags(flags); + local_irq_restore(flags); *start = buffer + (offset - begin); if (pos - buffer < offset - begin) return 0; @@ -999,8 +997,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * sense data is only guaranteed to be valid while the condition exists. */ - save_flags(flags); - cli(); + local_irq_save(flags); if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { LIST(cmd, hostdata->issue_queue); @@ -1013,7 +1010,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) LIST(cmd, tmp); NEXT(tmp) = cmd; } - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); @@ -1077,9 +1074,9 @@ static void NCR5380_main (void) return; main_running = 1; - save_flags(flags); + local_save_flags(flags); do { - cli(); /* Freeze request queues */ + local_irq_disable(); /* Freeze request queues */ done = 1; if (!hostdata->connected) { @@ -1112,7 +1109,8 @@ static void NCR5380_main (void) !(hostdata->busy[tmp->target] & (1 << tmp->lun)) #endif ) { - cli(); /* ++guenther: just to be sure, this must be atomic */ + /* ++guenther: just to be sure, this must be atomic */ + local_irq_disable(); if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); NEXT(prev) = NEXT(tmp); @@ -1123,7 +1121,7 @@ static void NCR5380_main (void) NEXT(tmp) = NULL; /* reenable interrupts after finding one */ - restore_flags(flags); + local_irq_restore(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1152,14 +1150,14 @@ static void NCR5380_main (void) TAG_NEXT)) { break; } else { - cli(); + local_irq_disable(); LIST(tmp, hostdata->issue_queue); NEXT(tmp) = hostdata->issue_queue; hostdata->issue_queue = tmp; #ifdef SUPPORT_TAGS cmd_free_tag( tmp ); #endif - restore_flags(flags); + local_irq_restore(flags); MAIN_PRINTK("scsi%d: main(): select() failed, " "returned to issue_queue\n", HOSTNO); if (hostdata->connected) @@ -1174,7 +1172,7 @@ static void NCR5380_main (void) && !hostdata->dma_len #endif ) { - restore_flags(flags); + local_irq_restore(flags); MAIN_PRINTK("scsi%d: main: performing information transfer\n", HOSTNO); NCR5380_information_transfer(instance); @@ -1187,7 +1185,7 @@ static void NCR5380_main (void) an interrupt could believe we'll pick up the work it left for us, but we won't see it anymore here... */ main_running = 0; - restore_flags(flags); + local_irq_restore(flags); } @@ -1428,10 +1426,9 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) * data bus during SELECTION. */ - save_flags(flags); - cli(); + local_irq_save(flags); if (hostdata->connected) { - restore_flags(flags); + local_irq_restore(flags); return -1; } NCR5380_write(TARGET_COMMAND_REG, 0); @@ -1444,7 +1441,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); - restore_flags(flags); + local_irq_restore(flags); /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT @@ -1950,8 +1947,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #else /* PSEUDO_DMA! */ #if defined(PSEUDO_DMA) && !defined(UNSAFE) - save_flags(flags); - cli(); + local_irq_save(flags); #endif /* KLL May need eop and parity in 53c400 */ if (hostdata->flags & FLAG_NCR53C400) @@ -1970,12 +1966,11 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, /* On the Medusa, it is a must to initialize the DMA before * starting the NCR. This is also the cleaner way for the TT. */ - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); - restore_flags(flags); + local_irq_restore(flags); #endif /* def REAL_DMA */ #ifndef EMULATE_PSEUDO_DMA @@ -2120,7 +2115,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, NCR5380_print_phase(instance); #endif #if defined(PSEUDO_DMA) && !defined(UNSAFE) - restore_flags(flags); + local_irq_restore(flags); #endif /* defined(REAL_DMA_POLL) */ return foo; #endif /* def REAL_DMA */ @@ -2410,12 +2405,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) cmd->request_buffer = (char *) cmd->sense_buffer; cmd->request_bufflen = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); + local_irq_save(flags); LIST(cmd,hostdata->issue_queue); NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: REQUEST SENSE added to head of " "issue queue\n", H_NO(cmd)); } else @@ -2466,14 +2460,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) case DISCONNECT: /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - save_flags(flags); - cli(); + local_irq_save(flags); cmd->device->disconnect = 1; LIST(cmd,hostdata->disconnected_queue); NEXT(cmd) = hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: command for target %d lun %d was " "moved from connected to the " "disconnected_queue\n", HOSTNO, @@ -2812,8 +2805,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) NCR5380_print_status (instance); - save_flags(flags); - cli(); + local_irq_save(flags); ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), @@ -2855,11 +2847,11 @@ int NCR5380_abort (Scsi_Cmnd *cmd) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - restore_flags(flags); + local_irq_restore(flags); cmd->scsi_done(cmd); return SCSI_ABORT_SUCCESS; } else { -/* restore_flags(flags); */ +/* local_irq_restore(flags); */ printk("scsi%d: abort of connected command failed!\n", HOSTNO); return SCSI_ABORT_ERROR; } @@ -2878,7 +2870,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) (*prev) = NEXT(tmp); NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", HOSTNO); /* Tagged queuing note: no tag to free here, hasn't been assigned @@ -2899,7 +2891,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) */ if (hostdata->connected) { - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); return SCSI_ABORT_SNOOZE; } @@ -2932,7 +2924,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = NEXT(tmp)) if (cmd == tmp) { - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); if (NCR5380_select (instance, cmd, (int) cmd->tag)) @@ -2942,8 +2934,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) do_abort (instance); - save_flags(flags); - cli(); + local_irq_save(flags); for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) @@ -2961,7 +2952,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - restore_flags(flags); + local_irq_restore(flags); tmp->scsi_done(tmp); return SCSI_ABORT_SUCCESS; } @@ -2977,7 +2968,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) * broke. */ - restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" KERN_INFO " before abortion\n", HOSTNO); @@ -3035,8 +3026,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) * into the issue_queue (via scsi_done()), the aborted commands are * remembered in local variables first. */ - save_flags(flags); - cli(); + local_irq_save(flags); connected = (Scsi_Cmnd *)hostdata->connected; hostdata->connected = NULL; disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; @@ -3049,7 +3039,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #ifdef REAL_DMA hostdata->dma_len = 0; #endif - restore_flags(flags); + local_irq_restore(flags); /* In order to tell the mid-level code which commands were aborted, * set the command status to DID_RESET and call scsi_done() !!! @@ -3108,8 +3098,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) if (hostdata->disconnected_queue) ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->issue_queue = NULL; hostdata->connected = NULL; hostdata->disconnected_queue = NULL; @@ -3121,14 +3110,28 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #ifdef REAL_DMA hostdata->dma_len = 0; #endif - restore_flags(flags); + local_irq_restore(flags); /* we did no complete reset of all commands, so a wakeup is required */ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; #endif /* 1 */ } -static Scsi_Host_Template driver_template = MAC_NCR5380; +static Scsi_Host_Template driver_template = { + .name = "Macintosh NCR5380 SCSI", + .detect = macscsi_detect, + .release = macscsi_release, + .info = macscsi_info, + .queuecommand = macscsi_queue_command, + .abort = macscsi_abort, + .reset = macscsi_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index dcaa2dbe8c3f..cc01741d1416 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -23,11 +23,11 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/init.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "mac_esp.h" #include <asm/io.h> @@ -41,6 +41,8 @@ #include <asm/macintosh.h> +/* #define DEBUG_MAC_ESP */ + #define mac_turnon_irq(x) mac_enable_irq(x) #define mac_turnoff_irq(x) mac_disable_irq(x) @@ -710,7 +712,22 @@ static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int wri #endif } -static Scsi_Host_Template driver_template = SCSI_MAC_ESP; +static Scsi_Host_Template driver_template = { + .proc_name = "esp", + .name = "Mac 53C9x SCSI", + .detect = mac_esp_detect, + .info = esp_info, + /* .command = esp_command, */ + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/mac_esp.h b/drivers/scsi/mac_esp.h deleted file mode 100644 index c0113e76132a..000000000000 --- a/drivers/scsi/mac_esp.h +++ /dev/null @@ -1,40 +0,0 @@ - -/* -mac_esp.h - -copyright 1997 David Weis, weisd3458@uni.edu -*/ - - -#include "NCR53C9x.h" - -#ifndef MAC_ESP_H -#define MAC_ESP_H - -/* #define DEBUG_MAC_ESP */ - -extern int mac_esp_detect(struct SHT *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); - - -#define SCSI_MAC_ESP { .proc_name = "esp", \ - .name = "Mac 53C9x SCSI", \ - .detect = mac_esp_detect, \ - .release = NULL, \ - .info = esp_info, \ - /* command: esp_command, */ \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = DISABLE_CLUSTERING } - -#endif /* MAC_ESP_H */ - diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index a1b77530096e..e045d02b5f83 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -370,9 +370,9 @@ void restore_irq(struct pt_regs *regs) { unsigned long flags; - save_flags(flags); + local_save_flags(flags); flags = (flags & ~0x0700) | (regs->sr & 0x0700); - restore_flags(flags); + local_irq_restore(flags); } /* @@ -621,10 +621,9 @@ void scsi_mac_debug (void) NCR5380_setup(default_instance); if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ) #endif - save_flags(flags); - cli(); + local_irq_save(flags); NCR5380_print_status(default_instance); - restore_flags(flags); + local_irq_restore(flags); } #if 0 polled_scsi_on = 1; @@ -651,10 +650,9 @@ void scsi_mac_polled (void) if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ) { printk("SCSI poll\n"); - save_flags(flags); - cli(); + local_irq_save(flags); NCR5380_intr(IRQ_MAC_SCSI, instance, NULL); - restore_flags(flags); + local_irq_restore(flags); } #if 0 } diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c index cbadd79b29ce..9918b52216da 100644 --- a/drivers/scsi/mca_53c9x.c +++ b/drivers/scsi/mca_53c9x.c @@ -44,13 +44,37 @@ #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "mca_53c9x.h" #include <asm/dma.h> #include <asm/irq.h> #include <asm/mca_dma.h> #include <asm/pgtable.h> +/* + * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk + * activity LED on and off + */ + +#define PS2_SYS_CTR 0x92 + +/* Ports the ncr's 53c94 can be put at; indexed by pos register value */ + +#define MCA_53C9X_IO_PORTS { \ + 0x0000, 0x0240, 0x0340, 0x0400, \ + 0x0420, 0x3240, 0x8240, 0xA240, \ + } + +/* + * Supposedly there were some cards put together with the 'c9x and 86c01. If + * they have different ID's from the ones on the 3500 series machines, + * you can add them here and hopefully things will work out. + */ + +#define MCA_53C9X_IDS { \ + 0x7F4C, \ + 0x0000, \ + } + static int dma_bytes_sent(struct NCR_ESP *, int); static int dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *); static void dma_dump_state(struct NCR_ESP *); @@ -419,7 +443,22 @@ static void dma_led_off(struct NCR_ESP *esp) outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); } -static Scsi_Host_Template driver_template = MCA_53C9X; +static Scsi_Host_Template driver_template = { + .proc_name = "esp", + .name = "NCR 53c9x SCSI", + .detect = mca_esp_detect, + .release = mca_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .unchecked_isa_dma = 1, + .use_clustering = DISABLE_CLUSTERING +}; + + #include "scsi_module.c" /* diff --git a/drivers/scsi/mca_53c9x.h b/drivers/scsi/mca_53c9x.h deleted file mode 100644 index 9b7b7df42ed8..000000000000 --- a/drivers/scsi/mca_53c9x.h +++ /dev/null @@ -1,66 +0,0 @@ -/* mca_53c94.h: Defines and structures for the SCSI adapter found on NCR 35xx - * (and maybe some other) Microchannel machines. - * - * Code taken mostly from Cyberstorm SCSI drivers - * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) - * - * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org) - * 1998 - */ - -#include "NCR53C9x.h" - -#ifndef MCA_53C9X_H -#define MCA_53C9X_H - -/* - * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk - * activity LED on and off - */ - -#define PS2_SYS_CTR 0x92 - -extern int mca_esp_detect(struct SHT *); -extern int mca_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - - -#define MCA_53C9X { .proc_name = "esp", \ - .name = "NCR 53c9x SCSI", \ - .detect = mca_esp_detect, \ - .release = mca_esp_release, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .unchecked_isa_dma = 1, \ - .use_clustering = DISABLE_CLUSTERING } - -/* Ports the ncr's 53c94 can be put at; indexed by pos register value */ - -#define MCA_53C9X_IO_PORTS { \ - 0x0000, 0x0240, 0x0340, 0x0400, \ - 0x0420, 0x3240, 0x8240, 0xA240, \ - } - -/* - * Supposedly there were some cards put together with the 'c9x and 86c01. If - * they have different ID's from the ones on the 3500 series machines, - * you can add them here and hopefully things will work out. - */ - -#define MCA_53C9X_IDS { \ - 0x7F4C, \ - 0x0000, \ - } - -#endif /* MCA_53C9X_H */ - diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index 81a2d699a821..5f081518ddce 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -3,6 +3,7 @@ #include <linux/blk.h> #include <linux/sched.h> #include <linux/version.h> +#include <linux/interrupt.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -115,7 +116,21 @@ int mvme147_detect(Scsi_Host_Template *tpnt) #include "mvme147.h" -static Scsi_Host_Template driver_template = MVME147_SCSI; +static Scsi_Host_Template driver_template = { + .proc_name = "MVME147", + .name = "MVME147 built-in SCSI", + .detect = mvme147_detect, + .release = mvme147_release, + .queuecommand = wd33c93_queuecommand, + .abort = wd33c93_abort, + .reset = wd33c93_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = ENABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h index e68f86fdada0..264a9fdce90d 100644 --- a/drivers/scsi/mvme147.h +++ b/drivers/scsi/mvme147.h @@ -29,22 +29,4 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int); #define CAN_QUEUE 16 #endif -#ifdef HOSTS_C - -#define MVME147_SCSI {.proc_name = "MVME147", \ - .proc_info = NULL, \ - .name = "MVME147 built-in SCSI", \ - .detect = mvme147_detect, \ - .release = mvme147_release, \ - .queuecommand = wd33c93_queuecommand, \ - .abort = wd33c93_abort, \ - .reset = wd33c93_reset, \ - .can_queue = CAN_QUEUE, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = CMD_PER_LUN, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* else def HOSTS_C */ - #endif /* MVME147_H */ diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c index dc5052dbb1c4..45df12009189 100644 --- a/drivers/scsi/mvme16x.c +++ b/drivers/scsi/mvme16x.c @@ -53,5 +53,18 @@ int mvme16x_scsi_detect(Scsi_Host_Template *tpnt) return 1; } -static Scsi_Host_Template driver_template = MVME16x_SCSI; +static Scsi_Host_Template driver_template = { + .name = "MVME16x NCR53c710 SCSI", + .detect = mvme16x_scsi_detect, + .queuecommand = NCR53c7xx_queue_command, + .abort = NCR53c7xx_abort, + .reset = NCR53c7xx_reset, + .can_queue = 24, + .this_id = 7, + .sg_tablesize = 63, + .cmd_per_lun = 3, + .use_clustering = DISABLE_CLUSTERING +}; + + #include "scsi_module.c" diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h index 33e4225a5980..f2e56196aff2 100644 --- a/drivers/scsi/mvme16x.h +++ b/drivers/scsi/mvme16x.h @@ -25,15 +25,4 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs); #include <scsi/scsicam.h> -#define MVME16x_SCSI {.name = "MVME16x NCR53c710 SCSI", \ - .detect = mvme16x_scsi_detect, \ - .queuecommand = NCR53c7xx_queue_command, \ - .abort = NCR53c7xx_abort, \ - .reset = NCR53c7xx_reset, \ - .can_queue = 24, \ - .this_id = 7, \ - .sg_tablesize = 63, \ - .cmd_per_lun = 3, \ - .use_clustering = DISABLE_CLUSTERING } - #endif /* MVME16x_SCSI_H */ diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c index cef821562879..cda75b428d50 100644 --- a/drivers/scsi/oktagon_esp.c +++ b/drivers/scsi/oktagon_esp.c @@ -32,7 +32,6 @@ #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "oktagon_esp.h" #include <linux/zorro.h> #include <asm/irq.h> @@ -46,6 +45,13 @@ #include <linux/unistd.h> +/* The controller registers can be found in the Z2 config area at these + * offsets: + */ +#define OKTAGON_ESP_ADDR 0x03000 +#define OKTAGON_DMA_ADDR 0x01000 + + static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); static void dma_dump_state(struct NCR_ESP *esp); @@ -571,12 +577,6 @@ void dma_advance_sg(Scsi_Cmnd *sp) #define HOSTS_C -#include "oktagon_esp.h" - -static Scsi_Host_Template driver_template = SCSI_OKTAGON_ESP; - -#include "scsi_module.c" - int oktagon_esp_release(struct Scsi_Host *instance) { #ifdef MODULE @@ -589,4 +589,24 @@ int oktagon_esp_release(struct Scsi_Host *instance) return 1; } + +static Scsi_Host_Template driver_template = { + .proc_name = "esp-oktagon", + .proc_info = &esp_proc_info, + .name = "BSC Oktagon SCSI", + .detect = oktagon_esp_detect, + .release = oktagon_esp_release, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING +}; + + +#include "scsi_module.c" + MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/oktagon_esp.h b/drivers/scsi/oktagon_esp.h deleted file mode 100644 index f4ba3350c726..000000000000 --- a/drivers/scsi/oktagon_esp.h +++ /dev/null @@ -1,57 +0,0 @@ -/* oktagon_esp.h: Defines and structures for the CyberStorm SCSI Mk II driver. - * - * Copyright (C) 1996 Jesper Skov (jskov@cs.auc.dk) - */ - -#include "NCR53C9x.h" - -#ifndef OKTAGON_ESP_H -#define OKTAGON_ESP_H - -/* The controller registers can be found in the Z2 config area at these - * offsets: - */ -#define OKTAGON_ESP_ADDR 0x03000 -#define OKTAGON_DMA_ADDR 0x01000 - - -/* The CyberStorm II DMA interface */ -struct oktagon_dma_registers { - volatile unsigned char cond_reg; /* DMA cond (ro) [0x000] */ -#define ctrl_reg cond_reg /* DMA control (wo) [0x000] */ - unsigned char dmapad4[0x3f]; - volatile unsigned char dma_addr0; /* DMA address (MSB) [0x040] */ - unsigned char dmapad1[3]; - volatile unsigned char dma_addr1; /* DMA address [0x044] */ - unsigned char dmapad2[3]; - volatile unsigned char dma_addr2; /* DMA address [0x048] */ - unsigned char dmapad3[3]; - volatile unsigned char dma_addr3; /* DMA address (LSB) [0x04c] */ -}; - -extern int oktagon_esp_detect(struct SHT *); -extern int oktagon_esp_release(struct Scsi_Host *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define SCSI_OKTAGON_ESP { \ - .proc_name = "esp-oktagon", \ - .proc_info = &esp_proc_info, \ - .name = "BSC Oktagon SCSI", \ - .detect = oktagon_esp_detect, \ - .release = oktagon_esp_release, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = ENABLE_CLUSTERING } - -#endif /* OKTAGON_ESP_H */ diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 1dd34aeb225e..62ee4cf8e5f3 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -567,14 +567,13 @@ static void NCR5380_print(struct Scsi_Host *instance) { unsigned char status, data, basr, mr, icr, i; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); data = NCR5380_read(CURRENT_SCSI_DATA_REG); status = NCR5380_read(STATUS_REG); mr = NCR5380_read(MODE_REG); icr = NCR5380_read(INITIATOR_COMMAND_REG); basr = NCR5380_read(BUS_AND_STATUS_REG); - restore_flags(flags); + local_irq_restore(flags); printk("STATUS_REG: %02x ", status); for (i = 0; signals[i].mask ; ++i) if (status & signals[i].mask) @@ -772,9 +771,7 @@ static int NCR5380_proc_info (char *buffer, char **start, off_t offset, } \ } while (0) - for (instance = first_instance; instance && HOSTNO != hostno; - instance = instance->next) - ; + instance = scsi_host_hn_get(hostno); if (!instance) return(-ESRCH); hostdata = (struct NCR5380_hostdata *)instance->hostdata; @@ -784,8 +781,7 @@ static int NCR5380_proc_info (char *buffer, char **start, off_t offset, } SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); check_offset(); - save_flags(flags); - cli(); + local_irq_save(flags); SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); check_offset(); if (!hostdata->connected) @@ -808,7 +804,7 @@ static int NCR5380_proc_info (char *buffer, char **start, off_t offset, check_offset(); } - restore_flags(flags); + local_irq_restore(flags); *start = buffer + (offset - begin); if (pos - buffer < offset - begin) return 0; @@ -978,8 +974,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) * sense data is only guaranteed to be valid while the condition exists. */ - save_flags(flags); - cli(); + local_irq_save(flags); /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. * Otherwise a running NCR5380_main may steal the lock. * Lock before actually inserting due to fairness reasons explained in @@ -1004,7 +999,7 @@ static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) NEXT(tmp) = cmd; } - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); @@ -1068,9 +1063,9 @@ static void NCR5380_main (void) return; main_running = 1; - save_flags(flags); + local_save_flags(flags); do { - cli(); /* Freeze request queues */ + local_irq_disable(flags); /* Freeze request queues */ done = 1; if (!hostdata->connected) { @@ -1103,7 +1098,8 @@ static void NCR5380_main (void) !(hostdata->busy[tmp->target] & (1 << tmp->lun)) #endif ) { - cli(); /* ++guenther: just to be sure, this must be atomic */ + /* ++guenther: just to be sure, this must be atomic */ + local_irq_disable(); if (prev) { REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); NEXT(prev) = NEXT(tmp); @@ -1114,7 +1110,7 @@ static void NCR5380_main (void) NEXT(tmp) = NULL; /* reenable interrupts after finding one */ - restore_flags(flags); + local_irq_restore(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1143,14 +1139,14 @@ static void NCR5380_main (void) TAG_NEXT)) { break; } else { - cli(); + local_irq_disable(); LIST(tmp, hostdata->issue_queue); NEXT(tmp) = hostdata->issue_queue; hostdata->issue_queue = tmp; #ifdef SUPPORT_TAGS cmd_free_tag( tmp ); #endif - restore_flags(flags); + local_irq_restore(flags); MAIN_PRINTK("scsi%d: main(): select() failed, " "returned to issue_queue\n", HOSTNO); if (hostdata->connected) @@ -1164,7 +1160,7 @@ static void NCR5380_main (void) && !hostdata->dma_len #endif ) { - restore_flags(flags); + local_irq_restore(flags); MAIN_PRINTK("scsi%d: main: performing information transfer\n", HOSTNO); NCR5380_information_transfer(instance); @@ -1177,7 +1173,7 @@ static void NCR5380_main (void) an interrupt could believe we'll pick up the work it left for us, but we won't see it anymore here... */ main_running = 0; - restore_flags(flags); + local_irq_restore(flags); } @@ -1418,10 +1414,9 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) * data bus during SELECTION. */ - save_flags(flags); - cli(); + local_irq_save(flags); if (hostdata->connected) { - restore_flags(flags); + local_irq_restore(flags); return -1; } NCR5380_write(TARGET_COMMAND_REG, 0); @@ -1434,7 +1429,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); - restore_flags(flags); + local_irq_restore(flags); /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT @@ -1931,8 +1926,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, c, (p & SR_IO) ? "to" : "from", *data); /* netbsd turns off ints here, why not be safe and do it too */ - save_flags(flags); - cli(); + local_irq_save(flags); /* send start chain */ sun3scsi_dma_start(c, *data); @@ -1955,7 +1949,7 @@ static int NCR5380_transfer_dma( struct Scsi_Host *instance, dregs->csr |= CSR_DMA_ENABLE; #endif - restore_flags(flags); + local_irq_restore(flags); sun3_dma_active = 1; return 0; @@ -2275,12 +2269,11 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) cmd->request_buffer = (char *) cmd->sense_buffer; cmd->request_bufflen = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); + local_irq_save(flags); LIST(cmd,hostdata->issue_queue); NEXT(cmd) = hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: REQUEST SENSE added to head of " "issue queue\n", H_NO(cmd)); } else @@ -2331,14 +2324,13 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) case DISCONNECT: /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - save_flags(flags); - cli(); + local_irq_save(flags); cmd->device->disconnect = 1; LIST(cmd,hostdata->disconnected_queue); NEXT(cmd) = hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); + local_irq_restore(flags); QU_PRINTK("scsi%d: command for target %d lun %d was " "moved from connected to the " "disconnected_queue\n", HOSTNO, @@ -2704,8 +2696,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) NCR5380_print_status (instance); - save_flags(flags); - cli(); + local_irq_save(flags); ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), @@ -2747,11 +2738,11 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - restore_flags(flags); + local_irq_restore(flags); cmd->scsi_done(cmd); return SCSI_ABORT_SUCCESS; } else { -/* restore_flags(flags); */ +/* local_irq_restore(flags); */ printk("scsi%d: abort of connected command failed!\n", HOSTNO); return SCSI_ABORT_ERROR; } @@ -2770,7 +2761,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) (*prev) = NEXT(tmp); NEXT(tmp) = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", HOSTNO); /* Tagged queuing note: no tag to free here, hasn't been assigned @@ -2791,7 +2782,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) */ if (hostdata->connected) { - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); return SCSI_ABORT_SNOOZE; } @@ -2824,7 +2815,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = NEXT(tmp)) if (cmd == tmp) { - restore_flags(flags); + local_irq_restore(flags); ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); if (NCR5380_select (instance, cmd, (int) cmd->tag)) @@ -2834,8 +2825,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) do_abort (instance); - save_flags(flags); - cli(); + local_irq_save(flags); for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) @@ -2853,7 +2843,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - restore_flags(flags); + local_irq_restore(flags); tmp->scsi_done(tmp); return SCSI_ABORT_SUCCESS; } @@ -2869,7 +2859,7 @@ static int NCR5380_abort (Scsi_Cmnd *cmd) * broke. */ - restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" KERN_INFO " before abortion\n", HOSTNO); @@ -2923,8 +2913,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) * into the issue_queue (via scsi_done()), the aborted commands are * remembered in local variables first. */ - save_flags(flags); - cli(); + local_irq_save(flags); connected = (Scsi_Cmnd *)hostdata->connected; hostdata->connected = NULL; disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; @@ -2937,7 +2926,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #ifdef REAL_DMA hostdata->dma_len = 0; #endif - restore_flags(flags); + local_irq_restore(flags); /* In order to tell the mid-level code which commands were aborted, * set the command status to DID_RESET and call scsi_done() !!! @@ -2997,8 +2986,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) if (hostdata->disconnected_queue) ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - save_flags(flags); - cli(); + local_irq_save(flags); hostdata->issue_queue = NULL; hostdata->connected = NULL; hostdata->disconnected_queue = NULL; @@ -3010,7 +2998,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) #ifdef REAL_DMA hostdata->dma_len = 0; #endif - restore_flags(flags); + local_irq_restore(flags); /* we did no complete reset of all commands, so a wakeup is required */ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 502f764b4233..7fd253d96f8a 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -402,10 +402,9 @@ void sun3_sun3_debug (void) NCR5380_local_declare(); if (default_instance) { - save_flags(flags); - cli(); + local_irq_save(flags); NCR5380_print_status(default_instance); - restore_flags(flags); + local_irq_restore(flags); } } #endif @@ -616,7 +615,21 @@ static int sun3scsi_dma_finish(int write_flag) #include "sun3_NCR5380.c" -static Scsi_Host_Template driver_template = SUN3_NCR5380; +static Scsi_Host_Template driver_template = { + .name = SUN3_SCSI_NAME, + .detect = sun3scsi_detect, + .release = sun3scsi_release, + .info = sun3scsi_info, + .queuecommand = sun3scsi_queue_command, + .abort = sun3scsi_abort, + .reset = sun3scsi_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_TABLESIZE, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h index 230f8c31c9ab..b7a569b3d2bb 100644 --- a/drivers/scsi/sun3_scsi.h +++ b/drivers/scsi/sun3_scsi.h @@ -93,22 +93,6 @@ static int sun3scsi_release (struct Scsi_Host *); #define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI" #endif -#define SUN3_NCR5380 { \ -.name = SUN3_SCSI_NAME, \ -.detect = sun3scsi_detect, \ -.release = sun3scsi_release, /* Release */ \ -.info = sun3scsi_info, \ -.queuecommand = sun3scsi_queue_command, \ -.abort = sun3scsi_abort, \ -.reset = sun3scsi_reset, \ -.can_queue = CAN_QUEUE, /* can queue */ \ -.this_id = 7, /* id */ \ -.sg_tablesize = SG_TABLESIZE, /* sg_tablesize */ \ -.cmd_per_lun = CMD_PER_LUN, /* cmd per lun */ \ -.unchecked_isa_dma = 0, /* unchecked_isa_dma */ \ -.use_clustering = DISABLE_CLUSTERING \ - } - #ifndef HOSTS_C #define NCR5380_implementation_fields \ diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index f6f2b810f577..056a65cd4551 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -387,10 +387,9 @@ void sun3_sun3_debug (void) NCR5380_local_declare(); if (default_instance) { - save_flags(flags); - cli(); + local_irq_save(flags); NCR5380_print_status(default_instance); - restore_flags(flags); + local_irq_restore(flags); } } #endif @@ -561,7 +560,21 @@ static int sun3scsi_dma_finish(int write_flag) #include "sun3_NCR5380.c" -static Scsi_Host_Template driver_template = SUN3_NCR5380; +static Scsi_Host_Template driver_template = { + .name = SUN3_SCSI_NAME, + .detect = sun3scsi_detect, + .release = sun3scsi_release, + .info = sun3scsi_info, + .queuecommand = sun3scsi_queue_command, + .abort = sun3scsi_abort, + .reset = sun3scsi_reset, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_TABLESIZE, + .cmd_per_lun = CMD_PER_LUN, + .use_clustering = DISABLE_CLUSTERING +}; + #include "scsi_module.c" diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 76607c5e190a..bfbdf74c018b 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -13,12 +13,12 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include "scsi.h" #include "hosts.h" #include "NCR53C9x.h" -#include "sun3x_esp.h" #include <asm/sun3x.h> #include <asm/dvma.h> #include <asm/irq.h> @@ -374,7 +374,23 @@ static void dma_advance_sg (Scsi_Cmnd *sp) sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address); } -static Scsi_Host_Template driver_template = SCSI_SUN3X_ESP; +static Scsi_Host_Template driver_template = { + .proc_name = "esp", + .proc_info = &esp_proc_info, + .name = "Sun ESP 100/100a/200", + .detect = sun3x_esp_detect, + .info = esp_info, + .command = esp_command, + .queuecommand = esp_queue, + .eh_abort_handler = esp_abort, + .eh_bus_reset_handler = esp_reset, + .can_queue = 7, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + #include "scsi_module.c" diff --git a/drivers/scsi/sun3x_esp.h b/drivers/scsi/sun3x_esp.h deleted file mode 100644 index 653a775ef185..000000000000 --- a/drivers/scsi/sun3x_esp.h +++ /dev/null @@ -1,39 +0,0 @@ -/* sun3x_esp.h: Defines and structures for the Sun3x ESP - * - * (C) 1995 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - */ - -#ifndef _SUN3X_ESP_H -#define _SUN3X_ESP_H - -/* For dvma controller register definitions. */ -#include <asm/dvma.h> - -extern int sun3x_esp_detect(struct SHT *); -extern const char *esp_info(struct Scsi_Host *); -extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -extern int esp_command(Scsi_Cmnd *); -extern int esp_abort(Scsi_Cmnd *); -extern int esp_reset(Scsi_Cmnd *, unsigned int); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); - -#define DMA_PORTS_P (dregs->cond_reg & DMA_INT_ENAB) - -#define SCSI_SUN3X_ESP { \ - .proc_name = "esp", \ - .proc_info = &esp_proc_info, \ - .name = "Sun ESP 100/100a/200", \ - .detect = sun3x_esp_detect, \ - .info = esp_info, \ - .command = esp_command, \ - .queuecommand = esp_queue, \ - .abort = esp_abort, \ - .reset = esp_reset, \ - .can_queue = 7, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .use_clustering = DISABLE_CLUSTERING, } - -#endif /* !(_SUN3X_ESP_H) */ diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 4ce9a4a76ec0..37bb9c87e677 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -315,7 +315,6 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { struct WD33C93_hostdata *hostdata; Scsi_Cmnd *tmp; - unsigned long flags; hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata; @@ -385,8 +384,7 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) * sense data is not lost before REQUEST_SENSE executes. */ - save_flags(flags); - cli(); + spin_lock_irq(&hostdata->lock); if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { cmd->host_scribble = (uchar *)hostdata->input_Q; @@ -407,7 +405,7 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid)) - restore_flags(flags); + spin_unlock_irq(&hostdata->lock); return 0; } @@ -765,7 +763,7 @@ unsigned long length, flags; if (!(asr & ASR_INT) || (asr & ASR_BSY)) return; - save_flags(flags); + spin_lock_irqsave(&hostdata->lock, flags); #ifdef PROC_STATISTICS hostdata->int_cnt++; @@ -831,7 +829,7 @@ DB(DB_INTR,printk("TIMEOUT")) * is here... */ - restore_flags(flags); + spin_unlock_irqrestore(&hostdata->lock, flags); /* We are not connected to a target - check to see if there * are commands waiting to be executed. @@ -885,7 +883,8 @@ printk(" sending SDTR "); hostdata->outgoing_len = 1; hostdata->state = S_CONNECTED; - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; case CSR_XFER_DONE|PHS_DATA_IN: @@ -895,7 +894,8 @@ DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) transfer_bytes(regs, cmd, DATA_IN_DIR); if (hostdata->state != S_RUNNING_LEVEL2) hostdata->state = S_CONNECTED; - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; case CSR_XFER_DONE|PHS_DATA_OUT: @@ -905,7 +905,8 @@ DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) transfer_bytes(regs, cmd, DATA_OUT_DIR); if (hostdata->state != S_RUNNING_LEVEL2) hostdata->state = S_CONNECTED; - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; /* Note: this interrupt should not occur in a LEVEL2 command */ @@ -916,7 +917,8 @@ DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid)) transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; case CSR_XFER_DONE|PHS_STATUS: @@ -935,7 +937,8 @@ DB(DB_INTR,printk("%02x",cmd->SCp.Status)) else { hostdata->state = S_CONNECTED; } - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; case CSR_XFER_DONE|PHS_MESS_IN: @@ -1085,7 +1088,7 @@ printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]); write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; } - restore_flags(flags); + spin_unlock_irqrestore(&hostdata->lock, flags); break; @@ -1117,12 +1120,13 @@ DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun)) /* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ - restore_flags(flags); + spin_unlock_irqrestore(&hostdata->lock, flags); wd33c93_execute(instance); } else { printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid); - } + spin_unlock_irqrestore(&hostdata->lock, flags); + } break; @@ -1133,7 +1137,8 @@ DB(DB_INTR,printk("SDP")) hostdata->state = S_RUNNING_LEVEL2; write_wd33c93(regs, WD_COMMAND_PHASE, 0x41); write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; case CSR_XFER_DONE|PHS_MESS_OUT: @@ -1163,7 +1168,8 @@ DB(DB_INTR,printk("MSG_OUT=")) DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0])) hostdata->outgoing_len = 0; hostdata->state = S_CONNECTED; - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; case CSR_UNEXP_DISC: @@ -1184,7 +1190,8 @@ DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0])) if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; - return; + spin_unlock_irqrestore(&hostdata->lock, flags); + return; } DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid)) hostdata->connected = NULL; @@ -1200,7 +1207,7 @@ DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid)) * there are commands waiting to be executed. */ /* look above for comments on scsi_done() */ - restore_flags(flags); + spin_unlock_irqrestore(&hostdata->lock, flags); wd33c93_execute(instance); break; @@ -1228,7 +1235,6 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status)) else cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); - restore_flags(flags); break; case S_PRE_TMP_DISC: case S_RUNNING_LEVEL2: @@ -1250,6 +1256,7 @@ DB(DB_INTR,printk(":%d",cmd->SCp.Status)) /* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ + spin_unlock_irqrestore(&hostdata->lock, flags); wd33c93_execute(instance); break; @@ -1367,7 +1374,8 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : "")) if (!cmd) { printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun); - return; + spin_unlock_irqrestore(&hostdata->lock, flags); + return; } /* Ok, found the command - now start it up again. */ @@ -1397,10 +1405,12 @@ DB(DB_INTR,printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : "")) hostdata->state = S_CONNECTED; DB(DB_INTR,printk("-%ld",cmd->pid)) - break; + spin_unlock_irqrestore(&hostdata->lock, flags); + break; default: printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs); + spin_unlock_irqrestore(&hostdata->lock, flags); } DB(DB_INTR,printk("} ")) @@ -1830,12 +1840,9 @@ char buf[32]; #endif - { unsigned long flags; - save_flags(flags); - cli(); - reset_wd33c93(instance); - restore_flags(flags); - } + spin_lock_irq(&hostdata->lock); + reset_wd33c93(instance); + spin_unlock_irq(&hostdata->lock); printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",instance->host_no, (hostdata->chip==C_WD33C93)?"WD33c93": @@ -1863,7 +1870,6 @@ int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int i char *bp; char tbuf[128]; -unsigned long flags; struct Scsi_Host *instance; struct WD33C93_hostdata *hd; Scsi_Cmnd *cmd; @@ -1928,8 +1934,7 @@ static int stop = 0; return len; } - save_flags(flags); - cli(); + spin_lock_irq(&hd->lock); bp = buf; *bp = '\0'; if (hd->proc & PR_VERSION) { @@ -2004,7 +2009,7 @@ static int stop = 0; } } strcat(bp,"\n"); - restore_flags(flags); + spin_unlock_irq(&hd->lock); *start = buf; if (stop) { stop = 0; diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index 7d55ed8bd47f..47fd46fc4022 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -217,6 +217,7 @@ struct sx_period { struct WD33C93_hostdata { struct Scsi_Host *next; wd33c93_regs regs; + spinlock_t lock; uchar clock_freq; uchar chip; /* what kind of wd33c93? */ uchar microcode; /* microcode rev */ diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d9767337fe1f..7faee8111c81 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o obj-$(CONFIG_FB_CLGEN) += clgenfb.o obj-$(CONFIG_FB_TRIDENT) += tridentfb.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o -obj-$(CONFIG_FB_TGA) += tgafb.o +obj-$(CONFIG_FB_TGA) += tgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ cfbimgblt.o vgastate.o @@ -76,7 +76,6 @@ obj-$(CONFIG_FB_SIS) += sis/ obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o obj-$(CONFIG_FB_SUN3) += sun3fb.o -obj-$(CONFIG_FB_BWTWO) += bwtwofb.o obj-$(CONFIG_FB_HGA) += hgafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_SA1100) += sa1100fb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index fd55dbcabf6f..1ef989cd66be 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -57,6 +57,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/setup.h> #include <asm/uaccess.h> @@ -2050,8 +2051,7 @@ static void st_ovsc_switch(void) if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) return; - save_flags(flags); - cli(); + local_irq_save(flags); mfp.tim_ct_b = 0x10; mfp.active_edge |= 8; @@ -2079,7 +2079,7 @@ static void st_ovsc_switch(void) ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0); } - restore_flags(flags); + local_irq_restore(flags); } /* ------------------- External Video ---------------------- */ diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 43c030ff9ad7..f99a1692d5cb 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -38,7 +38,7 @@ #define BYTES_PER_LONG 4 #else #define FB_WRITEL fb_writeq -#define FB_READL fb_readq(x) +#define FB_READL fb_readq #define SHIFT_PER_LONG 6 #define BYTES_PER_LONG 8 #endif diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 11a87a694a85..f47b173b383e 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -21,13 +21,13 @@ * * FIXME * The code for 24 bit is horrible. It copies byte by byte size instead of - * longs like the other sizes. Needs to be optimized. + * words like the other sizes. Needs to be optimized. * * Tony: * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds * up the code significantly. * - * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is + * Code for depths not multiples of BITS_PER_WORD is still kludgy, which is * still processed a bit at a time. * * Also need to add code to deal with cards endians that are different than @@ -48,7 +48,11 @@ #define DPRINTK(fmt, args...) #endif -static u32 cfb_tab8[] = { +/* The following code can *not* handle a 64-bit long. */ +#define WORD u32 +#define BITS_PER_WORD 32 + +static WORD const cfb_tab8[] = { #if defined(__BIG_ENDIAN) 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, @@ -64,7 +68,7 @@ static u32 cfb_tab8[] = { #endif }; -static u32 cfb_tab16[] = { +static WORD const cfb_tab16[] = { #if defined(__BIG_ENDIAN) 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff #elif defined(__LITTLE_ENDIAN) @@ -74,11 +78,11 @@ static u32 cfb_tab16[] = { #endif }; -static u32 cfb_tab32[] = { +static WORD const cfb_tab32[] = { 0x00000000, 0xffffffff }; -#if BITS_PER_LONG == 32 +#if BITS_PER_WORD == 32 #define FB_WRITEL fb_writel #define FB_READL fb_readl #else @@ -87,7 +91,7 @@ static u32 cfb_tab32[] = { #endif #if defined (__BIG_ENDIAN) -#define LEFT_POS(bpp) (BITS_PER_LONG - bpp) +#define LEFT_POS(bpp) (BITS_PER_WORD - bpp) #define NEXT_POS(pos, bpp) ((pos) -= (bpp)) #define SHIFT_HIGH(val, bits) ((val) >> (bits)) #define SHIFT_LOW(val, bits) ((val) << (bits)) @@ -99,25 +103,25 @@ static u32 cfb_tab32[] = { #endif static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1, - unsigned long start_index, unsigned long pitch_index) + WORD start_index, WORD pitch_index) { /* Draw the penguin */ int i, n; - unsigned long bitmask = SHIFT_LOW(~0UL, BITS_PER_LONG - p->var.bits_per_pixel); - unsigned long *palette = (unsigned long *) p->pseudo_palette; - unsigned long *dst, *dst2, color = 0, val, shift; - unsigned long null_bits = BITS_PER_LONG - p->var.bits_per_pixel; + WORD bitmask = SHIFT_LOW(~0UL, BITS_PER_WORD - p->var.bits_per_pixel); + u32 *palette = (u32 *) p->pseudo_palette; + WORD *dst, *dst2, color = 0, val, shift; + WORD null_bits = BITS_PER_WORD - p->var.bits_per_pixel; u8 *src = image->data; - dst2 = (unsigned long *) dst1; + dst2 = (WORD *) dst1; for (i = image->height; i--; ) { n = image->width; - dst = (unsigned long *) dst1; + dst = (WORD *) dst1; shift = 0; val = 0; if (start_index) { - unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index)); + WORD start_mask = ~(SHIFT_HIGH(~0UL, start_index)); val = FB_READL(dst) & start_mask; shift = start_index; @@ -134,14 +138,14 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 if (shift == null_bits) val = 0; else - val = SHIFT_LOW(color, BITS_PER_LONG - shift); + val = SHIFT_LOW(color, BITS_PER_WORD - shift); } shift += p->var.bits_per_pixel; - shift &= (BITS_PER_LONG - 1); + shift &= (BITS_PER_WORD - 1); src++; } if (shift) { - unsigned long end_mask = SHIFT_HIGH(~0UL, shift); + WORD end_mask = SHIFT_HIGH(~0UL, shift); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -149,35 +153,35 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 if (pitch_index) { dst2 += p->fix.line_length; dst1 = (char *) dst2; - (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1); + (size_t) dst1 &= ~(sizeof(WORD) - 1); start_index += pitch_index; - start_index &= BITS_PER_LONG - 1; + start_index &= BITS_PER_WORD - 1; } } } static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1, - unsigned long fgcolor, unsigned long bgcolor, - unsigned long start_index, unsigned long pitch_index) + WORD fgcolor, WORD bgcolor, + WORD start_index, WORD pitch_index) { - unsigned long i, j, l = 8; - unsigned long shift, color, bpp = p->var.bits_per_pixel; - unsigned long *dst, *dst2, val, pitch = p->fix.line_length; - unsigned long null_bits = BITS_PER_LONG - bpp; + WORD i, j, l = 8; + WORD shift, color, bpp = p->var.bits_per_pixel; + WORD *dst, *dst2, val, pitch = p->fix.line_length; + WORD null_bits = BITS_PER_WORD - bpp; u8 *src = image->data; - dst2 = (unsigned long *) dst1; + dst2 = (WORD *) dst1; for (i = image->height; i--; ) { shift = 0; val = 0; j = image->width; - dst = (unsigned long *) dst1; + dst = (WORD *) dst1; /* write leading bits */ if (start_index) { - unsigned long start_mask = ~(SHIFT_HIGH(~0UL, start_index)); + WORD start_mask = ~(SHIFT_HIGH(~0UL, start_index)); val = FB_READL(dst) & start_mask; shift = start_index; @@ -196,15 +200,15 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 if (shift == null_bits) val = 0; else - val = SHIFT_LOW(color, BITS_PER_LONG - shift); + val = SHIFT_LOW(color, BITS_PER_WORD - shift); } shift += bpp; - shift &= (BITS_PER_LONG - 1); + shift &= (BITS_PER_WORD - 1); if (!l) { l = 8; src++; }; } /* write trailing bits */ if (shift) { - unsigned long end_mask = SHIFT_HIGH(~0UL, shift); + WORD end_mask = SHIFT_HIGH(~0UL, shift); FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); } @@ -213,24 +217,24 @@ static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, u8 if (pitch_index) { dst2 += pitch; dst1 = (char *) dst2; - (unsigned long) dst1 &= ~(sizeof(unsigned long) - 1); + (size_t) dst1 &= ~(sizeof(WORD) - 1); start_index += pitch_index; - start_index &= BITS_PER_LONG - 1; + start_index &= BITS_PER_WORD - 1; } } } static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 *dst1, - unsigned long fgcolor, unsigned long bgcolor) + WORD fgcolor, WORD bgcolor) { int i, j, k, l = 8, n; - unsigned long bit_mask, end_mask, eorx; - unsigned long fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel; - unsigned long tmp = (1 << bpp) - 1; - unsigned long ppw = BITS_PER_LONG/bpp, ppos; - unsigned long *dst; + WORD bit_mask, end_mask, eorx; + WORD fgx = fgcolor, bgx = bgcolor, pad, bpp = p->var.bits_per_pixel; + WORD tmp = (1 << bpp) - 1; + WORD ppw = BITS_PER_WORD/bpp, ppos; + WORD *dst; u32 *tab = NULL; char *src = image->data; @@ -263,7 +267,7 @@ static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 k = image->width/ppw; for (i = image->height; i--; ) { - dst = (unsigned long *) dst1; + dst = (WORD *) dst1; for (j = k; j--; ) { l -= ppw; @@ -291,8 +295,8 @@ static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, u8 void cfb_imageblit(struct fb_info *p, struct fb_image *image) { int x2, y2, vxres, vyres; - unsigned long fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; - unsigned long bpl = sizeof(unsigned long), bpp = p->var.bits_per_pixel; + WORD fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; + WORD bpl = sizeof(WORD), bpp = p->var.bits_per_pixel; u8 *dst1; vxres = p->var.xres_virtual; @@ -315,7 +319,7 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image) image->height = y2 - image->dy; bitstart = (image->dy * p->fix.line_length * 8) + (image->dx * bpp); - start_index = bitstart & (BITS_PER_LONG - 1); + start_index = bitstart & (BITS_PER_WORD - 1); pitch_index = (p->fix.line_length & (bpl - 1)) * 8; bitstart /= 8; @@ -332,7 +336,7 @@ void cfb_imageblit(struct fb_info *p, struct fb_image *image) bgcolor = image->bg_color; } - if (BITS_PER_LONG % bpp == 0 && !start_index && !pitch_index && + if (BITS_PER_WORD % bpp == 0 && !start_index && !pitch_index && bpp >= 8 && bpp <= 32 && (image->width & 7) == 0) fast_imageblit(image, p, dst1, fgcolor, bgcolor); else diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 6b3bc39bc559..57cd3ca0a32d 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -75,6 +75,7 @@ #include <linux/selection.h> #include <linux/smp.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/irq.h> #include <asm/system.h> diff --git a/drivers/video/console/font.h b/drivers/video/console/font.h index d612657374d0..16564d51d28e 100644 --- a/drivers/video/console/font.h +++ b/drivers/video/console/font.h @@ -8,18 +8,10 @@ * for more details. */ -#ifndef _VIDEO_FONT_H -#define _VIDEO_FONT_H +#ifndef _VIDEO_CONSOLE_FONT_H +#define _VIDEO_CONSOLE_FONT_H -#include <linux/types.h> - -struct font_desc { - int idx; - char *name; - int width, height; - void *data; - int pref; -}; +#include <video/font.h> /* struct font_desc */ #define VGA8x8_IDX 0 #define VGA8x16_IDX 1 @@ -50,4 +42,4 @@ extern struct font_desc *get_default_font(int xres, int yres); /* Max. length for the name of a predefined font */ #define MAX_FONT_NAME 32 -#endif /* _VIDEO_FONT_H */ +#endif /* _VIDEO_CONSOLE_FONT_H */ diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 325f0ab1ae6c..230f0c971e66 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -1,1009 +1,725 @@ /* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * - * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha - * - * $Id: tgafb.c,v 1.12.2.3 2000/04/04 06:44:56 mato Exp $ - * - * This driver is partly based on the original TGA framebuffer device, which - * was partly based on the original TGA console driver, which are - * - * Copyright (C) 1997 Geert Uytterhoeven * Copyright (C) 1995 Jay Estabrook + * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha + * Copyright (C) 2002 Richard Henderson * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ -/* KNOWN PROBLEMS/TO DO ===================================================== * - * - * - How to set a single color register on 24-plane cards? - * - * - Hardware cursor/other text acceleration methods - * - * - Some redraws can stall kernel for several seconds - * [This should now be solved by the fast memmove() patch in 2.3.6] - * - * KNOWN PROBLEMS/TO DO ==================================================== */ - #include <linux/module.h> -#include <linux/sched.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/tty.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> #include <linux/init.h> -#include <linux/pci.h> +#include <linux/fb.h> #include <linux/selection.h> -#include <linux/console.h> +#include <linux/pci.h> #include <asm/io.h> +#include <video/tgafb.h> -#include <video/fbcon.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb32.h> -#include "tgafb.h" - - - /* - * Global declarations - */ - -static struct tgafb_info fb_info; -static struct tgafb_par current_par; -static int current_par_valid = 0; -static struct display disp; -static char default_fontname[40] __initdata = { 0 }; -static struct fb_var_screeninfo default_var; -static int default_var_valid = 0; +/* + * Local functions. + */ -static struct { u_char red, green, blue, pad; } palette[256]; -#ifdef FBCON_HAS_CFB32 -static u32 fbcon_cfb32_cmap[16]; +static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *); +static int tgafb_set_par(struct fb_info *); +static void tgafb_set_pll(struct tga_par *, int); +static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned, + unsigned, struct fb_info *); +static int tgafb_blank(int, struct fb_info *); +static void tgafb_init_fix(struct fb_info *); +static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *); +#ifdef MODULE +static void tgafb_pci_unregister(struct pci_dev *); #endif +static const char *mode_option = "640x480@60"; - /* - * Hardware presets - */ -static unsigned int fb_offset_presets[4] = { - TGA_8PLANE_FB_OFFSET, - TGA_24PLANE_FB_OFFSET, - 0xffffffff, - TGA_24PLUSZ_FB_OFFSET -}; +/* + * Frame buffer operations + */ -static unsigned int deep_presets[4] = { - 0x00014000, - 0x0001440d, - 0xffffffff, - 0x0001441d +static struct fb_ops tgafb_ops = { + .owner = THIS_MODULE, + .fb_check_var = tgafb_check_var, + .fb_set_par = tgafb_set_par, + .fb_setcolreg = tgafb_setcolreg, + .fb_blank = tgafb_blank, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, }; -static unsigned int rasterop_presets[4] = { - 0x00000003, - 0x00000303, - 0xffffffff, - 0x00000303 -}; -static unsigned int mode_presets[4] = { - 0x00002000, - 0x00002300, - 0xffffffff, - 0x00002300 -}; +/* + * PCI registration operations + */ -static unsigned int base_addr_presets[4] = { - 0x00000000, - 0x00000001, - 0xffffffff, - 0x00000001 +static struct pci_device_id const tgafb_pci_table[] = { + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 } }; - - /* - * Predefined video modes - * This is a subset of the standard VESA modes, recalculated from XFree86. - * - * XXX Should we store these in terms of the encoded par structs? Even better, - * fbcon should provide a general mechanism for doing something like this. - */ - -static struct { - const char *name; - struct fb_var_screeninfo var; -} tgafb_predefined[] __initdata = { - { "640x480-60", { - 640, 480, 640, 480, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2, - 0, - FB_VMODE_NONINTERLACED - }}, - { "800x600-56", { - 800, 600, 800, 600, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 27777, 128, 24, 22, 1, 72, 2, - 0, - FB_VMODE_NONINTERLACED - }}, - { "640x480-72", { - 640, 480, 640, 480, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 31746, 144, 40, 30, 8, 40, 3, - 0, - FB_VMODE_NONINTERLACED - }}, - { "800x600-60", { - 800, 600, 800, 600, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED - }}, - { "800x600-72", { - 800, 600, 800, 600, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 20000, 64, 56, 23, 37, 120, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED - }}, - { "1024x768-60", { - 1024, 768, 1024, 768, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 15384, 168, 8, 29, 3, 144, 6, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1152x864-60", { - 1152, 864, 1152, 864, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 11123, 208, 64, 16, 4, 256, 8, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1024x768-70", { - 1024, 768, 1024, 768, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 13333, 144, 24, 29, 3, 136, 6, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1024x768-76", { - 1024, 768, 1024, 768, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 11764, 208, 8, 36, 16, 120, 3, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1152x864-70", { - 1152, 864, 1152, 864, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 10869, 106, 56, 20, 1, 160, 10, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1280x1024-61", { - 1280, 1024, 1280, 1024, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 9090, 200, 48, 26, 1, 184, 3, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1024x768-85", { - 1024, 768, 1024, 768, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 10111, 192, 32, 34, 14, 160, 6, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1280x1024-70", { - 1280, 1024, 1280, 1024, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 7905, 224, 32, 28, 8, 160, 8, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1152x864-84", { - 1152, 864, 1152, 864, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 184, 312, 32, 0, 128, 12, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1280x1024-76", { - 1280, 1024, 1280, 1024, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 248, 32, 34, 3, 104, 3, - 0, - FB_VMODE_NONINTERLACED - }}, - { "1280x1024-85", { - 1280, 1024, 1280, 1024, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 6349, 224, 64, 44, 1, 160, 3, - 0, - FB_VMODE_NONINTERLACED - }}, - - /* These are modes used by the two fixed-frequency monitors I have at home. - * You may or may not find these useful. - */ - - { "WYSE1", { /* 1280x1024 @ 72 Hz, 130 Mhz clock */ - 1280, 1024, 1280, 1024, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 7692, 192, 32, 47, 0, 192, 5, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED - }}, - { "IBM3", { /* 1280x1024 @ 70 Hz, 120 Mhz clock */ - 1280, 1024, 1280, 1024, 0, 0, 0, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, FB_ACCELF_TEXT, 8333, 192, 32, 47, 0, 192, 5, - 0, - FB_VMODE_NONINTERLACED - }} +static struct pci_driver tgafb_driver = { + .name = "tgafb", + .id_table = tgafb_pci_table, + .probe = tgafb_pci_register, + .remove = __devexit_p(tgafb_pci_unregister), }; -#define NUM_TOTAL_MODES ARRAY_SIZE(tgafb_predefined) - - - /* - * Interface used by the world - */ - -static void tgafb_detect(void); -static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par, - struct fb_info_gen *info); -static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par, - struct fb_info_gen *info); -static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, - struct fb_info_gen *info); -static void tgafb_get_par(void *fb_par, struct fb_info_gen *info); -static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info); -static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info); -static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); -static int tgafb_blank(int blank, struct fb_info_gen *info); -static void tgafb_set_disp(const void *fb_par, struct display *disp, - struct fb_info_gen *info); - -#ifndef MODULE -int tgafb_setup(char*); -#endif - -static void tgafb_set_pll(int f); -#if 1 -static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static void tgafb_update_palette(void); -#endif - - - /* - * Chipset specific functions - */ - -static void tgafb_detect(void) +/** + * tgafb_check_var - Optional function. Validates a var passed in. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + */ +static int +tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - return; -} + struct tga_par *par = (struct tga_par *)info->par; + + if (par->tga_type == TGA_TYPE_8PLANE) { + if (var->bits_per_pixel > 8) + return -EINVAL; + } else { + if (var->bits_per_pixel > 32) + return -EINVAL; + } + if (var->xres_virtual != var->xres || var->yres_virtual != var->yres) + return -EINVAL; + if (var->nonstd) + return -EINVAL; + if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ) + return -EINVAL; + if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; -static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par, - struct fb_info_gen *info) -{ - struct tgafb_par *par = (struct tgafb_par *)fb_par; - - strcpy(fix->id, fb_info.gen.info.modename); - - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - if (fb_info.tga_type == TGA_TYPE_8PLANE) { - fix->visual = FB_VISUAL_PSEUDOCOLOR; - } else { - fix->visual = FB_VISUAL_TRUECOLOR; - } - - fix->line_length = par->xres * (par->bits_per_pixel >> 3); - fix->smem_start = fb_info.tga_fb_base; - fix->smem_len = fix->line_length * par->yres; - fix->mmio_start = fb_info.tga_regs_base; - fix->mmio_len = 0x1000; /* Is this sufficient? */ - fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0; - fix->accel = FB_ACCEL_DEC_TGA; - - return 0; + return 0; } - -static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par, - struct fb_info_gen *info) +/** + * tgafb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +tgafb_set_par(struct fb_info *info) { - struct tgafb_par *par = (struct tgafb_par *)fb_par; + static unsigned int const deep_presets[4] = { + 0x00014000, + 0x0001440d, + 0xffffffff, + 0x0001441d + }; + static unsigned int const rasterop_presets[4] = { + 0x00000003, + 0x00000303, + 0xffffffff, + 0x00000303 + }; + static unsigned int const mode_presets[4] = { + 0x00002000, + 0x00002300, + 0xffffffff, + 0x00002300 + }; + static unsigned int const base_addr_presets[4] = { + 0x00000000, + 0x00000001, + 0xffffffff, + 0x00000001 + }; + + struct tga_par *par = (struct tga_par *) info->par; + u32 htimings, vtimings, pll_freq; + u8 tga_type; + int i, j; + + /* Encode video timings. */ + htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB) + | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB)); + vtimings = (info->var.yres & TGA_VERT_ACTIVE); + htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP; + vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP; + htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC; + vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC; + htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP; + vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP; + + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + htimings |= TGA_HORIZ_POLARITY; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + vtimings |= TGA_VERT_POLARITY; + + par->htimings = htimings; + par->vtimings = vtimings; + + par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN); + + /* Store other useful values in par. */ + par->xres = info->var.xres; + par->yres = info->var.yres; + par->pll_freq = pll_freq = 1000000000 / info->var.pixclock; + par->bits_per_pixel = info->var.bits_per_pixel; + + tga_type = par->tga_type; + + /* First, disable video. */ + TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); + + /* Write the DEEP register. */ + while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ + continue; + mb(); + TGA_WRITE_REG(par, deep_presets[tga_type], TGA_DEEP_REG); + while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ + continue; + mb(); + + /* Write some more registers. */ + TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG); + TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG); + TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG); + + /* Calculate & write the PLL. */ + tgafb_set_pll(par, pll_freq); + + /* Write some more registers. */ + TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG); + TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG); + TGA_WRITE_REG(par, 0x12345678, TGA_BLOCK_COLOR0_REG); + TGA_WRITE_REG(par, 0x12345678, TGA_BLOCK_COLOR1_REG); + + /* Init video timing regs. */ + TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); + + /* Initalise RAMDAC. */ + if (tga_type == TGA_TYPE_8PLANE) { + + /* Init BT485 RAMDAC registers. */ + BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0), + BT485_CMD_0); + BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE); + BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */ + BT485_WRITE(par, 0x40, BT485_CMD_1); + BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */ + BT485_WRITE(par, 0xff, BT485_PIXEL_MASK); + + /* Fill palette registers. */ + BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + } + for (i = 0; i < 240*3; i += 4) { + TGA_WRITE_REG(par, 0x55|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8), + TGA_RAMDAC_REG); + } + + } else { /* 24-plane or 24plusZ */ + + /* Init BT463 registers. */ + BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40); + BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08); + BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2, + (par->sync_on_green ? 0x80 : 0x40)); + + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff); + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff); + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff); + BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); + + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); + BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); + + /* Fill the palette. */ + BT463_LOAD_ADDR(par, 0x0000); + TGA_WRITE_REG(par, BT463_PALETTE<<2, TGA_RAMDAC_REG); + + for (i = 0; i < 16; i++) { + j = color_table[i]; + TGA_WRITE_REG(par, default_red[j]|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_grn[j]|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, default_blu[j]|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + } + for (i = 0; i < 512*3; i += 4) { + TGA_WRITE_REG(par, 0x55|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10), + TGA_RAMDAC_REG); + } + + /* Fill window type table after start of vertical retrace. */ + while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) + continue; + TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); + mb(); + while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) + continue; + TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); + + BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE); + TGA_WRITE_REG(par, BT463_REG_ACC<<2, TGA_RAMDAC_SETUP_REG); + + for (i = 0; i < 16; i++) { + TGA_WRITE_REG(par, 0x00|(BT463_REG_ACC<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x01|(BT463_REG_ACC<<10), + TGA_RAMDAC_REG); + TGA_WRITE_REG(par, 0x80|(BT463_REG_ACC<<10), + TGA_RAMDAC_REG); + } - /* round up some */ - if (fb_info.tga_type == TGA_TYPE_8PLANE) { - if (var->bits_per_pixel > 8) { - return -EINVAL; - } - par->bits_per_pixel = 8; - } else { - if (var->bits_per_pixel > 32) { - return -EINVAL; } - par->bits_per_pixel = 32; - } - - /* check the values for sanity */ - if (var->xres_virtual != var->xres || - var->yres_virtual != var->yres || - var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ || - (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED -#if 0 /* fbmon not done. uncomment for 2.5.x -brad */ - || !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info)) -#else - ) -#endif - return -EINVAL; - - /* encode video timings */ - par->htimings = ((var->xres/4) & TGA_HORIZ_ACT_LSB) | - (((var->xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB); - par->vtimings = (var->yres & TGA_VERT_ACTIVE); - par->htimings |= ((var->right_margin/4) << 9) & TGA_HORIZ_FP; - par->vtimings |= (var->lower_margin << 11) & TGA_VERT_FP; - par->htimings |= ((var->hsync_len/4) << 14) & TGA_HORIZ_SYNC; - par->vtimings |= (var->vsync_len << 16) & TGA_VERT_SYNC; - par->htimings |= ((var->left_margin/4) << 21) & TGA_HORIZ_BP; - par->vtimings |= (var->upper_margin << 22) & TGA_VERT_BP; - - if (var->sync & FB_SYNC_HOR_HIGH_ACT) - par->htimings |= TGA_HORIZ_POLARITY; - if (var->sync & FB_SYNC_VERT_HIGH_ACT) - par->vtimings |= TGA_VERT_POLARITY; - if (var->sync & FB_SYNC_ON_GREEN) { - par->sync_on_green = 1; - } else { - par->sync_on_green = 0; - } - - /* store other useful values in par */ - par->xres = var->xres; - par->yres = var->yres; - par->pll_freq = 1000000000/var->pixclock; - par->bits_per_pixel = var->bits_per_pixel; - - return 0; -} + /* Finally, enable video scan (and pray for the monitor... :-) */ + TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG); -static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par, - struct fb_info_gen *info) -{ - struct tgafb_par *par = (struct tgafb_par *)fb_par; - - /* decode video timings */ - var->xres = ((par->htimings & TGA_HORIZ_ACT_LSB) | ((par->htimings & TGA_HORIZ_ACT_MSB) >> 19)) * 4; - var->yres = (par->vtimings & TGA_VERT_ACTIVE); - var->right_margin = ((par->htimings & TGA_HORIZ_FP) >> 9) * 4; - var->lower_margin = ((par->vtimings & TGA_VERT_FP) >> 11); - var->hsync_len = ((par->htimings & TGA_HORIZ_SYNC) >> 14) * 4; - var->vsync_len = ((par->vtimings & TGA_VERT_SYNC) >> 16); - var->left_margin = ((par->htimings & TGA_HORIZ_BP) >> 21) * 4; - var->upper_margin = ((par->vtimings & TGA_VERT_BP) >> 22); - - if (par->htimings & TGA_HORIZ_POLARITY) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (par->vtimings & TGA_VERT_POLARITY) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - if (par->sync_on_green == 1) - var->sync |= FB_SYNC_ON_GREEN; - - var->xres_virtual = var->xres; - var->yres_virtual = var->yres; - var->xoffset = var->yoffset = 0; - - /* depth-related */ - if (fb_info.tga_type == TGA_TYPE_8PLANE) { - var->red.offset = 0; - var->green.offset = 0; - var->blue.offset = 0; - } else { - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - } - var->bits_per_pixel = par->bits_per_pixel; - var->grayscale = 0; - var->red.length = var->green.length = var->blue.length = 8; - var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; - var->transp.offset = var->transp.length = var->transp.msb_right = 0; - - /* others */ - var->xoffset = var->yoffset = 0; - var->pixclock = 1000000000/par->pll_freq; - var->nonstd = 0; - var->activate = 0; - var->height = var->width = -1; - var->accel_flags = 0; - - return 0; + return 0; } - -static void tgafb_get_par(void *fb_par, struct fb_info_gen *info) +#define DIFFCHECK(X) \ +do { \ + if (m <= 0x3f) { \ + int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \ + if (delta < 0) \ + delta = -delta; \ + if (delta < min_diff) \ + min_diff = delta, vm = m, va = a, vr = r; \ + } \ +} while (0) + +static void +tgafb_set_pll(struct tga_par *par, int f) { - struct tgafb_par *par = (struct tgafb_par *)fb_par; + int n, shift, base, min_diff, target; + int r,a,m,vm = 34, va = 1, vr = 30; + + for (r = 0 ; r < 12 ; r++) + TGA_WRITE_REG(par, !r, TGA_CLOCK_REG); - if (current_par_valid) - *par = current_par; - else { - if (fb_info.tga_type == TGA_TYPE_8PLANE) - default_var.bits_per_pixel = 8; + if (f > TGA_PLL_MAX_FREQ) + f = TGA_PLL_MAX_FREQ; + + if (f >= TGA_PLL_MAX_FREQ / 2) + shift = 0; + else if (f >= TGA_PLL_MAX_FREQ / 4) + shift = 1; else - default_var.bits_per_pixel = 32; + shift = 2; - tgafb_decode_var(&default_var, par, info); - } -} + TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG); + for (r = 0 ; r < 10 ; r++) + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); -static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info) -{ - int i, j; - struct tgafb_par *par = (struct tgafb_par *)fb_par; - -#if 0 - /* XXX this will break console switching with X11, maybe I need to test KD_GRAPHICS? */ - /* if current_par is valid, check to see if we need to change anything */ - if (current_par_valid) { - if (!memcmp(par, ¤t_par, sizeof current_par)) { - return; + if (f <= 120000) { + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); } - } -#endif - current_par = *par; - current_par_valid = 1; - - /* first, disable video */ - TGA_WRITE_REG(TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); - - /* write the DEEP register */ - while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ - continue; - - mb(); - TGA_WRITE_REG(deep_presets[fb_info.tga_type], TGA_DEEP_REG); - while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */ - continue; - mb(); - - /* write some more registers */ - TGA_WRITE_REG(rasterop_presets[fb_info.tga_type], TGA_RASTEROP_REG); - TGA_WRITE_REG(mode_presets[fb_info.tga_type], TGA_MODE_REG); - TGA_WRITE_REG(base_addr_presets[fb_info.tga_type], TGA_BASE_ADDR_REG); - - /* calculate & write the PLL */ - tgafb_set_pll(par->pll_freq); - - /* write some more registers */ - TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG); - TGA_WRITE_REG(0xffffffff, TGA_PIXELMASK_REG); - TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG); - TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG); - - /* init video timing regs */ - TGA_WRITE_REG(par->htimings, TGA_HORIZ_REG); - TGA_WRITE_REG(par->vtimings, TGA_VERT_REG); - - /* initalise RAMDAC */ - if (fb_info.tga_type == TGA_TYPE_8PLANE) { - - /* init BT485 RAMDAC registers */ - BT485_WRITE(0xa2 | (par->sync_on_green ? 0x8 : 0x0), BT485_CMD_0); - BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE); - BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */ - BT485_WRITE(0x40, BT485_CMD_1); - BT485_WRITE(0x20, BT485_CMD_2); /* cursor off, for now */ - BT485_WRITE(0xff, BT485_PIXEL_MASK); - - /* fill palette registers */ - BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE); - TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); - - for (i = 0; i < 16; i++) { - j = color_table[i]; - TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - palette[i].red=default_red[j]; - palette[i].green=default_grn[j]; - palette[i].blue=default_blu[j]; + else if (f <= 200000) { + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); } - for (i = 0; i < 240*3; i += 4) { - TGA_WRITE_REG(0x55|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG); - } - - } else { /* 24-plane or 24plusZ */ - - /* init BT463 registers */ - BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40); - BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08); - BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2, - (par->sync_on_green ? 0x80 : 0x40)); - - BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff); - BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff); - BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_2, 0xff); - BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); - - BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); - BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); - BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); - BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); - - /* fill the palette */ - BT463_LOAD_ADDR(0x0000); - TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); - - for (i = 0; i < 16; i++) { - j = color_table[i]; - TGA_WRITE_REG(default_red[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(default_grn[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(default_blu[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG); + else { + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); } - for (i = 0; i < 512*3; i += 4) { - TGA_WRITE_REG(0x55|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - } - - /* fill window type table after start of vertical retrace */ - while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01)) - continue; - TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG); - mb(); - while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01)) - continue; - TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG); - - BT463_LOAD_ADDR(BT463_WINDOW_TYPE_BASE); - TGA_WRITE_REG((BT463_REG_ACC<<2), TGA_RAMDAC_SETUP_REG); - - for (i = 0; i < 16; i++) { - TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x01|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); + + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); + TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); + + target = (f << shift) / TGA_PLL_BASE_FREQ; + min_diff = TGA_PLL_MAX_FREQ; + + r = 7 / target; + if (!r) r = 1; + + base = target * r; + while (base < 449) { + for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) { + m = ((n + 3) / 7) - 1; + a = 0; + DIFFCHECK((m + 1) * 7); + m++; + DIFFCHECK((m + 1) * 7); + m = (n / 6) - 1; + if ((a = n % 6)) + DIFFCHECK(n); + } + r++; + base += target; } - - } - /* finally, enable video scan - (and pray for the monitor... :-) */ - TGA_WRITE_REG(TGA_VALID_VIDEO, TGA_VALID_REG); -} + vr--; + for (r = 0; r < 8; r++) + TGA_WRITE_REG(par, (vm >> r) & 1, TGA_CLOCK_REG); + for (r = 0; r < 8 ; r++) + TGA_WRITE_REG(par, (va >> r) & 1, TGA_CLOCK_REG); + for (r = 0; r < 7 ; r++) + TGA_WRITE_REG(par, (vr >> r) & 1, TGA_CLOCK_REG); + TGA_WRITE_REG(par, ((vr >> 7) & 1)|2, TGA_CLOCK_REG); +} -#define DIFFCHECK(x) { if( m <= 0x3f ) { \ - int delta = f - (TGA_PLL_BASE_FREQ * (x)) / (r << shift); \ - if (delta < 0) delta = -delta; \ - if (delta < min_diff) min_diff = delta, vm = m, va = a, vr = r; } } -static void tgafb_set_pll(int f) +/** + * tgafb_setcolreg - Optional function. Sets a color register. + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure + */ +static int +tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) { - int n, shift, base, min_diff, target; - int r,a,m,vm = 34, va = 1, vr = 30; - - for( r = 0 ; r < 12 ; r++ ) - TGA_WRITE_REG(!r, TGA_CLOCK_REG); - - if (f > TGA_PLL_MAX_FREQ) - f = TGA_PLL_MAX_FREQ; - - if (f >= TGA_PLL_MAX_FREQ / 2) - shift = 0; - else if (f >= TGA_PLL_MAX_FREQ / 4) - shift = 1; - else - shift = 2; - - TGA_WRITE_REG(shift & 1, TGA_CLOCK_REG); - TGA_WRITE_REG(shift >> 1, TGA_CLOCK_REG); - - for( r = 0 ; r < 10 ; r++ ) { - TGA_WRITE_REG(0, TGA_CLOCK_REG); - } - - if (f <= 120000) { - TGA_WRITE_REG(0, TGA_CLOCK_REG); - TGA_WRITE_REG(0, TGA_CLOCK_REG); - } - else if (f <= 200000) { - TGA_WRITE_REG(1, TGA_CLOCK_REG); - TGA_WRITE_REG(0, TGA_CLOCK_REG); - } - else { - TGA_WRITE_REG(0, TGA_CLOCK_REG); - TGA_WRITE_REG(1, TGA_CLOCK_REG); - } - - TGA_WRITE_REG(1, TGA_CLOCK_REG); - TGA_WRITE_REG(0, TGA_CLOCK_REG); - TGA_WRITE_REG(0, TGA_CLOCK_REG); - TGA_WRITE_REG(1, TGA_CLOCK_REG); - TGA_WRITE_REG(0, TGA_CLOCK_REG); - TGA_WRITE_REG(1, TGA_CLOCK_REG); - - target = (f << shift) / TGA_PLL_BASE_FREQ; - min_diff = TGA_PLL_MAX_FREQ; - - r = 7 / target; - if (!r) - r = 1; - - base = target * r; - while (base < 449) { - for (n = base < 7 ? 7 : base ; n < base + target && n < 449; n++) { - m = ((n + 3) / 7) - 1; - a = 0; - DIFFCHECK((m + 1) * 7); - m++; - DIFFCHECK((m + 1) * 7); - m = (n / 6) - 1; - if( (a = n % 6)) - DIFFCHECK( n ); + struct tga_par *par = (struct tga_par *) info->par; + + if (regno > 255) + return 1; + red >>= 8; + green >>= 8; + blue >>= 8; + + if (par->tga_type == TGA_TYPE_8PLANE) { + BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE); + TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); + } else if (regno < 16) { + u32 value = (red << 16) | (green << 8) | blue; + ((u32 *)info->pseudo_palette)[regno] = value; } - r++; - base += target; - } - - vr--; - - for( r=0; r<8 ; r++) { - TGA_WRITE_REG((vm >> r) & 1, TGA_CLOCK_REG); - } - for( r=0; r<8 ; r++) { - TGA_WRITE_REG((va >> r) & 1, TGA_CLOCK_REG); - } - for( r=0; r<7 ; r++) { - TGA_WRITE_REG((vr >> r) & 1, TGA_CLOCK_REG); - } - TGA_WRITE_REG(((vr >> 7) & 1)|2, TGA_CLOCK_REG); -} - -static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) -{ - if (regno > 255) - return 1; - *red = (palette[regno].red<<8) | palette[regno].red; - *green = (palette[regno].green<<8) | palette[regno].green; - *blue = (palette[regno].blue<<8) | palette[regno].blue; - *transp = 0; - return 0; + return 0; } -static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +/** + * tgafb_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + */ +static int +tgafb_blank(int blank, struct fb_info *info) { - if (regno > 255) - return 1; - red >>= 8; - green >>= 8; - blue >>= 8; - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; - -#ifdef FBCON_HAS_CFB32 - if (regno < 16 && fb_info.tga_type != TGA_TYPE_8PLANE) - fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue; -#endif - - if (fb_info.tga_type == TGA_TYPE_8PLANE) { - BT485_WRITE(regno, BT485_ADDR_PAL_WRITE); - TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); - TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); - TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); - TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); - } - /* How to set a single color register on 24-plane cards?? */ + struct tga_par *par = (struct tga_par *) info->par; + u32 vhcr, vvcr, vvvr; + unsigned long flags; + + local_irq_save(flags); + + vhcr = TGA_READ_REG(par, TGA_HORIZ_REG); + vvcr = TGA_READ_REG(par, TGA_VERT_REG); + vvvr = TGA_READ_REG(par, TGA_VALID_REG); + vvvr &= ~(TGA_VALID_VIDEO | TGA_VALID_BLANK); + + switch (blank) { + case 0: /* Unblanking */ + if (par->vesa_blanked) { + TGA_WRITE_REG(par, vhcr & 0xbfffffff, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vvcr & 0xbfffffff, TGA_VERT_REG); + par->vesa_blanked = 0; + } + TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO, TGA_VALID_REG); + break; + + case 1: /* Normal blanking */ + TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK, + TGA_VALID_REG); + break; + + case 2: /* VESA blank (vsync off) */ + TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG); + TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG); + par->vesa_blanked = 1; + break; + + case 3: /* VESA blank (hsync off) */ + TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG); + par->vesa_blanked = 1; + break; + + case 4: /* Poweroff */ + TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG); + TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG); + TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG); + par->vesa_blanked = 1; + break; + } - return 0; + local_irq_restore(flags); + return 0; } -#if 1 - /* - * FIXME: since I don't know how to set a single arbitrary color register - * on 24-plane cards, all color palette registers have to be updated - */ -static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - int err; - - if (!fb_display[con].cmap.len) { /* no colormap allocated? */ - if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0))) - return err; - } - if (con == info->currcon) { /* current console? */ - err = fb_set_cmap(cmap, kspc, info); -#if 1 - if (fb_info.tga_type != TGA_TYPE_8PLANE) - tgafb_update_palette(); -#endif - return err; - } else - fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); - return 0; -} +/* + * Initialisation + */ -static void tgafb_update_palette(void) +static void +tgafb_init_fix(struct fb_info *info) { - int i; + struct tga_par *par = (struct tga_par *)info->par; + u8 tga_type = par->tga_type; + const char *tga_type_name; - BT463_LOAD_ADDR(0x0000); - TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG); - - for (i = 0; i < 256; i++) { - TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG); - } -} -#endif + switch (tga_type) { + case TGA_TYPE_8PLANE: + tga_type_name = "Digital ZLXp-E1"; + break; + case TGA_TYPE_24PLANE: + tga_type_name = "Digital ZLXp-E2"; + break; + case TGA_TYPE_24PLUSZ: + tga_type_name = "Digital ZLXp-E3"; + break; + default: + tga_type_name = "Unknown"; + break; + } + strncpy(info->fix.id, tga_type_name, sizeof(info->fix.id) - 1); + info->fix.id[sizeof(info->fix.id)-1] = 0; -static int tgafb_blank(int blank, struct fb_info_gen *info) -{ - static int tga_vesa_blanked = 0; - u32 vhcr, vvcr, vvvr; - unsigned long flags; - - local_irq_save(flags); - - vhcr = TGA_READ_REG(TGA_HORIZ_REG); - vvcr = TGA_READ_REG(TGA_VERT_REG); - vvvr = TGA_READ_REG(TGA_VALID_REG) & ~(TGA_VALID_VIDEO | TGA_VALID_BLANK); - - switch (blank) { - case 0: /* Unblanking */ - if (tga_vesa_blanked) { - TGA_WRITE_REG(vhcr & 0xbfffffff, TGA_HORIZ_REG); - TGA_WRITE_REG(vvcr & 0xbfffffff, TGA_VERT_REG); - tga_vesa_blanked = 0; - } - TGA_WRITE_REG(vvvr | TGA_VALID_VIDEO, TGA_VALID_REG); - break; - - case 1: /* Normal blanking */ - TGA_WRITE_REG(vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); - break; - - case 2: /* VESA blank (vsync off) */ - TGA_WRITE_REG(vvcr | 0x40000000, TGA_VERT_REG); - TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG); - tga_vesa_blanked = 1; - break; - - case 3: /* VESA blank (hsync off) */ - TGA_WRITE_REG(vhcr | 0x40000000, TGA_HORIZ_REG); - TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG); - tga_vesa_blanked = 1; - break; - - case 4: /* Poweroff */ - TGA_WRITE_REG(vhcr | 0x40000000, TGA_HORIZ_REG); - TGA_WRITE_REG(vvcr | 0x40000000, TGA_VERT_REG); - TGA_WRITE_REG(vvvr | TGA_VALID_BLANK, TGA_VALID_REG); - tga_vesa_blanked = 1; - break; - } - - local_irq_restore(flags); - return 0; -} + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.visual = (tga_type == TGA_TYPE_8PLANE + ? FB_VISUAL_PSEUDOCOLOR + : FB_VISUAL_TRUECOLOR); + info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); + info->fix.smem_start = (size_t) par->tga_fb_base; + info->fix.smem_len = info->fix.line_length * par->yres; + info->fix.mmio_start = (size_t) par->tga_regs_base; + info->fix.mmio_len = 0x1000; /* Is this sufficient? */ -static void tgafb_set_disp(const void *fb_par, struct display *disp, - struct fb_info_gen *info) -{ - switch (fb_info.tga_type) { -#ifdef FBCON_HAS_CFB8 - case TGA_TYPE_8PLANE: - disp->dispsw = &fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case TGA_TYPE_24PLANE: - case TGA_TYPE_24PLUSZ: - disp->dispsw = &fbcon_cfb32; - disp->dispsw_data = &fbcon_cfb32_cmap; - break; -#endif - default: - disp->dispsw = &fbcon_dummy; - } + info->fix.xpanstep = 0; + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; - disp->scrollmode = SCROLL_YREDRAW; + info->fix.accel = FB_ACCEL_DEC_TGA; } +static __devinit int +tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static unsigned int const fb_offset_presets[4] = { + TGA_8PLANE_FB_OFFSET, + TGA_24PLANE_FB_OFFSET, + 0xffffffff, + TGA_24PLUSZ_FB_OFFSET + }; + + struct all_info { + struct fb_info info; + struct tga_par par; + u32 pseudo_palette[16]; + } *all; + + void *mem_base; + unsigned long bar0_start, bar0_len; + u8 tga_type; + int ret; + + /* Enable device in PCI config. */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR "tgafb: Cannot enable PCI device\n"); + return -ENODEV; + } -struct fbgen_hwswitch tgafb_hwswitch = { - tgafb_detect, tgafb_encode_fix, tgafb_decode_var, tgafb_encode_var, tgafb_get_par, - tgafb_set_par, tgafb_getcolreg, NULL, tgafb_blank, - tgafb_set_disp -}; - + /* Allocate the fb and par structures. */ + all = kmalloc(sizeof(*all), GFP_KERNEL); + if (!all) { + printk(KERN_ERR "tgafb: Cannot allocate memory\n"); + return -ENOMEM; + } + memset(all, 0, sizeof(*all)); + pci_set_drvdata(pdev, all); + + /* Request the mem regions. */ + bar0_start = pci_resource_start(pdev, 0); + bar0_len = pci_resource_len(pdev, 0); + ret = -ENODEV; + if (!request_mem_region (bar0_start, bar0_len, "tgafb")) { + printk(KERN_ERR "tgafb: cannot reserve FB region\n"); + goto err0; + } - /* - * Hardware Independent functions - */ + /* Map the framebuffer. */ + mem_base = ioremap(bar0_start, bar0_len); + if (!mem_base) { + printk(KERN_ERR "tgafb: Cannot map MMIO\n"); + goto err1; + } + /* Grab info about the card. */ + tga_type = (readl(mem_base) >> 12) & 0x0f; + all->par.pdev = pdev; + all->par.tga_mem_base = mem_base; + all->par.tga_fb_base = mem_base + fb_offset_presets[tga_type]; + all->par.tga_regs_base = mem_base + TGA_REGS_OFFSET; + all->par.tga_type = tga_type; + pci_read_config_byte(pdev, PCI_REVISION_ID, &all->par.tga_chip_rev); + + /* Setup framebuffer. */ + all->info.node = NODEV; + all->info.flags = FBINFO_FLAG_DEFAULT; + all->info.fbops = &tgafb_ops; + all->info.screen_base = (char *) all->par.tga_fb_base; + all->info.currcon = -1; + all->info.par = &all->par; + all->info.pseudo_palette = all->pseudo_palette; + + /* This should give a reasonable default video mode. */ + + ret = fb_find_mode(&all->info.var, &all->info, mode_option, + NULL, 0, NULL, + tga_type == TGA_TYPE_8PLANE ? 8 : 32); + if (ret == 0 || ret == 4) { + printk(KERN_ERR "tgafb: Could not find valid video mode\n"); + ret = -EINVAL; + goto err1; + } - /* - * Frame buffer operations - */ + if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { + printk(KERN_ERR "tgafb: Could not allocate color map\n"); + ret = -ENOMEM; + goto err1; + } -static struct fb_ops tgafb_ops = { - .owner = THIS_MODULE, - .fb_get_fix = fbgen_get_fix, - .fb_get_var = fbgen_get_var, - .fb_set_var = fbgen_set_var, - .fb_get_cmap = fbgen_get_cmap, - .fb_set_cmap = tgafb_set_cmap, - .fb_setcolreg = tgafb_setcolreg, - .fb_blank = fbgen_blank, -}; + tgafb_set_par(&all->info); + tgafb_init_fix(&all->info); + if (register_framebuffer(&all->info) < 0) { + printk(KERN_ERR "tgafb: Could not register framebuffer\n"); + ret = -EINVAL; + goto err1; + } -#ifndef MODULE - /* - * Setup - */ - -int __init tgafb_setup(char *options) { - char *this_opt; - int i; - - if (options && *options) { - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) { continue; } - - if (!strncmp(this_opt, "font:", 5)) { - strncpy(default_fontname, this_opt+5, sizeof default_fontname); - } - - else if (!strncmp(this_opt, "mode:", 5)) { - for (i = 0; i < NUM_TOTAL_MODES; i++) { - if (!strcmp(this_opt+5, tgafb_predefined[i].name)) - default_var = tgafb_predefined[i].var; - default_var_valid = 1; - } - } - - else { - printk(KERN_ERR "tgafb: unknown parameter %s\n", this_opt); - } - } - } - return 0; + printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", + all->par.tga_chip_rev); + printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n", + minor(all->info.node), all->info.fix.id, bar0_start); + + return 0; + + err1: + release_mem_region(bar0_start, bar0_len); + err0: + kfree(all); + return ret; } -#endif - - /* - * Initialisation - */ - -int __init tgafb_init(void) +int __init +tgafb_init(void) { - struct pci_dev *pdev; - - pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL); - if (!pdev) - return -ENXIO; - - /* divine board type */ - - fb_info.tga_mem_base = (unsigned long)ioremap(pdev->resource[0].start, 0); - fb_info.tga_type = (readl(fb_info.tga_mem_base) >> 12) & 0x0f; - fb_info.tga_regs_base = fb_info.tga_mem_base + TGA_REGS_OFFSET; - fb_info.tga_fb_base = (fb_info.tga_mem_base - + fb_offset_presets[fb_info.tga_type]); - pci_read_config_byte(pdev, PCI_REVISION_ID, &fb_info.tga_chip_rev); - - /* setup framebuffer */ - - fb_info.gen.info.node = NODEV; - fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; - fb_info.gen.info.fbops = &tgafb_ops; - fb_info.gen.info.screen_base = (char *)fb_info.tga_fb_base; - fb_info.gen.info.disp = &disp; - fb_info.gen.info.currcon = -1; - fb_info.gen.info.changevar = NULL; - fb_info.gen.info.switch_con = &fbgen_switch; - fb_info.gen.info.updatevar = &fbgen_update_var; - strcpy(fb_info.gen.info.fontname, default_fontname); - fb_info.gen.parsize = sizeof (struct tgafb_par); - fb_info.gen.fbhw = &tgafb_hwswitch; - fb_info.gen.fbhw->detect(); - - printk (KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", fb_info.tga_chip_rev); - printk (KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n", - pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - switch (fb_info.tga_type) - { - case TGA_TYPE_8PLANE: - strcpy (fb_info.gen.info.modename,"Digital ZLXp-E1"); - break; - - case TGA_TYPE_24PLANE: - strcpy (fb_info.gen.info.modename,"Digital ZLXp-E2"); - break; - - case TGA_TYPE_24PLUSZ: - strcpy (fb_info.gen.info.modename,"Digital ZLXp-E3"); - break; - } - - /* This should give a reasonable default video mode */ - - if (!default_var_valid) { - default_var = tgafb_predefined[0].var; - } - fbgen_get_var(&disp.var, -1, &fb_info.gen.info); - disp.var.activate = FB_ACTIVATE_NOW; - fbgen_do_set_var(&disp.var, 1, &fb_info.gen); - fbgen_set_disp(-1, &fb_info.gen); - do_install_cmap(0, &fb_info.gen); - if (register_framebuffer(&fb_info.gen.info) < 0) - return -EINVAL; - printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n", - minor(fb_info.gen.info.node), fb_info.gen.info.modename, - pdev->resource[0].start); - return 0; + return pci_module_init(&tgafb_driver); } +#ifdef MODULE +static void __exit +tgafb_pci_unregister(struct pci_dev *pdev) +{ + struct fb_info *info = pci_get_drvdata(pdev); + struct tga_par *par = info->par; + + if (!info) + return; + unregister_framebuffer(info); + iounmap(par->tga_mem_base); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + kfree(info); +} - /* - * Cleanup - */ - -void __exit tgafb_cleanup(void) +static void __exit +tgafb_exit(void) { - unregister_framebuffer(&fb_info.gen.info); + pci_unregister_driver(&tgafb_driver); } +#endif /* MODULE */ +#ifndef MODULE +int __init +tgafb_setup(char *arg) +{ + char *this_opt; + + if (arg && *arg) { + while ((this_opt = strsep(&arg, ","))) { + if (!*this_opt) + continue; + if (!strncmp(this_opt, "mode:", 5)) + mode_option = this_opt+5; + else + printk(KERN_ERR + "tgafb: unknown parameter %s\n", + this_opt); + } + } - /* - * Modularisation - */ + return 0; +} +#endif /* !MODULE */ + +/* + * Modularisation + */ #ifdef MODULE -MODULE_LICENSE("GPL"); module_init(tgafb_init); +module_exit(tgafb_exit); #endif -module_exit(tgafb_cleanup); +MODULE_DESCRIPTION("framebuffer driver for TGA chipset"); +MODULE_LICENSE("GPL"); diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h index f236e21749ab..5410e84760e6 100644 --- a/include/asm-i386/bugs.h +++ b/include/asm-i386/bugs.h @@ -193,6 +193,11 @@ static void __init check_config(void) && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11)) panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!"); #endif + +#ifdef CONFIG_X86_SSE2 + if (!cpu_has_sse2) + panic("Kernel compiled for SSE2, CPU doesn't have it."); +#endif } static void __init check_bugs(void) diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h index 92ff7f79dee4..5f019713fa4c 100644 --- a/include/asm-i386/cpufeature.h +++ b/include/asm-i386/cpufeature.h @@ -75,6 +75,7 @@ #define cpu_has_tsc boot_cpu_has(X86_FEATURE_TSC) #define cpu_has_pae boot_cpu_has(X86_FEATURE_PAE) #define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE) +#define cpu_has_sse2 boot_cpu_has(X86_FEATURE_XMM2) #define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC) #define cpu_has_sep boot_cpu_has(X86_FEATURE_SEP) #define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR) diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 9de3a8a9bf58..01cdbdc7a32b 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -489,7 +489,7 @@ static inline void rep_nop(void) #define cpu_relax() rep_nop() /* Prefetch instructions for Pentium III and AMD Athlon */ -#ifdef CONFIG_MPENTIUMIII +#ifdef CONFIG_X86_PREFETCH #define ARCH_HAS_PREFETCH extern inline void prefetch(const void *x) diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index fc8f116430bc..e085e51e9d25 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -288,9 +288,13 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, * nop for these. */ +#ifdef CONFIG_X86_SSE2 +#define mb() asm volatile("mfence" ::: "memory") +#define rmb() asm volatile("lfence" ::: "memory") +#else #define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") #define rmb() mb() - +#endif /** * read_barrier_depends - Flush all pending reads that subsequents reads * depend on. diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h index 1471687982a9..6b451e47441c 100644 --- a/include/asm-m68k/ide.h +++ b/include/asm-m68k/ide.h @@ -147,26 +147,28 @@ static __inline__ void ide_init_default_hwifs(void) #ifdef CONFIG_ATARI #define ATA_ARCH_LOCK -static __inline__ void ide_release_lock (int *ide_lock) +extern int ide_intr_lock; + +static __inline__ void ide_release_lock (void) { if (MACH_IS_ATARI) { - if (*ide_lock == 0) { + if (ide_intr_lock == 0) { printk("ide_release_lock: bug\n"); return; } - *ide_lock = 0; + ide_intr_lock = 0; stdma_release(); } } -static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data) +static __inline__ void ide_get_lock(void (*handler)(int, void *, struct pt_regs *), void *data) { if (MACH_IS_ATARI) { - if (*ide_lock == 0) { + if (ide_intr_lock == 0) { if (in_interrupt() > 0) panic( "Falcon IDE hasn't ST-DMA lock in interrupt" ); stdma_lock(handler, data); - *ide_lock = 1; + ide_intr_lock = 1; } } } diff --git a/include/asm-m68k/macintosh.h b/include/asm-m68k/macintosh.h index 47ad33cc2254..cbb1cb10cf73 100644 --- a/include/asm-m68k/macintosh.h +++ b/include/asm-m68k/macintosh.h @@ -76,9 +76,9 @@ struct mac_model #define MAC_IDE_BABOON 3 #define MAC_SCC_II 1 -#define MAC_SCC_QUADRA 2 -#define MAC_SCC_QUADRA2 3 -#define MAC_SCC_IOP 4 +#define MAC_SCC_IOP 2 +#define MAC_SCC_QUADRA 3 +#define MAC_SCC_PSC 4 #define MAC_ETHER_NONE 0 #define MAC_ETHER_SONIC 1 @@ -139,6 +139,7 @@ struct mac_model #define MAC_MODEL_P475F 90 /* aka: P475 w/ FPU (no LC040) */ #define MAC_MODEL_P575 92 /* aka: LC575, P577/P578 */ #define MAC_MODEL_Q605 94 +#define MAC_MODEL_Q605_ACC 95 /* Q605 accelerated to 33 MHz */ #define MAC_MODEL_Q630 98 /* aka: LC630, P630/631/635/636/637/638/640 */ #define MAC_MODEL_P588 99 /* aka: LC580, P580 */ #define MAC_MODEL_PB280 102 diff --git a/include/asm-m68k/mman.h b/include/asm-m68k/mman.h index a171fb7c7acf..59c2d3c265d1 100644 --- a/include/asm-m68k/mman.h +++ b/include/asm-m68k/mman.h @@ -18,6 +18,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff --git a/include/asm-m68k/module.h b/include/asm-m68k/module.h index a978a053c89f..c6d75af2d8d3 100644 --- a/include/asm-m68k/module.h +++ b/include/asm-m68k/module.h @@ -1,12 +1,7 @@ #ifndef _ASM_M68K_MODULE_H #define _ASM_M68K_MODULE_H -/* - * This file contains the m68k architecture specific module code. - */ - -#define module_map(x) vmalloc(x) -#define module_unmap(x) vfree(x) -#define module_arch_init(x) (0) -#define arch_init_modules(x) do { } while (0) - +struct mod_arch_specific { }; +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr #endif /* _ASM_M68K_MODULE_H */ diff --git a/include/asm-m68k/sbus.h b/include/asm-m68k/sbus.h index ed76953cafb1..5dd2fac1b9ce 100644 --- a/include/asm-m68k/sbus.h +++ b/include/asm-m68k/sbus.h @@ -5,7 +5,7 @@ #ifndef __M68K_SBUS_H #define __M68K_SBUS_H -struct linux_sbus_device { +struct sbus_dev { struct { unsigned int which_io; unsigned int phys_addr; diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h index 8fe94c6017fd..112ea2a6a047 100644 --- a/include/asm-m68k/system.h +++ b/include/asm-m68k/system.h @@ -74,12 +74,14 @@ static inline int irqs_disabled(void) #define mb() barrier() #define rmb() barrier() #define wmb() barrier() +#define read_barrier_depends() do { } while(0) #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while(0) #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h index 55244ef06d37..49988674166f 100644 --- a/include/asm-m68k/thread_info.h +++ b/include/asm-m68k/thread_info.h @@ -10,6 +10,7 @@ struct thread_info { struct exec_domain *exec_domain; /* execution domain */ __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ __u32 cpu; /* should always be 0 on m68k */ + struct restart_block restart_block; __u8 supervisor_stack[0]; }; @@ -20,6 +21,9 @@ struct thread_info { { \ .task = &tsk, \ .exec_domain = &default_exec_domain, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ } /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */ diff --git a/include/asm-um/a.out.h b/include/asm-um/a.out.h index 2e208223f860..7c26265e1d7a 100644 --- a/include/asm-um/a.out.h +++ b/include/asm-um/a.out.h @@ -1,7 +1,9 @@ #ifndef __UM_A_OUT_H #define __UM_A_OUT_H +#include "linux/config.h" #include "asm/arch/a.out.h" +#include "choose-mode.h" #undef STACK_TOP @@ -9,10 +11,10 @@ extern unsigned long stacksizelim; extern unsigned long host_task_size; -extern int honeypot; - #define STACK_ROOM (stacksizelim) -#define STACK_TOP (honeypot ? host_task_size : task_size) +extern int honeypot; +#define STACK_TOP \ + CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size) #endif diff --git a/include/asm-um/checksum.h b/include/asm-um/checksum.h index 4b38f37c822e..5b501361e361 100644 --- a/include/asm-um/checksum.h +++ b/include/asm-um/checksum.h @@ -1,6 +1,6 @@ #ifndef __UM_CHECKSUM_H #define __UM_CHECKSUM_H -#include "asm/arch/checksum.h" +#include "sysdep/checksum.h" #endif diff --git a/include/asm-um/mmu.h b/include/asm-um/mmu.h index d276d24f07df..2cf35c21d694 100644 --- a/include/asm-um/mmu.h +++ b/include/asm-um/mmu.h @@ -1,6 +1,22 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __MMU_H #define __MMU_H -#include "asm/arch/mmu.h" +#include "um_mmu.h" #endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h index 56ef77e1c1c8..e735fe0a95a9 100644 --- a/include/asm-um/mmu_context.h +++ b/include/asm-um/mmu_context.h @@ -1,20 +1,33 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + #ifndef __UM_MMU_CONTEXT_H #define __UM_MMU_CONTEXT_H #include "linux/sched.h" +#include "choose-mode.h" -#define init_new_context(task, mm) (0) #define get_mmu_context(task) do ; while(0) #define activate_context(tsk) do ; while(0) -#define destroy_context(mm) do ; while(0) static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) { } +extern void switch_mm_skas(int mm_fd); + static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) { + if(prev != next){ + clear_bit(cpu, &prev->cpu_vm_mask); + set_bit(cpu, &next->cpu_vm_mask); + if(next != &init_mm) + CHOOSE_MODE((void) 0, + switch_mm_skas(next->context.skas.mm_fd)); + } } static inline void enter_lazy_tlb(struct mm_struct *mm, @@ -22,4 +35,38 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, { } +extern int init_new_context_skas(struct task_struct *task, + struct mm_struct *mm); + +static inline int init_new_context_tt(struct task_struct *task, + struct mm_struct *mm) +{ + return(0); +} + +static inline int init_new_context(struct task_struct *task, + struct mm_struct *mm) +{ + return(CHOOSE_MODE_PROC(init_new_context_tt, init_new_context_skas, + task, mm)); +} + +extern void destroy_context_skas(struct mm_struct *mm); + +static inline void destroy_context(struct mm_struct *mm) +{ + CHOOSE_MODE((void) 0, destroy_context_skas(mm)); +} + #endif + +/* + * 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. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/page.h b/include/asm-um/page.h index e3279d1d0b31..f4c0f7eb0d05 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -18,6 +18,8 @@ struct page; #undef PAGE_OFFSET #undef KERNELBASE +extern unsigned long uml_physmem; + #define PAGE_OFFSET (uml_physmem) #define KERNELBASE PAGE_OFFSET diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index a79a756c3989..8d607c87418d 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -373,15 +373,15 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) } /* Find an entry in the third-level page table.. */ -#define __pte_offset(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define __pte_offset(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define pte_offset_kernel(dir, address) \ ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) #define pte_offset_map(dir, address) \ ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address)) #define pte_offset_map_nested(dir, address) \ ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address)) -#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) -#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) +#define pte_unmap(pte) kunmap_atomic((pte), KM_PTE0) +#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1) #if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G) typedef u32 pte_addr_t; diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index 7e771b8ca7db..435380cc08d7 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -12,9 +12,9 @@ struct task_struct; #include "linux/config.h" #include "linux/signal.h" -#include "asm/segment.h" #include "asm/ptrace.h" #include "asm/siginfo.h" +#include "choose-mode.h" struct mm_struct; @@ -22,9 +22,24 @@ struct mm_struct; #define cpu_relax() do ; while (0) -struct thread_struct { +#ifdef CONFIG_MODE_TT +struct proc_tt_mode { int extern_pid; int tracing; + int switch_pipe[2]; + int singlestep_syscall; + int vm_seq; +}; +#endif + +#ifdef CONFIG_MODE_SKAS +struct proc_skas_mode { + void *switch_buf; + void *fork_buf; +}; +#endif + +struct thread_struct { int forking; unsigned long kernel_stack; int nsyscalls; @@ -33,13 +48,18 @@ struct thread_struct { int err; void *fault_addr; void *fault_catcher; - int vm_seq; struct task_struct *prev_sched; unsigned long temp_stack; - int switch_pipe[2]; - void *jmp; + void *exec_buf; struct arch_thread arch; - int singlestep_syscall; + union { +#ifdef CONFIG_MODE_TT + struct proc_tt_mode tt; +#endif +#ifdef CONFIG_MODE_SKAS + struct proc_skas_mode skas; +#endif + } mode; struct { int op; union { @@ -60,8 +80,6 @@ struct thread_struct { #define INIT_THREAD \ { \ - extern_pid: -1, \ - tracing: 0, \ forking: 0, \ kernel_stack: 0, \ nsyscalls: 0, \ @@ -69,13 +87,10 @@ struct thread_struct { cr2: 0, \ err: 0, \ fault_addr: NULL, \ - vm_seq: 0, \ prev_sched: NULL, \ temp_stack: 0, \ - switch_pipe: { -1, -1 }, \ - jmp: NULL, \ + exec_buf: NULL, \ arch: INIT_ARCH_THREAD, \ - singlestep_syscall: 0, \ request: { 0 } \ } diff --git a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h index 18f6b5991856..0a5f77de79ba 100644 --- a/include/asm-um/ptrace-generic.h +++ b/include/asm-um/ptrace-generic.h @@ -8,6 +8,8 @@ #ifndef __ASSEMBLY__ +#include "linux/config.h" +#include "skas_ptrace.h" #include "asm/current.h" #define pt_regs pt_regs_subarch diff --git a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h index 24d97e5fcf20..80b24a31b5fe 100644 --- a/include/asm-um/system-generic.h +++ b/include/asm-um/system-generic.h @@ -17,6 +17,7 @@ extern void *switch_to(void *prev, void *next, void *last); +extern int get_signals(void); extern int set_signals(int enable); extern int get_signals(void); extern void block_signals(void); diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 1cb0f45359f5..bd3f4fe40c6b 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -20,14 +20,9 @@ struct thread_info { mm_segment_t addr_limit; /* thread address space: 0-0xBFFFFFFF for user 0-0xFFFFFFFF for kernel */ + struct restart_block restart_block; }; -/* - * macros/functions for gaining access to the thread information structure - * - * preempt_count needs to be 1 initially, until the scheduler is functional. - */ - #define INIT_THREAD_INFO(tsk) \ { \ task: &tsk, \ @@ -36,6 +31,9 @@ struct thread_info { cpu: 0, \ preempt_count: 1, \ addr_limit: KERNEL_DS, \ + restart_block: { \ + fn: do_no_restart_syscall, \ + }, \ } #define init_thread_info (init_thread_union.thread_info) diff --git a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h index a8a7dfb7e4c8..e1dfea108857 100644 --- a/include/asm-um/uaccess.h +++ b/include/asm-um/uaccess.h @@ -1,18 +1,11 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ #ifndef __UM_UACCESS_H #define __UM_UACCESS_H -#include "linux/string.h" -#include "linux/sched.h" -#include "asm/processor.h" -#include "asm/errno.h" -#include "asm/current.h" -#include "asm/a.out.h" - #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -26,8 +19,6 @@ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -#define ABOVE_KMEM (16 * 1024 * 1024) - #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) #define USER_DS MAKE_MM_SEG(TASK_SIZE) @@ -35,56 +26,12 @@ #define get_fs() (current_thread_info()->addr_limit) #define set_fs(x) (current_thread_info()->addr_limit = (x)) -extern unsigned long end_vm; -extern unsigned long uml_physmem; - -#define under_task_size(addr, size) \ - (((unsigned long) (addr) < TASK_SIZE) && \ - (((unsigned long) (addr) + (size)) < TASK_SIZE)) - -#define is_stack(addr, size) \ - (((unsigned long) (addr) < STACK_TOP) && \ - ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ - (((unsigned long) (addr) + (size)) <= STACK_TOP)) - #define segment_eq(a, b) ((a).seg == (b).seg) -#define access_ok(type, addr, size) \ - ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \ - (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ - (under_task_size(addr, size) || is_stack(addr, size)))) - -static inline int verify_area(int type, const void * addr, unsigned long size) -{ - return(access_ok(type, addr, size) ? 0 : -EFAULT); -} - -extern unsigned long get_fault_addr(void); - -extern int __do_copy_from_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); - -static inline int copy_from_user(void *to, const void *from, int n) -{ - return(access_ok(VERIFY_READ, from, n) ? - __do_copy_from_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} +#include "um_uaccess.h" #define __copy_from_user(to, from, n) copy_from_user(to, from, n) -extern int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher); - -static inline int copy_to_user(void *to, const void *from, int n) -{ - return(access_ok(VERIFY_WRITE, to, n) ? - __do_copy_to_user(to, from, n, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : n); -} - #define __copy_to_user(to, from, n) copy_to_user(to, from, n) #define __get_user(x, ptr) \ @@ -128,49 +75,6 @@ static inline int copy_to_user(void *to, const void *from, int n) __put_user(x, private_ptr) : -EFAULT); \ }) -extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, - void **fault_addr, void **fault_catcher); - -static inline int strncpy_from_user(char *dst, const char *src, int count) -{ - int n; - - if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT); - n = __do_strncpy_from_user(dst, src, count, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher); - if(n < 0) return(-EFAULT); - return(n); -} - -extern int __do_clear_user(void *mem, size_t len, void **fault_addr, - void **fault_catcher); - -static inline int __clear_user(void *mem, int len) -{ - return(__do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - -static inline int clear_user(void *mem, int len) -{ - return(access_ok(VERIFY_WRITE, mem, len) ? - __do_clear_user(mem, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher) : len); -} - -extern int __do_strnlen_user(const char *str, unsigned long n, - void **fault_addr, void **fault_catcher); - -static inline int strnlen_user(void *str, int len) -{ - return(__do_strnlen_user(str, len, - ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)); -} - #define strlen_user(str) strnlen_user(str, ~0UL >> 1) struct exception_table_entry diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h index 72e575a68a33..c98d3c64bba0 100644 --- a/include/asm-x86_64/bitops.h +++ b/include/asm-x86_64/bitops.h @@ -244,7 +244,7 @@ static __inline__ int constant_test_bit(int nr, const volatile void * addr) return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; } -static __inline__ int variable_test_bit(int nr, volatile void * addr) +static __inline__ int variable_test_bit(int nr, volatile const void * addr) { int oldbit; diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h index f5775b7ddde5..724777a946f6 100644 --- a/include/asm-x86_64/desc.h +++ b/include/asm-x86_64/desc.h @@ -131,7 +131,7 @@ static inline void set_tss_desc(unsigned cpu, void *addr) static inline void set_ldt_desc(unsigned cpu, void *addr, int size) { - set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (unsigned long)addr, + set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (unsigned long)addr, DESC_LDT, size); } diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h deleted file mode 100644 index e7e16901f686..000000000000 --- a/include/asm-x86_64/dma-mapping.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm-generic/dma-mapping.h> diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h index 9d7d039d5222..bb096fb7ab06 100644 --- a/include/asm-x86_64/hw_irq.h +++ b/include/asm-x86_64/hw_irq.h @@ -168,9 +168,24 @@ static inline void x86_do_profile (struct pt_regs *regs) struct notifier_block; +#ifdef CONFIG_PROFILING + int register_profile_notifier(struct notifier_block * nb); int unregister_profile_notifier(struct notifier_block * nb); +#else + +static inline int register_profile_notifier(struct notifier_block * nb) +{ + return -ENOSYS; +} + +static inline int unregister_profile_notifier(struct notifier_block * nb) +{ + return -ENOSYS; +} + +#endif /* CONFIG_PROFILING */ #ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */ static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { if (IO_APIC_IRQ(i)) diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86_64/ia32.h index f257195d1740..23d4d607a398 100644 --- a/include/asm-x86_64/ia32.h +++ b/include/asm-x86_64/ia32.h @@ -202,7 +202,7 @@ struct iovec32 { int iov_len; }; -#define IA32_PAGE_OFFSET 0xffff0000 +#define IA32_PAGE_OFFSET 0xffffe000 #define IA32_STACK_TOP IA32_PAGE_OFFSET #endif /* !CONFIG_IA32_SUPPORT */ diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h index 2975afd3f3e5..d5e3a3a81282 100644 --- a/include/asm-x86_64/io_apic.h +++ b/include/asm-x86_64/io_apic.h @@ -3,6 +3,7 @@ #include <linux/config.h> #include <asm/types.h> +#include <asm/mpspec.h> /* * Intel IO-APIC support for SMP and UP systems. diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h index 075a49ff9ba4..9c84b14139f2 100644 --- a/include/asm-x86_64/processor.h +++ b/include/asm-x86_64/processor.h @@ -256,7 +256,7 @@ static inline void clear_in_cr4 (unsigned long mask) /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ -#define TASK_UNMAPPED_32 0x40000000 +#define TASK_UNMAPPED_32 0xa0000000 #define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3) #define TASK_UNMAPPED_BASE \ (test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64) diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index a9f8d7e16ee6..9ca683849c42 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h @@ -42,6 +42,8 @@ extern void exception_table_check(void); extern int acpi_boot_init(char *); +extern int map_syscall32(struct mm_struct *mm, unsigned long address); + #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1)) #define round_down(x,y) ((x) & ~((y)-1)) diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h index 52047a7e928b..b502884f490a 100644 --- a/include/asm-x86_64/spinlock.h +++ b/include/asm-x86_64/spinlock.h @@ -48,8 +48,8 @@ typedef struct { "js 2f\n" \ LOCK_SECTION_START("") \ "2:\t" \ - "cmpb $0,%0\n\t" \ "rep;nop\n\t" \ + "cmpb $0,%0\n\t" \ "jle 2b\n\t" \ "jmp 1b\n" \ LOCK_SECTION_END diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index f1281d48dc93..268865b34785 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -254,7 +254,12 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, */ #define mb() asm volatile("mfence":::"memory") #define rmb() asm volatile("lfence":::"memory") -#define wmb() asm volatile("sfence":::"memory") + +/* could use SFENCE here, but it would be only needed for unordered SSE + store instructions and we always do an explicit sfence with them currently. + the ordering of normal stores is serialized enough. Just make it a compile + barrier. */ +#define wmb() asm volatile("" ::: "memory") #define read_barrier_depends() do {} while(0) #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h index 69cac4da715d..9f034cf938d1 100644 --- a/include/asm-x86_64/thread_info.h +++ b/include/asm-x86_64/thread_info.h @@ -100,6 +100,7 @@ static inline struct thread_info *stack_thread_info(void) #define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ #define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_IA32 18 /* 32bit process */ @@ -107,6 +108,7 @@ static inline struct thread_info *stack_thread_info(void) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) +#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_USEDFPU (1<<TIF_USEDFPU) #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h index 3cb62ac5fb08..065eb4c8dafb 100644 --- a/include/asm-x86_64/uaccess.h +++ b/include/asm-x86_64/uaccess.h @@ -103,7 +103,8 @@ extern void __get_user_8(void); /* Careful: we have to cast the result to the type of the pointer for sign reasons */ #define get_user(x,ptr) \ -({ long __ret_gu,__val_gu; \ +({ long __val_gu; \ + int __ret_gu; \ switch(sizeof (*(ptr))) { \ case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \ @@ -138,7 +139,7 @@ extern void __put_user_bad(void); #define __put_user_nocheck(x,ptr,size) \ ({ \ - long __pu_err; \ + int __pu_err; \ __put_user_size((x),(ptr),(size),__pu_err); \ __pu_err; \ }) @@ -146,7 +147,7 @@ extern void __put_user_bad(void); #define __put_user_check(x,ptr,size) \ ({ \ - long __pu_err = -EFAULT; \ + int __pu_err = -EFAULT; \ __typeof__(*(ptr)) *__pu_addr = (ptr); \ if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ __put_user_size((x),__pu_addr,(size),__pu_err); \ @@ -157,10 +158,10 @@ extern void __put_user_bad(void); do { \ retval = 0; \ switch (size) { \ - case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break; \ - case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break; \ - case 4: __put_user_asm(x,ptr,retval,"l","k","ir"); break; \ - case 8: __put_user_asm(x,ptr,retval,"q","","ir"); break; \ + case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\ + case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\ + case 4: __put_user_asm(x,ptr,retval,"l","k","ir",-EFAULT); break;\ + case 8: __put_user_asm(x,ptr,retval,"q","","ir",-EFAULT); break;\ default: __put_user_bad(); \ } \ } while (0) @@ -174,12 +175,12 @@ struct __large_struct { unsigned long buf[100]; }; * we do not write to any memory gcc knows about, so there are no * aliasing issues. */ -#define __put_user_asm(x, addr, err, itype, rtype, ltype) \ +#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno) \ __asm__ __volatile__( \ "1: mov"itype" %"rtype"1,%2\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ - "3: movq %3,%0\n" \ + "3: mov %3,%0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ @@ -187,32 +188,33 @@ struct __large_struct { unsigned long buf[100]; }; " .quad 1b,3b\n" \ ".previous" \ : "=r"(err) \ - : ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err)) + : ltype (x), "m"(__m(addr)), "i"(errno), "0"(err)) #define __get_user_nocheck(x,ptr,size) \ ({ \ - long __gu_err, __gu_val; \ + int __gu_err; \ + long __gu_val; \ __get_user_size(__gu_val,(ptr),(size),__gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ }) -extern long __get_user_bad(void); +extern int __get_user_bad(void); #define __get_user_size(x,ptr,size,retval) \ do { \ retval = 0; \ switch (size) { \ - case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break; \ - case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break; \ - case 4: __get_user_asm(x,ptr,retval,"l","k","=r"); break; \ - case 8: __get_user_asm(x,ptr,retval,"q","","=r"); break; \ + case 1: __get_user_asm(x,ptr,retval,"b","b","=q",-EFAULT); break;\ + case 2: __get_user_asm(x,ptr,retval,"w","w","=r",-EFAULT); break;\ + case 4: __get_user_asm(x,ptr,retval,"l","k","=r",-EFAULT); break;\ + case 8: __get_user_asm(x,ptr,retval,"q","","=r",-EFAULT); break;\ default: (x) = __get_user_bad(); \ } \ } while (0) -#define __get_user_asm(x, addr, err, itype, rtype, ltype) \ +#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno) \ __asm__ __volatile__( \ "1: mov"itype" %2,%"rtype"1\n" \ "2:\n" \ @@ -226,23 +228,77 @@ do { \ " .quad 1b,3b\n" \ ".previous" \ : "=r"(err), ltype (x) \ - : "m"(__m(addr)), "i"(-EFAULT), "0"(err)) + : "m"(__m(addr)), "i"(errno), "0"(err)) /* * Copy To/From Userspace - * - * This relies on an optimized common worker function. - * - * Could do special inline versions for small constant copies, but avoid this - * for now. It's not clear it is worth it. */ +/* Handles exceptions in both to and from, but doesn't do access_ok */ extern unsigned long copy_user_generic(void *to, const void *from, unsigned len); extern unsigned long copy_to_user(void *to, const void *from, unsigned len); extern unsigned long copy_from_user(void *to, const void *from, unsigned len); -#define __copy_to_user copy_user_generic -#define __copy_from_user copy_user_generic + +static inline int __copy_from_user(void *dst, void *src, unsigned size) +{ + if (!__builtin_constant_p(size)) + return copy_user_generic(dst,src,size); + int ret = 0; + switch (size) { + case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1); + return ret; + case 2:__get_user_asm(*(u16*)dst,(u16*)src,ret,"w","w","=r",2); + return ret; + case 4:__get_user_asm(*(u32*)dst,(u32*)src,ret,"l","k","=r",4); + return ret; + case 8:__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",8); + return ret; + case 10: + __get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16); + if (ret) return ret; + __get_user_asm(*(u16*)(8+dst),(u16*)(8+src),ret,"w","w","=r",2); + return ret; + case 16: + __get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16); + if (ret) return ret; + __get_user_asm(*(u64*)(8+dst),(u64*)(8+src),ret,"q","","=r",8); + return ret; + default: + return copy_user_generic(dst,src,size); + } +} + +static inline int __copy_to_user(void *dst, void *src, unsigned size) +{ + if (!__builtin_constant_p(size)) + return copy_user_generic(dst,src,size); + int ret = 0; + switch (size) { + case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1); + return ret; + case 2:__put_user_asm(*(u16*)src,(u16*)dst,ret,"w","w","ir",2); + return ret; + case 4:__put_user_asm(*(u32*)src,(u32*)dst,ret,"l","k","ir",4); + return ret; + case 8:__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",8); + return ret; + case 10: + __put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",10); + if (ret) return ret; + asm("":::"memory"); + __put_user_asm(4[(u16*)src],4+(u16*)dst,ret,"w","w","ir",2); + return ret; + case 16: + __put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",16); + if (ret) return ret; + asm("":::"memory"); + __put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8); + return ret; + default: + return copy_user_generic(dst,src,size); + } +} long strncpy_from_user(char *dst, const char *src, long count); long __strncpy_from_user(char *dst, const char *src, long count); diff --git a/include/linux/fb.h b/include/linux/fb.h index 23dd4c02ddec..188da2f94589 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -424,9 +424,11 @@ struct fb_info { #define fb_readb __raw_readb #define fb_readw __raw_readw #define fb_readl __raw_readl +#define fb_readq __raw_readq #define fb_writeb __raw_writeb #define fb_writew __raw_writew #define fb_writel __raw_writel +#define fb_writeq __raw_writeq #define fb_memset memset_io #else diff --git a/include/linux/ide.h b/include/linux/ide.h index 033e94a6d6e4..2e2718ebfd98 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -360,8 +360,8 @@ extern int ide_irq_lock; /* Currently only Atari needs it */ #ifndef IDE_ARCH_LOCK -# define ide_release_lock(lock) do {} while (0) -# define ide_get_lock(lock, hdlr, data) do {} while (0) +# define ide_release_lock() do {} while (0) +# define ide_get_lock(hdlr, data) do {} while (0) #endif /* IDE_ARCH_LOCK */ /* diff --git a/include/linux/nubus.h b/include/linux/nubus.h index a3fd37b33fdd..870e66a96286 100644 --- a/include/linux/nubus.h +++ b/include/linux/nubus.h @@ -28,18 +28,18 @@ enum nubus_category { }; enum nubus_type_network { - NUBUS_TYPE_ETHERNET = 0x0001, - NUBUS_TYPE_RS232 = 0x0002 + NUBUS_TYPE_ETHERNET = 0x0001, + NUBUS_TYPE_RS232 = 0x0002 }; enum nubus_type_display { - NUBUS_TYPE_VIDEO = 0x0001 + NUBUS_TYPE_VIDEO = 0x0001 }; enum nubus_type_cpu { - NUBUS_TYPE_68020 = 0x0003, - NUBUS_TYPE_68030 = 0x0004, - NUBUS_TYPE_68040 = 0x0005 + NUBUS_TYPE_68020 = 0x0003, + NUBUS_TYPE_68030 = 0x0004, + NUBUS_TYPE_68040 = 0x0005 }; /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots) @@ -80,22 +80,24 @@ enum nubus_type_cpu { /* Add known DrSW values here */ enum nubus_drsw { /* NUBUS_CAT_DISPLAY */ - NUBUS_DRSW_APPLE = 0x0001, - NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ + NUBUS_DRSW_APPLE = 0x0001, + NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ /* NUBUS_CAT_NETWORK */ - NUBUS_DRSW_CABLETRON = 0x0001, - NUBUS_DRSW_SONIC_LC = 0x0001, - NUBUS_DRSW_KINETICS = 0x0103, - NUBUS_DRSW_ASANTE = 0x0104, - NUBUS_DRSW_DAYNA = 0x010b, - NUBUS_DRSW_FARALLON = 0x010c, - NUBUS_DRSW_APPLE_SN = 0x010f, - NUBUS_DRSW_FOCUS = 0x011a, - NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */ + NUBUS_DRSW_CABLETRON = 0x0001, + NUBUS_DRSW_SONIC_LC = 0x0001, + NUBUS_DRSW_KINETICS = 0x0103, + NUBUS_DRSW_ASANTE = 0x0104, + NUBUS_DRSW_DAYNA = 0x010b, + NUBUS_DRSW_FARALLON = 0x010c, + NUBUS_DRSW_APPLE_SN = 0x010f, + NUBUS_DRSW_DAYNA2 = 0x0115, + NUBUS_DRSW_FOCUS = 0x011a, + NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */ + NUBUS_DRSW_DAYNA_LC = 0x011e, /* NUBUS_CAT_CPU */ - NUBUS_DRSW_NONE = 0x0000, + NUBUS_DRSW_NONE = 0x0000, }; /* DrHW: Uniquely identifies the hardware interface to a board (or at @@ -106,11 +108,13 @@ enum nubus_drsw { enum nubus_drhw { /* NUBUS_CAT_DISPLAY */ NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */ + NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High Res Video card */ NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */ NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */ NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */ + NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ NUBUS_DRHW_APPLE_VALKYRIE = 0x002e, - NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ + NUBUS_DRHW_THUNDER24 = 0x02cb, /* SuperMac Thunder/24 */ /* NUBUS_CAT_NETWORK */ NUBUS_DRHW_INTERLAN = 0x0100, @@ -119,6 +123,11 @@ enum nubus_drhw { NUBUS_DRHW_CABLETRON = 0x0109, NUBUS_DRHW_ASANTE_LC = 0x010f, NUBUS_DRHW_SONIC = 0x0110, + NUBUS_DRHW_SONIC_NB = 0x0118, + NUBUS_DRHW_SONIC_LC = 0x0119, + + /* NUBUS_CAT_COMMUNICATIONS */ + NUBUS_DRHW_DOVEFAX = 0x0100, }; /* Resource IDs: These are the identifiers for the various weird and @@ -153,8 +162,8 @@ enum nubus_board_res_id { NUBUS_RESID_SECONDINIT = 0x0026, /* Not sure why Apple put these next two in here */ - NUBUS_RESID_VIDNAMES = 0x0041, - NUBUS_RESID_VIDMODES = 0x007e + NUBUS_RESID_VIDNAMES = 0x0041, + NUBUS_RESID_VIDMODES = 0x007e }; /* Fields within the vendor info directory */ diff --git a/include/video/font.h b/include/video/font.h new file mode 100644 index 000000000000..fd332b3a7179 --- /dev/null +++ b/include/video/font.h @@ -0,0 +1,24 @@ +/* + * font.h -- `Soft' font definitions + * + * Created 1995 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _VIDEO_FONT_H +#define _VIDEO_FONT_H + +#include <linux/types.h> + +struct font_desc { + int idx; + char *name; + int width, height; + void *data; + int pref; +}; + +#endif /* _VIDEO_FONT_H */ diff --git a/drivers/video/tgafb.h b/include/video/tgafb.h index 748d53fbd313..fbfae108a525 100644 --- a/drivers/video/tgafb.h +++ b/include/video/tgafb.h @@ -13,17 +13,17 @@ #ifndef TGAFB_H #define TGAFB_H - /* - * TGA hardware description (minimal) - */ +/* + * TGA hardware description (minimal) + */ #define TGA_TYPE_8PLANE 0 #define TGA_TYPE_24PLANE 1 #define TGA_TYPE_24PLUSZ 3 - /* - * Offsets within Memory Space - */ +/* + * Offsets within Memory Space + */ #define TGA_ROM_OFFSET 0x0000000 #define TGA_REGS_OFFSET 0x0100000 @@ -52,9 +52,9 @@ #define TGA_CMD_STAT_REG 0x01f8 - /* - * useful defines for managing the registers - */ +/* + * Useful defines for managing the registers + */ #define TGA_HORIZ_ODD 0x80000000 #define TGA_HORIZ_POLARITY 0x40000000 @@ -77,17 +77,17 @@ #define TGA_VALID_CURSOR 0x04 - /* - * useful defines for managing the ICS1562 PLL clock - */ +/* + * Useful defines for managing the ICS1562 PLL clock + */ #define TGA_PLL_BASE_FREQ 14318 /* .18 */ #define TGA_PLL_MAX_FREQ 230000 - /* - * useful defines for managing the BT485 on the 8-plane TGA - */ +/* + * Useful defines for managing the BT485 on the 8-plane TGA + */ #define BT485_READ_BIT 0x01 #define BT485_WRITE_BIT 0x00 @@ -111,9 +111,9 @@ #define BT485_CUR_HIGH_Y 0x1e - /* - * useful defines for managing the BT463 on the 24-plane TGAs - */ +/* + * Useful defines for managing the BT463 on the 24-plane TGAs + */ #define BT463_ADDR_LO 0x0 #define BT463_ADDR_HI 0x1 @@ -139,61 +139,72 @@ #define BT463_WINDOW_TYPE_BASE 0x0300 +/* + * The framebuffer driver private data. + */ - /* - * Macros for reading/writing TGA and RAMDAC registers - */ - -#define TGA_WRITE_REG(v,r) \ - { writel((v), fb_info.tga_regs_base+(r)); mb(); } - -#define TGA_READ_REG(r) readl(fb_info.tga_regs_base+(r)) - -#define BT485_WRITE(v,r) \ - TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG); \ - TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG); - -#define BT463_LOAD_ADDR(a) \ - TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \ - TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \ - TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \ - TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG); - -#define BT463_WRITE(m,a,v) \ - BT463_LOAD_ADDR((a)); \ - TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \ - TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG); - - - /* - * This structure describes the board. - */ - -struct tgafb_info { - /* Use the generic framebuffer ops */ - struct fb_info_gen gen; - - /* Device dependent information */ - u8 tga_type; /* TGA_TYPE_XXX */ - u8 tga_chip_rev; /* dc21030 revision */ - u64 tga_mem_base; - u64 tga_fb_base; - u64 tga_regs_base; - struct fb_var_screeninfo default_var; /* default video mode */ +struct tga_par { + /* PCI device. */ + struct pci_dev *pdev; + + /* Device dependent information. */ + void *tga_mem_base; + void *tga_fb_base; + void *tga_regs_base; + u8 tga_type; /* TGA_TYPE_XXX */ + u8 tga_chip_rev; /* dc21030 revision */ + + /* Remember blank mode. */ + u8 vesa_blanked; + + /* Define the video mode. */ + u32 xres, yres; /* resolution in pixels */ + u32 htimings; /* horizontal timing register */ + u32 vtimings; /* vertical timing register */ + u32 pll_freq; /* pixclock in mhz */ + u32 bits_per_pixel; /* bits per pixel */ + u32 sync_on_green; /* set if sync is on green */ }; - /* - * This structure uniquely defines a video mode. - */ +/* + * Macros for reading/writing TGA and RAMDAC registers + */ -struct tgafb_par { - u32 xres, yres; /* resolution in pixels */ - u32 htimings; /* horizontal timing register */ - u32 vtimings; /* vertical timing register */ - u32 pll_freq; /* pixclock in mhz */ - u32 bits_per_pixel; /* bits per pixel */ - u32 sync_on_green; /* set if sync is on green */ -}; +static inline void +TGA_WRITE_REG(struct tga_par *par, u32 v, u32 r) +{ + writel(v, par->tga_regs_base +r); +} + +static inline u32 +TGA_READ_REG(struct tga_par *par, u32 r) +{ + return readl(par->tga_regs_base +r); +} + +static inline void +BT485_WRITE(struct tga_par *par, u8 v, u8 r) +{ + TGA_WRITE_REG(par, r, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(par, v | (r << 8), TGA_RAMDAC_REG); +} + +static inline void +BT463_LOAD_ADDR(struct tga_par *par, u16 a) +{ + TGA_WRITE_REG(par, BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(par, (BT463_ADDR_LO<<10) | (a & 0xff), TGA_RAMDAC_REG); + TGA_WRITE_REG(par, BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(par, (BT463_ADDR_HI<<10) | (a >> 8), TGA_RAMDAC_REG); +} + +static inline void +BT463_WRITE(struct tga_par *par, u32 m, u16 a, u8 v) +{ + BT463_LOAD_ADDR(par, a); + TGA_WRITE_REG(par, m << 2, TGA_RAMDAC_SETUP_REG); + TGA_WRITE_REG(par, m << 10 | v, TGA_RAMDAC_REG); +} #endif /* TGAFB_H */ diff --git a/kernel/printk.c b/kernel/printk.c index cbe027aaf151..bb1bcb0d723f 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -638,7 +638,7 @@ void register_console(struct console * console) } if (console->flags & CON_PRINTBUFFER) { /* - * release_cosole_sem() will print out the buffered messages for us. + * release_console_sem() will print out the buffered messages for us. */ spin_lock_irqsave(&logbuf_lock, flags); con_start = log_start; diff --git a/scripts/ver_linux b/scripts/ver_linux index edc3ec1f26a4..9fe09a9c7f94 100644 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -28,7 +28,7 @@ fdformat --version | awk -F\- '{print "util-linux ", $NF}' mount --version | awk -F\- '{print "mount ", $NF}' -insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}' +rmmod -V 2>&1 | awk 'NR==1 {print "module-init-tools ",$NF}' tune2fs 2>&1 | grep "^tune2fs" | sed 's/,//' | awk \ 'NR==1 {print "e2fsprogs ", $2}' |
